Precisely timed loops in assembly

edited February 2012 in Development
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?
Post edited by na_th_an on

Comments

  • edited February 2012
    double post hell
  • edited February 2012
    na_th_an wrote: »
    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?

    I've probably misunderstood (I usually do!) the question but won't this work? (well as you described really)
    halt  ;raster at tip
    ld a,4
    out (254),a
    big dec bc loop
    ld a,7
    out (254),a
    ret
    

    ..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 attribute
    

    Apologies in advance if I've missed the point :-)
  • edited February 2012
    na_th_an wrote: »
    But sadly I don't know where to start :lol: What should I learn to know how much should I wait?

    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
  • edited February 2012
    na_th_an wrote: »
    But sadly I don't know where to start :lol: What should I learn to know how much should I wait?

    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).
  • edited February 2012
    Awesome, that's the info I needed, thanks everyone!

    (D'oh, how come I didn't think in using the border to measure? Aw, noob time!)
  • edited February 2012
    I have a loop - I can't remember off the top of my head, but it's just a counter and a few NOPs - that takes exactly 32 T states to operate. So I know I need to do 7 loops for each line of the screen (assuming it's not running in contended memory).

    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.
    Joefish
    - IONIAN-GAMES.com -
  • edited February 2012
    Awesome stuff, thanks.

    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 :)
  • edited February 2012
    That's just what I did when I put fourspriter up in the forum a while back na_th_an:

    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
  • edited February 2012
    Lol - I just didn't notice :)
Sign In or Register to comment.