我试图了解汇编的工作原理,但是我真的很难受。教程无济于事,我没有人要亲自问,所以我想从某个地方开始。
有人可以逐步向我解释一下此代码中发生的情况以及以下问题的答案是什么?
执行以下指令后,R16,R17,R18的内容是什么?
ldi r16, 0xab
clr r17
ldi r18, 0x04
l1:
inc r16
dec r18
brne l1
sbrc r16, 2
ldi r17, 33
nop
我了解第一行,我们将十六进制值加载到寄存器16,然后出于某种原因清除了寄存器17,我不知道为什么,然后在第三行中,我们将十六进制值04加载到寄存器18,然后“ l1:”是循环吧?之后,我不确定发生了什么。我们递增寄存器16,递减寄存器18,但其余的我不明白吗?其他代码行又做什么?循环何时结束?
请先帮助并感谢!
答案 0 :(得分:2)
如果您不知道特定的汇编程序指令做什么,请始终参考AVR Instruction Set Manual,其中详细记录了所有指令。
brne
指令是条件分支(“如果不相等则分支”)。
brne l1
说:“如果不相等,则转到标签“ l1”,否则继续下一条指令”
不相等?什么应该“不等于”什么?
这是许多CPU和汇编语言的基础发挥作用的地方:
在所谓的“状态寄存器”(SREG
)中,有许多标志(单个位),其中一些标志在算术运算完成后会自动更新。
指令dec rXY
递减寄存器的值,并自动更新状态寄存器的“零标志”,即仅指示先前的算术指令是否得出值0的标志。
正常比较(指令cmp rAB, rXY
)是在减法之类的硬件中实现的,即cmp r1, r2
与sub r1, r2
几乎相同;特别是, both 指令都会更新与操作结果相对应的状态标志。两种操作之间的唯一区别是sub
会将r1
的值更改为减法的结果,而cmp
不会更改任何寄存器,只是丢弃结果值,但仍会更新状态标志。
如果将cmp
实现为减法,则可以看出cmp r1, r1
(两个值相等)得出的结果为 zero ,将零标志设置为{{ 1}}。不相等的值将导致非零结果,即零标志= 1
。
因此,如果上一个操作的结果没有产生0
,则brne ...
分支。
0
递减寄存器的值并根据结果设置零标志,即,如果递减后寄存器包含dec rXY
,则零标志被设置(0
),并且1
的有效含义是“如果brne ...
的结果不是为零,则分支”。
因此重复循环,直到dec
减为零为止。
r18
指令是“如果清除寄存器中的位则跳过”的代名词,它根据寄存器位的值使下一条指令跳过或不跳过。在说明手册中查找它。