32bit calculation in 8bit avr assembly

for example if i want to multiply two 16 bit numbers ? how do i do that .
like if i want to increment a 16bit number i increment with carry

add r30,1
adc r31,0

that takes two cycles but in commands like LD rd,X+ it seems to increment pair register X in about no time since the same command without incremention takes about the same time .

incrementing 32bit(4byte) numbers with carry seems not to be too complicated .
but what about multiplication ?? i cant seem to figure that ?

the "mul" commad only multiplies a couple of bytes and outputs a 16bit number on r1 and r2

Think back to school arithmetic, when you did long multiplication.

the only way i can figure is by making a loop of additions with carry ... that would take a shit load of cycles ,the mul command has no carry

oh i figured it out in code :slight_smile: thank you anyway

AWOL what you first said is correct .
here is the code i just wrote , it seems it will work

;input

;r10 LSB
;r11 MSB

;r12 LSB
;r13 MSB

;result

;r14 LSB
;r15 -
;r16 -
;r17 MSB

;r18 carry

mul r10,r12
ldi r14,r0 ; lsb
ldi r18,r1 ; load carry
mul r10,r13
add r0,r18 ; add carry
adc r1,0 ;
ldi r15,r0 ; -
ldi r18,r1 ; load carry
mul r12,r11
add r0,r18 ; add carry
adc r1,0
ldi r16,r0 ; -
ldi r18,r1 ; load carry
mul r11,r13
add r0,r18 ; add carry
adc r1,0
ldi r17,r0 ; MSB
ldi r18,r1 ; last carry output

that takes 22cycles
1.3us on the arduino uno , damn

amine2:
AWOL what you first said is correct .
here is the code i just wrote , it seems it will work

;input

;r10 LSB
;r11 MSB

;r12 LSB
;r13 MSB

;result

;r14 LSB
;r15 -
;r16 -
;r17 MSB

;r18 carry

mul r10,r12
ldi r14,r0 ; lsb
ldi r18,r1 ; load carry
mul r10,r13
add r0,r18 ; add carry
adc r1,0 ;
ldi r15,r0 ; -
ldi r18,r1 ; load carry
mul r12,r11
add r0,r18 ; add carry
adc r1,0
ldi r16,r0 ; -
ldi r18,r1 ; load carry
mul r11,r13
add r0,r18 ; add carry
adc r1,0
ldi r17,r0 ; MSB
ldi r18,r1 ; last carry output

This is an old post, but it needs to be corrected, in order for actual viewers to learn it by the right way.

First, AVR instruction LDI is LOAD IMMEDIATE, you can not use it to move data between registers, for that you use MOV instruction.

LDI R17, 5 ; will load the immediate value of 5 into R17. Also, LDI only works for registers R16 through R31.
Needing to load immediate a value into registers from R0 through R15, you need to load such value into a high register and then move it to the lower.

LDI R4, 5 ; does not work.
LDI R16, 5 and then MOV R4,R16 will work.

Second, all AVR assembly instructions using two registers or immediate values, use the destination to the left side of the "coma", and the source to the right.

LDI R16, 5 means the source is "5" and the destination is the R16.

This is valid for ADD, SUB, MOV, LD, etc.

Third, ADC instruction runs on two registers, not immediate value, so ADC R1,0 does not work.

So, the correct way to write your assembly routine for such 16x16 bits multiplication:

;Multiplication Operands:
;R11:R10
;R13:R12

;Result:
;R14:R15:R16:R17

;R18  zero

clr R18

mul R10, R12 ; Make this first (two low bytes)
mov R14, R0  ; Move values to empty result low bytes
mov R15, R1  ; Don't need to add anything, not even carry.
; replace both above with MOVW R15:R14, R1:R0 and save one instruction, it moves two registers at once.

mul R11, R13 ; Make this second (two high bytes)
mov R16, R0  ; Move values to empty result high bytes
mov R17, R1  ; Don't need to add anything, not even carry.
; replace both above with MOVW R17:R16, R1:R0 and save one instruction, it moves two registers at once.

mul R10, R13  ; Now make this crossing values, low and high
add R15, R0   ; Add over the previous
adc R16, R1   ; Add over the previous with carry
adc R17, R18 ; Add possible carry with zero

mul R11, R12 ; As above
add R15, R0
adc R16, R1
adc R17, R18

It is impossible to have a resulting carry at this end, since 2 x 2 bytes maximum values 0xFFFF x 0xFFFF will result in 0xFFFE, will never promote a resulting carry.

Replacing the 4 MOV instructions with MOVW;

CLR R18

MUL R10, R12  ; Make this first (two low bytes)
MOVW R15:R14, R1:R0 

MUL R11, R13  ; Make this second (two high bytes)
MOVW R17:R16, R1:R0

MUL R10, R13  ; Now make this crossing values, low and high
ADD R15, R0   ; Add over the previous
ADC R16, R1   ; Add over the previous with carry
ADC R17, R18  ; Add possible carry with zero

MUL R11, R12  ; As above
ADD R15, R0
ADC R16, R1
ADC R17, R18

If you don't want to use R18 as zero for the propagating possible carry, you can replace it with a conditional jump. Two additional instructions and saving one register. This is my suggestion:

MUL R10, R12        ; Make this first (two low bytes)
MOVW R15:R14, R1:R0 

MUL R11, R13        ; Make this second (two high bytes)
MOVW R17:R16, R1:R0

MUL R10, R13        ; Now make this crossing values, low and high
ADD R15, R0         ; Add over the previous
ADC R16, R1         ; Add over the previous with carry
BRCC PC+2           ; Jump over the next instruction
INC R17             ; Add carry

MUL R11, R12        ; As above
ADD R15, R0
ADC R16, R1
BRCC PC+2    
INC R17

amine2:
the "mul" commad only multiplies a couple of bytes and outputs a 16bit number on r1 and r2

AWOL:
Think back to school arithmetic, when you did long multiplication.

Add and shift

Partial products

519.png

519.png

multiplicant
multiplier
temp
edit: temp must be u-long

unsigned long result

temp=multiplicant;
for (byte x=0;x<16;x++){

temp <<temp, 1

if (bitread(multiplier, x)==1) result+=temp;
}

I think thats the idea

Not sure the point of all this.... There are highly optimized multi-byte multiply and shift functions in the existing math libraries, for which we all have source code. There is no magic to these algorithms, they've been around for many decades, and very well documented and understood. Why re-invent the wheel?

Regards,
Ray L.

RayLivingston:
... Why re-invent the wheel?

Regards,
Ray L.

ok, it was just an approach to

Think back to school arithmetic, when you did long multiplication.

to be absolutely true, it reminded me the "answer" I gave at exams back in 1979
:slight_smile:

Regards
demkat1