;*******************************************************************************
;* Module    : DELAYMS.SUB
;* Programmer: Tony Papadimitriou <tonyp@acm.org>
;* Purpose   : Hard delay A msec, regardless of CPU (HC08/9S08) or system clock
;* Language  : Motorola/Freescale/NXP HC08/9S08 Assembly Language (aspisys.com/ASM8)
;* Status    : FREEWARE Copyright (c) 2021 by Tony Papadimitriou <tonyp@acm.org>
;* Original  : http://www.aspisys.com/code/hc08/delayms.html
;* Note(s)   : Use: #Include delayms.sub
;*           :
;*           : The default version allows to get any msec delay upto 255 msec
;*           : using a fixed bus speed defined at assembly time.
;*           :
;*           : The number of msec is passed in RegA. (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 RegHX, 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
;*           : 255 msec with extreme accuracy for any bus speed upto 65535 KHz.
;*           :
;*           : Example calls:
;*           :                lda       #MSEC     ;number of milliseconds
;*           :                call      DelayMS
;*           :
;*           :                lda       #MSEC     ;number of milliseconds
;*           :                ldhx      #BUS_KHZ  ;(assemble w/ cond. ANY_BUS)
;*           :                call      DelayMS
;*           :
;* History   : 10.01.17 v1.00 Original
;*           : 10.03.26       Added #SPAUTO and :: and re-arranged stack vars
;*           : 10.03.28       Re-arranged stack vars and shortened overall size
;*           : 10.03.30       Further optimized for size
;*           : 10.03.31       Further optimized for size
;*           : 10.05.09       Further optimized for size and speed
;*           : 10.07.23       Better use of macros
;*           : 10.07.30       Minor optimization
;*           : 10.08.19       Added related macro
;*           : 10.10.19       Adapted to latest ASM8
;*           : 11.11.12       Minor optimization
;*           : 13.01.24       Removed #iftos (no code size gain in this case)
;*******************************************************************************

#ifmain ;-----------------------------------------------------------------------
HZ                  def       8000000
BDIV                def       1
                    #ListOff
                    #Uses     mcu.inc
                    #ListOn
#endif ;------------------------------------------------------------------------
?_OBJECT_?
;*******************************************************************************
; Purpose: Delay upto 255 msec
; Input  : A = number of milliseconds (zero returns immediately)
;        : HX = number of cycles that represent a msec for current bus speed
; Output : None
; Note(s): HX 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
                    #push
                    #spauto   :sp
          #ifparm ~2~
                    push
                    lda       ~1~
                    ldhx      ~2~
                    call      ~0~
                    pull
          #else
                    psha
                    lda       ~1~
                    call      ~0~
                    pula
          #endif
                    #pull
                    endm

;-------------------------------------------------------------------------------

                    #Cycles                       ;reset the cycle counter
                    #spauto

DelayMS             proc
                    cbeqa     #0,Done@@           ;nothing to do, get out

                    psha      msec@@
                    pshhx     msec_cycles@@
                    #ais

          ;multiply 1ms cycles by number of requested msec [A*BUS_KHZ]

          #ifdef ANY_BUS
                    #Message  DelayMS requires as parm in HX the bus KHz

                    ldx       msec_cycles@@+1,sp
          #else
                    ldx       #[BUS_KHZ
          #endif
                    mul
                    pshxa     burn_cycles@@       ;24-bit cycle total (LSW for now)

                    tsx
                    lda       msec@@,spx
          #ifdef ANY_BUS
                    ldx       msec_cycles@@,spx
          #else
                    ldx       #]BUS_KHZ
          #endif
                    mul
                    add       burn_cycles@@,sp
                    sta       burn_cycles@@,sp
                    txa
                    adc       #0
                    psha      burn_cycles@@,3     ;24-bit cycle total (full size)
          ;-------------------------------------- ;subtract the overhead cycles
                    tsx
                    @sub.s    burn_cycles@@,spx #EXTRACYCLES@@ burn_cycles@@,spx
          ;--------------------------------------
          ; divide total burn cycles by loop cycles
          ;--------------------------------------
                    @div.s    burn_cycles@@,sp #LOOPCYCLES@@

                    tsx

EXTRACYCLES@@       equ       :cycles

Loop@@              @sub.s    burn_cycles@@,spx #1 burn_cycles@@,spx
                    @cop                          ;in case of many iterations
                    @_tst_.s  burn_cycles@@,spx
                    bne       Loop@@              ;repeat for all cycles

LOOPCYCLES@@        equ       :cycles

                    ais       #:ais               ;de-allocate local variables
                    pull
Done@@              rtc

EXTRACYCLES@@       set       EXTRACYCLES@@+:cycles

                    #sp
;*******************************************************************************
                    #Exit
;*******************************************************************************
                    @EndStats

                    @cop      #save#

Start               proc
                    @rsp
                    clra
                    clrhx

          #ifdef ANY_BUS
                    @DelayMS  #10,#8000           ;sample bus = 8MHz (=8000 KHz)
          #else
                    @DelayMS  #10                 ;sample delay = 10 msec
          #endif
                    bra       *

                    @vector   Vreset,Start

                    end       :s19crc