Code: Select all
DIM code 511
:
ntsc=TRUE
:
cycles=&4243:line=17:phase=21:delay=21:pos=5
IF NOT ntsc THEN cycles=&5686:line=30:phase=88:delay=23:pos=1
:
aux_extbrd_1=&3C00
bck_intbrd_1=&3D00
aux_extbrd_2=&3E00
bck_intbrd_2=&3F00
:
FOR pass=4 TO 7 STEP 3
P%=&3B00:O%=code
[OPT pass
.Init
SEI
LDA #Server MOD 256:STA &0314
LDA #Server DIV 256:STA &0315
LDA #cycles MOD 256:STA &9124
LDY #line
.Init_00
CPY &9004:BNE Init_00:INY:INY
.Init_01
CPY &9004:BNE Init_01:JSR Init_06
INY:CPY &9004:BEQ Init_02:NOP:NOP
.Init_02
JSR Init_06:NOP
INY:CPY &9004:BEQ Init_03:BIT &24
.Init_03
JSR Init_06:NOP
INY:CPY &9004:BNE Init_04
.Init_04
LDX #pos
.Init_05
DEX:BNE Init_05
]
IF ntsc THEN [OPT pass:NOP:NOP:]
[OPT pass
LDA #cycles DIV 256:STA &9125
CLI
RTS
.Init_06
LDX #delay
.Init_07
DEX:BNE Init_07
]
IF NOT ntsc THEN [OPT pass:NOP:]
[OPT pass
RTS
.Server
CLD:SEC:LDA #phase:SBC &9124
CMP #10:BCC Server_00:JMP &EABF
.Server_00
STA Server_01+1
.Server_01
BCC Server_01
LDA #&A9
LDA #&A9
LDA #&A9
LDA #&A9
LDA #&A5
NOP
LDA &FB:PHA
LDX &900F
LDY #0
.Server_02
JMP Frame1
.Frame1
LDA &900E:EOR aux_extbrd_1,Y:AND #&0F:EOR aux_extbrd_1,Y:STA &FB
LDA aux_extbrd_1,Y:EOR bck_intbrd_1,Y:AND #&0F:STX &900F:EOR bck_intbrd_1,Y:TAX
LDA &FB:STA &900E:STX &900F:]:IF NOT ntsc THEN [OPT pass:CMP (&00,X):]
[OPT pass:LDA bck_intbrd_1,Y:STA &900F:NOP:INY:CPY #&C1:BCC Frame1
LDX #Frame2 MOD 256
LDY #Frame2 DIV 256
JMP Exit
.Frame2
LDA &900E:EOR aux_extbrd_2,Y:AND #&0F:EOR aux_extbrd_2,Y:STA &FB
LDA aux_extbrd_2,Y:EOR bck_intbrd_2,Y:AND #&0F:STX &900F:EOR bck_intbrd_2,Y:TAX
LDA &FB:STA &900E:STX &900F:]:IF NOT ntsc THEN [OPT pass:CMP (&00,X):]
[OPT pass:LDA bck_intbrd_2,Y:STA &900F:NOP:INY:CPY #&C1:BCC Frame2
LDX #Frame1 MOD 256
LDY #Frame1 DIV 256
.Exit
STX Server_02+1
STY Server_02+2
PLA:STA &FB
JMP &EABF
]
NEXT
This is not a PAL/NTSC issue. $9004 counts double raster lines. The lowest bit of the raster counter resides in $9003. For the positioning purposes during the init part, the double raster line precision is entirely sufficient.SparkyNZ wrote:So $9004 is the vertical beam position. Isn't there a high bit for the position, or is there only 256 lines due to the Vic'2 resolution? I know PAL has more scan lines than NTSC but I don't know the differences off hand.
The ".Init" part syncs a VIA timer to the electron beam, to a cycle exact position. Note the start value of $9004 (here 17) is parametrized and controls the vertical positioning. This first check for a value in $9004, in ".Init_00", is done to avoid a race condition. The next check in ".Init_01" results in a remaining uncertainty of 7 cycles for the horizontal position. The following checks of $9004 reduce that uncertainty to 3, 1 and 0 cycles, respectively. At ".Init_04", the routine sits on the electron beam and the delay at ".Init_05" does the horizontal positioning before starting the VIA timer.If I understand correctly, your code waits for line 17 and then 19. Is that to make sure that we're at the top of the display? Do you check 19 to make sure that it isn't wrapping around at near the bottom of the display for example?
The delay at ".Init_06" waits until the next change in $9004 is about due.Then I see there's a delay at Init_06.. and this is called a few times with ever increasing line values in Y.
You see these requirements here. I doubt the code can be made much more compact.[...] I am interested in knowing what the bare minimum requirements [...] for a stable raster routine [are.]
That is what interrupts are for.I am also wondering how tight-loop timing would work within a "game loop" too. A raster routine would need priority to display the right colours at the right time.. so would a game loop do other things once the raster has reached the bottom of the screen.. or reached a line where we don't care about register hacking/changing anymore?
Once the VIA timer has been synced, it triggers each frame at exactly the same vertical and horizontal position, which I defined in the example to suit the needs of the raster effect. However, the CPU itself has to finish the current instruction (and in very rare cases, also the next one!) before commencing the interrupt processing and this so-called "IRQ jitter" needs to be compensated once again. The example code does this at the beginning of the ".Server" part: the low byte of the VIA timer is read out at $9124 and then used to execute a variable "NOP slide" delay. After the final NOP instruction, the routine once again sits on the electron beam, everything else is just about counting cycles to place (colour) register changes at the intended positions.
Should the user intend to run other code with the interrupt, like a tracker routine, that can be appended after the raster effects part. Finally, the IRQ routine may set a workspace variable to inform the foreground process about the IRQ had taken place. The foreground process can then synchronize the animation by first clearing that workspace variable and then polling for it being set by the IRQ routine.