Reputation: 39
So we gotta make a simple program that gonna check out is number odd or even.
That is my first time with assembler. Many examples were about ARM and WASM, but its AVR is really pain.
start:
ldi r16, $0
ldi r17, $1 ; Load decimal 1 into r16
ldi r18, $2 ; Load decimal 2 into r17
ldi r19, $3 ; Load decimal 3 into r18
ldi r20, $4 ; Load decimal 4 into r19
ldi r21, $5 ; Load decimal 5 into r20
CLC ; clear carry flag
tst r21 ; check is r20 odd
BRHS isodd ; goto is odd
MOV r10, r18 ; not odd
JMP exit
isodd:
MOV r10, r17 ; is odd
exit:
nop
Upvotes: 1
Views: 1466
Reputation: 365557
AVR allows efficiently testing any single bit by copying it into the T flag with bst
where you can branch on it. (Or copy it to another bit of another register with bld
, as shown in the manual's example for bst
.)
The key instructions here:
BST
– Bit Store from Bit in Register to T Flag in SREG.BRTC
– Branch if the T Flag is Cleared (There's a corresponding BRTS
for T==1) bst r21, 0 ; T = (r21 >> 0) & 1
brtc is_even ; jump if (r21 & (1<<0) == 0)
Or even better, if your branch only needs to skip one instruction, sbrs
- Skip if Bit in Register is Set. (The skipped instruction could itself be a branch, if you wanted, but bst / brt[sc] may be faster in that case.)
sbrs r21, 0
nop ; runs only for even R21
... code that runs for both cases
e.g. GCC uses it when compiling if(x&1) bar();
(Godbolt):
foo:
sbrs r24,0
ret ; return (skipped for odd)
rjmp bar ; else tailcall
The manual says tst reg
is just an alias for and reg,reg
to set flags according to the whole value. (html extract).
Unlike some ISAs with more opcodes (like ARM where you would tst r0, #1
), AVR doesn't have a non-destructive AND-but-only-set-flags instruction, only a cmp
(which is like sub but doesn't modify the destination reg). If you wanted to do it that way, you could load a 1
into another register and AND into that, setting or clearing the Z flag for BRNE or BREQ.
Or andi r21, 1
if you don't mind destroying r21. Or right-shift it to shift the low bit into the carry flag. This does still let you branch on odd/even in 2 instructions instead of 3, in a way that's more like other ISAs.
Upvotes: 2
Reputation: 12515
Your tst opcode is checking for 0 or negative (zr or carry falg set). That won't capture odd/even. Consider using something like andi r21,1 and checking for zero flag on that. You could also use a shift right (lsr r21) and check carry for odd as well. These both affect the r21 register though so beware.
...
ldi r21, $5 ; Load decimal 5 into r20
andi r21, $1 ; check is r20 odd
breq is_even ; if zero flag is set, the low bit was clear. Even.
mov r10, r17 ; This is the Odd pass
jmp exit
is_even:
mov r10, r18 ; This is the Even pass
exit:
...
All opcode info pulled from http://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf
Standard disclaimer - I can't test this code locally, but it demonstrates the technique I believe that you need.
Upvotes: 1