mirror of
https://github.com/pret/pokegold-spaceworld.git
synced 2026-08-28 03:25:03 -05:00
Addresses of sections will now be added to the linkerscript via `org`, and the section name will be the path/to/file. If there is more than one section in the file, then add a @SectionName after the path/to/file to describe the section.
252 lines
6.1 KiB
NASM
252 lines
6.1 KiB
NASM
INCLUDE "constants.asm"
|
||
|
||
; if DEBUG
|
||
SECTION "home/print_num.asm", ROM0
|
||
; 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 |