用PICC编译器开发PIC系列单片机的代码
void func1(void){
asm("NOP");
#asm
nop
rlf_var,f
#endasm
asm("rlf_var,f");
}
需要注意的是,嵌入汇编不是完整意义上的汇编,是一种伪汇编指令,使用时必须注意它们与编译器生成代码之间的互相影响。
另一种方法是将汇编作为一个独立的模块,用汇编编译器(ASPIC)生成目标文件,然后用链接器和C语言生成的其它模块的目标文件链接在一起。如果变量要公用时,则在另一个模块中说明为外部类型,并允许使用形式参数和返回值。
例如,如果在C模块中使用汇编模块中的函数,那么在C中可知下声明:
extern char rotate_left(char);
本声明说明了要调用的这个外部函数有一个char型形式参数,并返回一个char型的值。而rotate_left()函数的真正函数体在外部可以被ASPIC编译的汇编模块(文件名后缀.as)中,具体代码可以如下编写:
processor16C84
PSECT text0,class=CODE,local,delta=2
GLOBAL _rotate_left
SIGNAT _rotate_4201
_rotate_left
movwf?a_rotate_left
rlf?a_rotate_left,w
return
FNSIZE _rotate_left,1,0
GLOBAL?a_rotate_left
END
需要注意的是,以C模块中声明的函数名称,在汇编模块中是以下划线开头的。GLOBAL定义了一个全局变量,也等同于C模块中的extern,SIGNAL强制链接器在链接各个目标文件模块时进行类型匹配检查,FNSIZE定义局部变量和形式参数的内存分配。
这种方法比较麻烦,如果对某一模块的执行效率要求较高时,可以采取这种办法;但是,为了保证汇编程序能正常运行,必须严格遵守函数参数传递和返回规则。当然,为避免这些规则带来的麻烦,一般情况下,可以先用C语言大致编写一个类似功能的函数,预先定义好各种变量,采用PICC-S选项对程序进行编译,然后手工优化编译器产生的汇编代码后将其作为独立的模块就可以了。
4 注意事项
使用PICC时,为了更有效地利用资源,应注意以下几点:
①尽量使用无符号数和字节变量。
②在寄存器资源允许的情况下,对某些执行效率要求较高的平级元相互调用函数中用到的内部变量,可将其定义为全局临时变量,编程时覆盖使用,这样可减少很多编译代码。而对于中断函数内部用到的变量,可用全局变量。
③对于有一定汇编经验的人在开始使用PICC时,应多注意观看编译后产生的汇编源代码,并经常观看经正确编译链接后产生的映像文件(.MAP文件)。在该文件中,详细列出了分配给变量和代码的地址和生成代码的大小等信息。使用者可了解代码是否优化,变量分配是否合理,堆栈是否溢出等,从而写出高效简洁的C源代码。
④在很多情况下,PICC不支持类型强制转换。即在类型不匹配时须查验编译后的汇编代码,看是否正确,尤其是对指针操作的时候一定要注意。
⑤对某位变量自操作时,比如求反,不可以直接简写,例如:!flag;编译后不能正确产生代码,而须写成:“flag=!flag;”
⑥尽量选择全局优化编译选项。为保证寄存器页(包括程序存储期页面和RAM寄存器页)的正确转换,PICC的编译代码中有大量的变换寄存器页的代码,选择全局优化PICC会优化去大量有关RP0、RP1、PCLAPH所增加的变换代码,从而加快程序执行速度,并节省大量的程序空间。
⑦若有某一代码很短的函数被多个函数经常调用,最好将其定义为宏。因为若函数代码很短时,由于被调函数和调用函数不在同一代码页所产生的附加代码可能都会超过函数代码本身的长度。
5 结论
PICC编译器产生的代码在有些时候虽然比较繁琐,但结构和逻辑性很强,开发效率大大提高,调试与维护都很方便。不论是从程序的开发速度、软件质量还是从程序的可维护性和可移植性上讲,PICC的优点绝非汇编语言所能比拟的。