[A83] Detecting clock frequency


[Prev][Next][Index][Thread]

[A83] Detecting clock frequency




Hi!

I'm new to this list, so I don't know if anyone has tried this before,
but I wrote a routine to attempt to detect the CPU clock frequency.

It works by sending a command to the LCD driver, and then counting how
many T-states elapse before the driver becomes ready to accept another
command. Since the driver will (hopefully) take about the same amount of
time to recover regardless of the clock speed (about 4us - 9us by my
calculations), this should provide a reasonably accurate reference for
calculating clock speed.

The acutal timing is done by copying code to APPBACKUPSCREEN to output a
command, and then test the busy bit of the LCD driver. Each time the LCD
is busy, a NOP instruction is inserted in between the output and the
busy test, and the test is tried again. The number of NOP's required (at
4 T-states each) to create a sufficient delay, plus about 7 T-states
overhead gives a fairly good delay timing. I do the complete test 256
times and take the average, just to be sure.

Unfornunately, since I own only a standard 83+, I have no way of
checking it works across all calcs (although it does report ~6Mhz for my
calc).

It would be greatly appreciated if anybody would try this code on their
calcs, especially owners of SE or over-clocked calcs.

Thanks for any help!

------ Code begins here -------

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Driver program for TestCPUFrequency
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

        call    TestCPUFrequency
        ei
        bcall(_GrBufClr)
        ld      bc, $0000
        ld      (penCol), bc
        ld      hl, txt_frequency
        bcall(_VPutS)
        ld      a, 4
        bcall(_DispOP1A)
        ld      hl, txt_mhz
        bcall(_VPutS)
        ld      bc, $1000
        ld      (penCol), bc
        ld      hl, txt_done
        bcall(_VPutS)
        bcall(_GetKey)
        ret
txt_frequency:  .db "CPU Frequency: ", 0
txt_mhz:        .db "Mhz", 0
txt_done:       .db "Press any key to continue...", 0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; End of driver program
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;





;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; Define T6A04_6MHZ_DELAY to be the number of T-states required to
provide
;; the average case delay between sending commands to the T6A04 LCD
driver.
;;
;; Accoring to T6A04 specs, the required delay (T) for the TI calcs
should be
;; 4.65us <= T <= 9.30us. If we take the mean value of 6.975us, this
gives us
;; approximately 42 T-states on a 6Mhz processor.
;;
;; Coincidently, 42 also happens to be the answer to the meaning of
life, the
;; universe and everything ;)

#define T6A04_6MHZ_DELAY        42


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;
;; TestCPUFrequency:
;;
;; This routine estimates the clock frequency of the CPU by taking the
;; average number of T-states spent waiting for the LCD driver to become

;; ready in response to a command over 256 iterations.
;;
;; Interrupts are disables by this routine. You must re-enable them
youself.
;;
;; INPUTS:
;;  none
;;
;; OUTPUTS:
;;  OP1 - Estimated clock frequency in Mhz
;;
;; DESTROYED:
;;  AF, BC, DE, HL, OP2, APPBACKUPSCREEN
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

TestCPUFrequency:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ;; Disable interrupts, save original X/Y counter mode and set
some
        ;; counters to zero.
        di
        in      a, ($10)
        and     $03
        push    af
        xor     a
        ld      h, a
        ld      l, a

_LCDTestLoop:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ;; At the beginning of each loop, save the loop counter (A) and
total
        ;; NOP count (HL). Then copy the initial LCD timing code to
        ;; APPBACKUPSCREEN.
        push    af
        push    hl
        ld      hl, _LCDTimerCodeA
        ld      de, APPBACKUPSCREEN
        ld      bc, _LCDTimerCodeC - _LCDTimerCodeA
        ldir


_LCDTestWaitTime:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ;; Inside the timing loop. Call the timing code and insert an
extra
        ;; NOP instruction each time it fails until eventual success.
        call    APPBACKUPSCREEN
        jp      nc, _LCDWaitTimeOK
        push    bc
        ld      hl, _LCDTimerCodeC - _LCDTimerCodeA + APPBACKUPSCREEN
        add     hl, bc
        ex      de, hl
        ld      hl, _LCDTimerCodeC - _LCDTimerCodeA + APPBACKUPSCREEN -
1
        add     hl, bc
        ld      bc, _LCDTimerCodeC - _LCDTimerCodeB
        lddr
        inc     hl
        ld      (hl), $00
        pop     bc
        inc     bc
        jp      _LCDTestWaitTime

_LCDWaitTimeOK:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ;; Add the number of NOP's used in this loop (BC) to the total
count
        ;; (HL) and then loop again until we have performed 256 tests.
        pop     hl
        pop     af
        add     hl, bc
        dec     a
        jp      nz, _LCDTestLoop


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ;; Testing is complete. Restore original X/Y counter mode.
        pop     af
        or      $04
        out     ($10), a


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ;; Convert HL, an 8.8 fixed point number representing the
average
        ;; number of NOP instructions used, to an FP number in OP1.
        push    hl
        ld      h, 0
        bcall(_SetXXXXOP2)
        bcall(_OP2ToOP1)
        ld      hl, 256
        bcall(_SetXXXXOP2)
        bcall(_FPDiv)
        pop     hl
        ld      l, h
        ld      h, 0
        bcall(_SetXXXXOP2)
        bcall(_FPAdd)


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ;; Finally, calculate the estimated CPU clock frequency.
        ld      hl, 4                   ; each NOP instruction takes 4
        bcall(_SetXXXXOP2)              ; T-states.
        bcall(_FPMult)
        ld      hl, 7                   ; plus the overhead for the LCD
        bcall(_SetXXXXOP2)              ; status read.
        bcall(_FPAdd)
        ld      hl, 6                   ; our reference point is a 6Mhz
calc.
        bcall(_SetXXXXOP2)
        bcall(_FPMult)
        ld      hl, T6A04_6MHZ_DELAY    ; and then divide by the average
LCD
        bcall(_SetXXXXOP2)              ; delay.
        bcall(_FPDiv)
        ret


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
        ;; This code is copied to APPBACKUPSCREEN, with the NOP
instructions
        ;; inserted at _LCDTimerCodeB.
_LCDTimerCodeA:
        scf
        ld      a, $05
        out     ($10), a                ; output X auto-increment
command.
_LCDTimerCodeB:
        in      a, ($10)                ; read status byte
        rla                             ; rotate busy bit to carry
        ret
_LCDTimerCodeC:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; End of TestCPUFrequency
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;