Stable Raster Interrupts

Basic and Machine Language

Moderator: Moderators

DrVeryEvil
Vic 20 Amateur
Posts: 69
Joined: Thu Jul 23, 2015 5:11 pm
Location: Lansing, MI, USA
Occupation: Data Analyst

Stable Raster Interrupts

Post by DrVeryEvil »

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? :?
User avatar
tokra
Vic 20 Scientist
Posts: 1120
Joined: Tue Apr 27, 2010 5:32 pm
Location: Scheessel, Germany

Re: Stable Raster Interrupts

Post by tokra »

Yes :-)

NOP = burn 2 cycles
BIT $xx = burn 3 cycles
DrVeryEvil
Vic 20 Amateur
Posts: 69
Joined: Thu Jul 23, 2015 5:11 pm
Location: Lansing, MI, USA
Occupation: Data Analyst

Re: Stable Raster Interrupts

Post by DrVeryEvil »

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.
User avatar
tokra
Vic 20 Scientist
Posts: 1120
Joined: Tue Apr 27, 2010 5:32 pm
Location: Scheessel, Germany

Re: Stable Raster Interrupts

Post by tokra »

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:

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
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.
DrVeryEvil
Vic 20 Amateur
Posts: 69
Joined: Thu Jul 23, 2015 5:11 pm
Location: Lansing, MI, USA
Occupation: Data Analyst

Re: Stable Raster Interrupts

Post by DrVeryEvil »

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.

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$ 
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. :lol:
DrVeryEvil
Vic 20 Amateur
Posts: 69
Joined: Thu Jul 23, 2015 5:11 pm
Location: Lansing, MI, USA
Occupation: Data Analyst

Re: Stable Raster Interrupts

Post by DrVeryEvil »

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?
User avatar
tokra
Vic 20 Scientist
Posts: 1120
Joined: Tue Apr 27, 2010 5:32 pm
Location: Scheessel, Germany

Re: Stable Raster Interrupts

Post by tokra »

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.
Kakemoms
Vic 20 Nerd
Posts: 740
Joined: Sun Feb 15, 2015 8:45 am

Re: Stable Raster Interrupts

Post by Kakemoms »

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.
FD22
Vic 20 Hobbyist
Posts: 148
Joined: Mon Feb 15, 2010 12:31 pm

Re: Stable Raster Interrupts

Post by FD22 »

User avatar
Mike
Herr VC
Posts: 4816
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Stable Raster Interrupts

Post by Mike »

DrVeryEvil wrote:

Code: Select all

[...]
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?
The answer lies in the bit of code you left out, namely before the sync loop you posted:

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.
groepaz
Vic 20 Scientist
Posts: 1180
Joined: Wed Aug 25, 2010 5:30 pm

Re: Stable Raster Interrupts

Post by groepaz »

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.
User avatar
Mike
Herr VC
Posts: 4816
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Stable Raster Interrupts

Post by Mike »

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. :mrgreen:
groepaz
Vic 20 Scientist
Posts: 1180
Joined: Wed Aug 25, 2010 5:30 pm

Re: Stable Raster Interrupts

Post by groepaz »

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.
I'm just a Software Guy who has no Idea how the Hardware works. Don't listen to me.
User avatar
tokra
Vic 20 Scientist
Posts: 1120
Joined: Tue Apr 27, 2010 5:32 pm
Location: Scheessel, Germany

Re: Stable Raster Interrupts

Post by tokra »

Yeah, that's pretty f*cked up. He explains it nicely here:

https://www.youtube.com/watch?v=po9IY5Kf0Mo#t=1021
User avatar
Mike
Herr VC
Posts: 4816
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Stable Raster Interrupts

Post by Mike »

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. :(
Post Reply