BBC Micro Elite

# Text: BPRNT

```       Name: BPRNT                                             [View in context]
Type: Subroutine
Category: Text
Summary: Print a 32-bit number, left-padded to n digits, and optional point

Print the 32-bit number stored in K(0 1 2 3) to a specific number of digits,
left-padding with spaces for numbers with fewer digits (so lower numbers are
right-aligned). Optionally include a decimal point.

Arguments:

K(0 1 2 3)           The number to print, stored with the most significant
byte in K and the least significant in K+3 (big-endian,
which is not the same way that 6502 assembler stores

U                    The maximum number of digits to print, including the
decimal point (spaces will be used on the left to pad
out the result to this width, so the number is right-
aligned to this width). The maximum number of characters
including any decimal point must be 11 or less

C flag               If set, include a decimal point followed by one
fractional digit (i.e. show the number to 1 decimal
place). In this case, the number in K to K+3 contains
10 * the number we end up printing, so to print 123.4,
we would pass 1234 in K to K+3 and would set the C flag

.BPRNT
{
LDX #11                \ Set T to the maximum number of digits allowed (11
STX T                  \ characters, which is the number of digits in 10
\ billion); we will use this as a flag when printing
\ characters in TT37 below

PHP                    \ Make a copy of the status register (in particular
\ the carry flag) so we can retrieve it later

BCC TT30               \ If the carry flag is clear, we do not want to print a
\ decimal point, so skip the next two instructions

DEC T                  \ As we are going to show a decimal point, decrement
DEC U                  \ both the number of characters and the number of
\ digits (as one of them is now a decimal point)

.TT30

LDA #11                \ Set A to 11, the maximum number of digits allowed

SEC                    \ Set the carry flag so we can do subtraction without
\ the carry flag affecting the result

STA XX17               \ Store the maximum number of digits allowed (11) in
\ XX17

SBC U                  \ Set U = 11 - U + 1, so U now contains the maximum
STA U                  \ number of digits minus the number of digits we want
INC U                  \ to display, plus 1 (so this is the number of digits
\ we should skip before starting to print the number
\ itself, and the plus 1 is there to ensure we at least
\ print one digit)

LDY #0                 \ In the main loop below, we use Y to count the number
\ of times we subtract 10 billion to get the leftmost
\ digit, so set this to zero (see below TT36 for an
\ of how this algorithm works)

STY S                  \ In the main loop below, we use location S as an
\ 8-bit overflow for the 32-bit calculations, so
\ we need to set this to 0 before joining the loop

JMP TT36               \ Jump to TT36 to start the process of printing this
\ number's digits

.TT35

\ This subroutine multiplies K(S 0 1 2 3) by 10 and
\ stores the result back in K(S 0 1 2 3), using the
\ (K * 2) + (K * 2 * 2 * 2) approach described above

ASL K+3                \ Set K(S 0 1 2 3) = K(S 0 1 2 3) * 2 by rotating left
ROL K+2
ROL K+1
ROL K
ROL S

LDX #3                 \ Now we want to make a copy of the newly doubled K in
\ XX15, so we can use it for the first (K * 2) in the
\ equation above, so set up a counter in X for copying
\ four bytes, starting with the last byte in memory
\ (i.e. the least significant)

.tt35

LDA K,X                \ Copy the X-th byte of K(0 1 2 3) to the X-th byte of
STA XX15,X             \ XX15(0 1 2 3), so that XX15 will contain a copy of
\ K(0 1 2 3) once we've copied all four bytes

DEX                    \ Decrement the loop counter so we move to the next
\ byte, going from least significant (3) to most
\ significant (0)

BPL tt35               \ Loop back to copy the next byte

LDA S                  \ Store the value of location S, our overflow byte, in
STA XX15+4             \ XX15+4, so now XX15(4 0 1 2 3) contains a copy of
\ K(S 0 1 2 3), which is the value of (K * 2) that we
\ want

ASL K+3                \ Now to calculate the (K * 2 * 2 * 2) part. We still
ROL K+2                \ have (K * 2) in K(S 0 1 2 3), so we just need to
ROL K+1                \ it twice. This is the first one, so we do this:
ROL K                  \
ROL S                  \   K(S 0 1 2 3) = K(S 0 1 2 3) * 2 = K * 4

ASL K+3                \ And then we do it again, so that means:
ROL K+2                \
ROL K+1                \   K(S 0 1 2 3) = K(S 0 1 2 3) * 2 = K * 8
ROL K
ROL S

CLC                    \ Clear the carry flag so we can do addition without
\ the carry flag affecting the result

LDX #3                 \ By now we've got (K * 2) in XX15(4 0 1 2 3) and
\ (K * 8) in K(S 0 1 2 3), so the final step is to add
\ these two 32-bit numbers together to get K * 10.
\ So we set a counter in X for four bytes, starting
\ with the last byte in memory (i.e. the least
\ significant)

.tt36

LDA K,X                \ Fetch the X-th byte of K into A

ADC XX15,X             \ Add the X-th byte of XX15 to A, with carry

STA K,X                \ Store the result in the X-th byte of K

DEX                    \ Decrement the loop counter so we move to the next
\ byte, going from least significant (3) to most
\ significant (0)

BPL tt36               \ Loop back to add the next byte

LDA XX15+4             \ Finally, fetch the overflow byte from XX15(4 0 1 2 3)

ADC S                  \ And add it to the overflow byte from K(S 0 1 2 3),
\ with carry

STA S                  \ And store the result in the overflow byte from
\ K(S 0 1 2 3), so now we have our desired result that
\ K(S 0 1 2 3) is now K(S 0 1 2 3) * 10

LDY #0                 \ In the main loop below, we use Y to count the number
\ of times we subtract 10 billion to get the leftmost
\ digit, so set this to zero

.TT36

\ This is the main loop of our digit-printing routine.
\ In the following loop, we are going to count the
\ number of times that we can subtract 10 million in Y,
\ which we have already set to 0

LDX #3                 \ Our first calculation concerns 32-bit numbers, so
\ set up a counter for a four-byte loop

SEC                    \ Set the carry flag so we can do subtraction without
\ the carry flag affecting the result

.tt37

\ Now we loop thorough each byte in turn to do this:
\
\   XX15(4 0 1 2 3) = K(S 0 1 2 3) - 100,000,000,000

LDA K,X                \ Subtract the X-th byte of TENS (i.e. 10 billion) from
SBC TENS,X             \ the X-th byte of K

STA XX15,X             \ Store the result in the X-th byte of XX15

DEX                    \ Decrement the loop counter so we move to the next
\ byte, going from least significant (3) to most
\ significant (0)

BPL tt37               \ Loop back to subtract from the next byte

LDA S                  \ Subtract the fifth byte of 10 billion (i.e. &17) from
SBC #&17               \ the fifth (overflow) byte of K, which is S

STA XX15+4             \ Store the result in the overflow byte of XX15

BCC TT37               \ If subtracting 10 billion took us below zero, jump to
\ TT37 to print out this digit, which is now in Y

LDX #3                 \ We now want to copy XX15(4 0 1 2 3) back to
\ K(S 0 1 2 3), so we can loop back up to do the next
\ subtraction, so set up a counter for a four-byte loop

.tt38

LDA XX15,X             \ Copy the X-th byte of XX15(0 1 2 3) to the X-th byte
STA K,X                \ of K(0 1 2 3), so that K will contain a copy of
\ XX15(0 1 2 3) once we've copied all four bytes

DEX                    \ Decrement the loop counter so we move to the next
\ byte, going from least significant (3) to most
\ significant (0)

BPL tt38               \ Loop back to copy the next byte

LDA XX15+4             \ Store the value of location XX15+4, our overflow
STA S                  \ byte in S, so now K(S 0 1 2 3) contains a copy of
\ XX15(4 0 1 2 3)

INY                    \ We have now managed to subtract 10 billion from our
\ number, so increment Y, which is where we are keeping
\ count of the number of subtractions so far

JMP TT36               \ Jump back to TT36 to subtract the next 10 billion

.TT37

TYA                    \ If we get here then Y contains the digit that we want
\ to print (as Y has now counted the total number of
\ subtractions of 10 billion), so transfer Y into A

BNE TT32               \ If the digit is non-zero, jump to TT32 to print it

LDA T                  \ Otherwise the digit is zero. If we are already
\ printing the number then we will want to print a 0,
\ but if we haven't started printing the number yet,
\ then we probably don't, as we don't want to print
\ leading zeroes unless this is the only digit before
\ the decimal point
\
\ To help with this, we are going to use T as a flag
\ that tells us whether we have already started
\ printing digits:
\
\   * If T <> 0 we haven't printed anything yet
\
\   * If T = 0 then we have started printing digits
\
\ We initially set T to the maximum number of
\ characters allowed at, less 1 if we are printing a
\ decimal point, so the first time we enter the digit
\ printing routine at TT37, it is definitely non-zero

BEQ TT32               \ If T = 0, jump straight to the print routine at TT32,
\ as we have already started printing the number, so we
\ definitely want to print this digit too

DEC U                  \ We initially set U to the number of digits we want to
BPL TT34               \ skip before starting to print the number. If we get
\ here then we haven't printed any digits yet, so
\ decrement U to see if we have reached the point where
\ we should start printing the number, and if not, jump
\ to TT34 to set up things for the next digit

LDA #' '               \ We haven't started printing any digits yet, but we
BNE tt34               \ have reached the point where we should start printing
\ our number, so call TT26 (via tt34) to print a space
\ so that the number is left-padded with spaces (this
\ BNE is effectively a JMP as A will never be zero)

.TT32

LDY #0                 \ We are printing an actual digit, so first set T to 0,
STY T                  \ to denote that we have now started printing digits as
\ opposed to spaces

CLC                    \ The digit value is in A, so add ASCII "0" to get the
ADC #'0'               \ ASCII character number to print

.tt34

JSR TT26               \ Print the character in A and fall through into TT34
\ to get things ready for the next digit

.TT34

DEC T                  \ Decrement T but keep T >= 0 (by incrementing it
BPL P%+4               \ again if the above decrement made T negative)
INC T

DEC XX17               \ Decrement the total number of characters to print in
\ XX17

BMI RR3+1              \ If it is negative, we have printed all the characters
\ so return from the subroutine (as RR3 contains an
\ ORA #&60 instruction, so RR3+1 is &60, which is the
\ opcode for an RTS)

BNE P%+10              \ If it is positive (> 0) loop back to TT35 (via the
\ last instruction in this subroutine) to print the
\ next digit

PLP                    \ If we get here then we have printed the exact number
\ of digits that we wanted to, so restore the carry
\ flag that we stored at the start of BPRNT

BCC P%+7               \ If carry is clear, we don't want a decimal point, so
\ look back to TT35 (via the last instruction in this
\ subroutine) to print the next digit

LDA #'.'               \ Print the decimal point
JSR TT26

JMP TT35               \ Loop back to TT35 to print the next digit
}
```