I have been playing around with some 8-bit ideas to settle my brain among the daily chaos, and recently arrived at this little ditty, in the key of NMOS:
Code:
; u16out: Print a 16-bit unsigned integer to stdout by
; Michael T. Barry 2018.07.31. Free to copy, use and
; modify, but with NO warranty of any kind whatsoever.
; Credit and thanks to John Brooks for inspiring the
; V-flag and "loaded rts" tricks. 57 bytes.
; Entry: X reg points to a zp data frame containing:
; 0,x LSB of unsigned integer to print
; 1,x MSB " " "
; 2,x radix of conversion (2,4,6, .. ,34,36)
; digits above '9' come from ('A' .. 'Z')
; 3,x minimum output field_width (three bytes of
; stack are used for each char output, so
; wide fields should be used with caution)
; 4,x pad_char to be added to the left of the
; output to achieve the minimum field_width
; (this parameter is only used if padding is
; required, and unlike the above paramenters
; is not trashed by this subroutine, making
; it optional)
; Exit: X contents are preserved
; A, Y & data frame contents are NOT preserved
; Uses 3*(field_width)+2 bytes of the system return stack
.or f00 ;
u16out: ; our optimized in-line divmod
lsr 2,x ; prefers to work with radix/2
dec 3,x ; at least one digit will be output
u16outa: ; repeat {
lda #0 ; initialize 8-bit remainder
bit u16oute ; set V (quotient==0 flag)
ldy #16 ; prepare 16-bit/8-bit divmod
u16outb: ; repeat {
cmp 2,x ; partial remainder >= radix/2?
bcc u16outc ; no: proceed
sbc 2,x ; yes: update partial remainder
u16outc: ; CS, VC (quotient != 0)
rol 0,x ; the new quotient gradually
rol 1,x ; replaces the dividend
rol ; A is gradually replaced with
dey ; the new remainder
bne u16outb ; } until divmod is completed
php ; save V flag
cmp #10 ; digit > 9?
bcc u16outd ;
adc #6 ; yes: offset to upper case ALPHA
u16outd: ;
adc #'0' ; translate digit to ASCII
plp ; restore V flag
u16oute: ;
pha ; stack the digit (or pad char)
lda #>u16outf ;
pha ; stack the (address-1) of the
lda #<u16outf ; output routine to retrieve
pha ; the char and print it
dec 3,x ; update the field width counter
bvc u16outa ; } until the quotient is 0
bmi u16outf ; need any pad_chars for left side?
lda 4,x ; yes: prepare pad char and loop
bvs u16oute ; (always)
u16outf: ; this rts is "pre-loaded" to print
rts ; all the digits in reverse order
pla ; retrieve digit
jmp cout ; print it and proceed
.en ;
It's a subroutine that tests a few ideas about parameter passing and return stack trickery, with the added bonus that it prints any unsigned 16-bit integer to stdout in any even base from 2 to 36, with optional minimum field width and pad character parameters. Here's a peek at some example runs:
Attachment:
u16out.JPG [ 49.7 KiB | Viewed 1884 times ]
It is no speed demon, but packs all of this general-purpose functionality into only 57 bytes. I tried to provide adequate comments, but I can answer any questions you might have about the details. Critiques and suggestions for further optimization are also most welcome.
Please enjoy!
_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some
VTL02C on it and see how it grows on you!
Mike B.
(about me) (learning how to github)