Precisely timed loops in assembly
I'm looking for a way to make my code stop until the raster has reached the lower screen border (right after having drawn the last pixel line). I understand that I should HALT first to wait until the raster reaches the top of the screen, and then create a loop to wait until it has finished drawing the upper border and the main screen.
But sadly I don't know where to start :lol: What should I learn to know how much should I wait?
But sadly I don't know where to start :lol: What should I learn to know how much should I wait?
Post edited by na_th_an on
Comments
http://www.worldofspectrum.org/faq/reference/128kreference.htm
I've probably misunderstood (I usually do!) the question but won't this work? (well as you described really)
..and just manually increase the size of the loop until the border reaches the bottom?
Or will this work?
start in a,(255) cp 255 jr z,start ret ;exits when drawing the first attributeApologies in advance if I've missed the point :-)
Well, if you are mean, you might want to check my timing test program. There is quite a few tricks to learn in there, like the routine for waiting exactly the specified amount of T cycles, the way of measuring the frame duration, the way of measuring time taken by code executed at specified T cycle, or just the means of aligning your code with the interrupt precisely. Combined with the timing info for the known platforms (line duration, top/middle/bottom durations), this will allow you to wait for whatever you wish precisely.
OTOH, if you are not bothered by single T state accuracy, just tuning the delay loop for each desired target platform like R-Tape suggests is the easiest way to go.
Patrik
Trial and error. Make a big delay loop with a counter in BC, pluck a number out of the air, adjust it until you get the right result. For 95% of border tricks that's all you need - you only need to start counting instruction cycles for the complex stuff (like changing border colour at a specific horizontal point, or doing useful work in the gaps between lines).
(D'oh, how come I didn't think in using the border to measure? Aw, noob time!)
I take the clock timings from this list:
http://www.z80.info/z80code.txt
As Fikee has linked, timing varies between 48K, 128K, +2A (and Pentagon) machines, but you can determine which you're using fairly simply. In Buzzsaw+ I do a repeated write into contended memory, counting between two interrupts, to see if I'm on a Pentagon (which has no contention) or a real Speccy. Then look in the ROM to determine which Speccy. See the first two messages here (and try not to get dragged into reading the rest):
http://www.worldofspectrum.org/forums/showthread.php?t=24242
I also provide a user-selectable override for the game, as some silly buggers like to swap the ROMs around.
- IONIAN-GAMES.com -
This is for my crappy "fourspriter" routine. It's designed to be used from BASIC (or from ZX Basic using Boriel's compiler). It just did a halt at the beginning, and the proceeded to update the screen. The problem is that it took more than the time the ULA is drawing the top border section, so there was flickering on the top of the screen. As most games using "fourspriter" need a couple of extra "halt"s, I thought of changing one of those halts for a loop which just waited for the lower border. That way I had more time for "fourspriter": both the lower and the top borders.
I've implemented it successfully and now the flicker is gone :)
http://www.boriel.com/forum/how-to-tutorials/topic402.html?sid=04d227c3e31544a8daf532174f3a3b5b
SUB fspRedraw()
asm
halt
; Wait for scan line
LD BC,2120
fspRedrawloop:
DEC BC
LD A,B
OR C
JR NZ,fspRedrawloop