		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