diff options
Diffstat (limited to 'engine/math')
-rw-r--r-- | engine/math/bcd.asm | 218 | ||||
-rwxr-xr-x | engine/math/multiply_divide.asm | 143 | ||||
-rwxr-xr-x | engine/math/random.asm | 13 |
3 files changed, 374 insertions, 0 deletions
diff --git a/engine/math/bcd.asm b/engine/math/bcd.asm new file mode 100644 index 00000000..92bf6f17 --- /dev/null +++ b/engine/math/bcd.asm @@ -0,0 +1,218 @@ +; divide hMoney by hDivideBCDDivisor +; return output in hDivideBCDQuotient (same as hDivideBCDDivisor) +; used only to halve player money upon losing a fight +DivideBCDPredef:: +DivideBCDPredef2:: +DivideBCDPredef3:: ; only used function +DivideBCDPredef4:: + call GetPredefRegisters + +DivideBCD:: + xor a + ldh [hDivideBCDBuffer], a + ldh [hDivideBCDBuffer+1], a + ldh [hDivideBCDBuffer+2], a + ld d, $1 +.mulBy10Loop +; multiply the divisor by 10 until the leading digit is nonzero +; to set up the standard long division algorithm + ldh a, [hDivideBCDDivisor] + and $f0 + jr nz, .next + inc d + ldh a, [hDivideBCDDivisor] + swap a + and $f0 + ld b, a + ldh a, [hDivideBCDDivisor+1] + swap a + ldh [hDivideBCDDivisor+1], a + and $f + or b + ldh [hDivideBCDDivisor], a + ldh a, [hDivideBCDDivisor+1] + and $f0 + ld b, a + ldh a, [hDivideBCDDivisor+2] + swap a + ldh [hDivideBCDDivisor+2], a + and $f + or b + ldh [hDivideBCDDivisor+1], a + ldh a, [hDivideBCDDivisor+2] + and $f0 + ldh [hDivideBCDDivisor+2], a + jr .mulBy10Loop + +.next + push de + push de + call DivideBCD_getNextDigit + pop de + ld a, b + swap a + and $f0 + ldh [hDivideBCDBuffer], a + dec d + jr z, .next2 + push de + call DivideBCD_divDivisorBy10 + call DivideBCD_getNextDigit + pop de + ldh a, [hDivideBCDBuffer] + or b + ldh [hDivideBCDBuffer], a + dec d + jr z, .next2 + push de + call DivideBCD_divDivisorBy10 + call DivideBCD_getNextDigit + pop de + ld a, b + swap a + and $f0 + ldh [hDivideBCDBuffer+1], a + dec d + jr z, .next2 + push de + call DivideBCD_divDivisorBy10 + call DivideBCD_getNextDigit + pop de + ldh a, [hDivideBCDBuffer+1] + or b + ldh [hDivideBCDBuffer+1], a + dec d + jr z, .next2 + push de + call DivideBCD_divDivisorBy10 + call DivideBCD_getNextDigit + pop de + ld a, b + swap a + and $f0 + ldh [hDivideBCDBuffer+2], a + dec d + jr z, .next2 + push de + call DivideBCD_divDivisorBy10 + call DivideBCD_getNextDigit + pop de + ldh a, [hDivideBCDBuffer+2] + or b + ldh [hDivideBCDBuffer+2], a +.next2 + ldh a, [hDivideBCDBuffer] + ldh [hDivideBCDQuotient], a ; the same memory location as hDivideBCDDivisor + ldh a, [hDivideBCDBuffer+1] + ldh [hDivideBCDQuotient+1], a + ldh a, [hDivideBCDBuffer+2] + ldh [hDivideBCDQuotient+2], a + pop de + ld a, $6 + sub d + and a + ret z +.divResultBy10loop + push af + call DivideBCD_divDivisorBy10 + pop af + dec a + jr nz, .divResultBy10loop + ret + +DivideBCD_divDivisorBy10: + ldh a, [hDivideBCDDivisor+2] + swap a + and $f + ld b, a + ldh a, [hDivideBCDDivisor+1] + swap a + ldh [hDivideBCDDivisor+1], a + and $f0 + or b + ldh [hDivideBCDDivisor+2], a + ldh a, [hDivideBCDDivisor+1] + and $f + ld b, a + ldh a, [hDivideBCDDivisor] + swap a + ldh [hDivideBCDDivisor], a + and $f0 + or b + ldh [hDivideBCDDivisor+1], a + ldh a, [hDivideBCDDivisor] + and $f + ldh [hDivideBCDDivisor], a + ret + +DivideBCD_getNextDigit: + ld bc, $3 +.loop + ld de, hMoney ; the dividend + ld hl, hDivideBCDDivisor + push bc + call StringCmp + pop bc + ret c + inc b + ld de, hMoney + 2 ; since SubBCD works starting from the least significant digit + ld hl, hDivideBCDDivisor + 2 + push bc + call SubBCD + pop bc + jr .loop + + +AddBCDPredef:: + call GetPredefRegisters + +AddBCD:: + and a + ld b, c +.add + ld a, [de] + adc [hl] + daa + ld [de], a + dec de + dec hl + dec c + jr nz, .add + jr nc, .done + ld a, $99 + inc de +.fill + ld [de], a + inc de + dec b + jr nz, .fill +.done + ret + + +SubBCDPredef:: + call GetPredefRegisters + +SubBCD:: + and a + ld b, c +.sub + ld a, [de] + sbc [hl] + daa + ld [de], a + dec de + dec hl + dec c + jr nz, .sub + jr nc, .done + ld a, $00 + inc de +.fill + ld [de], a + inc de + dec b + jr nz, .fill + scf +.done + ret diff --git a/engine/math/multiply_divide.asm b/engine/math/multiply_divide.asm new file mode 100755 index 00000000..2fcda158 --- /dev/null +++ b/engine/math/multiply_divide.asm @@ -0,0 +1,143 @@ +_Multiply:: + ld a, $8 + ld b, a + xor a + ldh [hProduct], a + ldh [hMultiplyBuffer], a + ldh [hMultiplyBuffer+1], a + ldh [hMultiplyBuffer+2], a + ldh [hMultiplyBuffer+3], a +.loop + ldh a, [hMultiplier] + srl a + ldh [hMultiplier], a ; (aliases: hDivisor, hMultiplier, hPowerOf10) + jr nc, .smallMultiplier + ldh a, [hMultiplyBuffer+3] + ld c, a + ldh a, [hMultiplicand+2] + add c + ldh [hMultiplyBuffer+3], a + ldh a, [hMultiplyBuffer+2] + ld c, a + ldh a, [hMultiplicand+1] + adc c + ldh [hMultiplyBuffer+2], a + ldh a, [hMultiplyBuffer+1] + ld c, a + ldh a, [hMultiplicand] ; (aliases: hMultiplicand) + adc c + ldh [hMultiplyBuffer+1], a + ldh a, [hMultiplyBuffer] + ld c, a + ldh a, [hProduct] ; (aliases: hProduct, hPastLeadingZeros, hQuotient) + adc c + ldh [hMultiplyBuffer], a +.smallMultiplier + dec b + jr z, .done + ldh a, [hMultiplicand+2] + sla a + ldh [hMultiplicand+2], a + ldh a, [hMultiplicand+1] + rl a + ldh [hMultiplicand+1], a + ldh a, [hMultiplicand] + rl a + ldh [hMultiplicand], a + ldh a, [hProduct] + rl a + ldh [hProduct], a + jr .loop +.done + ldh a, [hMultiplyBuffer+3] + ldh [hProduct+3], a + ldh a, [hMultiplyBuffer+2] + ldh [hProduct+2], a + ldh a, [hMultiplyBuffer+1] + ldh [hProduct+1], a + ldh a, [hMultiplyBuffer] + ldh [hProduct], a + ret + +_Divide:: + xor a + ldh [hDivideBuffer], a + ldh [hDivideBuffer+1], a + ldh [hDivideBuffer+2], a + ldh [hDivideBuffer+3], a + ldh [hDivideBuffer+4], a + ld a, $9 + ld e, a +.asm_37db3 + ldh a, [hDivideBuffer] + ld c, a + ldh a, [hDividend+1] ; (aliases: hMultiplicand) + sub c + ld d, a + ldh a, [hDivisor] ; (aliases: hDivisor, hMultiplier, hPowerOf10) + ld c, a + ldh a, [hDividend] ; (aliases: hProduct, hPastLeadingZeros, hQuotient) + sbc c + jr c, .asm_37dce + ldh [hDividend], a ; (aliases: hProduct, hPastLeadingZeros, hQuotient) + ld a, d + ldh [hDividend+1], a ; (aliases: hMultiplicand) + ldh a, [hDivideBuffer+4] + inc a + ldh [hDivideBuffer+4], a + jr .asm_37db3 +.asm_37dce + ld a, b + cp $1 + jr z, .asm_37e18 + ldh a, [hDivideBuffer+4] + sla a + ldh [hDivideBuffer+4], a + ldh a, [hDivideBuffer+3] + rl a + ldh [hDivideBuffer+3], a + ldh a, [hDivideBuffer+2] + rl a + ldh [hDivideBuffer+2], a + ldh a, [hDivideBuffer+1] + rl a + ldh [hDivideBuffer+1], a + dec e + jr nz, .asm_37e04 + ld a, $8 + ld e, a + ldh a, [hDivideBuffer] + ldh [hDivisor], a ; (aliases: hDivisor, hMultiplier, hPowerOf10) + xor a + ldh [hDivideBuffer], a + ldh a, [hDividend+1] ; (aliases: hMultiplicand) + ldh [hDividend], a ; (aliases: hProduct, hPastLeadingZeros, hQuotient) + ldh a, [hDividend+2] + ldh [hDividend+1], a ; (aliases: hMultiplicand) + ldh a, [hDividend+3] + ldh [hDividend+2], a +.asm_37e04 + ld a, e + cp $1 + jr nz, .asm_37e0a + dec b +.asm_37e0a + ldh a, [hDivisor] ; (aliases: hDivisor, hMultiplier, hPowerOf10) + srl a + ldh [hDivisor], a ; (aliases: hDivisor, hMultiplier, hPowerOf10) + ldh a, [hDivideBuffer] + rr a + ldh [hDivideBuffer], a + jr .asm_37db3 +.asm_37e18 + ldh a, [hDividend+1] ; (aliases: hMultiplicand) + ldh [hRemainder], a ; (aliases: hDivisor, hMultiplier, hPowerOf10) + ldh a, [hDivideBuffer+4] + ldh [hQuotient+3], a + ldh a, [hDivideBuffer+3] + ldh [hQuotient+2], a + ldh a, [hDivideBuffer+2] + ldh [hQuotient+1], a ; (aliases: hMultiplicand) + ldh a, [hDivideBuffer+1] + ldh [hDividend], a ; (aliases: hProduct, hPastLeadingZeros, hQuotient) + ret diff --git a/engine/math/random.asm b/engine/math/random.asm new file mode 100755 index 00000000..c8760157 --- /dev/null +++ b/engine/math/random.asm @@ -0,0 +1,13 @@ +Random_:: +; Generate a random 16-bit value. + ldh a, [rDIV] + ld b, a + ldh a, [hRandomAdd] + adc b + ldh [hRandomAdd], a + ldh a, [rDIV] + ld b, a + ldh a, [hRandomSub] + sbc b + ldh [hRandomSub], a + ret |