BBC Micro Elite

# Maths (Arithmetic): FMLTU (6502SP version)

```       Name: FMLTU                                             [View in context]
Type: Subroutine
Category: Maths (Arithmetic)
Summary: Calculate A = A * Q / 256

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

Let La be the a-th entry in the 16-bit log/logL table, so:

La = 32 * log(a) * 256

Let Ar be the r-th entry in the antilog table

Ar = 2^(r / 32 + 8) / 256

These are all logarithms to base 2, so this is true:

a * q = 2 ^ (log(a) + log(q))

Let's reduce this. First, we have the following:

log(a) + log(q) = (log(a) + log(q)) * 1
= (log(a) + log(q)) * (32 * 256) / (32 * 256)
= (32 * log(a) * 256 + 32 * log(q) * 256) / (32 * 256)
= (La + Lq) / (32 * 256)

Now we calculate La + Lq.

* If La + Lq < 256, then

log(a) + log(q) < 256 / (32 * 256)
= 1 / 32

So:

a * q = 2 ^ (log(a) + log(q))
< 2 ^ (1 / 32)
< 1

so, because this routine returns A = a * q / 256, we return A = 0

* If La + Lq >= 256, then

La + Lq >= 256

so:

La + Lq = r + 256

for some value of r > 0. Plugging this into the above gives:

log(a) + log(q) = (La + Lq) / (32 * 256)
= (r + 256) / (32 * 256)
= (r / 32 + 8) / 256

And plugging this into the above gives:

x * y = 2 ^ (log(a) + log(q))
= 2 ^ ((r / 32 + 8) / 256)
= Ar

so we return A = Ar

In summary, given two numbers A and Q, we can calculate A * Q / 256 by adding
La and Lq, and then using the result to look up the correct result in Ar.

.FMLTU

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

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

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

.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

TAX                    \ Otherwise La + Lq >= 256, so we return the A-th entry
LDA antilogODD,X       \ from the antilogODD table

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