# 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.

```asm
; 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.

```asm
; 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
```asm
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
```asm
; 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
```asm
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.

```asm
LDI R16, 23
LDI R17, 9
MUL R16, R17
; R1:R0 = 23 * 9 = 207 (16 bits wide)
```