I've been searching for a fast binary to decimal routine and the widespread solution is always dividing by 10 and all posible optmizations around division by 10.
But our beloved Z-80 doesn't like divisions. Although the BCD numbers are useful they can't be used everywhere specially for arithmetic intensive variables.
So I decided to make my own algorithm that converts from binary to BCD and then prints BCDs.
Googling around binary to BCDs is another bottleneck as the most common solution is the double-dabble. But for full 32-bit numbers that means shifting along 72 bits sequences for 32 times. Also conditional additions of 3 are performed between shifts for each nibble.
So I decided to make my very own binary to BCD using a good old LUT. For each bit I have a BCD number where I add using BCD math to the result. Then finally I convert the result BCD to a string.
.bios .page 2 .rom .start INIT db "DECIMAL PRINT", 0x1a BCD_LUT: db 0x00, 0x00, 0x00, 0x00, 0x01 db 0x00, 0x00, 0x00, 0x00, 0x02 db 0x00, 0x00, 0x00, 0x00, 0x04 db 0x00, 0x00, 0x00, 0x00, 0x08 db 0x00, 0x00, 0x00, 0x00, 0x16 db 0x00, 0x00, 0x00, 0x00, 0x32 db 0x00, 0x00, 0x00, 0x00, 0x64 db 0x00, 0x00, 0x00, 0x01, 0x28 db 0x00, 0x00, 0x00, 0x02, 0x56 db 0x00, 0x00, 0x00, 0x05, 0x12 db 0x00, 0x00, 0x00, 0x10, 0x24 db 0x00, 0x00, 0x00, 0x20, 0x48 db 0x00, 0x00, 0x00, 0x40, 0x96 db 0x00, 0x00, 0x00, 0x81, 0x92 db 0x00, 0x00, 0x01, 0x63, 0x84 db 0x00, 0x00, 0x03, 0x27, 0x68 db 0x00, 0x00, 0x06, 0x55, 0x36 db 0x00, 0x00, 0x13, 0x10, 0x72 db 0x00, 0x00, 0x26, 0x21, 0x44 db 0x00, 0x00, 0x52, 0x42, 0x88 db 0x00, 0x01, 0x04, 0x85, 0x76 db 0x00, 0x02, 0x09, 0x71, 0x52 db 0x00, 0x04, 0x19, 0x43, 0x04 db 0x00, 0x08, 0x38, 0x86, 0x08 db 0x00, 0x16, 0x77, 0x72, 0x16 db 0x00, 0x33, 0x55, 0x44, 0x32 db 0x00, 0x67, 0x10, 0x88, 0x64 db 0x01, 0x34, 0x21, 0x77, 0x28 db 0x02, 0x68, 0x43, 0x54, 0x56 db 0x05, 0x36, 0x87, 0x09, 0x12 db 0x10, 0x73, 0x74, 0x18, 0x24 db 0x21, 0x47, 0x48, 0x36, 0x48 INIT: xor a call CHGMOD ld hl,0 ld de,0 @@LOOP: push de push hl call PRINT_UINT32 pop hl pop de ld bc,1 and a adc hl,bc ex hl,de ld bc,0 adc hl,bc ex hl,de jp @@LOOP PRINT_UINT32: call BIN32_TO_BCD call PRINT_BCD ret PRINT_BCD: ld ix,BCD_RESULT ld b,5 ld iy,STR_RESULT @@LOOP: ld a,[ix] inc ix ld c,a srl a srl a srl a srl a add '0' ld [iy],a inc iy ld a,c and 0x0f add '0' ld [iy],a inc iy djnz @@LOOP ld hl,STR_RESULT ld de,0 ld bc,10 call LDIRVM ret BIN32_TO_BCD: ; DEHL = signed 32 bit value ld bc,5 ld iy,BCD_LUT ld ix,BCD_RESULT ld [ix],0 ld [ix+1],0 ld [ix+2],0 ld [ix+3],0 ld [ix+4],0 @@LOOP: sra d rr e rr h rr l jr nc,@@NEXT_BIT ld a,[ix+4] add a,[iy+4] daa ld [ix+4],a ld a,[ix+3] adc a,[iy+3] daa ld [ix+3],a ld a,[ix+2] adc a,[iy+2] daa ld [ix+2],a ld a,[ix+1] adc a,[iy+1] daa ld [ix+1],a ld a,[ix] adc a,[iy] daa ld [ix],a @@NEXT_BIT: add iy,bc ld a,d or e or h or l jr nz,@@LOOP ret .page 3 BCD_RESULT: ds 5 STR_RESULT: ds 10
If you have any tip to improve the speed let me know it.
