Yesterday I was looking at some delay methods on the C64. On the 8-bit
PIC microcontrollers I used nested loops. They are easy to calculate
as the vast majority of the assembly instructions takes 1 cycle to
execute.
If you look for delays and timing on the C64 you'll find a lot about
timer IRQs and cycle exact timing. But I am not writing a game or a
demo, I just thought about how to delay 2s for example. I don't even
need an IRQ, busy waiting is just fine.
I found some texts about the jiffy clock or watching out for some
raster lines and so on. Of course I do not like endlessly searching
for information so I gave up after some time. I wanted to find some
easy examples which delay for an approximate (I don't need exact
timing right now) amount of time.
I saw an example where one CIA timer was loaded with 985248, which is
the number of clock cycles per second on a PAL system. So this gives
you a 1s delay. The other timer was then used to count the underflows
of the first one so that the delay can be extended to multiple
seconds. But why? I think there is an easier way.
As a note for myself here is what I came up with:
There are two CIA chips in the C64 each having 2 16-bit timers.
The IOINIT ($FDA3) Kernal routine initializes the CIAs. A part of
this routine initializes CIA #1 timer A beginning at address $FDDD.
The routine first checks the PAL/NTSC flag at $02A6 and sets the timer
A value accordingly. As a result timer A reaches zero and generates an
interrupt at about every 1/60 second on both systems. Timer A runs in
continuous mode and serves as the interrupt source for reading the
keyboard and flashing the cursor.
CIA #1 timer B is not used by the system and is able to count how many
times timer A gets to zero. So why not load timer B with 120 and set
it to count timer A underflows? This way I would get a near 2s delay,
wouldn't I?
It is still busy waiting as I have to check when timer B gets to zero,
but I don't need anything more complicated right now. There are a few
unused bytes between $02A7-$02FF, let's put this handful of
instructions here.
Source is tmpx syntax.
; CIA #1 registers
timblo = $dc06 ; CIA #1 timer B low byte
timbhi = $dc07 ; CIA #1 timer B high byte
ciacrb = $dc0f ; CIA #1 control register B
*=$02a8 ; SYS680
ldx #$00 ; $0078 -> timer B latch
stx timbhi
lda #120
sta timblo
; bit 0: start timer B
; bit 3: in one-shot mode
; bit 4: load the value from the latch
; bit 5-6: count timer A zeros
lda #%01011001
sta ciacrb
wait lda timblo
bne wait ; not 0 -> goto wait
rts
It's probably lame, but works.
And even using only the low byte of timer B you can have a delay
between 1/60s and 4.25s.