| |
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.... |
| |
Flavioweb
Registered: Nov 2011 Posts: 463 |
Dma trick to stabilize raster is more useful if used to start a cia timer (reverse counter method).
This avoid to care about idle gfx and screen display.
But is better for no background gfx with sprites over rasterbars (or sprites with open sideborder) parts. |
| |
Mace
Registered: May 2002 Posts: 1799 |
That's what I was trying to do: open borders (using d020 instead of d016, to find the sweet spot). |
| |
Flavioweb
Registered: Nov 2011 Posts: 463 |
I never tried it, but i remember some trick like
LDX #$0B
STA $D016,X
with in .A the color.
If executed with right timing it should open border and put color on screen...
But i have not really tried it...
It's done using a 6502 bug that read and discard value from base address before add .X and write to the dest address.
You can give a try +) |
| |
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 |
Previous - 1 | 2 | 3 | 4 | 5 - Next |