Difference between revisions of "Number output in 6502 machine code"

From BeebWiki
Jump to: navigation, search
m (1 revision)
(Improved multiple-byte decimal output routines.)
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
 
[[Category:6502]]
 
[[Category:6502]]
==Print 8-bit Hexadecimal==
+
==Print 8-bit hexadecimal==
 
Print value in A in hexadecimal padded with zeros.
 
Print value in A in hexadecimal padded with zeros.
  
Line 18: Line 18:
 
     ADC #ASC"0":JMP OSWRCH    :\ Convert to character and print
 
     ADC #ASC"0":JMP OSWRCH    :\ Convert to character and print
  
==Print 8-bit Hexadecimal (more cunning)==
+
==Print 8-bit hexadecimal (more cunning)==
 
Print value in A in hexadecimal padded with zeros.
 
Print value in A in hexadecimal padded with zeros.
 
+
(I used http://www.obelisk.me.uk/6502/algorithms.html to refresh my memory.)
(I used http://www.obelisk.demon.co.uk/6502/algorithms.html to refresh my memory.)
 
  
 
     \ On entry, A=value to print
 
     \ On entry, A=value to print
Line 40: Line 39:
 
     JMP OSWRCH                :\ Print it
 
     JMP OSWRCH                :\ Print it
  
==Print 8-bit Decimal==
+
==Print 8-bit decimal==
 
Print value in A in decimal padded with zeros.
 
Print value in A in decimal padded with zeros.
  
Line 61: Line 60:
 
     PLA:RTS                    :\ Restore A and return
 
     PLA:RTS                    :\ Restore A and return
  
==Print 32-bit Decimal==
+
==Print multi-byte numbers in decimal==
Print 32-bit value in decimal with no padding or specified character
+
These routines will print 16-bit, 24-bit and 32-bit values in decimal with
padding. Smaller numbers can be printed by entering at PrDec32lp with
+
no padding or specified character padding. They can be optimised for for
Y set to an appropriate number of digits, eg <code>LDY #5</code> for
+
specific implementations.
printing a 16-bit number.
 
  
     \ -------------------------------------
+
===16-bit decimal===
     \ PrDec32 - Print 32-bit decimal number
+
     \ ---------------------------
     \ Originally from HADFS ROM source
+
     \ Print 16-bit decimal number
    \ -------------------------------------
+
     \ ---------------------------
     \ On entry, num..num+3=number
+
     \ On entry, num=number to print
     \          flg      =pad character or zero for no padding
+
     \          pad=0 or pad character (eg '0' or ' ')
     \          sub..sub+3=division workspace
+
    \ On entry at PrDec16Lp1,
     \ On exit, A,X,Y,num,sub,flg corrupted
+
     \          Y=(number of digits)*2-2, eg 8 for 5 digits
     \ ---------------------------------------------------------
+
     \ On exit, A,X,Y,num,pad corrupted
     .PrDec32
+
     \ Size      69 bytes
     LDY #9                        :\ 9+1 digits
+
    \ -----------------------------------------------------------------
     .PrDec32lp
+
     .PrDec16
     TYA:PHA                        :\ Save Y=power of ten
+
     LDY #8                                  :\ Offset to powers of ten
     JSR PrComma                    :\ Print a comma if needed
+
     .PrDec16Lp1
     LDX #3:LDA #0
+
     LDX #&FF:SEC                            :\ Start with digit=-1
    .Power10lp1
+
     .PrDec16Lp2
    STA sub,X:DEX:BPL Power10lp1  :\ sub=0
+
     LDA num+0:SBC PrDec16Tens+0,Y:STA num+0  :\ Subtract current tens
     INC sub:LDX #sub              :\ sub=1
+
     LDA num+1:SBC PrDec16Tens+1,Y:STA num+1
     .Power10lp2
+
     INX:BCS PrDec16Lp2                      :\ Loop until <0
    JSR Times10X:DEY:BNE Power10lp2:\ sub=10^Y
+
     LDA num+0:ADC PrDec16Tens+0,Y:STA num+0  :\ Add current tens back in
     JSR DivideNum:JSR PrDigit      :\ Divide, print digit or pad character
+
     LDA num+1:ADC PrDec16Tens+1,Y:STA num+1
    PLA:TAY:DEY:BNE PrDec32lp      :\ Loop through digits
+
     TXA:BNE PrDec16Digit                     :\ Not zero, print it
     LDA num:BPL PrDig1            :\ Print final digit
+
     LDA pad:BNE PrDec16Print:BEQ PrDec16Next :\ pad<>0, use it
     :
+
     .PrDec16Digit
    .PrDigit
+
     LDX #ASC"0":STX pad                      :\ No more zero padding
    BNE PrDig1                     :\ Non-zero, print digit
+
     ORA #ASC"0"                             :\ Print this digit
     LDA flg:BEQ PrDig2            :\ No pad character, return
+
    .PrDec16Print
    JMP OSWRCH                    :\ Pad character, print it
+
    JSR OSWRCH
     .PrDig1
+
     .PrDec16Next
     ORA #ASC"0":JSR OSWRCH        :\ Print digit
+
    DEY:DEY:BPL PrDec16Lp1                  :\ Loop for next digit
     LDA #ASC"0":STA flg            :\ Print zeros from now on
 
     .PrDig2
 
 
     RTS
 
     RTS
 
     :
 
     :
     \ Print a comma every three digits
+
    .PrDec16Tens
     \ Omit this code and JSR PrComma if no commas required
+
    EQUW 1
     \ ----------------------------------------------------
+
    EQUW 10
     .PrComma
+
    EQUW 100
     CPY #2:BEQ PrComma1
+
    EQUW 1000
     CPY #5:BEQ PrComma1
+
    EQUW 10000
     CPY #8:BEQ PrComma1
+
    \ -----------------------------------------------------------------
     .PrComma0
+
===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
 
     RTS
    .PrComma1
 
    LDX flg:LDA #ASC","            :\ Prepare a comma
 
    CPX #ASC"0":BEQ PrComma2      :\ Zeros being printed, print comma
 
    TXA                            :\ Otherwise print pad character
 
    .PrComma2
 
    TAX:BEQ PrComma0:JMP OSWRCH    :\ Print if not null pad character
 
 
     :
 
     :
     \ -------------------------------------
+
    .PrDec24Tens
    \ DivideNum - Divide num by sub
+
    EQUW 1      :EQUB 1 DIV 65536
     \ -------------------------------------
+
    EQUW 10      :EQUB 10 DIV 65536
     \ On entry, num=32-bit number
+
    EQUW 100    :EQUB 100 DIV 65536
     \          sub=32-bit divisor
+
    EQUW 1000    :EQUB 1000 DIV 65536
     \ On exit, A=num DIV sub, Z=(A=0)
+
    EQUW 10000  :EQUB 10000 DIV 65536
     \          num=num MOD sub
+
    EQUW 100000  :EQUB 100000 DIV 65536
     \           Y preserved, X corrupted
+
    EQUW 1000000 :EQUB 1000000 DIV 65536
     \ ----------------------------------------
+
    EQUW 10000000:EQUB 10000000 DIV 65536
     .DivideNum
+
     \ -----------------------------------------------------------------
     LDX #255:SEC
+
===32-bit decimal===
     .DivLp
+
     \ ---------------------------
    INX
+
    \ Print 32-bit decimal number
     LDA num+0:SBC sub+0:STA num+0
+
    \ ---------------------------
     LDA num+1:SBC sub+1:STA num+1
+
     \ On entry, num=number to print
     LDA num+2:SBC sub+2:STA num+2
+
     \          pad=0 or pad character (eg '0' or ' ')
     LDA num+3:SBC sub+3:STA num+3
+
     \ On entry at PrDec32Lp1,
     BCS DivLp
+
     \          Y=(number of digits)*4-4, eg 36 for 10 digits
     LDA num+0:ADC sub+0:STA num+0
+
     \ On exit,  A,X,Y,num,pad corrupted
     LDA num+1:ADC sub+1:STA num+1
+
    \ Size      129 bytes
     LDA num+2:ADC sub+2:STA num+2
+
     \ -----------------------------------------------------------------
     LDA num+3:ADC sub+3:STA num+3
+
     .PrDec32
     TXA:RTS
+
    LDY #36                                  :\ Offset to powers of ten
    :
+
    .PrDec32Lp1
    \ -------------------------------
+
     LDX #&FF:SEC                             :\ Start with digit=-1
     \ Times10 - Multiple number by 10
+
     .PrDec32Lp2
    \ -------------------------------
+
     LDA num+0:SBC PrDec32Tens+0,Y:STA num+0 :\ Subtract current tens
    \ On entry, X=>zero page number
+
     LDA num+1:SBC PrDec32Tens+1,Y:STA num+1
    \ On exit, X,Y preserved, A,F corrupted
+
     LDA num+2:SBC PrDec32Tens+2,Y:STA num+2
    \ -------------------------------------
+
     LDA num+3:SBC PrDec32Tens+3,Y:STA num+3
     .Times10X
+
     INX:BCS PrDec32Lp2                      :\ Loop until <0
     JSR TimesTwo              :\ n*2
+
     LDA num+0:ADC PrDec32Tens+0,Y:STA num+0 :\ Add current tens back in
     LDA 3,X:PHA:LDA 2,X:PHA    :\ save n*2
+
     LDA num+1:ADC PrDec32Tens+1,Y:STA num+1
     LDA 1,X:PHA:LDA 0,X:PHA
+
     LDA num+2:ADC PrDec32Tens+2,Y:STA num+2
     JSR TimesTwo:JSR TimesTwo  :\ n*8
+
     LDA num+3:ADC PrDec32Tens+3,Y:STA num+3
     PLA:ADC 0,X:STA 0,X        :\ n*8+n*2 = n*10
+
     TXA:BNE PrDec32Digit                    :\ Not zero, print it
     PLA:ADC 1,X:STA 1,X
+
     LDA pad:BNE PrDec32Print:BEQ PrDec32Next :\ pad<>0, use it
    PLA:ADC 2,X:STA 2,X
+
     .PrDec32Digit
    PLA:ADC 3,X:STA 3,X
+
     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
 
     RTS
 
     :
 
     :
     .TimesTwo
+
     .PrDec32Tens
     ASL 0,X:ROL 1,X            :\ n=n*2
+
     EQUD 1
     ROL 2,X:ROL 3,X:RTS
+
     EQUD 10
     :
+
    EQUD 100
 +
    EQUD 1000
 +
    EQUD 10000
 +
    EQUD 100000
 +
    EQUD 1000000
 +
    EQUD 10000000
 +
    EQUD 100000000
 +
    EQUD 1000000000
 +
     \ -----------------------------------------------------------------
 +
 
 
[[User:Jgharston|Jgharston]] 07:51, 25 December 2011 (UTC)
 
[[User:Jgharston|Jgharston]] 07:51, 25 December 2011 (UTC)
 +
[[User:Jgharston|Jgharston]] ([[User talk:Jgharston|talk]]) 07:13, 30 June 2018 (CEST)

Latest revision as of 06:13, 30 June 2018

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)