- 易迪拓培训,专注于微波、射频、天线设计工程师的培养
与编译器开发商密切合作优化微控制器开发
直接寻址
如在指针位移一节所述, AVR原来有一个页面直接寻址模式,但是,对于编译器该模式难于使用,且效率较低。由于我们需要更多的编码空间来增加位移量,因此取消了页面直接寻址模式。不过,如果完全没有直接寻址模式,代码效率也会降低,因为在有些情况下需要访问存放在数据存储器中的变量。尤其是处理静态字符时,代码开销将会很大(达到50%),因为静态变量必须保存在数据存储器中,不能自动放置到寄存器中。为了克服代码效率低下的问题,我们占用一个16位地址来增加一些非页面直接寻址指令。这样,就可用一条指令来完成64KB数据空间的寻址。要访问如此大的一个存储器区域,访问指令必须是两个16位字。
如果访问的字节数少(例如读取一个字符),使用这种寻址方式的效率高于指针方式。对于较大的区域,可能仍然是使用间接寻址比较有效(参见下面的示例)。
Loading of a character:
Indirect addressing (6 Bytes): Direct addressing (4 Bytes):
LDI R30,LOW(CHARVAR) LDS R16,CHARVAR
LDI R31,HIGH(CHARVAR)
LD R16, Z
Loading of a long integer:
Indirect addressing (12 Bytes) Direct addressing (16 Bytes)
LDI R30,LOW(LONGVAR) LDS R0,LONGVAR
LDI R31,HIGH(LONGVAR) LDS R1,LONGVAR+1
LDD R0,Z LDS R2,LONGVAR+2
LDD R1,Z+1 LDS R3,LONGVAR+3
LDD R2,Z+2
LDD R3,Z+3
零标志传播
为实现条件转移,需要使用一些指令来操作由一些标志(flag)构成的AVR状态寄存器。跟在这类指令之后的条件转移指令(conditional branch instruction)是否执行转移,取决于这些标志的设置。使用运算指令操作这些标志,就可检查一个数A与另一个数B之间的大小关系。当被检查的数为8位的数时,不存在什么问题,因为所有标志都依赖一条指令设置的标志值。当被检查的数为16位或32位的数时(这在C语言中是常有的情况),问题就有点棘手了,例如一个32位减法操作就相当于要连续进行4个8位减法操作,而每做一次8位减法,就会产生一组新的标志。
为传播进位标志,大多数处理器都包含一些能处理进位标志先前设置值的指令。例如,带进位的减法(SBC)指令;执行SBC A,B语句就相当于将A变成进位位。但要正确完成所有的条件转移操作,这里还有另一个标志需要传播,即零标志。
示例:
A=R3:R2:R1:R0,
B=R7:R6:R5:R4
我们打算从A中减去B,并如果A=B就跳转到一个指定位置。如果这个零标志只依赖于最后的运算指令,那么下面的指令将不会执行:
SUB R0,R4
SBC R1,R5
SBC R2,R6
SBC R3,R7 ; R3=R7
=> Zero flag set
BREQ destination
这是因为BREQ指令使用的标志值只取决于最后的SBC指令设置的标志值。如果大多数高位直接相等,即便32位数不相等,零标志也将被置位,而转移也会被执行。这种问题也会出现在其他的条件转移上。
有两种办法可以解决这个问题。一是保存每个指令产生的标志,然后在第四个减法完成后检查所有的零标志。另一个更精细的方法是在进位指令中传播零标志(参见下面方式):
Znew =Not(R7) AND
Not(R6) AND
...
Not(R0) AND
Zold
使用这种方式传播零标志,所有条件转移在最后一个减法操作完成后都会被执行,因为参与标志(溢出和正数标志)所剩部分只取决于最高位字节。
作者:爱特梅尔公司 来源:今日电子/21ic