微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > MCU和DSP > 与编译器开发商密切合作优化微控制器开发

与编译器开发商密切合作优化微控制器开发

时间:06-13 来源:互联网 点击:
微控制器开发团队与编译器开发人员的合作成果是生成的代码效率更高,性能更好。本文介绍的是为了使ATMEL AVR微控制器系列更适合C编译器,开发者在编译器开发阶段对微控制器架构和指令集所进行的调整。

AVR架构的核心是一个可快速访问RISC寄存器文件。该文件由32个8位通用寄存器构成。微控制器可在一个单时钟周期内加载该文件中的任意两个寄存器到算术逻辑单元(Arithmetic Logical Unit, ALU),完成所要求的操作,将结果写回到任意一个寄存器。ALU支持寄存器间或某一寄存器与一个常数之间的运算和逻辑功能,单寄存器操作也是在ALU中执行的。微控制器使用一个哈佛(Harvard)架构,在该架构中,程序存储器空间与数据存储器空间是相互隔离的。程序存储器采用单级管道访问技术,当一条指令被执行的同时,下一条指令已从程序存储器中被预先提取。由于其算术和逻辑操作都真正地在单周期内完成,因此AVR微控制器的性能达到每MHz一个 MIPS。


图1 AVR 架构

细调微控制器

采用高级语言(High Level Languange, HLL)代替汇编语言来开发微控制器应用程序有许多优势,但一直都有一个重大缺点,即代码量不断增加。我们在开发AVR微控制器时考虑了使用C语言来开发应用,使得我们有可能为器件构建出一个高效C编译器。为了进一步提升这项特性,我们在AVR的架构和指令集未完成前就开始着手C编译器的开发。我们先让瑞典 IAR Systems的编译器专业开发人员对我们的AVR架构和指令集进行评测,最后开发出非常适合运行C编译器生成代码的微控制器。

寻址模式

为让编译器生成高效的代码,重要的是让寻址模式匹配C语言的需要。AVR架构原来配了两个指针寄存器(Pointer Register)。这两个指针可用于间接寻址、算后增量(post increment)间接寻址、算前减量(pre-decrement)间接寻址,以及带位移(displacement)的间接寻址,能够很好地支持指针操作。此外,还有一个用于访问数据存储器中变量的页面直接寻址模式。

指针位移

带位移的间接寻址是一种非常有用的寻址模式,即使从C编译器的角度亦如此。例如,将指针指向某一结构(struct)的第一个成员,就可以访问该结构内位移量所允许的其他任何位置,无须变更16位指针。带位移的间接寻址模式也常常用于访问软件堆栈上的变量。函数参数和autos常常放在软件堆栈上,这样,不用变更指针就可进行读写操作。位移寻址在定位数组成员(addressing elements in an array)时也非常有用。

尽管位移模式在许多情况下非常有用,但仍存在一个位移受限的问题。位移原本被限制在16个位置以内,而实际应用往往超出该数量。这样,在位移模式无法访问的位置,就必须加载一个新的指针。为扩展位移模式的访问范围,我们不得不改变指令集的其他部分,以获得足够的编码空间。同时,我们还得知,C编译器很难使用页面直接寻址模式。于是,取消了页面直接寻址模式,使用腾出的空间将位移模式扩展为64个位置,足以满足大多数间接寻址的要求。原来的页面直接寻址模式变成一个两个字长的非页面直接寻址模式。

存储器指针数

AVR微控制器原来配置了两个16位存储器指针。如要采用C编译器,那么其中一个指针必须专门用作软件堆栈,这样,就只剩一个存储器指针。在许多情况下,需要将存储器从一个区域复制到另一个区域。但由于只有一个指针,需要读1字节,设置指针,确定写入目标位置,写入这字节,然后再将指针设回数据源位置。如果增加第三个存储器指针(精简功能),完成存储器区域复制就不需要设置指针。如下例所示,只要使用算后增量间接寻址模式就可构建非常高效的存储器读写循环(假设:将指针Z指向源的第一字节,X指向目标的第一字节):

LDI R16,0x60  ;Load byte count
loop:  LD R17,Z+  ;Load byte,   
increment pointer
  ST X+,R17  ;Store  
byte, increment pointer
  SUBI R16,1 ;Decrement
counter
BRNE loop ; Branch
if more bytes

具备指针算后增量(post increment)、算前减量(pre-decrement) (+1、-1)操作的可能性对于实现堆栈也非常有效。这当然也可用于软件运行时间堆栈。

直接寻址

如在指针位移一节所述, 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

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top