| |
ChristopherJam
Registered: Aug 2004 Posts: 1409 |
Stablising raster IRQ with DMA
I was a little surprised not to see this method on codebase64, as it's really quite old. It's most useful at the top of the screen, where you can do the DMA forcing in the border, but for that very reason I find it a useful prelude to (e.g.) line crunch and other HW scrolling techniques.
The concept's fairly simple; you start a character row above the visible area, set an interrupt for a subsequent non-badline, and force a DMA to absorb the unknown number of cycles between then and end-of-row. Set $d011 back to $1b, and the screen appears as normal!
A simple example:
#define poke(addr,val) .(:lda #val:sta addr:.)
#define doke(addr,val) .(:lda #<val:sta addr:lda #>val:sta addr+1:.)
#define endIRQ pla:tay:pla:tax:pla:rti
#define ackIRQ pha:lda $d019:sta $d019:txa:pha:tya:pha
*= $0801-2
.word *+2 ; load address
.byt $0b,$08,$0a,$00,$9e,$32,$30,$36,$31,0,0,0 ; 10 sys2061
main:
poke($d021,$04)
sta 646
lda#147
jsr $ffd2
poke($d021,0)
poke($0400,1) ;something to see
poke($0428,2)
jsr IRQstart
loop:
inc $7e7 ; a nice untidy main loop to ensure instability!
bpl loop
jmp loop
IRQstart
poke($dc0d,$7f) ; kill CIA irq
sei
poke($01, $35) ; disable ROM
poke($d01a,$01) ; enable VIC irq
poke($d011,$1b) ; clear high bit of irq rasterline
poke($d012,$32) ; last invisible line
doke($fffe,irq1 ) ; set irq vector
cli
rts
irq1:
ackIRQ
poke($d020,$0f) ; this is unstable!
poke($d011,$1a) ; force partial badline before screen starts
poke($d020,$0b) ; this is stable ^_^
poke($d011,$1b) ; trigger normal re-fetch of first row of chars
poke($d012,$ff) ; set end-of-screen irq
doke($fffe,irq2 )
endIRQ
irq2:
ackIRQ
;ensure first row of chars is already being displayed when badline forced by irq1
poke($d011,$18)
poke($d012,$32 )
doke($fffe,irq1 )
endIRQ
(build with Fachat's xa)
Does anyone know why this technique is so rarely mentioned?
|
|
... 37 posts hidden. Click here to view all posts.... |
| |
tlr
Registered: Sep 2003 Posts: 1790 |
The classic way assuming 8 sprites and no badlines is to do a 46 cycles/raster line loop including an inc $d016/dec $d016 (or vice versa). That will self stabilize after a few raster lines.
I'm guessing from your comment you want the screen open though. |
| |
Mace
Registered: May 2002 Posts: 1799 |
Okay, will try with some actual sprites on the screen and with a few more lines than just one. |
| |
Rastah Bar Account closed
Registered: Oct 2012 Posts: 336 |
Quote: Which is good enough for setting up the initial timer, THEN use the timer to jitter compensate at any raster line on any frame.
(i'd choose a 63 cycle timer though...)
For the sake of completeness: you can also use the sprite-to-sprite and sprite-to-background collision detection registers to find the exact position of the beam. E.g., put 8 1-byte-wide sprites next to each other on top of 8 characters at a suitable x-position. Let a raster interrupt occur, read $d01f and the number of bits set tells you were you are. Then use a timer to keep track. This method can handle 0-8 cycle jitter values. |
| |
algorithm
Registered: May 2002 Posts: 705 |
Is it not just easier to use the double IRQ method or polling (that would take more raster lines to stabilize) but no requirement for forcing badlines or placing sprites to stabilize? |
| |
Mace
Registered: May 2002 Posts: 1799 |
Algo, it's the other way around.
For me it's easier to use the double IRQ, but for education sake I was trying other methods :-) |
| |
zscs
Registered: Sep 2010 Posts: 49 |
Quote: For the sake of completeness: you can also use the sprite-to-sprite and sprite-to-background collision detection registers to find the exact position of the beam. E.g., put 8 1-byte-wide sprites next to each other on top of 8 characters at a suitable x-position. Let a raster interrupt occur, read $d01f and the number of bits set tells you were you are. Then use a timer to keep track. This method can handle 0-8 cycle jitter values.
Hm, interesting method. Sounds a bit overkill but I like the idea. :) Would be good to add an example to codebase64.org |
| |
Rastah Bar Account closed
Registered: Oct 2012 Posts: 336 |
I may do that. I can post some example code here and let people comment on it first.
;In the main routine:
sei
lda $d01f ;Clear sprite-to-background collision register.
...
;Place 1 byte wide sprites at suitable x-pos on 8 characters.
...
;Set up raster IRQ for first line where the sprites are
...
lda #$ff ; Turn sprites on.
sta $d015
cli
... ; rest of main routine
IRQ
lda $d01f ; read collision register
;Sprites must be placed such that $d01f equals either %00000000 or %10000000 or %11000000 or %11100000 ... or ... %11111111 depending on the jitter value.
; Now create 1 cycle extra delay for every zero bit
; (Caution: branches should not cross a page boundary)
asl
bcc *+2
asl
bcc *+2
asl
bcc *+2
asl
bcc *+2
asl
bcc *+2
asl
bcc *+2
asl
bcc *+2
asl
bcc *+2
...
;Set timer
;Turn sprites off
...
rti
This is a bit clumsy since the main routine shouldn't touch the sprites until synchronization has been achieved.
Therefore, in my code I did not use a raster interrupt but just waited in the main routine for $d01f to become unequal to zero:
sei
...
;Place sprites
...
lda $d01f ;Clear sprite-to-background collision register
lda #$ff ; Turn sprites on
sta $d015
lda $d01f ; Wait for nonzero collision bits
beq *-3 ;
;Add delay depending on number of zero bits
asl
bcc *+2
...
...
;Set timer
;Continue main program
cli
rts |
| |
Oswald
Registered: Apr 2002 Posts: 5094 |
innovative method, but using a CIA timer is much less trouble. You dont have to waste so much resources, and are free to use sprites, calculating cycles to waste is simpler aswell. |
| |
Rastah Bar Account closed
Registered: Oct 2012 Posts: 336 |
Not sure I understand you. I use $d01f only once to find the exact beam position, then I set a CIA timer that is used from then on to keep track of where the beam is. |
| |
enthusi
Registered: May 2004 Posts: 677 |
Nice, once you know xpos exactly you can even busy loop to the next start of the line anyway |
Previous - 1 | 2 | 3 | 4 | 5 - Next |