;*******************************************************************************
;* Module    : ASMCRC.SUB
;* Programmer: Tony Papadimitriou <tonyp@acm.org>
;* Purpose   : CRC Calculation
;* 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/asmcrc.html
;* History   : 10.12.09 v1.00 Original
;*           : 11.07.14       Minor change in test code
;*           : 11.11.11       Minor optimization in GetAsmCRC after MUL instruction
;*           : 16.08.01       BugFix: Moved @cop in GetAsmCRC before LDA ,X to
;*           :                avoid a potential problem of the CCR[Z] bit not
;*           :                corresponding to the LDA instruction
;*******************************************************************************

#ifmain ;-----------------------------------------------------------------------
;*******************************************************************************
; Test the CRC calculation routine
;*******************************************************************************

CRC_SEED            def       12345               ;example starting value

                    #ListOff
          #ifmmu
QE128
          #endif
                    #Uses     mcu.inc
                    #ListOn

                    #CRC      CRC_SEED

                    #ROM
?BEGIN_CRC

;*******************************************************************************

                    #spauto

Start               proc
                    @rsp

                    ldhx      #CRC_SEED
                    pshhx
                    ldhx      #?END_CRC
                    pshhx
                    ldhx      #?BEGIN_CRC
                    pshhx
                    call      GetAsmCRC           ;on exit, stack = CRC
                    ais       #4                  ;remove parms from stack
                    pulhx                         ;HX = CRC
?END_CRC            equ       *-1

                    #temp     :crc

Done                cphx      #:temp
                    beq       *
Error               bra       *

                    @vector   Vreset,Start

                    end       :s19crc
          #ifmmu
                    #SEG5
          #endif
#endif ;------------------------------------------------------------------------
?_OBJECT_?
;*******************************************************************************
; Purpose: Calculate the same user CRC as that produced by ASM8
; Input  : StackLo = StartAddress
;        : StackMd = EndAddress
;        : StackHi = Initial/Previous CRC
; Output : Stacked CRC updated
; Note(s): Call repeatedly for different address ranges, if skipping sections
; Call   :          ldhx      #CRC_SEED
;        :          pshhx
;        :          ldhx      #EndAddress
;        :          pshhx                         ;b
;        :          ldhx      #StartAddress
;        :          pshhx                         ;a
;        :          call      GetAsmCRC
;        :          ais       #4
;        :          pulhx                         ;HX = CRC
;        : --- OR (if using related macro) ---
;        :          @GetAsmCRC #StartAddress,#EndAddress,#CRC_SEED

GetAsmCRC           macro     [#]FromA,[#]ToB[,[#]CRC] ;CRC parm only for 1st call
                    mreq      1,2:[#]FromA,[#]ToB[,[#]CRC]
                    #push
                    #spauto   :sp
          #ifparm ~3~
                    ldhx      ~3~
                    pshhx
          #endif
                    #psp
                    ldhx      ~2~
                    pshhx
                    ldhx      ~1~
                    pshhx
                    call      ~0~
                    ais       #:psp
          #ifparm ~3~
                    pulhx                         ;HX = CRC
          #endif
                    #pull
                    endm

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

                    #spauto   :ab                 ;account for [RTS/RTC]

GetAsmCRC           proc
                    @parms    .a,.b,my_crc 2      ;define caller parameters
                    push
Loop@@
          #ifhcs
                    ldhx      .a@@,sp
                    cphx      .b@@,sp
          #else
                    tsx
                    @cmp.s    .a@@,spx .b@@,spx
                    lda       .a@@,spx
                    ldx       .a@@+1,spx
                    tah
          #endif
                    bhi       Done@@

                    @cop                          ;in case of many iterations

                    lda       ,x
                    beq       Skip@@              ;all zeros or ...
                    cbeqa     #$FF,Skip@@         ;... all ones are ignored

                    mul                           ;low address with data byte
                    pshx
                    tsx
                    add       my_crc@@+1,spx
                    sta       my_crc@@+1,spx
                    pula
                    adc       my_crc@@,spx
                    sta       my_crc@@,spx
          #ifhcs
                    ldhx      .a@@,sp
          #else
                    tsx
                    lda       .a@@,spx
                    ldx       .a@@+1,spx
                    tah
          #endif
                    lda       ,x
                    thx
                    mul                           ;high address with data byte
                    tsx
                    add       my_crc@@,spx
                    sta       my_crc@@,spx

Skip@@              tsx
                    @inc.s    .a@@,spx Loop@@
                    bra       Loop@@

Done@@              pull
                    rtc

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