Last active
May 7, 2021 14:14
-
-
Save bramhaag/c1185060a4bda825656aa73fafe284b9 to your computer and use it in GitHub Desktop.
Multiplication without the MUL instruction in 10 lines
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; General explaination of the program: | |
; To replicate the MUL instruction, we came up with the following formula: | |
; aaaa * bbbb = | |
; (aaaa >> 0 & 1) * (bbbb << 0) + | |
; (aaaa >> 1 & 1) * (bbbb << 1) + | |
; (aaaa >> 2 & 1) * (bbbb << 2) + | |
; (aaaa >> 3 & 1) * (bbbb << 3) | |
; This formula still uses the multiply instruction, however since the result | |
; of (aaaa >> 3 & 1) will always be a 0 or a 1, we can use a branch instruction. | |
; | |
; The problem with this formula is that doing more than one shift at a time takes | |
; up a lot of instructions, since it it only possible to do one shift at a time with | |
; the LSL/LSR instruction | |
; | |
; To solve this problem we simplified the formula according to this rule: | |
; aaaa >> 3 & 1 = aaaa & (1 << 3) = aaaa & 8 | |
; | |
; This results in the following formula: | |
; aaaa * bbbb = | |
; (aaaa & 1) * (bbbb << 0) + | |
; (aaaa & 2) * (bbbb << 1) + | |
; (aaaa & 4) * (bbbb << 2) + | |
; (aaaa & 8) * (bbbb << 3) | |
; | |
; This formula is no longer mathematically correct: (aaaa & n) can yield | |
; values larger than 1. However this is not an issue since we're using branches | |
; instead of multiplication. | |
; | |
; We keep track of the number used for the AND operation in CA (register 21). | |
; Every iteration of the loop, CA is shifted to the left using the LSL operation | |
; meaning the value of CA will go from 1 to 2 to 4 to 8. | |
; | |
; The result of the summations are stored in SUM (register 16) | |
; | |
; The total length of the multiplication calculation is 10 lines (line 49 to 61, excluding the empty lines) | |
.device atmega168 | |
.def SUM = r16 ; Sum of calculations | |
.def A = r17 ; Multiplicand A | |
.def B = r18 ; Multiplicand B | |
.def TA = r19 ; Temporary place to store multiplicand A | |
.def TB = r20 ; Temporary place to store multiplicand B | |
.def CA = r21 ; And counter | |
ldi A, 5 ; Initialize multiplicand A. Try changing this value! | |
ldi B, 8 ; Initialize multiplicand B. Try changing this value! | |
ldi SUM, 0 ; Set the initial value of the sum. This is necessary because the Arduino does not | |
; clear its RAM on startup. In the case where the Arduino is rebooted | |
; (e.g when uploading code), the registers may still contain old values. | |
ldi CA, 1 ; Set the initial value of the number used for the and operation | |
loop: mov TA, A ; Loop 4 times. Initialize temporary multiplicand A | |
and TA, CA ; And operation between A and CA | |
breq skip ; Skip summation if the value of the operation is 0 | |
add SUM, B ; Add multiplicand B to the result | |
skip: lsl B ; Shift bits of multiplicand B to the left | |
lsl CA ; Shift bits of the number used for the and operation to the left (values will be: 1, 2, 4, 8) | |
cpi CA, 16 ; Compare C to 4 (Loop has 4 iterations, but C starts at 0. The 4 is to compensate for the unneccesary increase in the last iteration) | |
brne loop ; Go back to the start of the loop if C is not 4 | |
call sendr16tolaptop ; Send result (SUM) to the laptop | |
again: rjmp again ; Stop program by creating an infinite loop | |
.include "rs232link.inc" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment