声明:本文转载自微信公众号SoftAuto文章《嵌入式软件时序(3)—— 代码执行》,略有改动。
微处理器提供的指令在处理器的指令集参考手册中有所描述。对一个处理器的指令集的了解对于在代码层面上优化软件是至关重要的。
微处理器的计算内核一直在处理机器指令。这些指令按顺序从程序存储器(或代码存储器)加载到执行单元,在那里被解码,然后执行。程序计数器(PC)已经被提及,它可以被认为是指向程序存储器中的当前指令。只要没有跳转指令或调用函数的指令,一旦完成指令的处理,PC就会增加一个内存位置,指向下一条要执行的指令地址。因此,PC指向下一条命令,而下一条命令又被加载到执行单元,然后被解码和执行。程序存储器主要是机器命令的序列。在这一点上,应该提到,没有任何跳转或调用的一系列机器命令被称为“基本块”。更准确地说,基本块是一系列机器指令,其执行总是从第一条指令开始,然后按顺序执行其所有指令,并以执行最后一条指令结束。处理器不会在第一条或最后一条指令之外的任何其他点跳入或跳出基本块。基本块在静态代码分析中起着重要的作用,所以我们将在后面回到这个话题。
下面我们以8位Microchip AVR处理器的加法指令为例,说明指令集是如何被记录、编码和处理的。
Microchip AVR处理器有32个数据/地址寄存器。它们作为数据寄存器或地址寄存器的作用取决于指令。上图是Microchip AVR ATmega处理器的指令集参考手册的部分,即描述带进位标志的加法指令的部分。在文字和操作形式的描述(Rd ← Rd + Rr + C)之后是语法的定义。这是一个与汇编代码中的符号完全相同的命令。这样的 "汇编代码命令"也被称为助记符。语法下面的表格显示了命令的操作码,也就是内存中代表该命令的值。其中,高六位是固定的(二进制000111),代表带进位加法,其余的十个位定义了哪些寄存器要被加在一起。标有 "d "的位是针对寄存器Rd的,而标有 "r "的位是针对寄存器Rr的。例如,如果寄存器R3和R22要相加,并且结果要存储在R3中,操作码看起来如下面汇编代码片段所示。每当在汇编代码中发现adc r3,r22时,在程序内存的相应位置会出现0x1D63。
上面的例子中用于解释二进制机器码的注释已被证明对编程非常有用。每当信息以二进制编码并需要解释时,这种类型的注释是非常有用的。位的位置由两行注释表示:上面一行是表示第10位的位置,下面一行是按位的位置序号。可以帮助读者快速定位到指令的第几位。现在可以简单地从上到下读取位的位置。例如,15是指最左边的MSB。此外,建议用空格将四位一组(一个nibble)分开,因为每个半字节(4位)也可以用一个十六进制数字表示。
在AVR ATmega处理器的指令集参考的操作码的描述中,有关于状态寄存器(在这个处理器中称为 "SREG")的哪些标志被修改以及如何修改的确切说明。接下来是一个使用普通加法指令“add”,然后是带进位加法“adc”的例子。这两条指令显示了在8位处理器上实现16位加法的过程。指令的描述以操作码在程序存储器中需要两个字节并在一个时钟周期内执行结束。
Peter Gliwa, 《Embedded Software Timing》