Prnum16.asm
Revision as of 09:06, 4 December 2010 by Mr z (talk | contribs) (Protected "Prnum16.asm" ([edit=autoconfirmed] (indefinite) [move=autoconfirmed] (indefinite)))
Functions Provided
Entry point | Function provided | Notes |
---|---|---|
PRNUM16.l | Print a 16-bit decimal number | Prints the number left-justified. (The name is PRNUM16.l with a lower-case L at the end, not a 1.) |
PRNUM16.b | Prints the number with leading blanks, right justified in a fixed-width field. | |
PRNUM16.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 is used by prnum32.asm. Therefore, you will need to include both in your application if you're using prnum32.asm to print 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 *; ;* ======================================================================== *; ;; ======================================================================== ;; ;; _PW10 ;; ;; Lookup table holding the first 5 powers of 10 (1 thru 10000) as ;; ;; 16-bit numbers. ;; ;; ======================================================================== ;; IF (DEFINED _PW10) = 0 _PW10 PROC ; 0 thru 10000 DECLE 10000, 1000, 100, 10, 1, 0 ENDP ENDI ;; ======================================================================== ;; ;; PRNUM16.l -- Print an unsigned 16-bit number left-justified. ;; ;; PRNUM16.b -- Print an unsigned 16-bit number with leading blanks. ;; ;; PRNUM16.z -- Print an unsigned 16-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 Number to print. ;; ;; R2 Width of field. Ignored by PRNUM16.l. ;; ;; R3 Format word, added to digits to set the color. ;; ;; Note: Bit 15 MUST be cleared when building with PRNUM32. ;; ;; R4 Pointer to location on screen to print number ;; ;; ;; ;; OUTPUTS ;; ;; R0 Zeroed ;; ;; R1 Unmodified ;; ;; R2 Unmodified ;; ;; R3 Unmodified ;; ;; R4 Points to first character after field. ;; ;; ;; ;; DESCRIPTION ;; ;; These routines print unsigned 16-bit numbers in a field up to 5 ;; ;; 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. ;; ;; ;; ;; This code handles fields wider than 5 characters, padding with ;; ;; zeros or blanks as necessary. ;; ;; ;; ;; Routine Value(hex) Field Output ;; ;; ---------- ---------- ---------- ---------- ;; ;; PRNUM16.l $0045 n/a "69" ;; ;; PRNUM16.b $0045 4 " 69" ;; ;; PRNUM16.b $0045 6 " 69" ;; ;; PRNUM16.z $0045 4 "0069" ;; ;; PRNUM16.z $0045 6 "000069" ;; ;; ;; ;; TECHNIQUES ;; ;; This routine uses repeated subtraction to divide the number ;; ;; to display by various powers of 10. This is cheaper than a ;; ;; full divide, at least when the input number is large. It's ;; ;; also easier to get right. :-) ;; ;; ;; ;; The printing routine first pads out fields wider than 5 spaces ;; ;; with zeros or blanks as requested. It then scans the power-of-10 ;; ;; table looking for the first power of 10 that is <= the number to ;; ;; display. While scanning for this power of 10, it outputs leading ;; ;; blanks or zeros, if requested. This eliminates "leading digit" ;; ;; logic from the main digit loop. ;; ;; ;; ;; Once in the main digit loop, we discover the value of each digit ;; ;; by repeated subtraction. We build up our digit value while ;; ;; subtracting the power-of-10 repeatedly. We iterate until we go ;; ;; a step too far, and then we add back on power-of-10 to restore ;; ;; the remainder. ;; ;; ;; ;; NOTES ;; ;; The left-justified variant ignores field width. ;; ;; ;; ;; The code is fully reentrant. ;; ;; ;; ;; 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. ;; ;; ;; ;; When using with PRNUM32, one must either include PRNUM32 before ;; ;; this function, or define the symbol _WITH_PRNUM32. PRNUM32 ;; ;; needs a tiny bit of support from PRNUM16 to handle numbers in ;; ;; the range 65536...99999 correctly. ;; ;; ;; ;; CODESIZE ;; ;; 73 words, including power-of-10 table ;; ;; 80 words, if compiled with PRNUM32. ;; ;; ;; ;; To save code size, you can define the following symbols to omit ;; ;; some variants: ;; ;; ;; ;; _NO_PRNUM16.l: Disables PRNUM16.l. Saves 10 words ;; ;; _NO_PRNUM16.b: Disables PRNUM16.b. Saves 3 words. ;; ;; ;; ;; Defining both symbols saves 17 words total, because it omits ;; ;; some code shared by both routines. ;; ;; ;; ;; STACK USAGE ;; ;; This function uses up to 4 words of stack space. ;; ;; ======================================================================== ;; IF (DEFINED PRNUM16) = 0 PRNUM16 PROC ;; ---------------------------------------------------------------- ;; ;; PRNUM16.l: Print unsigned, left-justified. ;; ;; ---------------------------------------------------------------- ;; IF (DEFINED _NO_PRNUM16.l) = 0 @@l: PSHR R5 ; save return address @@l1: MVII #$1, R5 ; set R5 to 1 to counteract screen ptr update ; in the 'find initial power of 10' loop PSHR R2 MVII #5, R2 ; force effective field width to 5. B @@z2 ENDI ;; ---------------------------------------------------------------- ;; ;; PRNUM16.b: Print unsigned with leading blanks. ;; ;; ---------------------------------------------------------------- ;; IF (DEFINED _NO_PRNUM16.b) = 0 @@b: PSHR R5 @@b1: CLRR R5 ; let the blank loop do its thing INCR PC ; skip the PSHR R5 ENDI ;; ---------------------------------------------------------------- ;; ;; PRNUM16.z: Print unsigned with leading zeros. ;; ;; ---------------------------------------------------------------- ;; @@z: PSHR R5 @@z1: PSHR R2 @@z2: PSHR R1 ;; ---------------------------------------------------------------- ;; ;; Find the initial power of 10 to use for display. ;; ;; Note: For fields wider than 5, fill the extra spots above 5 ;; ;; with blanks or zeros as needed. ;; ;; ---------------------------------------------------------------- ;; MVII #_PW10+5,R1 ; Point to end of power-of-10 table SUBR R2, R1 ; Subtract the field width to get right power PSHR R3 ; save format word IF ((DEFINED _NO_PRNUM16.l) AND (DEFINED _NO_PRNUM16.b)) = 0 CMPI #2, R5 ; are we leading with zeros? BNC @@lblnk ; no: then do the loop w/ blanks IF (DEFINED _NO_PRNUM16.l) = 0 CLRR R5 ; force R5==0 ENDI ENDI ADDI #$80, R3 ; yes: do the loop with zeros B @@lblnk @@llp MVO@ R3, R4 ; print a blank/zero IF (DEFINED _NO_PRNUM16.l) = 0 SUBR R5, R4 ; rewind pointer if needed. ENDI INCR R1 ; get next power of 10 @@lblnk DECR R2 ; decrement available digits BEQ @@ldone CMPI #5, R2 ; field too wide? BGE @@llp ; just force blanks/zeros 'till we're narrower. CMP@ R1, R0 ; Is this power of 10 too big? BNC @@llp ; Yes: Put a blank and go to next @@ldone PULR R3 ; restore format word ;; ---------------------------------------------------------------- ;; ;; The digit loop prints at least one digit. It discovers digits ;; ;; by repeated subtraction. ;; ;; ---------------------------------------------------------------- ;; @@digit TSTR R0 ; If the number is zero, print zero and leave BNEQ @@dig1 ; no: print the number MOVR R3, R5 ;\ ADDI #$80, R5 ; |-- print a 0 there. MVO@ R5, R4 ;/ B @@done IF (DEFINED PRNUM32) OR (DEFINED _WITH_PRNUM32) @@dig1: MOVR R3, R5 ; for first digit only: check to see if BPL @@cont ; we need to add '5'. ADDI #$80+4*8,R5 ; start our digit as one just before '5' B @@spcl ELSE @@dig1: ENDI @@nxdig MOVR R3, R5 ; save display format word @@cont: ADDI #$80-8, R5 ; start our digit as one just before '0' @@spcl: ;; ---------------------------------------------------------------- ;; ;; Divide by repeated subtraction. This divide is constructed ;; ;; to go "one step too far" and then back up. ;; ;; ---------------------------------------------------------------- ;; @@div: ADDI #8, R5 ; increment our digit SUB@ R1, R0 ; subtract power of 10 BC @@div ; loop until we go too far ADD@ R1, R0 ; add back the extra power of 10. MVO@ R5, R4 ; display the digit. INCR R1 ; point to next power of 10 DECR R2 ; any room left in field? BPL @@nxdig ; keep going until R2 < 0. @@done: PULR R1 ; restore R1 PULR R2 ; restore R2 PULR PC ; return ENDP ENDI ;; ======================================================================== ;; ;; End of File: prnum16.asm ;; ;; ======================================================================== ;;