Timing how long something takes
Posted: Sun Dec 01, 2024 3:36 pm
Sometimes you want to know how long something takes to complete. While emulators generally do a good job of timing methods, they're not always accurate so there are times where you just have to check on the hardware.
If the function takes less than ~65k cycles you can use the VIA1 timer to time your function. We do this using the 'timer 1' within the 65c22. This timer can be set to start from a 16bit number and counts down to zero at the same rate as the CPU clock. At zero it can optionally fire an interrupt. So if we set this to $ffff, perform our function and then read the counter, we can determine how many CPU cycles have elapsed.
First we need to setup the VIA. We do this by writing `01` to the Timer 1 Control to put it in continuous but no interrupt. (PB7 is connected to the CPU's interrupt line, and we don't want that firing randomly!) This is on `V_ACR` ($9f0b)
Set the timer to start at $ffff by writing $ff to `V_T1L_L` ($9f06) and `V_T1L_H` ($9f07). Now when we write $ff to `V_T1_H` ($9f05) the counter will reset to $ffff and start counting down.
(Note: I'm not sure setting the `V_T1L_H` is necessary, as I think writing to V_T1_H sets the high latch value.)
Once the method has completed, the timer can be read from `V_T1_L` ($9f04) and `V_T1_H` ($9f05). Reading from the low register latches the counter's value so we don't have to worry about the ticks between reading low and high values.
Because there is some overhead on this process, I perform this function w/o any method to get the VIA test 'latency'. This will also correct for any VIA emulator timing issues.
After sampling a method remove the latency to get the time elapsed.
Example code performing this function:
Running the code we can see the correct value is displayed.
Of course this only works if the method will take less than ~64k CPU cycles. For longer calls you'll need to employ other methods.
If the function takes less than ~65k cycles you can use the VIA1 timer to time your function. We do this using the 'timer 1' within the 65c22. This timer can be set to start from a 16bit number and counts down to zero at the same rate as the CPU clock. At zero it can optionally fire an interrupt. So if we set this to $ffff, perform our function and then read the counter, we can determine how many CPU cycles have elapsed.
First we need to setup the VIA. We do this by writing `01` to the Timer 1 Control to put it in continuous but no interrupt. (PB7 is connected to the CPU's interrupt line, and we don't want that firing randomly!) This is on `V_ACR` ($9f0b)
Set the timer to start at $ffff by writing $ff to `V_T1L_L` ($9f06) and `V_T1L_H` ($9f07). Now when we write $ff to `V_T1_H` ($9f05) the counter will reset to $ffff and start counting down.
(Note: I'm not sure setting the `V_T1L_H` is necessary, as I think writing to V_T1_H sets the high latch value.)
Once the method has completed, the timer can be read from `V_T1_L` ($9f04) and `V_T1_H` ($9f05). Reading from the low register latches the counter's value so we don't have to worry about the ticks between reading low and high values.
Because there is some overhead on this process, I perform this function w/o any method to get the VIA test 'latency'. This will also correct for any VIA emulator timing issues.
After sampling a method remove the latency to get the time elapsed.
Example code performing this function:
Code: Select all
; we don't want interrupts firing which would mess up the timing
sei
; setup timer 1
lda V_ACR
and #$3f
ora #$40
sta V_ACR ; set to continuous
lda #$ff
sta V_T1L_L
sta V_T1L_H
; test VIA latency
lda #$ff
sta V_T1_H ; resets counter
; invert the value and store
clc
lda V_T1_L
eor #$ff
adc #1
sta via_latency
lda V_T1_H
eor #$ff
adc #0
sta via_latency + 1
lda #$ff
sta V_T1_H
lda $a000 ; test command, should be 4 cycles
; capture this sample
clc
lda V_T1_L
eor #$ff
adc #1
sta via_elapsed
lda V_T1_H
eor #$ff
adc #0
sta via_elapsed + 1
; take the latency off
sec
lda via_elapsed
sbc via_latency
sta via_elapsed
lda via_elapsed + 1
sbc via_latency + 1
sta via_elapsed + 1
; BitMagic macros to output text
NewLine();
Display("latency_display");
DisplayHex("via_latency", 4);
Display("elapsed_display");
DisplayHex("via_elapsed", 4);
.loop:
jmp -loop
.padvar ushort via_latency
.padvar ushort via_elapsed
.latency_display:
BM.Bytes(BM.StringToPetscii("VIA LATENCY : "));
.elapsed_display:
BM.Bytes(BM.StringToPetscii("ELAPSED : "));