diff options
Diffstat (limited to 'home/print_num.asm')
-rw-r--r-- | home/print_num.asm | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/home/print_num.asm b/home/print_num.asm new file mode 100644 index 0000000..3ae1c10 --- /dev/null +++ b/home/print_num.asm @@ -0,0 +1,252 @@ +INCLUDE "constants.asm" + +if DEBUG +SECTION "Number Printing Functions", ROM0[$3460] +else +SECTION "Number Printing Functions", ROM0[$3424] +endc + +PrintNumber:: ; 3460 (0:3460) +; function to print a number +; de = address of number in little-endian format +; hl = destination address +; b = flags and length +; bit 7: if set, do not print leading zeroes +; if unset, print leading zeroes +; bit 6: if set, left-align the string (do not pad empty digits with spaces) +; if unset, right-align the string +; bits 0-5: length of number in bytes +; 01 - 1 byte +; 02 - 2 bytes +; <> - 3 bytes +; c = number of digits from 2 to 7 +; For 1-digit numbers, add the value to char "0" +; instead of calling PrintNumber. +; This function works as follow +; There are three temporary registers +; - hPrintNumDividend, +; - hPrintNumDivisor, +; - hPrintNumTemp +; All are three bytes long and organized in big-endian order. +; To produce digits, PrintNumber is going to +; 1. Store Input in hPrintNumDividend +; 1a. Init hPrintNumLeadingDigit to zero (no prior leading digit) +; 2. Repeatedly call .PrintDigit for required digits 7 thru 3: +; 2a. Store divisor in hPrintNumDivisor +; 2b. Divide dividend by divisor to get digit +; 2c. hPrintNumTemp is used, because dividend < divisor might +; not be immediately visible in byte-wise division +; 2d. Update hPrintNumLeadingDigit in case digit > 0 +; 3. Perform the same operations for two digits as byte-wide operations +; as opposed to three-byte-wide operations +; 4. Check if at least one non-zero digit was printed, else print zero. +; 5. Done. + push bc + xor a + ldh [hPrintNumLeadingDigit], a + ldh [hPrintNumDividend], a + ldh [hPrintNumDividend + 1], a + ld a, b + and $0f + cp $01 + jr z, .byte + cp $02 + jr z, .word + ld a, [de] + ldh [hPrintNumDividend], a + inc de + ld a, [de] + ldh [hPrintNumDividend + 1], a + inc de + ld a, [de] + ldh [hPrintNumDividend + 2], a + jr .start +.word + ld a, [de] + ldh [hPrintNumDividend + 1], a + inc de + ld a, [de] + ldh [hPrintNumDividend + 2], a + jr .start +.byte + ld a, [de] + ldh [hPrintNumDividend + 2], a +.start + push de + ld d, b + ld a, c + ld b, a + xor a + ld c, a + ld a, b + cp $02 + jr z, .two_digits + cp $03 + jr z, .three_digits + cp $04 + jr z, .four_digits + cp $05 + jr z, .five_digits + cp $06 + jr z, .six_digits +.seven_digits + ld a, 1000000 / $10000 % $100 + ldh [hPrintNumDivisor], a + ld a, 1000000 / $100 % $100 + ldh [hPrintNumDivisor + 1], a + ld a, 1000000 % $100 + ldh [hPrintNumDivisor + 2], a + call .PrintDigit + call .AdvancePointer +.six_digits + ld a, 100000 / $10000 % $100 + ldh [hPrintNumDivisor], a + ld a, 100000 / $100 % $100 + ldh [hPrintNumDivisor + 1], a + ld a, 100000 % $100 + ldh [hPrintNumDivisor + 2], a + call .PrintDigit + call .AdvancePointer +.five_digits + xor a + ldh [hPrintNumDivisor], a + ld a, 10000 / $100 + ldh [hPrintNumDivisor + 1], a + ld a, 10000 % $100 + ldh [hPrintNumDivisor + 2], a + call .PrintDigit + call .AdvancePointer +.four_digits + xor a + ldh [hPrintNumDivisor], a + ld a, 1000 / $100 + ldh [hPrintNumDivisor + 1], a + ld a, 1000 % $100 + ldh [hPrintNumDivisor + 2], a + call .PrintDigit + call .AdvancePointer +.three_digits + xor a + ldh [hPrintNumDivisor], a + xor a + ldh [hPrintNumDivisor + 1], a + ld a, 100 + ldh [hPrintNumDivisor + 2], a + call .PrintDigit + call .AdvancePointer +.two_digits + ld c, $00 + ldh a, [hPrintNumDividend + 2] +.mod_10 + cp $0a + jr c, .modded_10 + sub $0a + inc c + jr .mod_10 +.modded_10 + ld b, a + ldh a, [hPrintNumLeadingDigit] + or c + ldh [hPrintNumLeadingDigit], a + jr nz, .LeadingNonZero + call .PrintLeadingZero + jr .PrintLeastSignificantDigit +.LeadingNonZero + ld a, "0" + add c + ld [hl], a +.PrintLeastSignificantDigit + call .AdvancePointer + ld a, "0" + add b + ld [hli], a + pop de + pop bc + ret + +.PrintDigit: ; 3525 (0:3525) + ld c, $00 +.loop + ldh a, [hPrintNumDivisor] + ld b, a + ldh a, [hPrintNumDividend] + ldh [hPrintNumTemp], a ; store high byte in case dividend < divisor + cp b ; in subsequent bytes + jr c, .DividendLessThanDivisor ; dividend < divisor --> the digit is zero + sub b + ldh [hPrintNumDividend], a + ldh a, [hPrintNumDivisor + 1] + ld b, a + ldh a, [hPrintNumDividend + 1] + ldh [hPrintNumTemp + 1], a ; store mid byte in case dividend < divisor + cp b ; in subsequent byte + jr nc, .SubtractMidNoBorrow + ldh a, [hPrintNumDividend] ; try to borrow from upper byte + or $00 + jr z, .DividendLessThanDivisorRestoreHigh ; can't borrow, because dividend < divisor + dec a + ldh [hPrintNumDividend], a + ldh a, [hPrintNumDividend + 1] +.SubtractMidNoBorrow + sub b + ldh [hPrintNumDividend + 1], a + ldh a, [hPrintNumDivisor + 2] + ld b, a + ldh a, [hPrintNumDividend + 2] + ldh [hPrintNumTemp + 2], a ; store low byte in case dividend < divisor, which + cp b ; goes unused, because the algorithm doesn't + jr nc, .SubtractLoNoBorrow ; clobber hPrintNumDividend + 2 in that case + ldh a, [hPrintNumDividend + 1] + and a + jr nz, .SubtractLoBorrow + ldh a, [hPrintNumDividend] ; if mid byte == zero, we need to borrow from high + and a + jr z, .DividendLessThanDivisorRestoreMid +.SubtractLoBorrowFromHigh + dec a + ldh [hPrintNumDividend], a + xor a +.SubtractLoBorrow + dec a + ldh [hPrintNumDividend + 1], a + ldh a, [hPrintNumDividend + 2] +.SubtractLoNoBorrow + sub b + ldh [hPrintNumDividend + 2], a + inc c + jr .loop +.DividendLessThanDivisorRestoreMid + ldh a, [hPrintNumTemp + 1] + ldh [hPrintNumDividend + 1], a +.DividendLessThanDivisorRestoreHigh + ldh a, [hPrintNumTemp] + ldh [hPrintNumDividend], a +.DividendLessThanDivisor + ldh a, [hPrintNumLeadingDigit] + or c + jr z, .PrintLeadingZero + ld a, "0" + add c + ld [hl], a + ldh [hPrintNumLeadingDigit], a + ret +.PrintLeadingZero: +; prints a leading zero unless they are turned off in the flags + bit 7, d + ret z + ld [hl], "0" + ret + +.AdvancePointer: ; 3589 (0:3589) +; increments the pointer unless leading zeroes are not being printed, +; the number is left-aligned, and no nonzero digits have been printed yet + bit 7, d ; print leading zeroes? + jr nz, .inc + bit 6, d ; left alignment or right alignment? + jr z, .inc + ldh a, [hPrintNumLeadingDigit] + and a + ret z ; don't advance if leading digit is zero +.inc + inc hl + ret |