15th of March 2022 – Mystery continued!

(For the first part look at: 20th-of-february 2019)

This time it is: “If you wait a little – you will be faster!”
Actually it is exactly the same topic and the same phenomenon as described above, but this time viewed from another angle.

You remember, last time it was (see image):

The effect of the “open end” vectors seem to be caused by different reaction times of the ~RAMP signal and the ~BLANK signal.

The differences in the gaps “length” was due to different cycle values when entering the wait that finished every move or vector draw.

Interlude: How to Draw a line or Move to a position
Move to a position and drawing a line is actually exactly same same thing – nearly. The only difference is that with the one, you switch the light “ON” and with the other you switch the light “OFF”. So these two functionalities are programming wise nearly identical.

Each of those functions has the following:
a) setup before actually drawing:
set the time (scale) how long the movement should be done
b) give parameters to function:
set the strength (or speed) for the horizontal and vertical direction to move the “cursor” with (y,x position)
c) start move (or draw)
d) wait in a busy loop, till the time for movement has finished

Programming “tight” vectrex programs often times calls for optimization. One such optimization is to use the above busy loop for some additional calculations, that are certain to be finished before the time has run out. That way the busy loop has less time to be busy and the before “wasted” time is put to good use by doing some needed calculations.

Often time when coding I thus do not use the BIOS MoveTo_d function, but I use two macros instead, namely:
MY_MOVE_TO_D_START
and
MY_MOVE_TO_B_END

Both macros correspond to above mentioned sections c) and d).
I will not go further into the programming of those… except:

MY_MOVE_TO_B_END macro
   LDB #$40 ; [4]
waitLoop\?:
   BITB <VIA_int_flags ; [4]
   BEQ waitLoop\? ; [3]
endm


This is the busy loop. It waits till the sixth bit ($40) of the VIA interrupt flag register is set. This happens, when the timer T1 runs out, the timer contains the time (or scale) for how long the moving (drawing) should continue. Once the interrupt flag is set, the moving (drawing) is done – and the program leaves the busy loop and can continue.

In the following I will show with an example the strange effect this wait loop can have and how you can wait a little bit to gain some cycles :-).

For one reason or another I was trying out (again) to display a raster image, this I will use as an example, look at following image:

This is an image of text, with the complete height being 38 lines. For each line I position the cursor at the start of the line. In this special case these are 38 MoveTo_d, each with the same scale, the scale is $60.
This means each positioning takes $60 + x cycles to do (x being the time needed for above mentioned a) and b) ).
The MoveTo_d I realized with above two macro definitions to have them seperated.

The actual time I spent in the busy loop is more than $50 cycles, I am not discussing how to use these cycles now… but I’ll show a different effect.

Interlude, waiting!
Following macros I defined for exact wait cycles:

WAIT2 macro
   nop ; wait 2 cycles
endm
WAIT3 macro
   brn 0 ; wait 3 cycles
endm
WAIT4 macro
   WAIT2
   WAIT2
endm
WAIT5 macro
   WAIT3
   WAIT2
endm
WAIT6 macro
   tfr a,a ; wait 6 cycles
endm
WAIT7 macro
   WAIT5
   WAIT2
endm
WAIT8 macro
   WAIT6
   WAIT2
endm
WAIT9 macro
   WAIT6
   WAIT3
endm
WAIT10 macro
   WAIT6
   WAIT4
endm
WAIT11 macro
   WAIT8
   WAIT3
endm
WAIT12 macro
   pshs cc ; wait 12 cycles
   puls cc
endm

In a series of test runs, I added right befor the MY_MOVE_TO_B_END above defined wait macors. The overall execution cycle values are:

  • WAIT 0: 32205 cycles
  • WAIT 2: 32279 cycles
  • WAIT 3: 32316 cycles maximum
  • WAIT 4: 32094 cycles minimum
  • WAIT 5: 32131 cycles
  • WAIT 6: 32168 cycles
  • WAIT 7: 32205 cycles
  • WAIT 8: 32242 cycles
  • WAIT 9: 32279 cycles
  • WAIT 10: 32316 cycles
  • WAIT 11: 32094 cycles

You can see (as with the other mystery), that the values repeat after a 7 cycle gap, this is due to the fact, that the busy loop takes exactly 7 cycles per “round”.

The difference in cycles is due to the fact, that the actual compare to the interrupt flag is only done in ONE cycle, if the interrupt flag is set just after the compare… in the worst case you have to wait (waste) additional 6 cycles in order for you to actually REALIZE the interrupt flag was set!

Optimization

If you are crazy about optimization – you can use this knowledge to your advantage!

In many games following facts are common:

  • all (many) moves use the same scale
  • there are many objects on the screen
  • the cycles between
    MY_MOVE_TO_D_START
    and
    MY_MOVE_TO_B_END
    are fixed and not dynamic

If above is true you can with a simple test run (above wait macros) determin your own personal “best” wait, and save up to 6 cycles per move.

In a crowded game that might be 50 objects – meaning up to 300 cycles saved!

For a really tight optimization – this is a nice addition to cycles being saved… small things add up :-).

Tagged on: ,

3 thoughts on “15th of March 2022 – Mystery continued!

  1. Phillip Eaton

    Thanks for the observations and write up. I can imagine if you’re having to go that extra level to perform processing whilst doing moves, the code could get quite complex!

    For a regular BIOS MoveTo_d, would having a scale factor based on 7 also give an slight optimization? I’d to experiment to be sure, but I’m thinking it would.

    Perhaps you could consider adding a SmartList MoveTo_d-SF=7f (for example) generator that sets up everything for you. Currently I’ve rolled my own custom SmartList MoveTo_d for medium moves, but it’s currently a quick hack and I can’t remember how I did it or whether it’s optimal. 🙂

    1. Malban Post author

      No processing – a one time “manual” test and look at the cycle counter in Vide.

      I have not done any tests with MoveTo_D_7f, I don’t know if the current BIOS implementation uses the “best” WAIT scanario. Out of the blue -> I doubt it 🙂

      As long as the “MoveTo_d” Macros, the in between and the scale does not change the “WAIT” is a fixed values.
      I think this is quite often the case.

Leave a Reply to Malban Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.