Prnum32.asm
Functions Provided
Entry point | Function provided | Notes |
---|---|---|
PRNUM32.l | Print a 32-bit decimal number | Prints the number left-justified. (The name is PRNUM32.l with a lower-case L at the end, not a 1.) |
PRNUM32.b | Prints the number with leading blanks, right justified in a fixed-width field. | |
PRNUM32.z | Prints the number with leading zeros, right justified in a fixed-width field. |
See source code below for calling convention.
Examples
(todo... please contribute!)
Notes
This function uses prnum16.asm. Therefore, you will need to include both this and prnum16.asm in your application if you're printing 32-bit numbers.
Source Code
;* ======================================================================== *; ;* These routines are placed into the public domain by their author. All *; ;* copyright rights are hereby relinquished on the routines and data in *; ;* this file. -- Joseph Zbiciak, 2008 *; ;* ======================================================================== *; 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 <im14u2c AT globalcrossing DOT net> ;; ;; ;; ;; 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. ;; ;; ======================================================================== ;; 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 ;; ;; ======================================================================== ;;