4. Advanced Arithmetic Operations

As a refresher, here are some fundamental AVR arithmetic and logical instructions. 
 
 
 
 Mnemonic 
 Operand 
 Description 
 Example 
 Notes 
 
 
 
 
 ADD 
 Rd, Rr 
 Add 
 ADD R1, R2 
 Rd = Rd + Rr 
 
 
 ADC 
 Rd, Rr 
 Add with Carry 
 ADC R1, R2 
 Rd = Rd + Rr + C (Carry flag) 
 
 
 ADIW 
 Rd, K 
 Add Immediate to Word 
 ADIW R24, 40 
 R[d+1]:Rd = R[d+1]:Rd + K 
 
 
 SUB 
 Rd, Rr 
 Subtract 
 SUB R16, R17 
 Rd = Rd - Rr 
 
 
 SBC 
 Rd, Rr 
 Subtract with Carry 
 SBC R16, R17 
 Rd = Rd - Rr - C 
 
 
 SUBI 
 Rd, K 
 Subtract Immediate 
 SUBI R16, 67 
 Rd = Rd - K 
 
 
 SBIW 
 Rd, K 
 Substract Immediate from Word 
 SBIW R24, 40 
 R[d+1]:Rd = R[d+1]:Rd - K 
 
 
 SBCI 
 Rd, K 
 Subtract Immediate with Carry 
 SBCI R17, 0 
 Rd = Rd - K - C 
 
 
 INC 
 Rd 
 Increment 
 INC R16 
 Rd = Rd + 1 
 
 
 DEC 
 Rd 
 Decrement 
 DEC R16 
 Rd = Rd - 1 
 
 
 MUL 
 Rd, Rr 
 Multiply Unsigned 
 MUL R16, R17 
 R1:R0 = Rd × Rr (16-bit result) 
 
 
 MULS 
 Rd, Rr 
 Multiply Signed 
 MULS R16, R17 
 R1:R0 = Rd × Rr (signed) 
 
 
 NEG 
 Rd 
 Negate (Two's Complement) 
 NEG R16 
 Rd = 0x00 - Rd 
 
 
 AND 
 Rd, Rr 
 Logical AND 
 AND R1, R2 
 Rd = Rd AND Rr 
 
 
 ANDI 
 Rd, K 
 AND Immediate 
 ANDI R16, 0x0F 
 Rd = Rd AND K 
 
 
 OR 
 Rd, Rr 
 Logical OR 
 OR R1, R2 
 Rd = Rd OR Rr 
 
 
 ORI 
 Rd, K 
 OR Immediate 
 ORI R16, 0x80 
 Rd = Rd OR K 
 
 
 EOR 
 Rd, Rr 
 Exclusive OR 
 EOR R16, R17 
 Rd = Rd XOR Rr 
 
 
 COM 
 Rd 
 One's Complement 
 COM R16 
 Rd = 0xFF - Rd (inverts all bits) 
 
 
 NEG 
 Rd 
 Two's Complement 
 NEG R16 
 Rd = -Rd (Signed) 
 
 
 CLR 
 Rd 
 Clear Register 
 CLR R16 
 Rd = 0 
 
 
 SER 
 Rd 
 Set Register 
 SER R16 
 Rd = 0xFF (R16-R31 only) 
 
 
 
 Register Pair Arithmetic 
 To perform arithmetic operations with 16 bit words (0 - 65535), we can utilize the Carry Flag to perform ripple carry arithmetic operations. 
 16 Bit Word Addition 
 Suppose you want to add two big 16 bit numbers 26983 and 4882 stored in two register pairs R16:R17 and R18:R19. You can add the lower byte first then add the higher byte with a carry addition. 
 ; DEC 26983 = HEX 0x6967
LDI R16, 0x69 ; upper byte
LDI R17, 0x67 ; lower byte

; DEC 4882 = HEX 0x1312
LDI R18, 0x13 ; upper byte
LDI R19, 0x12 ; lower byte 

ADD R17, R19 ; add lower byte
ADC R16, R18 ; add upper byte + carry from lower

; R16:R17 = 31865
 
 16 Bit Word Substraction 
 A similar thing can be done for substracting two 16 bit numbers. 
 ; DEC 26983 = HEX 0x6967
LDI R16, 0x69 ; upper byte
LDI R17, 0x67 ; lower byte

; DEC 4882 = HEX 0x1312
LDI R18, 0x13 ; upper byte
LDI R19, 0x12 ; lower byte 

SUB R17, R19 ; substract lower byte
SBC R16, R18 ; substract upper byte - borrow (C) from lower

; R16:R17 = 22101
 
 Immediate Arithmetic 
 There are 3 immediate arithmetic instructions: ADIW , SBIW , and SUBI . In AVR there is no "Add with immediate" instruction. To do so, you can utilize the SUBI Rd, K instruction to substract a negative immediate number to achieve addition. 
 Suppose you want to add 67 to 61 stored in R16. You can do the following 
 LDI R16, 61
SUBI R16, -67 ; - -61 = + 61
; R16 = 128
 
 Notice how there are only immediate instructions for word addition and substraction? Recall that word immediate addressing ( ADIW & SBIW ) can only operate on 6 bit values (0 - 63). How can we perform immediate arithmetic operations on bigger numbers like 26983? 
 Word Immediate Arithmetic 
 To perform addition/substraction operation with immediate numbers greater than 63, we simply split the word operation into two byte immediate operations similar to the previously explained 16 bit operations. 
 16 Bit Immediate Addition 
 ; DEC 4882 = HEX 0x1312
LDI R16, 0x13 ; upper byte
LDI R17, 0x12 ; lower byte

.EQU num, 0x5457 ; immediate constant DEC 21591
SUBI R17, lo8(-num) ; 0x12 - -0x57 = 0x12 + 0x57 ; add lower byte
SBCI R16, hi8(-num) ; 0x13 - -0x54 - C = 0x13 + 0x54 + C ; add upper byte
; R16:R17 = 26473
 
 16 Bit Immediate Substraction 
 LDI R16, 0x67 ; yeah you get the idea atp
LDI R17, 0x69

.EQU num, 0x1312
SUBI R17, lo8(num) ; this time we simply just substract it
SBCI R16, hi8(num) ; no need to be negative :)
; R16:R17 = 26983
 
 Multiplying Numbers 
 There are multiple multiplication instructions in AVR, each supporting different data formats such as MUL Rd, Rr for unsigned numbers, MULS Rd, Rr for signed numbers, and MULSU Rd, Rr for multiplying a signed with an unsigned number. 
 Generally, the way they behave are similar: they multiply Rd with Rr then storing a 16 bit result in R1:R0. 
 LDI R16, 23
LDI R17, 9
MUL R16, R17
; R1:R0 = 23 * 9 = 207 (16 bits wide)