# AVR Assembly - Operations with two 8-bit registers in 16-bit

R20 = (4 * R16 + 3 * R17 - R18) / 8

.org 0
start:
ldi r16, 10
ldi r17, 20
ldi r18, 10
lsl r16
lsl r16
mov r20,r17
lsl r20
sub r20,r18
asr r20
asr r20
asr r20

konec:
rjmp konec


I created this program (ATMega169), to compute the expression and for the sake of accuracy I would need the operations to be performed in 16 bits. I know that there are R26 R27 registers that "act" as one, but I have no idea how to work with it. I need some study material or some kind of advice. Thank you in advance

• study the ATmega datasheet ... there may also be a programming manual .... it is possible that there is s sequence of events to follow when dealing with 16 bit data transfers .... possibly operate on upper byte first and the lower byte on the next operation Commented Apr 22, 2021 at 0:38
• There’s X,Y and Z which are register pairs 26:27,28:29,30:31. Mainly for pointer (indirect addressing) use. For your math, X,Y or Z won’t help you much. Commented Apr 22, 2021 at 1:18
• And if I convert the registers to these x and y, then I don't get more range or any benefits? Commented Apr 22, 2021 at 1:27
• AVR doesn't have 16-bit arithmetic operations, you just do your operation on lower registers first, then use carry bit and do the higher part. Check addc and subc operations. Commented Dec 30, 2022 at 12:20

The $$\x\$$ and $$\y\$$ and $$\z\$$ registers are mostly for indirect references: "These registers are 16-bit address pointers for indirect addressing of the data space." There aren't any ALU operations that support 16-bit because the ALU is an 8-bit ALU, not a 16-bit ALU. There's no escaping that requirement here.

Compute an exact integer value for (4a + 3b - c) / 8

Arithmetic is arithmetic - don't let using assembly transfix you.
The simplest thing that can be expected to do even for cores lacking mul/muls is stubbornly processing carries:

; Compute an exact integer value for (4a + 3b - c) / 8

.DEF a    = R16
.DEF b    = R17
.DEF c    = R18
.DEF sum  = R20
.DEF high = R21
.DEF zero = R19

clr  zero
clr  high
mov  sum, a       ; sum =  a
lsl  sum
rol  high         ; sum = 2a
lsl  sum
rol  high         ; sum = 4a
addc high, zero   ; sum = 4a +  b
addc high, zero   ; sum = 4a + 3b
sub  sum, c
subc high, zero   ; sum = 4a + 3b - c
lsr  high
ror  sum          ; sum = trunc((4a + 3b - c) / 2)
lsr  high
ror  sum
lsr  high
ror  sum          ; sum = trunc((4a + 3b - c) / 8)
;   addc sum, zero    ; sum = round((4a + 3b - c) / 8)


(An optimising compiler's "interesting" way to fuse zeroing high and incorporating a carry:
subc high, high)

Trying not to first multiply by 4 and finally divide by (4*2): \begin{align} (4a + 3b - c) / 8 & = (4(a + b) - b - c) / 8 \\ & = (4(a + b)/4 - (b + c)/4) / 2 \\ \end{align}

; Compute an exact integer value for (4a + 3b - c) / 8 = (4(a+b)/4 - (b+c)/4) / 2

.DEF subtrahend = R21
.DEF bit8       = R19

mov  sum, a          ; sum = a
add  sum, b          ; C##sum = a + b  (C: carry flag; ##: concatenated)
rol  bit8            ; save carry
mov  subtrahend, b   ; subtrahend = b
add  subtrahend, c   ; C##subtrahend = b + c
sbrc subtrahend, 0   ; if one of the bits to shift out is 1,
sbr  subtrahend, 1   ;  carry will be set as a result of the asr below
ror  subtrahend      ; subtrahend = trunc((b + c) / 2) (conceptionally)
asr  subtrahend      ; subtrahend = trunc((b + c) / 4) (conceptionally)
subc sum, subtrahend ; sum = 4(a + b) / 4 - ceil((b + c) / 4) (hopefully)
sbci bit8, 0
ror  bit8
ror  sum             ; sum = (4a + 3b -c) / 8 (hopefully)