Aviator on the BBC Micro

# Maths: Multiply4x16

```       Name: Multiply4x16                                            [Show more]
Type: Subroutine
Category: Maths
Summary: Multiply a 4-bit and a 16-bit number
Deep dive: Times tables and nibble arithmetic
Context: See this subroutine in context in the source code
References: This subroutine is called as follows:
* SetObjPointCoords (Part 1 of 2) calls Multiply4x16

This routine multiplies a 4-bit number by a 16-bit number, using the lookup
table at timesTable for fast results. It does the following calculation:

(G W) = V * (S R) >> 8

If bit 7 of K is set, the routine returns double this amount.

Arguments:

(S R)                A 16-bit number

V                    A 4-bit number (0 to 15), can be positive or negative
(i.e. bit 7 contains the sign, bits 0-3 the magnitude)

K                    Bit 7 determines whether to multiply the result by 2:

* If bit 7 of K = 0, calculate (G W) = V * (S R) >> 8

* If bit 7 of K = 1, calculate (G W) = V * (S R) >> 7

.Multiply4x16

LDX S                  \ Set X = S = %SSSSssss

LDY V                  \ Set Y = V = %VVVVvvvv

LDA shift4Left,Y       \ Set A = V << 4
\       = %vvvv0000

ORA shift4Right,X      \ Set Y = A OR (S >> 4)
TAY                    \       = %vvvv0000 OR %0000SSSS
\       = %vvvvSSSS

AND #%11110000         \ Set U = (A AND %11110000) OR (X AND %00001111)
ORA lowNibble,X        \       = (%vvvvSSSS AND %11110000) OR (X AND %00001111)
STA U                  \       = %vvvv0000 OR (%SSSSssss AND %00001111)
\       = %vvvvssss

LDX R                  \ Set X = R = %RRRRrrrr

AND #%11110000         \ Set X = (A AND %1111000) OR (X >> 4)
ORA shift4Right,X      \       = (%vvvvssss AND %11110000) OR (%RRRRrrrr >> 4)
TAX                    \       = %vvvv0000 OR %0000RRRR
\       = %vvvvRRRR

LDA timesTable,X       \ Set X = %vvvv * %RRRR
TAX                    \
\ Call this %XXXXxxxx

STX T                  \ Set T = %XXXXxxxx

LDA timesTable,Y       \ Set Y = %vvvv * %SSSS
TAY                    \
\ Call this %YYYYyyyy

LDA shift4Right,X      \ Set A = (X >> 4) OR (Y << 4)
ORA shift4Left,Y       \       = %0000XXXX OR %yyyy0000
\       = %yyyyXXXX

CLC                    \ Set W = A + (%vvvv * %ssss)
LDX U                  \       = %yyyyXXXX + (%vvvv * %ssss)
STA W

LDA shift4Right,Y      \ Set G = (Y >> 4) + carry
ADC #0                 \       = %0000YYYY + carry
STA G

\ So (G W) = %YYYYyyyyXXXX + (%vvvv * %ssss)
\          = %YYYYyyyy0000 + %XXXX + (%vvvv * %ssss)
\          =   %vvvv * %SSSS << 4
\            + %vvvv * %RRRR >> 4
\            + %vvvv * %ssss
\          = %vvvv * (%SSSS << 4 + %ssss + %RRRR >> 4)
\          = %vvvv * (%SSSSssss + %RRRR >> 4)
\          = %vvvv * (%SSSSssss + %RRRRrrrr >> 8)
\          = %vvvv * (S R) >> 8
\          = V * (S R) >> 8

BIT K                  \ If bit 7 of K is clear, jump to mulp2 to skip the
BPL mulp2              \ following and apply the correct sign to the result

LDX R                  \ Set X = R = %RRRRrrrr

LDA V                  \ Set Y = (V AND %00001111) OR (X << 3)
AND #%00001111         \       = %0000vvvv OR %rrrr0000
ORA shift4Left,X       \       = %rrrrvvvv
TAY

LDX T                  \ Set X = T = %XXXXxxxx

LDA shift4Left,X       \ Set A = (X << 4) + (%rrrr * %vvvv)
CLC                    \       = %xxxx0000 + (%rrrr * %vvvv)
ADC timesTable,Y       \       = %vvvv * %RRRR << 4 + %rrrr * %vvvv
\       = %vvvv * (%RRRR << 4 + %rrrr)
\       = %vvvv * %RRRRrrrr
\       = V * R

BCC mulp1              \ If the addition didn't overflow, i.e. V * R < 256,

INC W                  \ Set (G W) = (G W) + 1
BNE mulp1              \
INC G                  \ to round the result up, as the low bytes of the
\ multiplication produced a carry

.mulp1

ASL A                  \ Set (G W A) = (G W A) * 2
ROL W                  \
ROL G                  \ so the result is doubled when bit 7 of K is set

.mulp2

LDA V                  \ If V is positive, skip the following
BPL mulp3

LDA #0                 \ V is negative, so we now negate (G W) by subtracting
SEC                    \ it from 0, first the low byte and then the high byte
SBC W
STA W
LDA #0
SBC G
STA G

.mulp3

RTS                    \ Return from the subroutine
```