Stable Raster Interrupts
Moderator: Moderators
-
- Vic 20 Amateur
- Posts: 69
- Joined: Thu Jul 23, 2015 5:11 pm
- Location: Lansing, MI, USA
- Occupation: Data Analyst
Stable Raster Interrupts
I am looking at some code on how to make a stable raster interrupt on the VIC 20, Commodore Hacker #10, and was wondering if anyone can tell me the purpose of the BIT $24 in the code. Is that just a way to burn some cycles?
Re: Stable Raster Interrupts
Yes
NOP = burn 2 cycles
BIT $xx = burn 3 cycles
NOP = burn 2 cycles
BIT $xx = burn 3 cycles
-
- Vic 20 Amateur
- Posts: 69
- Joined: Thu Jul 23, 2015 5:11 pm
- Location: Lansing, MI, USA
- Occupation: Data Analyst
Re: Stable Raster Interrupts
Would it be more efficient to syncronise to the high bit of $9003? This could be done with a simple BIT$9003, instead of actually reading the register.
Re: Stable Raster Interrupts
Not if you want to sync to a specific rasterline. Unlike the C64 the high bit in $9003 is actually the lowest bit of the rasterline-counter, not the highest. So it switches after every rasterline.
Furthermore, regarding the raster-routine: it may be possible that the check for the first raster actually happens WHILE that rasterline is being displayed. Chances should be 1 in 131, but I noticed this behaviour in developing my graphic modes as well. Since then to be safe I do it like this:
Note: you must do the second check at least 2 values later (like here #$01 then #$03), since you may be at the very end of #$01 when you check and this could again lead to incorrect timing.
Furthermore, regarding the raster-routine: it may be possible that the check for the first raster actually happens WHILE that rasterline is being displayed. Chances should be 1 in 131, but I noticed this behaviour in developing my graphic modes as well. Since then to be safe I do it like this:
Code: Select all
ldy #$01 ; make sure next command really STARTS at line #$03 and not SOMEWHERE in it
raster0 cpy $9004
bne raster0
ldy #$03 ; wait for this raster line (times 2)
raster1 cpy $9004
bne raster1 ; at this stage, the inaccuracy is 7 clock cycles
-
- Vic 20 Amateur
- Posts: 69
- Joined: Thu Jul 23, 2015 5:11 pm
- Location: Lansing, MI, USA
- Occupation: Data Analyst
Re: Stable Raster Interrupts
I see the bit instruction is of no use in this, because the value needs to be stored for the compare that comes later, and that makes the code take up more bytes.
I am still curious why the bit instruction is needed after .Y is loaded with 9. There is no need to waste 3 cycles at that point, is there? In your code above, wouldn't there be 2 cycles added to the 7 for the last branch? Ok, scratch that last question.
Code: Select all
ldy #9
bit $24
1$ ldx $9004
txa
bit $24
bit $24
ldx #21
dex
bne *-1
cmp $9004
bcs *+2
dey
bne 1$
-
- Vic 20 Amateur
- Posts: 69
- Joined: Thu Jul 23, 2015 5:11 pm
- Location: Lansing, MI, USA
- Occupation: Data Analyst
Re: Stable Raster Interrupts
I have also found an error, I think, in the refresh rate calculation that Marko does, in claims that Commodore does not meet the video standard of the time. Marko gives 261 as the number of raster lines drawn by the NTSC 6560, which does give quite a bit of error on the refresh rate. I believe he is forgetting that the raster values in $9004 go from zero to 130, not one to 130. If you count zero to 130, you have 131 values. Multiply times two and you get 262. Then add one for the low bit value in $9003, gives you 263 raster lines. The NTSC standard used to be 262.5 lines, before high def digital TV. Even if the 6560 doesn't account for that half line, the calculation using 262 or 263 comes very close to a refresh rate of 60hz. Am I doing this correctly?
Re: Stable Raster Interrupts
No, you really do have only 261 lines in NTSC. Rasterlines 0-129 have two values each in $9003 (0 and 1), while rasterline 130 has only 0 in $9003 = 130*2+1=261 rasterlines.
In Interlace-mode you really have 525 rasterlines: Rasterlines 0-130 have two values each in $9003 for both half-frames = 524 lines. Plus you have rasterline 131 in one half-frame (forgot which) which has only 0 in $9003 for a total of 525 rasterlines. That means in NTSC-interlace you have to stabilize to line 131.
In Interlace-mode you really have 525 rasterlines: Rasterlines 0-130 have two values each in $9003 for both half-frames = 524 lines. Plus you have rasterline 131 in one half-frame (forgot which) which has only 0 in $9003 for a total of 525 rasterlines. That means in NTSC-interlace you have to stabilize to line 131.
Re: Stable Raster Interrupts
Yea, its quite confusing with respect to the 6561-101 not supporting interlaced either. This is a good source: http://tinyvga.com/6561
Chip 6560-101 6561-101
System NTSC-M PAL-B
Cycles/line 65 71
Lines/frame 261 312
- interlaced 525 N/A
Crystal 14318181 Hz 4433618 Hz
Bus clock crystal/14 crystal/4
Screen width 210 233
Screen height 233 284
So, like me, if you design for PAL-B and want to go to the other.. well, not really a good idea I guess.
Chip 6560-101 6561-101
System NTSC-M PAL-B
Cycles/line 65 71
Lines/frame 261 312
- interlaced 525 N/A
Crystal 14318181 Hz 4433618 Hz
Bus clock crystal/14 crystal/4
Screen width 210 233
Screen height 233 284
So, like me, if you design for PAL-B and want to go to the other.. well, not really a good idea I guess.
Re: Stable Raster Interrupts
This might be interesting for you: http://vicpp.blogspot.co.uk/2012/03/in- ... tions.html
- Mike
- Herr VC
- Posts: 4839
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: Stable Raster Interrupts
The answer lies in the bit of code you left out, namely before the sync loop you posted:DrVeryEvil wrote:I am still curious why the bit instruction is needed after .Y is loaded with 9. There is no need to waste 3 cycles at that point, is there?Code: Select all
[...]
At first, the start of a certain line is waited for in the way tokra already described: wait for (double-)line X-2, then wait for (double-)line X.
The raster register changes at one certain point during horizontal retrace. As long as the waited-for value doesn't appear, the wait loop has a jitter of 7 cycles: 4 because of the CMP instruction, 3 because of the branch when it is executed. The CMP instruction reads the register in its fourth cycle and compares it directly; on success the not executed branch needs 2 cycles. Now, depending on all of the preceding code ...
... you may be 'lucky', and just are spot on the transition (in 'cycle' 0), then BNE executes for cycles 1 and 2, and the instruction after BNE starts execution in cycle 3.
... or you have 'bad luck', and CMP just sees the value of the preceding (double-)line for the last time it's there (i.e., in 'cycle' -1) - then the loop executes BNE once in cycles 0, 1 and 2; another CMP (which succeeds) in cycles 3, 4, 5 and 6; and finally the non-executed BNE in cycles 7 and 8. Thus, the instruction after BNE starts in cycle 9.
Thats means, with the possible positions 3, 4, 5, 6, 7, 8 and 9 there are 7 different positions, where the simple wait loop can come out, and for this reason, this still isn't stable.
Now, the sync loop works by wasting 129 cycles per double-line (for NTSC), when CMP $9004 returns the value of the next double-line, and wasting 130 cycles per double-line when both LDX and CMP instructions return the same value. In the former case, the start of the loop clocks in one cycle earlier, and thus 'drifts' to the left. In the latter case, that iteration and all following ones are kept in lock with the raster beam.
The BIT instruction now makes sure this final sync loop doesn't already start too early with possibly matching LDX/CMP values! Ideally, the LDX load fetch and CMP compare fetch should be 129 cycles apart. But this isn't the case here, so the sync could report a false positive, when the LDX is little bit too far left. Rather a little more time is wasted (but not too much), to ensure there can't be a false positive. Then, within 9 iterations, the sync loop locks in.
...
The technique described here is mainly used to define a exact position to start the timer.
The interrupt processing itself requires another compensation, as it is only started when the current instruction has finished, which will introduce another jitter of up to 7 cycles. The interrupt service routine has then to execute a variable delay to counteract that jitter and have the rest of the ISR execute (once again) in sync with the raster beam. The low-byte of the timer is read to derive that variable delay.
Please take a look at the following threads for examples: VIC 20 in Black and White mode and ** New Frontiers in VIC-Hires-Graphics, Part 10. Actually, I use another technique for the initial sync, which uses a binary decision tree and syncs in faster, but needs more code.
Re: Stable Raster Interrupts
iirc marko makäla described all this stuff in much detail in some C=Hacking issue ("stable interrupts with auxiliary timer" or sth like that).
I'm just a Software Guy who has no Idea how the Hardware works. Don't listen to me.
- Mike
- Herr VC
- Posts: 4839
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: Stable Raster Interrupts
Well, yes. The OP referred to C= Hacking #10, indeed.
At the time I found that article (years ago), I actually couldn't make much sense of Marko's method. For this reason I devised my own method: as said, a binary decision tree, which syncs in faster. I also need only one timer. In the ISR, the compensation of the interrupt delay then is done by branching over a chain of LDA #$A9 instructions.
At the time I found that article (years ago), I actually couldn't make much sense of Marko's method. For this reason I devised my own method: as said, a binary decision tree, which syncs in faster. I also need only one timer. In the ISR, the compensation of the interrupt delay then is done by branching over a chain of LDA #$A9 instructions.
Re: Stable Raster Interrupts
ooops =)
my favourite became the "ninja method", which puts a jmp opcode into one (unused) CIA register and then jumps to it which automagically compensates for the interrupt delay. wastes 7 pages (or whatever amount of delay you need to compensate) though - not sure if it could be adapted to VIA too.
my favourite became the "ninja method", which puts a jmp opcode into one (unused) CIA register and then jumps to it which automagically compensates for the interrupt delay. wastes 7 pages (or whatever amount of delay you need to compensate) though - not sure if it could be adapted to VIA too.
I'm just a Software Guy who has no Idea how the Hardware works. Don't listen to me.
Re: Stable Raster Interrupts
Yeah, that's pretty f*cked up. He explains it nicely here:
https://www.youtube.com/watch?v=po9IY5Kf0Mo#t=1021
https://www.youtube.com/watch?v=po9IY5Kf0Mo#t=1021
- Mike
- Herr VC
- Posts: 4839
- Joined: Wed Dec 01, 2004 1:57 pm
- Location: Munich, Germany
- Occupation: electrical engineer
Re: Stable Raster Interrupts
Could go along: put $4C, $00 into $91x2, $91x3; let T1 count down from 71(-2) or 65(-2) so it repeats every raster, etc. - up to the point the read of T1-L as high-byte of the JMP instruction target auto-acknowledges the IRQ or NMI.
Unfortunately, the hardware interrupt vectors are fixed on the VIC-20. The standard NMI handler at $FEA9 is reasonably short (just a SEI - for whatever reason - and an indirect JMP), but the IRQ handler at $FF72 goes through the whole lengths to determine whether it was a BRK or a hardware interrupt.
Unfortunately, the hardware interrupt vectors are fixed on the VIC-20. The standard NMI handler at $FEA9 is reasonably short (just a SEI - for whatever reason - and an indirect JMP), but the IRQ handler at $FF72 goes through the whole lengths to determine whether it was a BRK or a hardware interrupt.