; C02 library stdiox.h02 assembly language subroutines

ANYKEP: DC  "PRESS ANY KEY...",0

;
;char anykey(nls) - wait for character with ANY KEY prompt
;Args: A = Print Newlines (0 = No, otherwise Yes)
;Calls: GETCPR, NEWLIN - Print Newline to Screen
;Affects: C,N,Z
;Returns: A = Character code of keypress
ANYKEY: JSR NEWLIN      ;Start at Beginning of Next Line
.NONL   LDY #>ANYKEP    ;Load Prompt High Byte
        LDX #<ANYKEP    ;Load Prompt Low Byte
                        ;Drop into GETCPR

;char getcpr(nls, &s) - GET Character with PRompt
;Args: A = Print Newlines (0 = No, otherwise Yes)
;      Y,X = Address of Prompt String
;Sets: TEMP0 - Character code of keypress
;      TEMP1 - Newline Flag
;Calls: PUTS - Put String to Screen
;       GETC - Get Character from Keyboard
;       NEWLIN - Print Newline to Screen
;Affects: C,N,Z
;Returns: A = Character code of keypress
GETCPR: JSR PUTS        ;Print Prompt
        JSR GETC        ;Wait for and Return Keypress
        STA TEMP0       ;Save Key Code
        JSR NEWLIN      ;Move to Next Line
        JSR NEWLIN      ;Generate Blank Line
.NONLS  LDA TEMP0       ;Load Key Code
        RTS

;void putbin(b) - PUT Binary
;Args: A = number to print
;Destroys: TEMP0, TEMP1
;Affects: A,Y,C,N,X
PUTBIN: LDY #$FF        ;Set Bitmask to All 1's

;void putmsk(b) - PUT bitMaSK
;Args: A = byte to print
;      Y = Bitmask
;Destroys: TEMP0, TEMP1
;Affects: A,Y,C,N,X
PUTMSK: STA TEMP2       ;Save Byte
        STY TEMP1       ;Save Bitmask
        LDX #8          ;Print 8 Binary Digits
.MASKL  LDA #0          ;Clear Accumulator
        ASL TEMP2       ;Shift Top Bit Out of Byte
        ADC #$30        ;Convert to '0' or '1'
        ASL TEMP1       ;Shift Top Bit Out of Mask
        BCC .MASKP      ;If Set
        JSR PUTCHR      ;  Print Digit
.MASKP  DEX             ;Decrement Index
        BNE .MASKL      ;Loop if Not Done
        RTS

;void putdel(b) - PUT DEcimal Left justified
;Args: A = number to print
;Sets: TEMP0 - ones digit
;      TEMP1 - tens digit
;      TEMP2 - hundreds digit
;      TEMP3 - number that was printed
;.putdel - Alternate Entry Point if number is already in TEMP3
;.spaces - Alternate Entry Point to print only padding spaces
PUTDEL: STA TEMP3
.PUTDEL JSR PUTDEC      ;Print Decimal Representation of number
        LDA TEMP3       ;
.SPACES CMP #100        ;If Number < 100
        BCS .ONES       ;
        JSR PUTSPC      ;  Print a Space
        LDA TEMP3       ;
.ONES   CMP #10         ;  If Number < 10  
        BCS .RETURN     ;
        JSR PUTSPC      ;    Print another Space
.RETURN RTS

;void putdeh(b) - PUT DEcimal Hundred
;Args: A = number to print
;Sets: TEMP0 - ones digit
;      TEMP1 - tens digit
;      TEMP2 - hundreds digit
PUTDEH: JSR CUBCD       ;Convert Accumulator to Unpacked BCD
        LDX #2          ;Print 2 Digits
        BNE .DEZLP

;void putdez(b) - PUT DEcimal Zero filled
;Args: A = number to print
;Sets: TEMP0 - ones digit
;      TEMP1 - tens digit
;      TEMP2 - hundreds digit
PUTDEZ: JSR CUBCD       ;Convert Accumulator to Unpacked BCD
        LDX #3          ;Print 3 Digits
.DEZLP  LDA TEMP0-1,X   ;Get Byte
        JSR PUTDGT      ;Print Digit
        DEX             ;Decrement Counter
        BNE .DEZLP      ;  And Loop if Not Done
        RTS

;void putder(b) - PUT DEcimal Right justified
;Args: A = number to print
;Sets: TEMP0 - ones digit
;      TEMP1 - tens digit
;      TEMP2 - hundreds digit
;      TEMP3 - number that was printed
PUTDER: STA TEMP3
.PUTDER JSR .SPACES
        LDA TEMP3

;void putdec(b) - PUT DECimal
;Args: A = number to print
;Sets: TEMP0 - ones digit
;      TEMP1 - tens digit
;      TEMP2 - hundreds digit
PUTDEC: JSR CUBCD       ;Convert Accumulator to Unpacked BCD
        LDA TEMP2       ;Get High Byte
        BEQ .DIGIT1      ;If Not Zero
        JSR PUTDGT      ;  Print Digit
.DIGIT1 LDA TEMP1       ;Get Low Byte
        BNE .DIGIT2      ;If Not Zero
        CMP TEMP2       ;  and Hundreds 
        BEQ .DIGIT3      ;  not Zero   
.DIGIT2 JSR PUTDGT      ;  Print Digit
.DIGIT3 LDA TEMP0       ;Get Low Byte
PUTDGT: ORA #$30        ;Convert to ASCII digit
        JMP PUTCHR      ;And Print

;puthex(b) - PUT HEXadecimal
PUTHEX  EQU PRBYTE      ;Print Byte as Hexadecimal

;putinr(&.HEXW) - PUT INteger Right justified
PUTINR: SEC             ;Mode = Justified
        BCS .PUTINT     ;Print Integer

;putint(&.HEXW) - PUT INTeger
PUTINT: CLC             ;Mode =  Not Justified
.PUTINT JSR CVIBCD      ;Convert Integer to Packed BCD
        LDY #4          ;Set Initial Digit Number
.IZERO  JSR UPBCDI      ;Unpack Digit X
        BNE .IDIGIT     ;If Zero
        BCC .INEXT      ; If Justified
        JSR PUTSPC      ;   Print a Space
.INEXT  DEY             ; Decrement Digit Number
        BNE .IZERO      ; and If Not Zero Loop
.ILOOP  JSR UPBCDI      ;Unpack Digit X
.IDIGIT JSR PUTDGT      ;Print Digit
        DEY             ;Decrement Digit Number
        BPL .ILOOP      ;Loop if >= Zero
        RTS

;putnyb(b) - PUT NYBble
PUTNYB  EQU PRHEX       ;Print Nybble as Hexadecimal

;putsqb(&.HEXW) - PUT SesQuiByte
;Args: Y = High Nybble
;      X = Low Byte
;Calls: PUTHEX = Print Byte
;       PRHEX = Print Hex Digit
;       SAVRXY = Save X and Y Registers
;Affects: A,Y,X,N,Z,C
PUTSQB: JSR SAVRXY      ;Save Address
.PUTSQB LDA TEMP2       ;Load Address MSB
        JSR PRHEX       ;Print High Nybble 
        LDA TEMP1       ;Load Address LSB
        JMP PUTHEX      ;Print and Return`

;putexh(&.HEXW) - PUT EXtended Hexadecimal
;Args: A = Value Extended Byte
;      Y = Value High Byte
;      X = Value Low Byte
;Calls: PUTHEX = Print Byte
;       SAVRXY = Save X and Y Registers
;       .PUTWRD = Put .HEXW (Alternate Entry Point)
;Affects: A,Y,X,N,Z,C
PUTEXH: JSR SAVRXY      ;Save High and Low Bytes
        JSR PUTHEX      ;Print Extended Byte
        JMP .PUTWRD      ;Print High and Low Bytes

;putwrd(&.HEXW) - PUT .HEXW
;Args: Y = .HEXW MSB
;      X = .HEXW LSB
;Calls: PUTHEX = Print Byte
;       SAVRXY = Save X and Y Registers
;Affects: A,Y,X,N,Z,C
PUTWRD: JSR SAVRXY      ;Save .HEXW
.PUTWRD LDA TEMP2       ;Load .HEXW MSB
        JSR PUTHEX      ;Print as Hexadecimal
        LDA TEMP1       ;Load .HEXW LSB
        JMP PUTHEX      ;Print and Return`

;Print a Space
PUTSPC: LDA #32         ;Load Space Character
        JMP PUTCHR      ;and Print it

;Print Repeated Spaces
PUTRPS: TAY             ;Set Counter to Number of Spaces
        LDA #32
        
;Print Repeated Character
PUTRPT: JSR PUTCHR      ;Print Space Character
        DEY             ;Decrement Counter
        BNE PUTRPT      ;If Not 0, Loop
        RTS

;void printf(b, &s) - PRINT Formatted byte and/or string
;Args: A = byte to format
;      Y,X = address of formatting string
;Uses: DSTLO,DSTHI = Address of %S string
;Sets: SRCLO,SRCHI = Address of formatting string
;      TEMP3 - number to format
;Destroys: TEMP0,TEMP1,TEMP2
;Returns: A,Y = Total number of characters printed
PRINTF: STA TEMP3       ;Save Byte to Format
        JSR SETSRC      ;Initialize Source String
.FLOOP  LDA (SRCLO),Y   ;Read next character in string
        BEQ .FDONE      ;If Not 0
        CMP #'%'        ;  If Format Specified 
        BEQ .FEVAL      ;    Jump to Formatter
.FPUTC  JSR PUTCHR      ;  Print character at offset,
.FNEXT  INY             ;  increment offset, and
        BPL .FLOOP      ;  loop if less than 128
.FDONE  TYA             ;Return Number of
        RTS             ;  characters printed
;Process Format Specifier
.FEVAL: INY             ;Increment Offset
        LDA (SRCLO),Y   ;Get Formatting Character
        BEQ .FDONE      ;If NUL, then Exit
        CMP #'%'        ;If Percent Sign 
        BEQ .FPUTC      ;  Print it and Continue
        AND #$DF        ;Convert to Upper Case
.HNDRD  CMP #'H'        ;If "z" or "Z" 
        BNE .ZEROF
        LDA TEMP3       ;  Load Byte to Format
        JSR PUTDEH      ;  Print Zero Filled
        JMP .FNEXT      ;  and Continue .INTGRng String
.ZEROF  CMP #'Z'        ;If "z" or "Z" 
        BNE .LJUST
        LDA TEMP3       ;  Load Byte to Format
        JSR PUTDEZ      ;  Print Zero Filled
        JMP .FNEXT      ;  and Continue .INTGRng String
.LJUST  CMP #'L'        ;If "l" or "L" 
        BNE .RJUST
        LDA TEMP3       ;  Load Byte to Format
        JSR .PUTDEL      ;  Print Left Justified
        JMP .FNEXT      ;  and Continue .INTGRng String
.RJUST  CMP #'R'        ;If "r" or "R" 
        BNE .DECML
        LDA TEMP3       ;  Load Byte to Format
        JSR .PUTDER      ;  Print Right Justified
        JMP .FNEXT      ;  and Continue .INTGRng String
.DECML  CMP #'D'        ;Else If "d" or "D" 
        BNE .NYBBL
        LDA TEMP3       ;  Load Byte to Format
        JSR PUTDEC      ;  Print as Decimal
        JMP .FNEXT      ;  and Continue .INTGRng String
.NYBBL  CMP #'Y'        ;Else If "y" or "Y" 
        BNE .HEXB 
        LDA TEMP3       ;  Load Byte to Format
        JSR PUTNYB      ;  Print as Low Nybble as Hexadecimal
        JMP .FNEXT      ;  and Continue .INTGRng String
.HEXB   CMP #'X'        ;Else If "x" or "Y" 
        BNE .BNRY 
        LDA TEMP3       ;  Load Byte to Format
        JSR PUTHEX      ;  Print as Hexadecimal
        JMP .FNEXT      ;  and Continue .INTGRng String
.BNRY   CMP #'B'        ;Else If "b" or "B" 
        BNE .NEWLN
        STY TEMP0       ;  Save Index
        LDA TEMP3       ;  Load Byte to Format
        JSR PUTBIN      ;  Print as Binary
        LDY TEMP0       ;  Restore Index
        JMP .FNEXT      ;  and Continue .INTGRng String
.NEWLN  CMP #'N'        ;Else If "n" or "N" 
        BNE .STRNG
        STY TEMP0       ;  Save Index
        JSR NEWLIN      ;  Execute Newline Function
        LDY TEMP0       ;  Restore Index
        JMP .FNEXT      ;  and Continue .INTGRng String
.STRNG  CMP #'S'        ;Else If "s" or "S" 
        BEQ .FDEST      ;  Print Destination String
.SQBYT  CMP #'Q'        ;Else If "w" or "W" 
        BEQ .FDEST      ;  Print Sesquibyte as Hex
.HEXW   CMP #'W'        ;Else If "w" or "W" 
        BEQ .FDEST      ;  Print Word as Hex
.INTGR  CMP #'I'        ;Else If "i" or "I" 
        BEQ .FDEST      ;  Print Decimal Integer
.IJUST  CMP #'J'        ;Else If "j" or "J" 
        BEQ .FDEST      ;  Print Right-Justified Decimal
.FECHO  LDA TEMP3       ;Else
        JMP .FPUTC      ;  Print Raw Byte and Continue

;Process Value in DSTPTR
.FDEST  TAX             ;Save Specifier
        TYA             ;Save Index
        PHA
        TXA             ;Restore Specifier
        JSR GETDST      ;Get Integer in DSTLO, DSTHI
        CMP #'I'        ;If 'i' or 'I'
        BNE .FDESTJ
        JSR PUTINT      ;  Print Integer Right Justified
        BMI .FSKIP
.FDESTJ CMP #'J'        ;Else If 'J' or 'J'
        BNE .FDESTQ
        JSR PUTINR      ;Print Integer Right Justified
        BMI .FSKIP
.FDESTQ CMP #'Q'        ;Else If 'q' or 'Q'
        BNE .FDESTW
        JSR .PUTSQB      ;  Print MSB and LSB as Hex
        BNE .FSKIP
.FDESTW CMP #'W'        ;Else If 'w' or 'J'
        BNE .FDESTS
        JSR PUTWRD      ;  Print MSB and LSB as Hex
        BNE .FSKIP
.FDESTS JSR PUTDST      ;Else Print Destination String
.FSKIP  PLA             ;Restore Index
        TAY
        JMP .FNEXT

                       ;char putdst()
PUTDST  LDY #0         ;Initialize character offset
.DLOOP  LDA (DSTLO),Y  ;Read next character in string
        BEQ .DRETY     ;If Not 0
        JSR PUTC       ;  Print character at offset,
        INY            ;  increment offset, and
        BPL .DLOOP     ;  loop if less than 128
.DRETY  TYA            ;Return number of
        RTS            ;  characters printed
