| |
ChristopherJam
Registered: Aug 2004 Posts: 1409 |
SID envelope rate counter phase alignment
<Post edited by moderator on 17/3-2020 08:25>
Continuing the discussion that forked off Lft's post about Avoiding the ADSR bug in the decay phase.
I've been refining the part of the SID envelope reset that gets the internal rate counter into one of a number of states that are all equal modulo 9. LFT's state table was highly informative, but I still couldn't quite see what I was doing, so I wrote a script to generate diagrams from rate counter limit sequences.
In each of the images below, the horizontal axis is time, and the vertical has a pixel set for each possible rate counter value at that time. They are colour coded with (rate counter - time)%9, so any potential values that are equal modulo nine show up as streams of equal colour. Horizontal pink bars show the counter limit values. All but the last two have had the tops cut off so we can focus on the interesting bit, but you can see the highest rate counter reached in the annotations above the images.
original: 567 cycles, highest rc is 535 (runlog)
This was the code I initially contributed to the discussion. It takes forever! Only harvesting a result every two cycles through the 32 rate limit is extraordinarily wasteful (slaps self). This image is half the scale of the others just to avoid it breaking the page format.
lft: 342 cycles, highest rc is 324 (runlog)
LFT's contribution. Vastly improved
lft_compacted: 279 cycles, highest rc is 261 (runlog)
I then compacted this a bit, by dropping a redundant nine cycles from each iteration.
sieve: 248 cycles, highest rc is 252 (runlog)
First attempt at a different approach. The single cycles at Attack=0 should be doable by using an INC instruction, but that relies on SID reading zero. Not sure if this is safe?
Only way it could be faster would be to use the 220 cycle limit for the stream that would otherwise require eight 32 cycle resets.
sieve2: 280 cycles, highest rc is 288 (runlog)
A safer sieve, that only uses 4 cycle writes. Downside of the sieve is it still lets the rate count get pretty high.
bottle: 280 cycles, highest rc is 99 (runlog)
LFT's comment about recapturing got me thinking. The next phase of the reset would run faster if we could bottle as many streams as possible into the 63 cycle limit (attack=2).
We can only manage seven of them, but that still brings down max rc by a factor of three!
bottle2: 280 cycles, highest rc is 90 (runlog)
..a slight reshuffle of the last couple of iterations, and we save enough cycles to use a rate limit of 95 for whatever comes next
bottle3: 375 cycles, highest rc is 72 (runlog)
This last one's definitely more of theoretical interest, but for another 95 cycles we can group all the possible states into a single tight packet.
The benefit of all of the above is less than I thought when I first set out, as it was only a day or two ago that I finally looked into the envelope overflow/underflow, and made sense of LFT's remarks about using env3=0xff; hence there's only a couple of loops required at a rate limit of 95, one to drop back down to env3=0xfe, and another to recapture at decay=0
I'd initially thought I was saving thousands of cycles as we rose from env3=0xee, but it's not to be. C'est la vie!
Still, onward to implementation; bottle2 should still save a few raster lines at the point in time that there's work to be done by CPU.
|
|
| |
Mixer
Registered: Apr 2008 Posts: 452 |
Table from the script source. This table is also at resid sources and quoted elsewhere.
Never figured out why following timing is calculated with 1.0Mhz instead of 985248, or whether it makes any difference, as it is the full cycles that count. Though there are some curious roundings.
rcp=[
9, # 2ms*1.0MHz/256 = 7.81 # rate 0
32, # 8ms*1.0MHz/256 = 31.25
63, # 16ms*1.0MHz/256 = 62.50 # rate 2
95, # 24ms*1.0MHz/256 = 93.75
149, # 38ms*1.0MHz/256 = 148.44 # rate 4
220, # 56ms*1.0MHz/256 = 218.75
267, # 68ms*1.0MHz/256 = 265.63 # rate 6
313, # 80ms*1.0MHz/256 = 312.50
392, # 100ms*1.0MHz/256 = 390.63 # rate 8
977, # 250ms*1.0MHz/256 = 976.56
1954, # 500ms*1.0MHz/256 = 1953.13
3126, # 800ms*1.0MHz/256 = 3125.00
3907, # 1 s*1.0MHz/256 = 3906.25
11720, # 3 s*1.0MHz/256 = 11718.75
19532, # 5 s*1.0MHz/256 = 19531.25
31251 # 8 s*1.0MHz/256 = 31250.00
]
Also, any thoughts on verifying "the method of getting to known state" with real sid(s)? Test/Measure. |
| |
ChristopherJam
Registered: Aug 2004 Posts: 1409 |
The counter limits have all been verified by both SID measurements and die photographs; I suspect the comments are just an attempt to see how they line up with the numbers from the datasheet.
As for verifying "the method of getting to known state", I implemented the one labelled "original" a few years back, and it works!
"bottle2" combined with LFT's epilogue I'll hopefully get to in a few days. I partly published the above just so I'd stop tinkering with graphs and get on with writing some actual code.. |
| |
lft
Registered: Jul 2007 Posts: 369 |
This is highly encouraging! Looking forward to the first actual implementation of Perfect Restart now. Keep up the good work! |
| |
Frantic
Registered: Mar 2003 Posts: 1648 |
In a way it is kinda funny how people/we still struggle to this day with the bugs in the sid that once came about in a period of rushed hardware development. :) |
| |
ChristopherJam
Registered: Aug 2004 Posts: 1409 |
Indeed. If only they'd loaded the limit value and compared to zero instead of the other way round, eh? |
| |
ChristopherJam
Registered: Aug 2004 Posts: 1409 |
OK, core of an implementation's now up at Codebase64 (cf A new kind of hard-restart )
Test harness attached, feedback welcome.
I just used bottle1 in the end; debugging the timing of the epilogue kept me more than busy enough. Thanks for all your help and encouragement, lft and Frantic! |
| |
Frantic
Registered: Mar 2003 Posts: 1648 |
Nothing less than a milestone! |
| |
Pex Mahoney Tufvesson
Registered: Sep 2003 Posts: 52 |
Cool! I love this! / Pex
---
Have a noise night!
http://mahoney.c64.org |
| |
Stainless Steel
Registered: Mar 2003 Posts: 966 |
Ok now everybody implement this into their player/editor (GLENN, GEIR!! SDI!!!) :D |
| |
Frantic
Registered: Mar 2003 Posts: 1648 |
Now I didn't analyze this in full detail yet but if I understand correctly the whole algorithm would have to be repeated 3 times (~30 raster lines) in order to perform this kind of stabilization on all three channels of the SID, right? I mean, that 63 cycle bottle isn't "wide" enough to allow stabilization of all three channels (or any combination of two channels) in the same loop, because there is not enough time to write to all three sid channels inside of it, right? If so, it would be cool to have a version of this thing that allows more than one channel to be stabilized at the same time. Should be possible to do that in less than ~30 lines, right? And best of all would of course be if it was possible to specify flexibly which of the three channels that should be stabilized... :) |
... 17 posts hidden. Click here to view all posts.... |
Previous - 1 | 2 | 3 - Next |