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