;******************************************************************************* ;* Module : DELAYMS.SUB ;* Programmer: Tony Papadimitriou <tonyp@acm.org> ;* Purpose : Hard delay D msec, regardless of system clock ;* Language : Motorola/Freescale/NXP 68HC11 Assembly Language (aspisys.com/ASM11) ;* Status : FREEWARE Copyright (c) 2020 by Tony Papadimitriou <tonyp@acm.org> ;* Note(s) : Use: #Include delayms.sub ;* : ;* : The default version allows to get any msec delay upto 65535 msec ;* : using a fixed bus speed defined at assembly time. ;* : ;* : The number of msec is passed in RegD. (Zero returns immediately.) ;* : ;* : An alternate version is possible by using the conditional ANY_BUS ;* : When ANY_BUS is undefined, the fixed BUS_KHZ value is used. ;* : However, when the conditional ANY_BUS is defined, a second ;* : parameter is required in RegX, which holds the number of cycles ;* : that represent a single millisecond. This is useful for programs ;* : that dynamically change the bus clock speed for different parts ;* : of the program. This one routine can accommodate all delays upto ;* : 65535 msec with extreme accuracy for any bus speed upto 65535 KHz. ;* : ;* : Example calls: ;* : ldd #MSEC ;number of milliseconds ;* : jsr DelayMS ;* : ;* : ldd #MSEC ;number of milliseconds ;* : ldx #BUS_KHZ ;(assemble w/ cond. ANY_BUS) ;* : jsr DelayMS ;* : ;* History : 10.01.17 v1.00 Original ;* : 18.06.10 Added #spauto for easier local variable manipulation ;* : Minor X->Y optimization by moving TSX up one instruction [-1 byte] ;******************************************************************************* #ifmain ;----------------------------------------------------------------------- #ListOff #Uses mcu.inc #ListOn #ROM Start proc lds #STACKTOP clrd ;(to keep simulator happy) clrx ; -//- clry ; -//- ldd #1000 ;sample delay = 1000 msec #ifdef ANY_BUS ldx #4000 ;sample bus = 4MHz (=4000 KHz) #endif bsr DelayMS bra * @vector Vreset,Start end :s19crc #ROM #endif ;------------------------------------------------------------------------ ;******************************************************************************* ; Purpose: Delay upto 65535 msec ; Input : D = number of milliseconds (zero returns immediately) ; : X = number of cycles that represent a msec for current bus speed ; Output : None ; Note(s): X parameter is only required if assembled with conditional ANY_BUS DelayMS macro [#]msec[,[#]BUS_KHZ] mreq 1:[#]msec - number of milliseconds to delay #ifdef ANY_BUS mreq 2:[#]BUS_KHZ - current bus speed in KHz #endif ldd ~1~ ;number of milliseconds #ifparm ~2~ ldx ~2~ ;;(if assembled w/ cond. ANY_BUS) #endif jsr ~0~ endm ;------------------------------------------------------------------------------- #spauto #Cycles ;reset the cycle counter DelayMS proc cmpd #0 jeq Done@@ ;nothing to do, get out pshy pshx user_x@@ pshb user_b@@ psha user_a@@ #ais getx #4 ;allocate local variables burn_cycles@@ equ ::,4 ;32-bit cycle total tsy ;multiply 1ms cycles by number of requested msec [D*BUS_KHZ] #ifdef ANY_BUS #Message DelayMS requires as parm in X the bus KHz lda user_x@@+1,spx #else lda #[BUS_KHZ #endif ldb user_b@@,spx mul std burn_cycles@@+2,spx clrd std burn_cycles@@,spx #ifdef ANY_BUS lda user_x@@,spx #else lda #]BUS_KHZ #endif ldb user_b@@,spx mul addd burn_cycles@@+1,spx std burn_cycles@@+1,spx clra adca burn_cycles@@,spx sta burn_cycles@@,spx #ifdef ANY_BUS lda user_x@@+1,spx #else lda #[BUS_KHZ #endif ldb user_a@@,spx mul addd burn_cycles@@+1,spx std burn_cycles@@+1,spx clra adca burn_cycles@@,spx sta burn_cycles@@,spx #ifdef ANY_BUS lda user_x@@,spx #else lda #]BUS_KHZ #endif ldb user_a@@,spx mul addd burn_cycles@@,spx std burn_cycles@@,spx ;subtract the overhead cycles ldd burn_cycles@@+2,spx subd #ExtraCycles@@ std burn_cycles@@+2,spx ldd burn_cycles@@,spx sbcb #0 sbca #0 std burn_cycles@@,spx ;divide total burn cycles by loop cycles clra ldb burn_cycles@@,spx ldx #LoopCycles@@ ;divisor idiv ;D/X -> X,D xgdx stb burn_cycles@@,spy xgdx tba ldb burn_cycles@@+1,spy ldx #LoopCycles@@ ;divisor idiv ;D/X -> X,D xgdx stb burn_cycles@@+1,spy xgdx tba ldb burn_cycles@@+2,spy ldx #LoopCycles@@ ;divisor idiv ;D/X -> X,D xgdx stb burn_cycles@@+2,spy xgdx tba ldb burn_cycles@@+3,spy ldx #LoopCycles@@ ;divisor idiv ;D/X -> X,D xgdx tsx ;X -> stack frame stb burn_cycles@@+3,spx ExtraCycles@@ equ :cycles Loop@@ ldd burn_cycles@@+2,spx decd std burn_cycles@@+2,spx ldd burn_cycles@@,spx sbcb #0 sbca #0 std burn_cycles@@,spx @cop ;in case of many iterations lda burn_cycles@@,spx ora burn_cycles@@+1,spx ora burn_cycles@@+2,spx ora burn_cycles@@+3,spx bne Loop@@ ;repeat for all cycles LoopCycles@@ equ :cycles givex #:ais ;de-allocate local variables pull Done@@ rts ExtraCycles@@ set ExtraCycles@@+:cycles #sp ;******************************************************************************* #Exit ;******************************************************************************* #Message Size: {*-DelayMS} bytes