Skip to navigation

Elite on the BBC Micro and NES

Version analysis of FMLTU

This code appears in the following versions (click to see it in the source code):

Code variations between these versions are shown below.

Name: FMLTU Type: Subroutine Category: Maths (Arithmetic) Summary: Calculate A = A * Q / 256

Code variation 1 of 7A variation in the comments only

This variation is blank in the Cassette, Disc (flight), Disc (docked) and Electron versions.


Do the following multiplication of two unsigned 8-bit numbers, returning only the high byte of the result: (A ?) = A * Q or, to put it another way: A = A * Q / 256

Code variation 2 of 7A variation in the comments only

Tap on a block to expand it, and tap it again to revert.

Returns: C flag The C flag is set
The Master and 6502 Second Processor versions use logarithms to speed up the multiplication process. See the deep dive on "Multiplication using logarithms" for more details. Returns: C flag The C flag is clear if A = 0, or set if we return a result from one of the log tables
.FMLTU

Code variation 3 of 7Other (e.g. bug fix, optimisation)

The FMLTU routine in the advanced versions uses logarithms to speed up the multiplication.

Tap on a block to expand it, and tap it again to revert.

EOR #%11111111 \ Flip the bits in A, set the C flag and rotate right, SEC \ so the C flag now contains bit 0 of A inverted, and P ROR A \ contains A inverted and shifted right by one, with bit STA P \ 7 set to a 1. We can now use P as our source of bits \ to shift right, just as in MU11, just with the logic \ reversed LDA #0 \ Set A = 0 so we can start building the answer in A .MUL3 BCS MU7 \ If C (i.e. the next bit from P) is set, do not do the \ addition for this bit of P, and instead skip to MU7 \ to just do the shifts ADC Q \ Do the addition for this bit of P: \ \ A = A + Q + C \ = A + Q ROR A \ Shift A right to catch the next digit of our result. \ If we were interested in the low byte of the result we \ would want to save the bit that falls off the end, but \ we aren't, so we can ignore it LSR P \ Shift P right to fetch the next bit for the \ calculation into the C flag BNE MUL3 \ Loop back to MUL3 if P still contains some set bits \ (so we loop through the bits of P until we get to the \ 1 we inserted before the loop, and then we stop) \ If we get here then the C flag is set as we just \ rotated a 1 out of the right end of P RTS \ Return from the subroutine .MU7 LSR A \ Shift A right to catch the next digit of our result, \ pushing a 0 into bit 7 as we aren't adding anything \ here (we can't use a ROR here as the C flag is set, so \ a ROR would push a 1 into bit 7) LSR P \ Fetch the next bit from P into the C flag BNE MUL3 \ Loop back to MUL3 if P still contains some set bits \ (so we loop through the bits of P until we get to the \ 1 we inserted before the loop, and then we stop) \ If we get here then the C flag is set as we just \ rotated a 1 out of the right end of P RTS \ Return from the subroutine
STX P \ Store X in P so we can preserve it through the call to \ FMULTU STA widget \ Store A in widget, so now widget = argument A TAX \ Transfer A into X, so now X = argument A BEQ MU3 \ If A = 0, jump to MU3 to return a result of 0, as \ 0 * Q / 256 is always 0 \ We now want to calculate La + Lq, 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 La \ = low byte of La (as we set X to A above) LDX Q \ Set X = Q BEQ MU3again \ If X = 0, jump to MU3again to return a result of 0, as \ A * 0 / 256 is always 0 CLC \ Set A = A + low byte of Lq ADC logL,X \ = low byte of La + low byte of Lq

Code variation 4 of 7Other (e.g. bug fix, optimisation)

In the FMLTU multiplication routine, the Master version omits half of the logarithm algorithm when compared to the 6502SP version. The effect of this in-game is most noticeable in the Short-range Chart, where the fuel circle is a different shape to the other versions (the Master version looks rather less smooth, as if it has a slightly larger step size, though it's actually down to the less accurate FMLTU routine).

See below for more variations related to this code.

This variation is blank in the Cassette, Disc (flight), Disc (docked), Master and Electron versions.

BMI oddlog \ If A > 127, jump to oddlog

Code variation 5 of 7Other (e.g. bug fix, optimisation)

See variation 4 above for details.

This variation is blank in the Cassette, Disc (flight), Disc (docked) and Electron versions.

Tap on a block to expand it, and tap it again to revert.

LDA log,X \ Set A = high byte of Lq LDX widget \ Set A = A + C + high byte of La ADC log,X \ = high byte of Lq + high byte of La + C \ \ so we now have: \ \ A = high byte of (La + Lq) BCC MU3again \ If the addition fitted into one byte and didn't carry, \ then La + Lq < 256, so we jump to MU3again to return a \ result of 0 and the C flag clear \ If we get here then the C flag is set, ready for when \ we return from the subroutine below TAX \ Otherwise La + Lq >= 256, so we return the A-th entry LDA alogh,X \ from the antilog table LDX P \ Restore X from P so it is preserved RTS \ Return from the subroutine
LDA log,X \ Set A = high byte of Lq LDX widget \ Set A = A + C + high byte of La ADC log,X \ = high byte of Lq + high byte of La + C \ \ so we now have: \ \ A = high byte of (La + Lq) BCC MU3again \ If the addition fitted into one byte and didn't carry, \ then La + Lq < 256, so we jump to MU3again to return a \ result of 0 and the C flag clear \ If we get here then the C flag is set, ready for when \ we return from the subroutine below TAX \ Otherwise La + Lq >= 256, so we return the A-th entry LDA antilog,X \ from the antilog table LDX P \ Restore X from P so it is preserved RTS \ Return from the subroutine

Code variation 6 of 7Other (e.g. bug fix, optimisation)

See variation 4 above for details.

This variation is blank in the Cassette, Disc (flight), Disc (docked), Master and Electron versions.

.oddlog LDA log,X \ Set A = high byte of Lq LDX widget \ Set A = A + C + high byte of La ADC log,X \ = high byte of Lq + high byte of La + C \ \ so we now have: \ \ A = high byte of (La + Lq) BCC MU3again \ If the addition fitted into one byte and didn't carry, \ then La + Lq < 256, so we jump to MU3again to return a \ result of 0 and the C flag clear \ If we get here then the C flag is set, ready for when \ we return from the subroutine below TAX \ Otherwise La + Lq >= 256, so we return the A-th entry LDA antilogODD,X \ from the antilogODD table

Code variation 7 of 7Other (e.g. bug fix, optimisation)

See variation 4 above for details.

This variation is blank in the Cassette, Disc (flight), Disc (docked) and Electron versions.

Tap on a block to expand it, and tap it again to revert.

.MU3again LDA #0 \ Set A = 0 .MU3 \ If we get here then A (our result) is already 0 LDX P \ Restore X from P so it is preserved RTS \ Return from the subroutine
.MU3 \ If we get here then A (our result) is already 0 LDX P \ Restore X from P so it is preserved RTS \ Return from the subroutine .MU3again LDA #0 \ Set A = 0 LDX P \ Restore X from P so it is preserved RTS \ Return from the subroutine