C02/include/intlib.a02

433 lines
14 KiB
Plaintext

; C02 module intlib.h02 assembly language subroutines
; Requires external zero page words DSTPTR, SRCPTR,
; external bytes TEMP0, TEMP1, TEMP2, and TEMP3, and
; external words INTACC, INTARG, and INTOVR.
SUBROUTINE INTLIB
;iacc(i) - Set Integer Accumulator to i
;Args: Y,X = Argument
;Sets: INTACC = Y,X
IACC: STX INTACC
STY INTACC+1
RTS
;Set Integer Argument
.SETARG STX INTARG
STY INTARG+1
RTS
;Clear Integer Overflow
;Sets: INTOVR = 0
;Returns A = 0
.CLROVR LDA #0
STA INTOVR
STA INTOVR+1
RTS
;iabs(i) - Get Integer ABSolute Value
;Args: Y,X = Integer to get Absolute Value Of
;Sets: TEMP1, TEMP2
;Affects: C, N, Z
;Returns: A = Absolute Value of Argument
IABS: CPY #$80 ;If Negative (High Bit Set)
BCC .RETURN ; Carry will Already be Set
JSR SAVRXY ; Copy LSB, MSB to TEMP1. TEMP2
LDA #0 ; Subtract LSB
SBC TEMP1 ; from 0
TAX ; and Copy to X Register
LDA #0 ; Subtract MSB
SBC TEMP2 ; from 0
TAY ; and Copy to Y Register
.RETURN RTS
;imax(i) - Get MAXimum of Two Integers
;Args: Y,X = Second Integer
;Uses: INTACC = First Integer
;Affects: N,Z,C
;Returns: Y,X = Larger of the Two Arguments
IMAX: CPY INTACC+1 ;If Y < INTACC MSB
BCC .GETACC ; Return INTACC
CPX INTACC ;IF X >= INTACC LSB
BCS .IMSET ; Set INTACC to and Return Argument
.GETACC LDX INTACC ;Return Integer Accumulator
LDY INTACC+1
RTS
;imin(i) - Get MINimum of Two Integers
;Args: Y,X = Second Integer
;Uses: INTACC = First Integer
;Sets: IINTACC = Result
;Affects: N,Z,C
;Returns: Y,X = Larger of the Two Arguments
IMIN: CPY INTACC+1 ;If Y < INTACC+1
BCC .RETURN ; Return Argument
BNE .GETACC ;If Y > INTACC+1
CPX INTACC ;or X >= INTACC
BCS .GETACC ; Return INTACC
.IMSET JMP IACC ;Else Set INTACC to and Return Argument
;iaddc(c,i) - Integer ADD Char c to int i
IADDC: JSR IACC ;Store Integer in Accumulator
LDY #0 ;Set Argument MSB to 0
TAX ;Copy Byte to LSB and drop into IADD
;iand(d) - Integer ADD g + d
;Args: Y,X = Addend
;Requires: IACC(g) - Augend
;Sets: INTACC = Result
;Affects: Z
;Returns: Y,X = Sum
;IAND: TXA ;AND Argument LSB
; AND IACC ;with Accumulator LSB
; TAX
; TYA ;AND Argument MSB
; AND IACC+1 ;with Accumulator MSB
; TAY
; JMP IACC ;Set INTACC to And Return Result
;iadd(d) - Integer ADD g + d
;Args: Y,X = Addend
;Requires: IACC(g) - Augend
;Sets: INTACC = Sum
;Affects: Z
;Returns: A,C = Carry
; Y,X = Sum
; N = Sign of Result
IADD: CLC ;Clear Carry for Addition
TXA ;Add Addend LSB
ADC INTACC ;to Augend LSB
TAX ;and Copy to X
TYA ;Add Addend MSB
ADC INTACC+1 ;to Augebd MSB
TAY ;and Copy to Y
PHP ;Save Result Flags
LDA #0 ;Clear CHR Result to 0
STA INTOVR+1 ; and Clear Overflow MSB
ROL ;Rotate Carry Flag into CHR Result
STA INTOVR ; and store in INTOVR
PLP ;Restore Result Flags
JMP IACC ;Set INTACC to And Return Result
;ineg(i) - Integer NEGate int i
;Args: Y,X = Integer to Negate
;Sets: INTACC = Result
; INTARG = Argument
;Returns: Y,X = Negated Integer
; N = Sign of Result
INEG: LDA #0 ;Set Minuend to Zero
STA INTACC
STA INTACC+1
;isub(s) - Integer SUBtract m - s
;Args: Y,X = Subtrahend
;Requires: IACC(m) - Minuend
;Sets: INTACC = Difference
; INTARG = Subtrahend
;Affects: Z
;Returns: A,C = Carry
; Y,X = Difference
; N = Sign of Result
ISUB: JSR .SETARG ;Store Subtrahend in INTARG
SEC ;Set Carry for Subtraction
LDA INTACC ;Load Minuend LSB
SBC INTARG ;Subtract Subtrahend LSB
TAX ;Copy Difference LSB to X
LDA INTACC+1 ;Load Minuend MSB
SBC INTARG+1 ;Subtract Subtrahend MSB
TAY ;Copy Difference MSB to Y
PHP ;Save Result Flags
LDA #0 ;Set Overflow Byte to 0
SBC #0 ;and Subtract Carry
PLP ;Restore Result Flags
JMP IACC ;Set INTACC to And Return Result
;imultc(c,m) - Multiply Int m by Char c
;Args: A - Multiplicand
; Y,X - Multiplier
;Sets: INTACC - Product MSB, LSB
IMULTC: STA INTACC ;Set Integer Accumulator to int(A)
LDA #0
STA INTACC+1 ;and execute IMULT
;imult(m) = MULTiply Integer n * Integer m
;Args: Y,X = Multiplier
;Uses: INTACC = Multiplicand
;Sets: INTACC = Product MSB, LSB
;Sets: INTOVR = Product MSB, LSB
;Destroys: TEMP0,TEMP1,TEMP2,TEMP3
;Affects: C,Z,N
;Returns: A,Y,X = 24 Bit Product
IMULT: JSR .SETARG ;Save Multiplier
LDY #0
STY INTOVR ;Clear Upper Bits of Product
STY INTOVR+1
LDX #16 ;Rotate Through 16 Bits
.MSHFTR LSR INTARG+1 ;Divide Multiplier by 2
ROR INTARG
BCC .MROTR ;If Shifted out Bit is 1
LDA INTACC ; Add Multiplicand
CLC ; to Upper Half of Product
ADC INTOVR
STA INTOVR
LDA INTOVR+1
ADC INTACC+1
STA INTOVR+1
.MROTR ROR INTOVR+1
ROR INTOVR
ROR TEMP1
ROR TEMP0
DEX ;Decrement Counter
BNE .MSHFTR ;and Process Next Bit
LDA INTOVR ;Get Bits 16-24 of Result
LDY TEMP1 ;Get Bits 8-15 of Result
LDX TEMP0 ;Get Bits 0-7 of Result
JMP IACC ;Store Y,X in INTACC and Return in Y,X
;imod(d) - Integer MODulus d % s
;Args: Y,X - Divisor
;Requires: IACC(d) = Dividend
;Sets: INTARG = Divisor
; INTACC, INTOVR = Modulus
;Affects: A,C,Z,N
;Returns: Y,X = 16 Bit Modulus
IMOD: JSR IDIV ;Do Division
LDX INTOVR ;get Remainder
LDY INTOVR+1 l
JMP IACC ;Store in INTACC and Return in Y,X
;idiv(s) - Integer DIVide d / s
;Args: Y,X - Divisor
;Requires: IACC(d) = Dividend
;Sets: INTARG = Divisor
; INTACC = Quotient
; INTOVR = Remainder
;Affects: A,C,Z,N
;Returns: Y,X = 16 Bit Quotient
IDIV: JSR .SETARG ;Save Divisor
LDY #0
STY INTOVR
STY INTOVR+1
LDX #16 ;repeat for each bit: ...
.IDLOOP ASL INTACC ;dividend lb & hb*2, msb -> Carry
ROL INTACC+1
ROL INTOVR ;remainder lb & hb * 2 + msb from carry
ROL INTOVR+1
LDA INTOVR
SEC
SBC INTARG ;subtract divisor to see if it fits in
TAY ;lb result -> Y, for we may need it later
LDA INTOVR+1
SBC INTARG+1
BCC .IDSKIP ;if carry=0 then divisor didn't fit in yet
STA INTOVR+1 ;else save substraction result as new remainder,
STY INTOVR
INC INTACC ;and INCrement result cause divisor fit in 1 times
.IDSKIP DEX
BNE .IDLOOP
JMP .GETACC ;Return Integer Accumulator
;ishftl(n,i) - Shift Integer i to the Left n Bits
;Args: A = Number of Bits to Shift
; Y,X = Integer Value to Shift
;Sets: INTACC = Bits 0 to 15 of Result
; INTOVR = Bits 16 to 31 of Result
;Sets: INTACC = Shifted Intger
;Affects: N,Z,C
;Returns: A = LSB of Underflow
; Y,X = Shifted Integer
ISHFTL: JSR IACC ;Save Argument in INTACC
LDX #0 ;Clear Overflow
STX INTOVR
STX INTOVR
TAX ;Set Counter to Number of Bits
BEQ .LSDONE ;If Zero, Return 0
.LSLOOP ASL INTACC ;Shift Bits 0-7 to Left
ROL INTACC+1 ;Rotate Bits 8-15 to Left
ROL INTOVR ;Rotate Bits 16-23 to Left
ROL INTOVR+1 ;Rotate Bits 24-31 to Left
DEX ;Decrement Counter
BNE .LSLOOP ; and Loop if Not 0
LDA INTOVR ;Return Bits 16-23 in A
.LSDONE JMP .GETACC ;and Bits 0-15 in Y,X
;ishftr(n,i) - Shift Integer i to the Right n Bits
;Args: A = Number of Bits to Shift
; Y,X = Integer Value to Shift
;Sets: INTACC = Bits 0 to 15 of Result
; INTOVR = Bits -1 to -16 of Result
;Sets: INTACC = Shifted Intger
;Affects: N,Z,C
;Returns: A = MSB of Underflow
; Y,X = Shifted Result
ISHFTR: JSR IACC ;Save Argument in INTACC
LDX #0 ;Clear Overflow
STX INTOVR
STX INTOVR
TAX ;Set Counter to Number of Bits
BEQ .RSDONE ;If Zero, Return Argument
.RSLOOP LSR INTACC+1 ;Shift MSB to Right
ROR INTACC ;Rotate LSB to Right
ROR INTOVR+1 ;Rotate Underflow MSB
ROR INTOVR ;Rotate Underflow LSB
DEX ;Decrement Counter
BNE .RSLOOP ; and Loop if Not 0
LDA INTOVR+1 ;Return Underflow MSB in A
.RSDONE JMP .GETACC ;and Result in Y,X
;atoi(&s) - ASCII string TO Integer
;Args: Y,X = Address of String to Convert
;Sets: INTACC = Integer Value
;Affects: TEMP0,TEMP1,TEMP2
;Returns: A = Number of Digits
; Y,X = Integer Value
ATOI: JSR SETSRC ;Initialize Source String
STY TEMP1 ;Initialize Result
STY TEMP2
.AILOOP LDA (SRCPTR),Y ;Get Next Character
CMP #$30 ;If Less Than '0'
BCC .AIDONE ; Exit
CMP #$3A ;If Greater Than '9'
BCS .AIDONE ; Exit
AND #$0F ;Convert to Binary Nybble
STA TEMP0 ; and Save It
LDA TEMP1 ;Load Result
LDX TEMP2
ASL TEMP1 ;Multiply by 5 by
ROL TEMP2
ASL TEMP1 ; Multiplying by 4
ROL TEMP2
CLC ; And Adding Itself
ADC TEMP1
STA TEMP1
TXA
ADC TEMP2
STA TEMP2
ASL TEMP1 ;Multiply that by 2
ROL TEMP2
LDA TEMP0 ;Get Saved Nybble
CLC ;and Add to Result
ADC TEMP1 ;Add Saved Nybble
STA TEMP1 ; and Store Result
LDA #0
ADC TEMP2
STA TEMP2
INY ;Increment Index
BPL .AILOOP ; and Loop
.AIDONE TYA ;Return Number of Digits
.RESRXY JSR RESRXY ;and Integer Value
JMP IACC
;itoa(&d) - Integer TO ASCII string
;Args: Y,X = Address of Destination String
;Uses: INTACC = Integer to Convert
;Uses: DSTPTR = Destination String
;Affects: X
;Returns: A,Y = Length of String
ITOA: JSR SETDST ;Store String Pointer Agrumenr
JSR .GETACC ;Load INTACC
JSR CVIBCD ;Convert Integer to Packed BCD
LDY #0 ;Initialize Index into String
STY TEMP3
.ITOAA LDY #4 ;Set Initial Digit Number
.IAZERO JSR UPBCDI ;Unpack Digit Y
BNE .IASKIP ;If Zero
DEY ; Decrement Digit Number
BNE .IAZERO ; If Not Zero Loop
BEQ .IASKIP ; Else Branch into .IALOOP
.IALOOP JSR UPBCDI ;Unpack Digit #Y
.IASKIP TAX ;Save Digit in X
TYA ;Push Unpack Index into Stack
PHA
TXA ;and Restore Digit
ORA #$30 ;Convert Digit to ASCII
LDY TEMP3 ;Get Index into String
STA (DSTPTR),Y ;and Store in String
INC TEMP3 ;Increment Index into String
PLA ;Pull Digit Number off Stack
TAY
DEY ;Decrement Digit Number
BPL .IALOOP ;Loop if >= Zero
LDA #0 ;Terminate String
STA (DSTPTR),Y
TYA ;Return String Length
JMP .GETACC ;and INTACC
;upbcdi() - UnPack digits from BCD Integer
; Assumes that TEMP0, TEMP1, and TEMP2
; are in consecutive memory locations
;Args: Y = Digit Number to Unpack (0-5)
;Uses: TEMP0 = Low Byte
; TEMP1 = Middle Byte
; TEMP2 = High Nybble
;Affects: X,N,Z
;Returns: A = Unpacked Digit
UPBCDI: PHP
TYA ;Divide Digit Number by 2,
LSR ; Setting Carry
TAX ; if Digit Number is Odd
LDA TEMP0,X ;Load BCD Byte
BCC .UPSKIP ;If Digit Number is Odd
LSR ; Shift High Nybble to Low Nybble
LSR
LSR
LSR
.UPSKIP PLP
AND #$0F ;Strip Off High Nybble
RTS
;cvibcd(int) - ConVert Integer to packed Binary Coded Decimal
;Args: Y,X - Integer to Convert
;Sets: TEMP0 = Tens and Ones Digit
; TEMP1 = Thousands and Hundreds Digit
; TEMP2 = Ten-Thousands Digit
;Affects: A
CVIBCD: JSR IACC ;Store Argument
LDA #0 ;Clear BCD Bytes
STA TEMP0
STA TEMP1
STA TEMP2
PHP ;Save Status Register
SEI ;Disable Interrupts
SED ;Set Decimal Mode
LDY #16 ;Process 16 bits of Binary
.CVLOOP ASL INTACC ;Shift High Bit Into Carry
ROL INTACC+1
LDA TEMP0 ;Add 6 Digit BCD Number Itself
ADC TEMP0 ; Effectively Multiplying It by 2
STA TEMP0 ; and Adding in the Shifted Out Bit
LDA TEMP1
ADC TEMP1
STA TEMP1
LDA TEMP2
ADC TEMP2
STA TEMP2
DEY ;Decrement Counter and
BNE .CVLOOP ; Process Next Bit
PLP ;Restore Status Register
RTS
;icmp(j) - Compare Int i to Int j
;Requires: IACC(i) - int to compare against
;Args: X,Y = int to compare
; N based on return value of A
;Returns A=$01 and C=1 if INTACC > Arg
; A=$00 and Z=1, C=1 if INTACC = Arg
; A=$FF and C=0 if INTACC < Arg
ICMP: CPY INTACC+1 ;Compare MSBs
BCC .GT ;INTACC < Y,X
BNE .LT ;INTACC > Y,X
CPX INTACC ;Compare LSBs
BCC .GT ;INTACC < Y,X
BNE .LT ;INTACC > Y,X
LDA #0
RTS ;Return INTACC = YX
.LT LDA #$FF
RTS ;Return INTACC < YX
.GT LDA #1
RTS ;Return INTACC > YX
ENDSUBROUTINE