Skip to navigation

Elite on the BBC Micro and NES

Maths (Arithmetic): LL28

[NES version, Bank 7]

Name: LL28 [Show more] Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate R = 256 * A / Q Deep dive: Multiplication and division using logarithms
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * ARCTAN calls LL28 * GetScrollDivisions calls LL28 * LAUN calls LL28 * LL145 (Part 3 of 4) calls LL28 * LL164 calls LL28 * LL61 calls LL28 * LL9 (Part 3 of 12) calls LL28 * LL9 (Part 8 of 12) calls LL28 * ProjectScrollText calls LL28

Calculate the following, where A < Q: R = 256 * A / Q This is a sister routine to LL61, which does the division when A >= Q. If A >= Q then 255 is returned and the C flag is set to indicate an overflow (the C flag is clear if the division was a success). The result is returned in one byte as the result of the division multiplied by 256, so we can return fractional results using integers. This routine uses the same logarithm algorithm that's documented in FMLTU, except it subtracts the logarithm values, to do a division instead of a multiplication.
Returns: C flag Set if the answer is too big for one byte, clear if the division was a success
Other entry points: LL28+4 Skips the A >= Q check and always returns with C flag cleared, so this can be called if we know the division will work
.LL2 LDA #255 ; The division is very close to 1, so return the closest STA R ; possible answer to 256, i.e. R = 255 RTS ; Return from the subroutine .LL28 CMP Q ; If A >= Q, then the answer will not fit in one byte, BCS LL2 ; so jump to LL2 to return 255 STA widget ; Store A in widget, so now widget = argument A TAX ; Transfer A into X, so now X = argument A BEQ LLfix ; If A = 0, jump to LLfix to return a result of 0, as ; 0 * Q / 256 is always 0 ; We now want to calculate log(A) - log(Q), first adding ; the low bytes (from the logL table), and then the high ; bytes (from the log table) LDA logL,X ; Set A = low byte of log(X) ; = low byte of log(A) (as we set X to A above) LDX Q ; Set X = Q SEC ; Set A = A - low byte of log(Q) SBC logL,X ; = low byte of log(A) - low byte of log(Q) BMI noddlog ; If the subtraction is negative, jump to noddlog LDX widget ; Set A = high byte of log(A) - high byte of log(Q) LDA log,X LDX Q SBC log,X BCS LL2 ; If the subtraction fitted into one byte and didn't ; underflow, then log(A) - log(Q) < 256, so we jump to ; LL2 return a result of 255 TAX ; Otherwise we return the A-th entry from the antilog LDA antilog,X ; table .LLfix STA R ; Set the result in R to the value of A RTS ; Return from the subroutine .noddlog LDX widget ; Set A = high byte of log(A) - high byte of log(Q) LDA log,X LDX Q SBC log,X BCS LL2 ; If the subtraction fitted into one byte and didn't ; underflow, then log(A) - log(Q) < 256, so we jump to ; LL2 to return a result of 255 TAX ; Otherwise we return the A-th entry from the antilogODD LDA antilogODD,X ; table STA R ; Set the result in R to the value of A RTS ; Return from the subroutine