Arithmetic Instructions
| Mnemonic | Description | Cycles |
|---|---|---|
add |
add without carry | 1 |
adc |
add with carry | 1 |
adiw |
add immediate to word | 2 |
sub |
subtract without carry | 1 |
subi |
subtract immediate | 1 |
sbc |
subtract with carry | 1 |
sbci |
subtract immediate with carry | 1 |
sbiw |
subtract immediate from word | 2 |
inc |
increment | 1 |
dec |
decrement | 1 |
mul |
multiply unsigned * | 2 |
muls |
multiply signed * | 2 |
mulsu |
multiply signed with unsigned * | 2 |
fmul |
fractional multiply unsigned * | 2 |
fmuls |
fractional multiply signed * | 2 |
fmulsu |
fractional multiply signed with unsigned * | 2 |
( * ) : means, these are not implemented in ATtiny.
Addition and Subtraction¶
Addition¶
::add¶
add takes two arg. Computes their sum and stores the value int the first arg.
ldi r16, 5
ldi r17, 6
add r16, r17
; r16 :> 5 + 6 = 11
::adc¶
Similary, adc - add with carry - takes two registers as input and computes their sum, then adds carry bit if needed. This is very usefull for adding more than 8-Bit values.
; 0x1234
ldi r16, 0x34 ; lower
ldi r17, 0x12 ; upper
; 0xABCD
ldi r18, 0xCD ; lower
ldi r19, 0xAB ; upper
add r16, r18 ; first lower bytes, this may activates carry bit
adc r17, r19 ; adds upper bytes, then adds carry bit
; r17, r16 :> 0xBE01
Subtraction¶
::sub & sbc¶
Same as add & adc.
::sbi¶
Subtraction with constant.
ldi r16, 0x05
sbi r16, 0x05
; r16 :> 0x00
| ⚠️ REMINDER |
|---|
Unfortunately, there is NO immediate instruction of add. |
::inc¶
Increase the value of register by one.
clr r16 ; clears r16 :> 0
inc r16 ; r16 :> 1
::dec¶
Decrease the value of register by one.
clr r16 ; clears r16 :> 0
inc r16 ; r16 :> 1
dec r16 ; r16 :> 0
::adiw & sbiw¶
These instructions allow us to operate on 16-Bit values. Needs 2 Cycle. Allows you to add a constant value of the range 0 - 63 to the register pair.
X ( r26 : r27 ) , Y ( r28 : r29 ) , Z ( r30 : r31 ) If only one register is specified the compiler will automatically fill in the next ( i.e. r24 → r25:r24 ).
; Load 0x1000 into two register
ldi r24, 0x00
ldi r25, 0x10
adiw r24, 0x0A ; add 0x0A to r24:r25 (result = 0x100A)
; Load 0x8080 into two register
ldi XL, 0x80
ldi XH, 0x80
adiw X, 1 ; increment X pointer (result = 0x8081)
; Load 0x55AA into two register
ldi YL, 0xAA
ldi YH, 0x55
sbiw Y, 0x10 ; subtract 0x10 from Y (result = 0x559A)
| ⚠️ REMINDER |
|---|
adiw and sbiw can only be used on the registers from r24 through r31. Also, they will only work on register pairs for which the lower is an even number, i.e. r25:r24 are valid operands, but r26:r25 are not. |
Multiplication¶
ATtiny family has no hardware multiplication instruction.
::mul¶
mul allows us to compute unsigned product of any 32 register. Result needs two register. Result always be stored in r1 for upper and r0 for lower bytes.
ldi r16, 0x18 ; 22
ldi r17, 0x37 ; 55
mul r16, r17 ; r1:r0 :> 0x0528 = 1210
::muls¶
muls allows us to compute signed product of only r16 through r31. Signed arg must be in Two's Complement format.
ldi r16, 0xF2 ; -14 in Two's Complement
ldi r17, 0x37 ; -33 in Two's Complement
mul r16, r17 ; r1:r0 :> 0x01CE = 462
| ❓ QUICK CHEAT |
|---|
| To convert a value to Two's Complement format, simply add 256 if it is less than zero. |
-14 + 256 = 242 (0xF2) in Two's Comp.: -14 |
::mulsu¶
mulsu allows us to compute product of two arg when one of them is signed and the second one is unsigned. But some limitations, there are. It works only on r16 through r23.
Fractional Multiplication¶
ATmega supports limited multiplication of fractional numbers. Fractional number between [0,2) can be presented by an 8-Bit number in a 1.7 Format.
| Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
|---|---|---|---|---|---|---|---|
| 20 | 2-1 | 2-2 | 2-3 | 2-4 | 2-5 | 2-6 | 2-7 |
| 1 | 0.5 | 0.25 | 0.125 | 0.0625 | 0.03125 | 0.015625 | 0.0078125 |
For example: 0b01001100 would equal 0x1 + 1x0.5 + 0x0.25 + 0x0.125 + 1x0.0625 + 1x0.03125 + 0x0.015625 + 0x0.0078125 = 0.59375 using this format.
::fmul¶
fmul computes the sum of two 8-bit numbers in the 1.7 format and outputs the result in r1 and r0 in a 1.15 format. In 1.15, the first bit of the higher byte represents an integer component and the rest of the bits represent fractional components. fmul will only work with r16 through r23.
ldi r16, 0xC0 ; 1.5
ldi r17, 0xA0 ; 1.25
fmul r16, r17 ; r1:r0 :> 0xF000 = 1.875
::fmuls¶
fmuls is signed version of fmul. Range is [-1,1).
ldi r16, 0xA0 ; -0.75
ldi r17, 0xF0 ; -0.125
fmuls r16, r17 ; r1:r0 :> 0x0C00 = 0.04375
| ❓ QUICK CHEAT |
|---|
| To convert a fractional value to Two's Complement format, simply add 2 if it is less than zero. |
-0.75 + 2 = 1.25 (0xA0) in Two's Comp.: -0.75 |
::fmulsu¶
And also we have first signed, second unsigned version.
ldi r16, 0xC0 ; -0.5
ldi r17, 0x60 ; 0.75
fmuls r16, r17 ; r1:r0 :> 0xD000 = -0x375