开发51时,选择IAR,而不选择Keil,一般会有两个理由:
1、IAR的编译器十分灵活,尤其是XCL的文件配置,几乎比GCC的ld文件更加强大。
2、IAR的切BANK机制了。
说到IAR的切BANK机制,就要说起IAR的版本了。
在720H以前,都是旧的BANK机制,而到了750A以后的版本,基本都是新的BANK机制了。由于这中间几个版本找不到软件下载,根据官方网站上的说明,Hanny暂且判断IAR 730A为使用新的BANK机制的一个分届版本。
在旧的BANK机制中,切BANK是这样的:
MOV DPTR, #func_ptr<br />
MOV A, #bank_num<br />
LCALL ?B_CALL
主要就是,将目标函数放入DPTR,BankNum放入 A寄存器,然后调用公共区的?B_CALL函数进行切换
而新的BANK机制中,切BANK是这样的:
LCALL func?relay
然后,relay接口如下:
func?relay: LCALL XXXX<br />
DB func_ptr
大约这样,具体可参考IAR帮助。
其实,Hanny更喜欢IAR720H的机制。何解?IAR官方虽说新的机制更好。理论上,新的机制,在多次调用时确实减少了程序的总大小,但是却浪费了宝贵的COMMON CODE区。新的版本会给每个函数生成 relay 入口,存放在 BANK_RELAYS 段中。而 BANK_RELAYS 必须放在公共区。
一般来说,旧的版本在新的IAR下编译有可能出以下错误:
Error: Segment BANK_RELAYS must be defined in a segment definition option (-Z, -b or -P)
这时,只能用回720H的版本就OK了。
IAR有个关键词 __root。不过,Hanny今天又被这个关键词给坑了。
IAR有几个关键词:__root的本意是指该内容不要被链接器优化,可用于函数和变量。__no_init是指变量不需要初始化,一般给变量定位分段时要加。
按照这个理解,加上__root的,是一定要被链接了。可是今天,Hanny发现如果整个.C文件都没有调用的话,即使加上__root也是没有用的。不知道和版本有没有关。Hanny现在用的版本是IAR720H,就为了它的BANK机制。
在IAR中,编译器会根据函数情况对函数进行控制。但是有时,我们需要对某些函数进行强制内嵌或者强制不内嵌的操作。
如果需要对函数进行强制内嵌的操作,可以在函数上加上
#pragma inline=forced
来进行强制内嵌。
如果想函数不进行内嵌,则可加上
#pragma optimize=no_inline
来进行强制不内嵌。
以上程序对IAR720H有效。其它版本,需要根据相应的帮助来进行。
版本是IAR720H
使用了下面一断程序
#define YEAR_DAYS 365<br />
#define FOURYEAR_DAYS (YEAR_DAYS * 4 + 1)
猜猜FOURYEAR_DAYS值是多少?
按照Hanny最初的想法,结果应该是365 * 4 + 1 = 1461。
结果实际预处理的结果却是365 * (4 + 1) = 1825。
Hanny怀疑是宏嵌套的问题,于是又实验了
#define FOURYEAR_DAYS (365 * 4 + 1)
结果,还是1825。
看来,IAR的预处理在乘和加的优先级上,优先计算了加!
多加个括号就可以了。要注意啊!
IAR对局部部变量,一般是采取虚拟寄存器的方式来进行访问。如果是外部堆栈的话,有时它会将SPH,SP的值赋至DPTR中,然后使用DPTR来对堆栈进行操作。
然而,除了将SPH和SP的值赋至DPTR外,它还会做一些动作。
ANL A,#0x03 ; Maks out relevant ESP bits.<br />
ORL A,#(HIGH(sfb(EXT_STACK)) & 0xFC)<br />
MOV DPH,A
其实就是会将堆栈的高6BIT地址强制不可改。具体作用暂时不明。
不过,如果有做一些多BIN的工程时,可就要小心了,需要保证堆栈的高6BIT地址不变,否则可能出一些不可预料的错误。