General Information \\
Author: Andrew John Jacobs \\
Published: 1999 \\

This file contains a number of useful 6502
algorithms for number, string and memory
operations. The code is written in the form of
macros rather than subroutines to make them
more flexible.

The routines in the library assume that 16 and
32 bit numbers are represented in little endian
order, that is the least significant byte in
the lowest memory location, so that they can
be applied to addresses as well as pure
numbers.

The string routines assume that they are
working with null terminated 'C' style strings.

The main routines sacrifice code size for speed
and are coded without any iteration. Compact
versions which use iteration are provided for
some algorithms and have the same name as the
original routine with a 'C' suffix (eg. _XFR32
=> _XFR32C).

Some of the macros use 65SC02 instructions for
speed or to reduce the amount code generated if
the assembler will accept them.

Where possible the macros detect optimizable
cases and generate more efficient code.

Bugs & Enhancments:

If you find a bug I missed or have a new
routine you would like to submit to the library
then mail me at:

Andrew@obelisk.demon.co.uk

fount at [http://www.obelisk.demon.co.uk/6502/algorithms.html]

----

{{{
      NOLIST
;------------------------------------------------
; 6502 Standard Macro Library
;------------------------------------------------
; Copyright (C),1999 Andrew John Jacobs.
; All rights reserved.
;------------------------------------------------

;------------------------------------------------
; Revision History:
;
; 16-Aug-99 AJJ   Initial version.
;
; 14-Nov-01 AJJ Finally got around to filling in
;      some missing comments.
;
;------------------------------------------------

; Notes:
;
; This file contains a number of useful 6502
; algorithms for number, string and memory
; operations. The code is written in the form of
; macros rather than subroutines to make them
; more flexible.
;
; The routines in the library assume that 16 and
; 32 bit numbers are represented in little endian
; order, that is the least significant byte in
; the lowest memory location, so that they can
; be applied to addresses as well as pure
; numbers.
;
; The string routines assume that they are
; working with null terminated 'C' style strings.
;
; The main routines sacrifice code size for speed
; and are coded without any iteration. Compact
; versions which use iteration are provided for
; some algorithms and have the same name as the
; original routine with a 'C' suffix (eg. _XFR32
; => _XFR32C).
;
; Some of the macros use 65SC02 instructions for
; speed or to reduce the amount code generated if
; the assembler will accept them.
;
; Where possible the macros detect optimizable
; cases and generate more efficient code.
;
; Bugs & Enhancments:
;
; If you find a bug I missed or have a new
; routine you would like to submit to the library
; then mail me at:
;
; Andrew@obelisk.demon.co.uk

      PAGE
;------------------------------------------------
; Basic Operations
;------------------------------------------------

; Clear 2 bytes of memory at any location by
; setting it to zero. If 65SC02 instructions are
; available then STZ is used.
;
; On exit: A = ??, X & Y are unchanged.

      IF __65SC02__
_CLR16       MACRO MEM
       STZ MEM+0
       STZ MEM+1
       ENDM
      ELSE
_CLR16       MACRO MEM
       LDA #0
       STA MEM+0
       STA MEM+1
       ENDM
      ENDIF

; Clear 4 bytes of memory at any location by
; setting it to zero. If 65SC02 instructions are
; available then STZ is used.
;
; On exit: A = ??, X & Y are unchanged.

      IF __65SC02__
_CLR32       MACRO MEM
       STZ MEM+0
       STZ MEM+1
       STZ MEM+2
       STZ MEM+3
       ENDM
      ELSE
_CLR32       MACRO MEM
       LDA #0
       STA MEM+0
       STA MEM+1
       STA MEM+2
       STA MEM+3
       ENDM
      ENDIF

; Clear 4 bytes of memory at any location by
; setting it to zero iteratively. If 65SC02
; instructions are available then STZ is used.
;
; On exit: A = ??, X = $FF, Y is unchanged.

      IF __65SC02__
_CLR32C       MACRO MEM
       LDX #3
_LOOP\?       STZ MEM,X
       DEX
       BPL _LOOP\?
       ENDM
      ELSE
_CLR32C       MACRO MEM
       LDA #0
       LDX #3
_LOOP\?       STA MEM,X
       DEX
       BPL _LOOP\?
       ENDM
      ENDIF

; Transfer 2 bytes of memory from one location to
; another using the accumulator. The order in
; which the bytes are moved depends on the
; relative positions of SRC and DST. If SRC and
; DST are the same then no code is generated.
;
; On exit: A = ??, X & Y are unchanged.

_XFR16      MACRO SRC,DST
      IF SRC != DST
       IF SRC > DST
        LDA SRC+0
        STA DST+0
        LDA SRC+1
        STA DST+1
       ELSE
        LDA SRC+1
        STA DST+1
        LDA SRC+0
        STA DST+0
       ENDIF
      ENDIF
      ENDM

; Transfer 4 bytes of memory from one location to
; another using the accumulator. The order in
; which the bytes are moved depends on the
; relative positions of SRC and DST. If SRC and
; DST are the same then no code is generated.
;
; On exit: A = ??, X & Y are unchanged.

_XFR32      MACRO SRC,DST
      IF SRC != DST
       IF SRC > DST
        LDA SRC+0
        STA DST+0
        LDA SRC+1
        STA DST+1
        LDA SRC+2
        STA DST+2
        LDA SRC+3
        STA DST+3
       ELSE
        LDA SRC+3
        STA DST+3
        LDA SRC+2
        STA DST+2
        LDA SRC+1
        STA DST+1
        LDA SRC+0
        STA DST+0
       ENDIF
      ENDIF
      ENDM

; Transfer 4 bytes of memory from one location to
; another iteratively using the accumulator. The
; transfer may fail if SRC and DST overlap. If
; SRC and DST are the same then no code is
; generated.
;
; On exit: A = ??, X = $FF, Y is unchanged.

_XFR32C      MACRO SRC,DST
      IF SRC != DST
       LDX #3
_LOOP\?       LDA SRC,X
       STA DST,X
       DEX
       BPL _LOOP\?
      ENDIF
      ENDM

; Set the value of a 16 bit location DST with
; the given constant value.
;
; On exit: A = ??, X & Y unchanged.

_SET16I      MACRO NUM,DST
      IF NUM != 0
       LDA #LO NUM
       STA DST+0
       LDA #HI NUM
       STA DST+1
      ELSE
       _CLR16 DST
      ENDIF

      PAGE
;------------------------------------------------
; Logical Operations
;------------------------------------------------

; Calculate the logical NOT of the 16 bit value
; at location VLA and stores it in location RES.
;
; On exit: A = ??, X & Y are unchanged.

_NOT16      MACRO VLA,RES
      LDA VLA+0
      EOR #$FF
      STA RES+0
      LDA VLA+1
      EOR #$FF
      STA RES+1
      ENDM

; Calculate the logical NOT of the 32 bit value
; at location VLA and stores it in location RES.
;
; On exit: A = ??, X & Y are unchanged.

_NOT32      MACRO VLA,RES
      LDA VLA+0
      EOR #$FF
      STA RES+0
      LDA VLA+1
      EOR #$FF
      STA RES+1
      LDA VLA+2
      EOR #$FF
      STA RES+2
      LDA VLA+3
      EOR #$FF
      STA RES+3
      ENDM

; Calculate the logical NOT of the 32 bit value
; at location VLA iteratively and stores it in
; location RES.
;
; On exit: A = ??, X = $FF, Y are unchanged.

_NOT32C      MACRO VLA,RES
      LDX #3
_LOOP\?      LDA VLA,X
      EOR #$FF
      STA RES,X
      DEX
      BPL _LOOP\?
      ENDM

; Calculate the logical OR of the two 16 bit
; values at locations VLA and VLB. The result is
; stored in location RES. If VLA and VLB are the
; same the macro expands to a _XFR16.
;
; On exit: A = ??, X & Y are unchanged.

_ORA16      MACRO VLA,VLB,RES
      IF VLA != VLB
       LDA VLA+0
       ORA VLB+0
       STA RES+0
       LDA VLA+1
       ORA VLB+1
       STA RES+1
      ELSE
       _XFR16 VLA,RES
      ENDIF
      ENDM

; Calculate the logical OR of a 16 value at
; location VLA with a constant value and
; store the result at location RES.
;
; On exit: A = ??, X & Y are unchanged.

_ORA16I      MACRO VLA,NUM,RES
       LDA VLA+0
       ORA #LO NUM
       STA RES+0
       LDA VLA+1
       ORA #HI NUM
       STA RES+1
      ENDM

; Calculate the logical OR of the two 32 bit
; values at locations VLA and VLB. The result is
; stored in location RES. If VLA and VLB are the
; same the macro expands to a _XFR32.
;
; On exit: A = ??, X & Y are unchanged.

_ORA32      MACRO VLA,VLB,RES
      IF VLA != VLB
       LDA VLA+0
       ORA VLB+0
       STA RES+0
       LDA VLA+1
       ORA VLB+1
       STA RES+1
       LDA VLA+2
       ORA VLB+2
       STA RES+2
       LDA VLA+3
       ORA VLB+3
       STA RES+3
      ELSE
       _XFR32 VLA,RES
      ENDIF
      ENDM

; Calculate the logical OR of the two 32 bit
; values at locations VLA and VLB iteratively.
; The result is stored in location RES. If VLA
; and VLB are the same the macro expands to a
; _XFR32C.
;
; On exit: A = ??, X = $FF, Y is unchanged.

_ORA32C      MACRO VLA,VLB,RES
      IF VLA != VLB
       LDX #3
_LOOP\?       LDA VLA,X
       ORA VLB,X
       STA RES,X
       DEX
       BPL _LOOP\?
      ELSE
       _XFR32C VLA,RES
      ENDIF
      ENDM

; Calculate the logical AND of the two 16 bit
; values at locations VLA and VLB. The result is
; stored in location RES. If VLA and VLB are the
; same the macro expands to a _XFR16.
;
; On exit: A = ??, X & Y are unchanged.

_AND16      MACRO VLA,VLB,RES
      IF VLA != VLB
       LDA VLA+0
       AND VLB+0
       STA RES+0
       LDA VLA+1
       AND VLB+1
       STA RES+1
      ELSE
       _XFR16 VLA,RES
      ENDIF
      ENDM

; Calculate the logical AND of a 16 value at
; location VLA with a constant value and
; store the result at location RES.
;
; On exit: A = ??, X & Y are unchanged.

_AND16I      MACRO VLA,NUM,RES
       LDA VLA+0
       AND #LO NUM
       STA RES+0
       LDA VLA+1
       AND #HI NUM
       STA RES+1
      ENDM

; Calculate the logical AND of the two 32 bit
; values at locations VLA and VLB. The result is
; stored in location RES. If VLA and VLB are the
; same the macro expands to a _XFR32.
;
; On exit: A = ??, X & Y are unchanged.

_AND32      MACRO VLA,VLB,RES
      IF VLA != VLB
       LDA VLA+0
       AND VLB+0
       STA RES+0
       LDA VLA+1
       AND VLB+1
       STA RES+1
       LDA VLA+2
       AND VLB+2
       STA RES+2
       LDA VLA+3
       AND VLB+3
       STA RES+3
      ELSE
       _XFR32 VLA,RES
      ENDIF
      ENDM

; Calculate the logical AND of the two 32 bit
; values at locations VLA and VLB iteratively.
; The result is stored in location RES. If VLA
; and VLB are the same the macro expands to a
; _XFR32C.
;
; On exit: A = ??, X = $FF, Y is unchanged.

_AND32C      MACRO VLA,VLB,RES
      IF VLA != VLB
       LDX #3
_LOOP\?       LDA VLA,X
       AND VLB,X
       STA RES,X
       DEX
       BPL _LOOP\?
      ELSE
       _XFR32C VLA,RES
      ENDIF
      ENDM

; Calculate the exclusive OR of the two 16 bit
; values at locations VLA and VLB. The result is
; stored in location RES. If VLA and VLB are the
; same the macro expands to a _CLR16.
;
; On exit: A = ??, X & Y are unchanged.

_EOR16      MACRO VLA,VLB,RES
      IF VLA != VLB
       LDA VLA+0
       EOR VLB+0
       STA RES+0
       LDA VLA+1
       EOR VLB+1
       STA RES+1
      ELSE
       _CLR16 RES
      ENDIF
      ENDM

; Calculate the exclusive OR of a 16 value at
; location VLA with a constant value and
; store the result at location RES.
;
; On exit: A = ??, X & Y are unchanged.

_EOR16I      MACRO VLA,NUM,RES
       LDA VLA+0
       EOR #LO NUM
       STA RES+0
       LDA VLA+1
       EOR #HI NUM
       STA RES+1
      ENDM

; Calculate the exclusive OR of the two 32 bit
; values at locations VLA and VLB. The result is
; stored in location RES. If VLA and VLB are the
; same the macro expands to a _CLR32.
;
; On exit: A = ??, X & Y are unchanged.

_EOR32      MACRO VLA,VLB,RES
      IF VLA != VLB
       LDA VLA+0
       EOR VLB+0
       STA RES+0
       LDA VLA+1
       EOR VLB+1
       STA RES+1
       LDA VLA+2
       EOR VLB+2
       STA RES+2
       LDA VLA+3
       EOR VLB+3
       STA RES+3
      ELSE
       _CLR32 RES
      ENDIF
      ENDM

; Calculate the exclusive OR of the two 32 bit
; values at locations VLA and VLB iteratively.
; The result is stored in location RES. If VLA
; and VLB are the same the macro expands to a
; _XFR32C.
;
; On exit: A = ??, X = $FF, Y is unchanged.

_EOR32C      MACRO VLA,VLB,RES
      IF VLA != VLB
       LDX #3
_LOOP\?       LDA VLA,X
       EOR VLB,X
       STA RES,X
       DEX
       BPL _LOOP\?
      ELSE
       _CLR32C RES
      ENDIF
      ENDM

      PAGE
;------------------------------------------------
; Shift Operations
;------------------------------------------------

; Perform an arithmetic shift left on the 16 bit
; number at location VLA and store the result at
; location RES. If VLA and RES are the same then
; the operation is applied directly to the memory
; otherwise it is done in the accumulator.
;
; On exit: A = ??, X & Y are unchanged.

_ASL16      MACRO VLA,RES
      IF VLA != RES
       LDA VLA+0
       ASL A
       STA RES+0
       LDA VLA+1
       ROL A
       STA RES+1
      ELSE
       ASL VLA+0
       ROL VLA+1
      ENDIF
      ENDM

; Perform an arithmetic shift left on the 32 bit
; number at location VLA and store the result at
; location RES. If VLA and RES are the same then
; the operation is applied directly to the memory
; otherwise it is done in the accumulator.
;
; On exit: A = ??, X & Y are unchanged.

_ASL32      MACRO VLA,RES
      IF VLA != RES
       LDA VLA+0
       ASL A
       STA RES+0
       LDA VLA+1
       ROL A
       STA RES+1
       LDA VLA+2
       ROL A
       STA RES+2
       LDA VLA+3
       ROL A
       STA RES+3
      ELSE
       ASL VLA+0
       ROL VLA+1
       ROL VLA+2
       ROL VLA+3
      ENDIF
      ENDM

; Perform a left rotation on the 16 bit number at
; location VLA and store the result at location
; RES. If VLA and RES are the same then the
; operation is applied directly to the memory,
; otherwise it is done in the accumulator.
;
; On exit: A = ??, X & Y are unchanged.

_ROL16      MACRO VLA,RES
      IF VLA != RES
       LDA VLA+0
       ROL A
       STA RES+0
       LDA VLA+1
       ROL A
       STA RES+1
      ELSE
       ROL VLA+0
       ROL VLA+1
      ENDIF
      ENDM

; Perform a left rotation on the 32 bit number at
; location VLA and store the result at location
; RES. If VLA and RES are the same then the
; operation is applied directly to the memory,
; otherwise it is done in the accumulator.
;
; On exit: A = ??, X & Y are unchanged.

_ROL32      MACRO VLA,RES
      IF VLA != RES
       LDA VLA+0
       ROL A
       STA RES+0
       LDA VLA+1
       ROL A
       STA RES+1
       LDA VLA+2
       ROL A
       STA RES+2
       LDA VLA+3
       ROL A
       STA RES+3
      ELSE
       ROL VLA+0
       ROL VLA+1
       ROL VLA+2
       ROL VLA+3
      ENDIF
      ENDM

; Perform an logical shift right on the 16 bit
; number at location VLA and store the result at
; location RES. If VLA and RES are the same then
; the operation is applied directly to the memory
; otherwise it is done in the accumulator.
;
; On exit: A = ??, X & Y are unchanged.

_LSR16      MACRO VLA,RES
      IF VLA != RES
       LDA VLA+1
       LSR A
       STA RES+1
       LDA VLA+0
       ROR A
       STA RES+0
      ELSE
       LSR VLA+1
       ROR VLA+0
      ENDIF
      ENDM

; Perform an logical shift right on the 32 bit
; number at location VLA and store the result at
; location RES. If VLA and RES are the same then
; the operation is applied directly to the memory
; otherwise it is done in the accumulator.
;
; On exit: A = ??, X & Y are unchanged.

_LSR32      MACRO VLA,RES
      IF VLA != RES
       LDA VLA+3
       LSR A
       STA RES+3
       LDA VLA+2
       ROR A
       STA RES+2
       LDA VLA+1
       ROR A
       STA RES+1
       LDA VLA+0
       ROR A
       STA RES+0
      ELSE
       LSR VLA+3
       ROR VLA+2
       ROR VLA+1
       ROR VLA+0
      ENDIF
      ENDM

; Perform a right rotation on the 16 bit number
; at location VLA and store the result at
; location RES. If VLA and RES are the same then
; the operation is applied directly to the memory
; otherwise it is done in the accumulator.
;
; On exit: A = ??, X & Y are unchanged.

_ROR16      MACRO VLA,RES
      IF VLA != RES
       LDA VLA+1
       ROR A
       STA RES+1
       LDA VLA+0
       ROR A
       STA RES+0
      ELSE
       ROR VLA+1
       ROR VLA+0
      ENDIF
      ENDM

; Perform a right rotation on the 32 bit number
; at location VLA and store the result at
; location RES. If VLA and RES are the same then
; the operation is applied directly to the memory
; otherwise it is done in the accumulator.
;
; On exit: A = ??, X & Y are unchanged.

_ROR32      MACRO VLA,RES
      IF VLA != RES
       LDA VLA+3
       ROR A
       STA RES+3
       LDA VLA+2
       ROR A
       STA RES+2
       LDA VLA+1
       ROR A
       STA RES+1
       LDA VLA+0
       ROR A
       STA RES+0
      ELSE
       ROR VLA+3
       ROR VLA+2
       ROR VLA+1
       ROR VLA+0
      ENDIF
      ENDM

      PAGE
;------------------------------------------------
; Arithmetic Operations
;------------------------------------------------

; Increment the 16 bit value at location MEM
; by one.
;
; On exit: A, X & Y are unchanged.

_INC16      MACRO MEM
      INC MEM+0
      BNE _DONE\?
      INC MEM+1
_DONE\?      EQU *
      ENDM

; Increment the 32 bit value at location MEM
; by one.
;
; On exit: A, X & Y are unchanged.

_INC32      MACRO MEM
      INC MEM+0
      BNE _DONE\?
      INC MEM+1
      BNE _DONE\?
      INC MEM+2
      BNE _DONE\?
      INC MEM+3
_DONE\?      EQU *
      ENDM

; Decrement the 16 bit value at location MEM
; by one.
;
; On exit: A = ??, X & Y are unchanged.

_DEC16      MACRO MEM
      LDA MEM+0
      BNE _DONE\?
      DEC MEM+1
_DONE\?      DEC MEM+0
      ENDM

; Decrement the 32 bit value at location MEM
; by one.
;
; On exit: A = ??, X & Y are unchanged.

_DEC32      MACRO MEM
      LDA MEM+0
      BNE _DEC0\?
      LDA MEM+1
      BNE _DEC1\?
      LDA MEM+2
      BNE _DEC2\?
      DEC MEM+3
_DEC2\?      DEC MEM+2
_DEC1\?      DEC MEM+1
_DEC0\?      DEC MEM+0
      ENDM

; Add two 16 bit numbers together and store the
; result in another memory location. RES may be
; the same as either VLA or VLB.
;
; On exit: A = ??, X & Y are unchanged.

_ADD16      MACRO VLA,VLB,RES
      IF VLA != VLB
        CLC
        LDA VLA+0
       ADC VLB+0
       STA RES+0
       LDA VLA+1
       ADC VLB+1
       STA RES+1
      ELSE
       _ASL16 VLA,RES
      ENDIF
      ENDM

; Add two 32 bit numbers together and store the
; result in another memory location. RES may be
; the same as either VLA or VLB.
;
; On exit: A = ??, X & Y are unchanged.

_ADD32      MACRO VLA,VLB,RES
      IF VLA != VLB
       CLC
       LDA VLA+0
       ADC VLB+0
       STA RES+0
       LDA VLA+1
       ADC VLB+1
       STA RES+1
       LDA VLA+2
       ADC VLB+2
       STA RES+2
       LDA VLA+3
       ADC VLB+3
       STA RES+3
      ELSE
       _ASL32 VLA,RES
      ENDIF
      ENDM

; Subtract two 16 bit numbers and store the
; result in another memory location. RES may be
; the same as VLA or VLB.
;
; On exit: A = ??, X & Y are unchanged.

_SUB16      MACRO VLA,VLB,RES
      SEC
      LDA VLA+0
      SBC VLB+0
      STA RES+0
      LDA VLA+1
      SBC VLB+1
      STA RES+1
      ENDM

; Subtract two 32 bit numbers and store the
; result in another memory location. RES may be
; the same as VLA or VLB.
;
; On exit: A = ??, X & Y are unchanged.

_SUB32      MACRO VLA,VLB,RES
      SEC
      LDA VLA+0
      SBC VLB+0
      STA RES+0
      LDA VLA+1
      SBC VLB+1
      STA RES+1
      LDA VLA+2
      SBC VLB+2
      STA RES+2
      LDA VLA+3
      SBC VLB+3
      STA RES+3
      ENDM

; Negate the signed 16 bit number at location VLA
; and stored the result at location RES. RES may
; be the same as VLA.
;
; On exit: A = ??, X & Y are unchanged.

_NEG16      MACRO VLA,RES
      SEC
      LDA #0
      SBC VLA+0
      STA RES+0
      LDA #0
      SBC VLA+1
      STA RES+1
      ENDM

; Negate the signed 32 bit number at location VLA
; and stored the result at location RES. RES may
; be the same as VLA.
;
; On exit: A = ??, X & Y are unchanged.

_NEG32      MACRO VLA,RES
      SEC
      LDA #0
      SBC VLA+0
      STA RES+0
      LDA #0
      SBC VLA+1
      STA RES+1
      LDA #0
      SBC VLA+2
      STA RES+2
      LDA #0
      SBC VLA+3
      STA RES+3
      ENDM

; Calculates the absolute value of signed 16 bit
; number at location VLA and stores it in the RES
; location. Less code is generated if VLA and RES
; are the same location. If 65SC02 instructions
; are available a BRA is used to shorten the
; generated code.
;
; On exit: A = ??, X & Y are unchanged.

_ABS16      MACRO VLA,RES
      BIT VLA+0
      IF VLA != RES
       BPL _MOVE\?
       _NEG16 VLA,RES
       IF __65SC02__
        BRA _DONE\?
       ELSE
        JMP _DONE\?
       ENDIF
_MOVE\?       EQU *
       _XFR16 VLA,RES
      ELSE
       BPL _DONE\?
       _NEG16 VLA,RES
      ENDIF
_DONE\?      EQU *
      ENDM

; Calculates the absolute value of signed 32 bit
; number at location VLA and stores it in the RES
; location. Less code is generated if VLA and RES
; are the same location. If 65SC02 instructions
; are available a BRA is used to shorten the
; generated code.
;
; On exit: A = ??, X & Y are unchanged.

_ABS32      MACRO VLA,RES
      BIT VLA+0
      IF VLA != RES
       BPL _MOVE\?
       _NEG32 VLA,RES
       IF __65SC02__
        BRA _DONE\?
       ELSE
        JMP _DONE\?
       ENDIF
_MOVE\?       EQU *
       _XFR32 VLA,RES
      ELSE
       BPL _DONE\?
       _NEG32 VLA,RES
      ENDIF
_DONE\?      EQU *
      ENDM

; Calculate the 16 bit product of two 16 bit
; unsigned numbers. Any overflow during the
; calculation is lost. The number at location
; VLA is destroyed.
;
; On exit: A = ??, X = $FF, Y is unchanged.

_MUL16      MACRO VLA,VLB,RES
      _CLR16 RES
      LDX #16
_LOOP\?      EQU *
      _ASL16 RES,RES
      _ASL16 VLA,VLA
      BCC _NEXT\?
      _ADD16 VLB,RES,RES
_NEXT\?      DEX
      BPL _LOOP\?
      ENDM

; Calculate the 32 bit product of two 16 bit
; unsigned numbers. The number at location VLA
; is destroyed.
;
; On exit: A = ??, X = $FF, Y is unchanged.

_MUL16X      MACRO VLA,VLB,RES
      _CLR32 RES
      LDX #16
_LOOP\?      EQU *
      _ASL32 RES,RES
      _ASL16 VLA,VLA
      BCC _NEXT\?
      _ADD16 VLB,RES,RES
      BCC _NEXT\?
      _INC16 RES+2
_NEXT\?      EQU *
      DEX
      BPL _LOOP\?
      ENDM

; Calculate the 32 bit product of two 32 bit
; unsigned numbers. Any overflow during the
; calculation is lost. The number at location
; VLA is destroyed.
;
; On exit: A = ??, X = $FF, Y is unchanged.

_MUL32      MACRO VLA,VLB,RES
      _CLR32 RES
      LDX #32
_LOOP\?      EQU *
      _ASL32 RES,RES
      _ASL32 VLA,VLA
      BCC _NEXT\?
      _ADD32 VLB,RES,RES
_NEXT\?      EQU *
      DEX
      BPL _LOOP\?
      ENDM

; These two macros write the code necessary
; to multiply a 16 bit at location VLA by
; a 16 bit constant NUM and store the 16 bit
; result in location RES.
;
; On exit: A = ??, X & Y unchanged.

_MUL16I      MACRO VLA,NUM,RES
      IF NUM = 1
       _XFR16 VLA,RES
      ELSE
       _CLR16 RES
       __MUL16I VLA,NUM,RES
      ENDIF
      ENDM

__MUL16I   MACRO VLA,NUM,RES
       IF NUM & $FFFE
        __MUL16I VLA,(NUM/2),RES
        _ASL16 RES,RES
       ENDIF
       IF NUM & $0001
         _ADD16 VLA,RES,RES
       ENDIF
      ENDM

; Divide the 16 bit number at location VLA
; by the 16 bit number at location VLB
; leaving the 16 bit quotient at QUO and
; the 16 bit remainder in REM. The value in
; location VLA is destroyed.
;
; On exit: A = ??, X = $FF, Y is unchanged.

_DIV16      MACRO VLA,VLB,QUO,REM
      _CLR16 REM
      LDX #16
_LOOP\?      EQU *
      _ASL16 VLA,VLA
      _ROL16 REM,REM
      _SUB16 REM,VLB,REM
      BCS _NEXT\?
      _ADD16 REM,VLB,REM
_NEXT\?      EQU *
      _ROL16 QUO,QUO
      DEX
      BPL _LOOP\?
      ENDM

; Divide the 32 bit number at location VLA
; by the 16 bit number at location VLB
; leaving the 16 bit quotient at QUO and
; the 16 bit remainder in REM. The value in
; location VLA is destroyed.
;
; On exit: A = ??, X = $FF, Y is unchanged.

_DIV16X      MACRO VLA,VLB,QUO,REM
      _CLR16 REM
      LDX #32
_LOOP\?      EQU *
      _ASL32 VLA,VLA
      _ROL16 REM,REM
      _SUB16 REM,VLB,REM
      BCS _NEXT\?
      _ADD16 REM,VLB,REM
_NEXT\?      EQU *
      _ROL16 QUO,QUO
      DEX
      BPL _LOOP\?
      ENDM

; Divide the 32 bit number at location VLA
; by the 32 bit number at location VLB
; leaving the 32 bit quotient at QUO and
; the 32 bit remainder in REM. The value in
; location VLA is destroyed.
;
; On exit: A = ??, X = $FF, Y is unchanged.

_DIV32      MACRO VLA,VLB,QUO,REM
      _CLR32 REM
      LDX #32
_LOOP\?      EQU *
      _ASL32 VLA,VLA
      _ROL32 REM,REM
      _SUB32 REM,VLB,REM
      BCS _NEXT\?
      _ADD32 REM,VLB,REM
_NEXT\?      EQU *
      _ROL32 QUO,QUO
      DEX
      BPL _LOOP\?
      ENDM

      PAGE
;------------------------------------------------
; Comparative Operations
;------------------------------------------------

; Compares two 16 bit values in memory areas VLA
; and VLB. The comparison starts with the most
; significant bytes and returns as soon as a
; difference is detected.
;
; On exit: A = ??, X & Y are unchanged.

_CMP16      MACRO VLA,VLB
      LDA VLA+1
      CMP VLB+1
      BNE _DONE\?
      LDA VLA+0
      CMP VLB+0
_DONE\?      EQU *
      ENDM

; Compares two 32 bit values in memory areas VLA
; and VLB. The comparison starts with the most
; significant bytes and returns as soon as a
; difference is detected.
;
; On exit: A = ??, X & Y are unchanged.

_CMP32      MACRO VLA,VLB
      LDA VLA+3
      CMP VLB+3
      BNE _DONE\?
      LDA VLA+2
      CMP VLB+2
      BNE _DONE\?
      LDA VLA+1
      CMP VLB+1
      BNE _DONE\?
      LDA VLA+0
      CMP VLB+0
_DONE\?      EQU *
      ENDM

      PAGE
;------------------------------------------------
; Memory Operations
;------------------------------------------------

; Transfers a block of memory from one place to
; another by copying the bytes starting at the
; front of the block and going forward. SRC and
; DST are destroyed during the copy.
;
; On exit: A, X & Y = ??.

_MEMFWD      MACRO  SRC,DST,LEN
      LDY #0
      LDX LEN+1
      BEQ _FRAG\?
_PAGE\?      LDA (SRC),Y
      STA (DST),Y
      INY
      BNE _PAGE\?
      INC SRC+1
      INC DST+1
      DEX
      BNE _PAGE\?
_FRAG\?      CPY LEN+0
      BEQ _DONE\?
      LDA (SRC),Y
      STA (DST),Y
      INY
      BNE _FRAG\?
_DONE\?      EQU *
      ENDM

; Transfers a block of memory from one place to
; another by copying the bytes starting at the
; end of the block and going backwards.

_MEMREV      MACRO  SRC,DST,LEN
      NOP
      ENDM

; Tranfers a block of memory from one location to
; another. Depending on the relative positions of
; the blocks an appropriate transfer method is
; used.

_MEMCPY      MACRO  SRC,DST,LEN
      _CMP16 SRC,DST
      BCC _SAFE\?
      _MEMFWD SRC,DST,LEN
      IF __65SC02__
       BRA _DONE\?
      ELSE
       JMP _DONE\?
      ENDIF
_SAFE\?      _MEMREV SRC,DST,LEN
_DONE\?      EQU *
      ENDM

      PAGE
;------------------------------------------------
; String Operations
;------------------------------------------------

; Calculates length of a null terminated string
; by searching for its end. The address of the
; string in STR is destroyed during the search.
;
; On exit: A & Y = ??, X is unchanged.

_STRLEN      MACRO  STR,LEN
      LDY #0
      STY LEN+1
_LOOP\?      LDA (STR),Y
      BEQ _DONE\?
      INY
      BNE _LOOP\?
      INC LEN+1
      INC STR+1
      IF __65SC02__
       BRA _LOOP\?
      ELSE
       JMP _LOOP\?
      ENDIF
_DONE\?      STY LEN+0
      ENDM

; Copies a null terminated string from one memory
; location to another. The source and destination
; addresses are destroyed during the copy process.
;
; On exit: A & Y = ??, X is unchanged.

_STRCPY      MACRO SRC,DST
      LDY #0
_LOOP\?      LDA (SRC),Y
      STA (DST),Y
      BEQ _DONE\?
      INY
      BNE _LOOP\?
      INC SRC+1
      INC DST+1
      IF __65SC02__
       BRA _LOOP\?
      ELSE
       JMP _LOOP\?
      ENDIF
_DONE\?      EQU *
      ENDM

;

_STRCMP      MACRO VLA,VLB
      LDY #0
_LOOP\?      LDA (VLA),Y
      CMP (VLB),Y
      BNE _DONE\?
      LDA (VLA),Y
      BEQ _DONE\?
      INY
      BNE _LOOP\?
      INC VLA+1
      INC VLB+1
      IF __65SC02__
       BRA _LOOP\?
      ELSE
       JMP _LOOP\?
      ENDIF
_DONE\?      EQU *
      ENDM

;

_STRNCMP   MACRO VLA,VLB,LEN
      ENDM

      LIST
}}}