Log inRegister an accountBrowse CSDbHelp & documentationFacts & StatisticsThe forumsAvailable RSS-feeds on CSDbSupport CSDb Commodore 64 Scene Database
You are not logged in - nap
CSDb User Forums


Forums > C64 Coding > Stablising raster IRQ with DMA
2012-01-08 19:49
ChristopherJam

Registered: Aug 2004
Posts: 1359
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....
 
2014-01-12 08:57
Flavioweb

Registered: Nov 2011
Posts: 442
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.
2014-01-12 09:01
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).
2014-01-12 09:34
Flavioweb

Registered: Nov 2011
Posts: 442
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 +)
2014-01-12 09:55
tlr

Registered: Sep 2003
Posts: 1701
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.
2014-01-12 11:49
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.
2014-01-12 21:45
Rastah Bar

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.
2014-01-13 13:26
algorithm

Registered: May 2002
Posts: 702
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?
2014-01-13 14:02
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 :-)
2014-01-14 21:50
zscs

Registered: Sep 2010
Posts: 45
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
2014-01-15 12:31
Rastah Bar

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
RefreshSubscribe to this thread:

You need to be logged in to post in the forum.

Search the forum:
Search   for   in  
All times are CET.
Search CSDb
Advanced
Users Online
Mason/Unicess
Guests online: 359
Top Demos
1 Next Level  (9.8)
2 Mojo  (9.7)
3 Coma Light 13  (9.7)
4 Edge of Disgrace  (9.6)
5 No Bounds  (9.6)
6 Comaland 100%  (9.6)
7 Uncensored  (9.6)
8 The Ghost  (9.6)
9 Wonderland XIV  (9.6)
10 Bromance  (9.6)
Top onefile Demos
1 Party Elk 2  (9.7)
2 Cubic Dream  (9.6)
3 Copper Booze  (9.5)
4 Rainbow Connection  (9.5)
5 TRSAC, Gabber & Pebe..  (9.5)
6 Onscreen 5k  (9.5)
7 Dawnfall V1.1  (9.5)
8 Quadrants  (9.5)
9 Daah, Those Acid Pil..  (9.5)
10 Birth of a Flower  (9.5)
Top Groups
1 Booze Design  (9.3)
2 Nostalgia  (9.3)
3 Oxyron  (9.3)
4 Censor Design  (9.3)
5 Crest  (9.3)
Top Crackers
1 Mr. Z  (9.9)
2 S!R  (9.9)
3 Mr Zero Page  (9.8)
4 Antitrack  (9.8)
5 OTD  (9.8)

Home - Disclaimer
Copyright © No Name 2001-2024
Page generated in: 0.055 sec.