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
– Bit Store from Bit in Register to T Flag in SREG.
BRTC
– Branch if the T Flag is Cleared(T==1有对应的BRTS
)
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。
所以我们要做一个简单的程序来检查是奇数还是偶数。
那是我第一次接触汇编程序。 很多例子都是关于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
– Bit Store from Bit in Register to T Flag in SREG.BRTC
– Branch if the T Flag is Cleared(T==1有对应的BRTS
)
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。