Reputation: 87
Using an Arduino, I have to write a function in Atmel AVR Assembly for my computer science class that computes the 8-bit average of two 8-bit values in assembly. I am not allowed to use any branching instructions either (but skips are fine).
This is what I have so far:
.global average
average:
add r24, r22
asr r24
ret
For the part of my program where I have to compute the average of 69 and 60, it returns -64 instead of 64. Does anyone know how I would make this function work? Any help would be much appreciated.
Upvotes: 2
Views: 1499
Reputation: 365267
The trick is to add and then rotate-with-carry to divide the 9-bit result by 2 and leave an 8-bit result in a register.
Two of the answers on the question I linked in comments use that: first, second.
An AVR implementation of that is:
add r24, r25 ; 9-bit result in C and r24
ror r24 ; rotate-through-carry, like x86's RCR instruction
This works for signed or unsigned interpretation of the bits, since all we're doing is discarding the low bit from the 9-bit full result of the addition. There's no arithmetic vs. logical shift choice, and no wraparound.
Also note that division by shifting rounds towards -infinity (not truncating towards zero like C's integer division operator). So (1 + -2) >> 1
is -1
.
This is small enough that you should put it in a macro, not a function. It probably takes at least 2 instructions at most call sites, so inlining this saves code size even if you could have used the 1-word RCALL instruction instead of 2-word CALL.
Upvotes: 10