在使用CW的全芯片仿真的时候,会出现各种内存错误,如:
No memory at [XXXX’L:n]
这是因为仿真时模拟器只会自动分配它认为你使用到了的内存,或说链接器自动分配了的内存,而其他地址则会认为其不存在并受到了保护。如果代码访问了受保护的区域,则会跳出此提示。这其实是一个很好的功能,可以帮助你发现程序的严重错误。
但有的时候我们就是想访问每个地址,而且硬件上实际在这个地址上存在内存。比如上面这个错误是由这一小段代码引发的。
#include <hidef.h> /* common defines and macros */
#include "derivative.h" /* derivative-specific definitions */
#include <string.h>
const char str[] = "This is a string";
char * buf = (char *)0x3000;
void main(void) {
int i;
EnableInterrupts;
strcpy(buf,str);
for(;;) {
++i; // loop forever
}
}
我就是知道0x3000这个地方是RAM,而且我就想把它开始的地方用来存字符串。
但是链接器不知道呀!所以它仍然会把这块区域保护起来。为了达成同样的目的,比较推荐的解决方法如下:
将
char * buf = (char *)0x3000;
这句改为
char buf[N] @0x3000;
这样链接器就知道你要求在0x3000这个地址起分配N个字节,并命名为buf了。
然后这段代码就能成功运行了,并且仿真还能帮你检查字符串没有超出N这个大小。
但是要注意,这样绝对定位的变量,默认是不会帮你初始化为0的。
注意:这里的buf其实只是起到了一个占位符的作用,你想要放什么东西都是可以的,哪怕是复制了段代码都可以。
Protected at [XXXX’L:n]
这是因为你想要写入 链接器认为只读的区域。
我会遇到上述报错是因为我知道C00开始的这个区域是用作EEPROM的,然后就改了下prm文件后就直接把变量分配到了EEPROM区去了。然后就在程序中很放心的读写它。然后就报错了。
其实本质原因是我忘记改这个segment的属性了。写成了
SEGMENTS
...
EEPROM = READ_ONLY DATA_NEAR IBCC_NEAR 0x0C00 TO 0x0FFF;
...
END
所以仿真器把这块内存标记为了只读。
把READ_ONLY改成READ_WRITE或者NO_INIT(对于EEPROM更推荐)后,问题解决。
杀手锏
暂时还没遇到其他非程序写错而导致内存错误的情况。
但是一开始我没有发现可以通过前面正常方法解决问题的时候是通过很简单粗暴地方案解决内存报错的问题的:
直接在调试器中改内存配置!!hhhh。
如图,HiWave的FCS菜单栏->Configure就是配置内存映射的地方。
这是上一章EEPROM访问出错时的配置,可以看到C00到FFF这段地址的类型为ROM,将这两个Segment的类型都改为EEPROM,点Updata,然后OK。然后你就会发现程序能够正常运行了。
对于第一章那种情况则要点Add,然后自己配置好新Segment的类型为RAM,起始地址和终止地址。然后就行了。
但是这样子,第二次打开你会发现还得重新设一次。
目前我的解决方法是这样的,看到上图中的Save键了没有?配置完后点击保存,随便起个名字如a.mem放在跟default.mem同一个目录下也就是工程的根目录下就行。
然后找到工程目录下的cmd文件夹中的XXXXXXXpostload.cmd文件,文本编辑器打开,后面另起一行加一句
loadmem a.mem
然后你再次打开来时就自动加载好你这个内存配置了。
但是这种方法有一个最大的问题就是。要是你改动了程序,比如加了代码,很可能之前这个内存范围就不对了,那么就会在运行正常的代码时报运行错误,于是每次改动代码后都得重新弄个内存配置,比较麻烦。
目前的理解就是这样了,有更好的方法欢迎留言。