AVR 汇编程序检查是奇数

AVR Assembler check is number odd

所以我们要做一个简单的程序来检查是奇数还是偶数。

那是我第一次接触汇编程序。 很多例子都是关于ARM和WASM的,但是它的AVR真的很蛋疼

start:
ldi r16, [=10=]
ldi r17,  ; Load decimal 1 into r16
ldi r18,  ; Load decimal 2 into r17
ldi r19,  ; Load decimal 3 into r18
ldi r20,  ; Load decimal 4 into r19
ldi r21,  ; 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

您的 tst 操作码正在检查 0 或负数(zr 或进位 falg 集)。那不会捕获 odd/even。考虑使用类似 andi r21,1 的东西并检查其上的零标志。您也可以使用右移 (lsr r21) 并检查进位是否为奇数。这些都会影响 r21 寄存器,但要小心。

...
ldi  r21,    ; Load decimal 5 into r20
andi r21,    ; 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:
...  

http://ww1.microchip.com/downloads/en/devicedoc/atmel-0856-avr-instruction-set-manual.pdf

中提取的所有操作码信息

标准免责声明 - 我无法在本地测试此代码,但它演示了我认为您需要的技术。

AVR 允许有效地测试任何单个位 ,方法是将其复制到带有 bst 的 T 标志中,您可以在其中进行分支。 (或者使用 bld 将其复制到另一个寄存器的另一位,如手册中 bst 的示例所示。)

这里的关键说明:

   bst   r21, 0            ; T = (r21 >> 0) & 1
   brtc  is_even           ; jump if (r21 & (1<<0) == 0)

甚至更好,如果您的分支只需要跳过 一条 指令,sbrs - Skip if Bit in Register is Set。 (如果你愿意,跳过的指令本身可以是一个分支,但 bst / brt[sc] 在这种情况下可能更快。)

   sbrs r21, 0
     nop              ; runs only for even R21

   ... code that runs for both cases

例如GCC 在编译时使用它 if(x&1) bar(); (Godbolt):

foo:
        sbrs r24,0
        ret             ; return (skipped for odd)
        rjmp bar        ; else tailcall

手册说tst reg只是and reg,reg的一个别名,根据整个值设置标志。 (html extract).

与一些具有更多操作码的 ISA(如 ARM,你会 tst r0, #1)不同,AVR 没有非破坏性的 AND-but-only-set-flags 指令,只有 cmp (类似于 sub 但不修改目标 reg)。如果你想那样做,你可以将 1 加载到另一个寄存器中,然后将 AND 加载到该寄存器中,设置或清除 BRNE 或 BREQ 的 Z 标志。

andi r21, 1 如果您不介意破坏 r21。或者右移它以将低位移入进位标志。这仍然可以让您在 odd/even 上以 2 条指令而不是 3 条指令进行分支,其方式更像其他 ISA。