base:a_new_kind_of_hard-restart
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
base:a_new_kind_of_hard-restart [2015-05-11 20:20] – shrydar | base:a_new_kind_of_hard-restart [2015-05-23 17:18] (current) – shrydar | ||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== A new kind of hard-restart | ||
+ | By shrydar, with contributions from lft. | ||
+ | |||
+ | This article explains how to perform a stable hard-restart; | ||
+ | |||
+ | Back in 2011 I wanted to get the SID envelope generator into a known state to the cycle level, so I could then take some measurements of envelope behaviour. | ||
+ | |||
+ | Then in early April 2015, lft had a cunning plan. The first step was still to perform an OHR, as per my original. | ||
+ | |||
+ | The envelope overflow bug (where an attack triggered when env=$ff causes env to wrap back to $00) can then be used to bring the envelope back down. | ||
+ | |||
+ | |||
+ | The CPU intensive part of the process takes a mere ten raster lines. | ||
+ | |||
+ | The core implementation is included below; details of how the magic part works to follow in a future update. | ||
+ | |||
+ | < | ||
+ | ; | ||
+ | ; stabiliseRC3 | ||
+ | ; ; | ||
+ | ; place SID in a known state, with quiescent env3 and ADSR=0000 | ||
+ | ; ; | ||
+ | ; All DMA and interrupts must be disabled for the last 600 cycles | ||
+ | ; ; | ||
+ | ; | ||
+ | |||
+ | .align 256 | ||
+ | |||
+ | stabiliseRC3: | ||
+ | lda#$00 | ||
+ | sta v3AD | ||
+ | sta v3CR | ||
+ | lda#$f0 | ||
+ | sta v3SR | ||
+ | |||
+ | ldy# | ||
+ | ldx#128 | ||
+ | : dex | ||
+ | bne :- | ||
+ | dey | ||
+ | bpl :- | ||
+ | |||
+ | lda#$01 | ||
+ | sta v3CR ; start rise to $ff | ||
+ | |||
+ | ldx# | ||
+ | : dex | ||
+ | bne :- | ||
+ | : dex | ||
+ | bne :- | ||
+ | ; from this point on, timing is critical | ||
+ | lda#$02 | ||
+ | ldx#$01 | ||
+ | ldy#$00 | ||
+ | .repeat 7 ; here's where the magic happens. | ||
+ | sta | ||
+ | jsr wait20 | ||
+ | stx v3AD | ||
+ | nop | ||
+ | nop | ||
+ | sty v3AD | ||
+ | .endrep | ||
+ | sta v3AD | ||
+ | waitNy 18 ; wait 18 cycles (clobbers Y, as ncycles> | ||
+ | |||
+ | lda# | ||
+ | stx v3AD | ||
+ | sta v3AD | ||
+ | sta v3SR | ||
+ | ; rate counter should now be one of 9 different values that | ||
+ | ; are all equal modulo 9, in the range 0 to 99 | ||
+ | lda#$00 | ||
+ | sta v3CR ; ADSR=$4444, env=$ff, switching to release | ||
+ | |||
+ | waitNy 170 ; wait for env to drop to $fe | ||
+ | ldx# | ||
+ | stx v3CR ; we've now a few cycles grace before env reaches ff in which to switch ADSR to $40f0 | ||
+ | |||
+ | lda#$40 | ||
+ | sta v3AD | ||
+ | lda#$f0 | ||
+ | sta v3SR | ||
+ | waitNy 99 ; wait for the entire packet of potential values to be captured into the 9 cycle decay limit loop | ||
+ | ; now ADSR = 40f0, RC is synchronised, | ||
+ | |||
+ | lda #$11 ; next we need to force overflow | ||
+ | sta v3AD ; by switching to decay, then back to attack before env drops below $ff | ||
+ | lda# | ||
+ | sta v3SR | ||
+ | ldx #0 | ||
+ | stx v3CR ; drop into decay | ||
+ | |||
+ | ldx #1 | ||
+ | stx v3CR ; return to attack - this' | ||
+ | waitNy 5 | ||
+ | lda# | ||
+ | sta v3AD ; this write must be performed while RC<9, or we'll trigger the bug again. | ||
+ | sta v3SR | ||
+ | sta v3CR ; and drop back to release state | ||
+ | rts | ||
+ | |||
+ | wait20: | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | nop | ||
+ | rts | ||
+ | |||
+ | </ | ||
+ | |||
+ | Source for a full implementation and test harness may be found at {{: |