Here's an untested
65C02 "
cycle-accurate" delay sub-system I'd like to use for serial protocol experiments. The minimum delay is 24 cycles and you can adjust the upper limit by changing the number of cycles used in the timing loop (the '
dloop' constant). Determine the loop size by multiplying the largest delay you require (in microseconds) by the clock (1, 2, 3, 4, 8, etc.) then divide by 65536. Use the integer result + 1 for the '
dloop' value.
Cheerful regards, Mike
Code:
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; file: serial_test.s ~
; author: Mike McLaren, K8LH ~
; date: 06-Nov-23 (last rev 09-Nov-23) ~
; ~
; ~
; asm: CA65 v2.13.3 ~
; ~
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.debuginfo +
.setcpu "65C02"
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; 65C02 delayCy() sub-system macro inserts 3 instructions ~
; and calls the 'uloop' 16-bit counter subroutine. ~
; ~
; 24 cycles minimum to dloop*65536+23 cycles maximum. ~
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.define cyc .byte $03 ; new 65C02 single-cycle opcode
clock := 8 ; 1, 2, 3, 4, 8, etc. (clock)
usecs := clock ; cycles/microsecond multiplier
msecs := clock*1000 ; cycles/millisecond multiplier
dloop := 13 ; timing loop size (minimum 9)
.macro delayCy cycles
.if (cycles < 24) || (cycles > dloop*65536+23)
.error "delayCy() range error"
.endif
lda #>(((cycles-24)/dloop)+1).mod 256 ; (2)
ldy #<(((cycles-24)/dloop)+1).mod 256 ; (2)
jsr uloop-((cycles-24).mod dloop) ; (6)
.endmac
.org $F000
;**************************************************************
; example delayCy() code
port_b := $6100
start:
delayCy(100*msecs) ; delay 100-msecs
test2:
delayCy(8*usecs-13) ; 8-usecs minus 13 cycles
lda port_b ; (4)
eor #%00000001 ; toggle b0 bit (2)
sta port_b ; precise 125-kHz intervals (4)
bra test2 ; (3)
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; 65C02 delayCy() sub-system 16-bit counter subroutine ~
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.repeat (dloop-1) ; insert all (cycles-24)%dloop
cyc ; single-cycle entry points
.endrep ;
; cyc ; (cycles-24)%dloop == 8 entry (1)
; cyc ; (cycles-24)%dloop == 7 entry (1)
; cyc ; (cycles-24)%dloop == 6 entry (1)
; cyc ; (cycles-24)%dloop == 5 entry (1)
; cyc ; (cycles-24)%dloop == 4 entry (1)
; cyc ; (cycles-24)%dloop == 3 entry (1)
; cyc ; (cycles-24)%dloop == 2 entry (1)
; cyc ; (cycles-24)%dloop == 1 entry (1)
uloop:
dey ; decrement 16-bit lo byte (2)
bne uloop-dloop+5 ; zero? no, branch, else (2)(3)
dec A ; decrement 16-bit hi byte (2)
bne uloop-dloop+9 ; zero? no, branch, else (2)(3)
rts ; exit (6)
;
; alternative: Bruce Clark's single-loop 16-bit counter
;
cpy #1 ; set or clear carry (2)
dey ; decrement lo byte (2)
sbc #0 ; decrement hi byte, or not (2)
bcs uloop-dloop+9 ; done? no, branch, else (2)(3)
rts ; exit (6)
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.segment "VECTS"
.org $FFFA
.word start ; NMI
.word start ; RESET
.word start ; IRQ