Skip to navigation


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) ADC timesTable,X 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, \ jump to mulp1 to skip the following 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