IF (DEFINED PRNUM16) AND ((DEFINED _WITH_PRNUM32)) = 0
ERR "Must INCLUDE PRNUM16 after PRNUM32."
ENDI
;; ======================================================================== ;;
;; PRNUM32.l -- Print an unsigned 32-bit number left-justified. ;;
;; PRNUM32.b -- Print an unsigned 32-bit number with leading blanks. ;;
;; PRNUM32.z -- Print an unsigned 32-bit number with leading zeros. ;;
;; ;;
;; AUTHOR ;;
;; Joseph Zbiciak ;;
;; ;;
;; REVISION HISTORY ;;
;; 30-Mar-2003 Initial complete revision ;;
;; ;;
;; INPUTS for all variants ;;
;; R0 Lower 16 bits of number to print ;;
;; R1 Upper 16 bits of number to print ;;
;; R2 Width of field. Must be >= 5. Ignored by PRNUM32.l. ;;
;; R3 Format word, added to digits to set the color, etc. ;;
;; Note: Bit 15 is ignored and manipulated internally. ;;
;; R4 Pointer to location on screen to print number ;;
;; R5 Return address ;;
;; ;;
;; OUTPUTS ;;
;; R0 Zeroed ;;
;; R1 Trashed ;;
;; R2 Unmodified ;;
;; R3 Unmodified, except for bit 15, which may be set. ;;
;; R4 Points to first character after field. ;;
;; R5 Trashed ;;
;; ;;
;; DESCRIPTION ;;
;; These routines print unsigned 32-bit numbers in a field 5 to 10 ;;
;; positions wide. The number is printed either in left-justified ;;
;; or right-justified format. Right-justified numbers are padded ;;
;; with leading blanks or leading zeros. Left-justified numbers ;;
;; are not padded on the right. ;;
;; ;;
;; See PRNUM16 for a table illustrating output formats. ;;
;; ;;
;; TECHNIQUES ;;
;; This routine uses a 32-by-16 integer divide to cut the 32-bit ;;
;; number into two 5-digit segments. It divides the initial number ;;
;; by 100000. The quotient provides the upper half, and the ;;
;; remainder provides the lower half. ;;
;; ;;
;; Both halves are printed by reusing the PRNUM16 routines. The ;;
;; lower half is always printed using PRNUM16.z. The upper half is ;;
;; printed using one of PRNUM16.l, PRNUM16.b, or PRNUM16.z, based on ;;
;; which entry point the caller used for invoking PRNUM32. ;;
;; ;;
;; The number in the lower half can be in the range 00000...99999. ;;
;; Some of this range is outside the range of a 16-bit value. We ;;
;; handle this by passing a special flag to PRNUM16 in bit 15 of ;;
;; the format word. When set, PRNUM16 will add '5' to the leading ;;
;; digit of the number. When clear, it leaves it unmodified. ;;
;; Thus, when our lower half is in the range 65536...99999, we cope ;;
;; by adding 15536 to the lower 16 bits and setting the "add 5" flag. ;;
;; This works, because the lower 16 bits are in the range 0 - 34463. ;;
;; After the 'tweak', they're in the range 15536 - 49999. ;;
;; ;;
;; NOTES ;;
;; The left-justified variant ignores the field width. ;;
;; ;;
;; This code is fully reentrant, although it has a significant stack ;;
;; footprint. ;;
;; ;;
;; This code does not handle numbers which are too large to be ;;
;; displayed in the provided field. If the number is too large, ;;
;; non-digit characters will be displayed in the initial digit ;;
;; position. Also, the run time of this routine may get excessively ;;
;; large, depending on the magnitude of the overflow. ;;
;; ;;
;; This code requires PRNUM16. Since PRNUM16 requires a minor tweak ;;
;; to support PRNUM32, it must either be included after PRNUM32, or ;;
;; assembled with the symbol "_WITH_PRNUM32" set. ;;
;; ;;
;; CODESIZE ;;
;; 81 words (not including PRNUM16.) ;;
;; ;;
;; To save code size, you can define the following symbols to omit ;;
;; some variants: ;;
;; ;;
;; _NO_PRNUM32.l: Disables PRNUM32.l. Saves 8 words. ;;
;; _NO_PRNUM32.b: Disables PRNUM32.b. Saves 8 words. ;;
;; ;;
;; Defining both symbols saves 18 words total, because it omits ;;
;; some code shared by both routines. ;;
;; ;;
;; STACK USAGE ;;
;; This function uses up to 8 words of stack space. That includes ;;
;; 4 words of stack space consumed by PRNUM16 when printing the ;;
;; two halves of the number. ;;
;; ;;
;; LICENSE ;;
;; GNU General Public License, Version 2.0. ;;
;; ;;
;; This program is free software; you can redistribute it and/or ;;
;; modify it under the terms of the GNU General Public License as ;;
;; published by the Free Software Foundation; either version 2 of the ;;
;; License, or (at your option) any later version. ;;
;; ;;
;; This program is distributed in the hope that it will be useful, ;;
;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;
;; General Public License for more details. ;;
;; ;;
;; You should have received a copy of the GNU General Public License ;;
;; along with this program; if not, write to the Free Software ;;
;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ;;
;; ------------------------------------------------------------------------ ;;
;; Copyright (c) 2003, Joseph Zbiciak ;;
;; ======================================================================== ;;
IF (DEFINED PRNUM32) = 0
PRNUM32 PROC
IF (DEFINED _NO_PRNUM32.l) = 0
;; ---------------------------------------------------------------- ;;
;; PRNUM32.l: Print unsigned, left-justified. ;;
;; ---------------------------------------------------------------- ;;
@@l: TSTR R1
BEQ PRNUM16.l
PSHR R5
MVII #PRNUM16.l, R5
B @@com
ENDI
IF (DEFINED _NO_PRNUM32.b) = 0
;; ---------------------------------------------------------------- ;;
;; PRNUM32.b: Print unsigned with leading blanks. ;;
;; ---------------------------------------------------------------- ;;
@@b: TSTR R1
BEQ PRNUM16.b
PSHR R5
MVII #PRNUM16.b, R5
B @@com
ENDI
;; ---------------------------------------------------------------- ;;
;; PRNUM32.z: Print unsigned with leading zeros. ;;
;; ---------------------------------------------------------------- ;;
@@z: TSTR R1
BEQ PRNUM16.z
PSHR R5
IF NOT ((DEFINED _NO_PRNUM32.l) AND (DEFINED _NO_PRNUM32.b))
MVII #PRNUM16.z, R5
ENDI
@@com PSHR R2 ; save our field width
PSHR R3 ; save our format word
;; ---------------------------------------------------------------- ;;
;; Divide the 32-bit number by 100000, and remember the remainder. ;;
;; This will give us two 5-digit numbers for the two halves. ;;
;; The upper half will always be in the range 0 to 42949, and so ;;
;; we can print it with one of the PRNUM16 routines. The lower ;;
;; half is in the range 0...99999, so we have to do some fancy ;;
;; footwork in the case that it's above 65535. ;;
;; ;;
;; The loop below looks like it divides by 50000, but really we've ;;
;; aligned the divisor within a 16-bit number. ;;
;; ---------------------------------------------------------------- ;;
MVII #50000, R2 ; 100000, right shifted by 1.
MVII #1, R3 ; Divide is done when this bit falls out of R3
B @@div1 ; jump to the first divide step.
@@div: RLC R0, 1 ;\__ 32 bit left shift of numerator.
RLC R1, 1 ;/
BC @@divf ; last shift overflowed, force a subtract
@@div1: CMPR R2, R1 ; can we subtract from upper half?
BNC @@divn ; nope, then don't subtract.
@@divf: SUBR R2, R1 ; subtract upper half.
SETC ; usu. the SUBR sets carry, except when forced
@@divn: RLC R3, 1 ; left-shift the quotient, including new bit
BNC @@div ; loop until quotient is full.
;; ---------------------------------------------------------------- ;;
;; At this point, R1:R0 is our remainder, and R3 is our quotient. ;;
;; The remainder occupies the upper 17 bits of the R1:R0 pair. ;;
;; For now, hide this on the stack. We do this dance carefully ;;
;; since we need to restore two items from the stack as well, ;;
;; and we don't want to lose the values in R4 or R5 either. ;;
;; ;;
;; If there was no "upper half" (eg. our value is 65536...99999) ;;
;; go handle that case specially. Urgl. ;;
;; ---------------------------------------------------------------- ;;
SLLC R0, 1 ; put 17th bit into carry
MOVR R3, R0 ; save quotient into R0
PULR R3 ; recall our format word into R3
PULR R2 ; recall our field width
RLC R1, 1 ; R1 is bits 15 downto 0 of remainder
SLL R3, 1 ; \_ Force bit 15 of format word to 1 or 0.
RRC R3, 1 ; / This will add 5 to leading digit.
TSTR R3 ;
BPL @@lt64k ; if there was no carry, rmdr is 0...65535
ADDI #15536, R1 ; add "15536" to rest of digits
@@lt64k:
TSTR R0
BEQ @@notop ; convert bottom into top if top = 0.
PSHR R2 ; save field width on stack
PSHR R3 ; save format word for bottom half
PSHR R1 ; save quotient for bottom half
;; ---------------------------------------------------------------- ;;
;; Go ahead and print the first 5 digits of the result. ;;
;; ---------------------------------------------------------------- ;;
SUBI #5, R2 ; bottom accounts for 5 digits of field width
ANDI #$7FFF, R3 ; force bit 15 of R3 clear.
IF (DEFINED _NO_PRNUM32.l) AND (DEFINED _NO_PRNUM32.b)
CALL PRNUM16.z
ELSE
MOVR R5, R1 ; R5 contains branch target.
MVII #@@ret, R5 ; remember return address.
MOVR R1, PC ; call one of PRNUM16.z, .b, or .l as needed
@@ret:
ENDI
;; ---------------------------------------------------------------- ;;
;; Print the bottom half of the number. We branch into the ;;
;; heart of PRNUM16, which effectively always leads with zeros. ;;
;; ---------------------------------------------------------------- ;;
MVII #4, R2 ; bottom is always exactly 5 digits.
PULR R0 ; get bits 15 downto 0 of remainder
PULR R3 ; get format word.
INCR SP ; save garbage in R1 slot on stack
MVII #_PW10, R1 ; need to set up power-of-10 pointer first
B PRNUM16.dig1 ; chain return via PRNUM16.digit
;; ---------------------------------------------------------------- ;;
;; If there was no "upper half", convert the "lower half" into an ;;
;; upper half. This actually isn't too gross. ;;
;; ---------------------------------------------------------------- ;;
@@notop:
MOVR R1, R0 ; convert bottom half to top half
IF (DEFINED _NO_PRNUM32.l) AND (DEFINED _NO_PRNUM32.b)
PULR R5
B PRNUM16.z
ELSE
MOVR R5, R1 ; \
PULR R5 ; |__ chain return via target PRNUM16 routine
JR R1 ; /
ENDI
ENDP
ENDI
;; ======================================================================== ;;
;; End of File: prnum32.asm ;;
;; ======================================================================== ;;