Number output in 6502 machine code

From BeebWiki
Revision as of 06:13, 30 June 2018 by Jgharston (talk | contribs) (Improved multiple-byte decimal output routines.)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Print 8-bit hexadecimal

Print value in A in hexadecimal padded with zeros.

   \ On entry, A=value to print
   \ On exit,  A corrupted
   
   .PrHex
   PHA                        :\ Save A
   LSR A:LSR A:LSR A:LSR A    :\ Move top nybble to bottom nybble
   JSR PrNybble               :\ Print this nybble
   PLA                        :\ Get A back and print bottom nybble
   .PrNybble
   AND #15                    :\ Keep bottom four bits
   CMP #10:BCC PrDigit        :\ If 0-9, jump to print
   ADC #6                     :\ Convert ':' to 'A'
   .PrDigit
   ADC #ASC"0":JMP OSWRCH     :\ Convert to character and print

Print 8-bit hexadecimal (more cunning)

Print value in A in hexadecimal padded with zeros. (I used http://www.obelisk.me.uk/6502/algorithms.html to refresh my memory.)

   \ On entry, A=value to print
   \ On exit,  A corrupted
   
   .PrHex
   PHA                        :\ Save A
   LSR A:LSR A:LSR A:LSR A    :\ Move top nybble to bottom nybble
   JSR PrNybble
   PLA
   AND #15                    :\ Mask out original bottom nybble
   .PrNybble
   SED
   CLC
   ADC #&90                   :\ Produce &90-&99 or &00-&05
   ADC #&40                   :\ Produce &30-&39 or &41-&46
   CLD
   JMP OSWRCH                 :\ Print it

Print 8-bit decimal

Print value in A in decimal padded with zeros.

   \ On entry, A=value to print
   \ On exit,  A corrupted
   
   .PrDec
   LDX #&FF:SEC               :\ Prepare for subtraction
   .PrDec100
   INX:SBC #100:BCS PrDec100  :\ Count how many 100s
   ADC #100:JSR PrDecDigit    :\ Print the 100s
   LDX #&FF:SEC               :\ Prepare for subtraction
   .PrDec10
   INX:SBC #10:BCS PrDec10    :\ Count how many 10s
   ADC #10:JSR PrDecDigit     :\ Print the 10s
   TAX                        :\ Pass 1s into X
   .PrDecDigit
   PHA:TXA                    :\ Save A, pass digit to A
   ORA #ASC"0":JSR OSWRCH     :\ Convert to character and print it
   PLA:RTS                    :\ Restore A and return

Print multi-byte numbers in decimal

These routines will print 16-bit, 24-bit and 32-bit values in decimal with no padding or specified character padding. They can be optimised for for specific implementations.

16-bit decimal

   \ ---------------------------
   \ Print 16-bit decimal number
   \ ---------------------------
   \ On entry, num=number to print
   \           pad=0 or pad character (eg '0' or ' ')
   \ On entry at PrDec16Lp1,
   \           Y=(number of digits)*2-2, eg 8 for 5 digits
   \ On exit,  A,X,Y,num,pad corrupted
   \ Size      69 bytes
   \ -----------------------------------------------------------------
   .PrDec16
   LDY #8                                   :\ Offset to powers of ten
   .PrDec16Lp1
   LDX #&FF:SEC                             :\ Start with digit=-1
   .PrDec16Lp2
   LDA num+0:SBC PrDec16Tens+0,Y:STA num+0  :\ Subtract current tens
   LDA num+1:SBC PrDec16Tens+1,Y:STA num+1
   INX:BCS PrDec16Lp2                       :\ Loop until <0
   LDA num+0:ADC PrDec16Tens+0,Y:STA num+0  :\ Add current tens back in
   LDA num+1:ADC PrDec16Tens+1,Y:STA num+1
   TXA:BNE PrDec16Digit                     :\ Not zero, print it
   LDA pad:BNE PrDec16Print:BEQ PrDec16Next :\ pad<>0, use it
   .PrDec16Digit
   LDX #ASC"0":STX pad                      :\ No more zero padding
   ORA #ASC"0"                              :\ Print this digit
   .PrDec16Print
   JSR OSWRCH
   .PrDec16Next
   DEY:DEY:BPL PrDec16Lp1                   :\ Loop for next digit
   RTS
   :
   .PrDec16Tens
   EQUW 1
   EQUW 10
   EQUW 100
   EQUW 1000
   EQUW 10000
   \ -----------------------------------------------------------------

24-bit decimal

   \ ---------------------------
   \ Print 24-bit decimal number
   \ ---------------------------
   \ On entry, num=number to print
   \           pad=0 or pad character (eg '0' or ' ')
   \ On entry at PrDec24Lp1,
   \           Y=(number of digits)*3-3, eg 21 for 8 digits
   \ On exit,  A,X,Y,num,pad corrupted
   \ Size      98 bytes
   \ -----------------------------------------------------------------
   .PrDec24
   LDY #21                                  :\ Offset to powers of ten
   .PrDec24Lp1
   LDX #&FF:SEC                             :\ Start with digit=-1
   .PrDec24Lp2
   LDA num+0:SBC PrDec24Tens+0,Y:STA num+0  :\ Subtract current tens
   LDA num+1:SBC PrDec24Tens+1,Y:STA num+1
   LDA num+2:SBC PrDec24Tens+2,Y:STA num+2
   INX:BCS PrDec24Lp2                       :\ Loop until <0
   LDA num+0:ADC PrDec24Tens+0,Y:STA num+0  :\ Add current tens back in
   LDA num+1:ADC PrDec24Tens+1,Y:STA num+1
   LDA num+2:ADC PrDec24Tens+2,Y:STA num+2
   TXA:BNE PrDec24Digit                     :\ Not zero, print it
   LDA pad:BNE PrDec24Print:BEQ PrDec24Next :\ pad<>0, use it
   .PrDec24Digit
   LDX #ASC"0":STX pad                      :\ No more zero padding
   ORA #ASC"0"                              :\ Print this digit
   .PrDec24Print
   JSR OSWRCH
   .PrDec24Next
   DEY:DEY:DEY:BPL PrDec24Lp1               :\ Loop for next digit
   RTS
   :
   .PrDec24Tens
   EQUW 1       :EQUB 1 DIV 65536
   EQUW 10      :EQUB 10 DIV 65536
   EQUW 100     :EQUB 100 DIV 65536
   EQUW 1000    :EQUB 1000 DIV 65536
   EQUW 10000   :EQUB 10000 DIV 65536
   EQUW 100000  :EQUB 100000 DIV 65536
   EQUW 1000000 :EQUB 1000000 DIV 65536
   EQUW 10000000:EQUB 10000000 DIV 65536
   \ -----------------------------------------------------------------

32-bit decimal

   \ ---------------------------
   \ Print 32-bit decimal number
   \ ---------------------------
   \ On entry, num=number to print
   \           pad=0 or pad character (eg '0' or ' ')
   \ On entry at PrDec32Lp1,
   \           Y=(number of digits)*4-4, eg 36 for 10 digits
   \ On exit,  A,X,Y,num,pad corrupted
   \ Size      129 bytes
   \ -----------------------------------------------------------------
   .PrDec32
   LDY #36                                  :\ Offset to powers of ten
   .PrDec32Lp1
   LDX #&FF:SEC                             :\ Start with digit=-1
   .PrDec32Lp2
   LDA num+0:SBC PrDec32Tens+0,Y:STA num+0  :\ Subtract current tens
   LDA num+1:SBC PrDec32Tens+1,Y:STA num+1
   LDA num+2:SBC PrDec32Tens+2,Y:STA num+2
   LDA num+3:SBC PrDec32Tens+3,Y:STA num+3
   INX:BCS PrDec32Lp2                       :\ Loop until <0
   LDA num+0:ADC PrDec32Tens+0,Y:STA num+0  :\ Add current tens back in
   LDA num+1:ADC PrDec32Tens+1,Y:STA num+1
   LDA num+2:ADC PrDec32Tens+2,Y:STA num+2
   LDA num+3:ADC PrDec32Tens+3,Y:STA num+3
   TXA:BNE PrDec32Digit                     :\ Not zero, print it
   LDA pad:BNE PrDec32Print:BEQ PrDec32Next :\ pad<>0, use it
   .PrDec32Digit
   LDX #ASC"0":STX pad                      :\ No more zero padding
   ORA #ASC"0"                              :\ Print this digit
   .PrDec32Print
   JSR OSWRCH
   .PrDec32Next
   DEY:DEY:DEY:DEY:BPL PrDec32Lp1           :\ Loop for next digit
   RTS
   :
   .PrDec32Tens
   EQUD 1
   EQUD 10
   EQUD 100
   EQUD 1000
   EQUD 10000
   EQUD 100000
   EQUD 1000000
   EQUD 10000000
   EQUD 100000000
   EQUD 1000000000
   \ -----------------------------------------------------------------

Jgharston 07:51, 25 December 2011 (UTC) Jgharston (talk) 07:13, 30 June 2018 (CEST)