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.

```6502SP, Master  Deep dive: Multiplication and division using logarithms
```
```

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.

```Cassette, Flight, Docked, Electron6502SP, Master 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.

```Cassette, Flight, Docked, Electron6502SP, Master 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
\ to just do the shifts

\
\   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.

```6502SP 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.

```Master6502SP 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.

```6502SP.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.

```Master6502SP.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
```