DSP

DSP芯片CMD文件中各段的实验验证(上)

2019-07-13 10:37发布

上篇文章详细讲解了DSP中的CMD文件,请看:http://blog.csdn.net/qq_29545231/article/details/78175977《超详细的CMD文件讲解(DSP28035)》 。文中介绍了DSP中内存分配MEMORY以及内存存储段SECTIONS各自的功能和作用。
这节通过实验来论证上节中原理的正确性。主要是验证SECTIONS中各个段的存储及使用情况。
为了方便对照,首先把CMD文件贴出来,如下:
MEMORY { PAGE 0: /* Program Memory */ RAML0 : origin = 0x008000, length = 0x000800 /* L0 */ RAML1 : origin = 0x008800, length = 0x000400 /* L1 */ OTP : origin = 0x3D7800, length = 0x000400 /* OTP */ FLASHH : origin = 0x3E8000, length = 0x002000 /* FLASH */ FLASHG : origin = 0x3EA000, length = 0x002000 /* FLASH */ FLASHF : origin = 0x3EC000, length = 0x002000 /* FLASH */ FLASHE : origin = 0x3EE000, length = 0x002000 /* FLASH */ FLASHD : origin = 0x3F0000, length = 0x002000 /* FLASH */ FLASHC : origin = 0x3F2000, length = 0x002000 /* FLASH */ FLASHA : origin = 0x3F6000, length = 0x001F80 /* FLASH */ CSM_RSVD : origin = 0x3F7F80, length = 0x000076 /* Part of FLASHA.*/ BEGIN : origin = 0x3F7FF6, length = 0x000002 /* Part of FLASHA.*/ CSM_PWL_P0 : origin = 0x3F7FF8, length = 0x000008 /* Part of FLASHA.*/ IQTABLES : origin = 0x3FE000, length = 0x000B50 /* IQ Math Tables in Boot ROM */ IQTABLES2 : origin = 0x3FEB50, length = 0x00008C /* IQ Math Tables in Boot ROM */ IQTABLES3 : origin = 0x3FEBDC, length = 0x0000AA /* IQ Math Tables in Boot ROM */ ROM : origin = 0x3FF27C, length = 0x000D44 /* Boot ROM */ RESET : origin = 0x3FFFC0, length = 0x000002 /* part of boot ROM */ VECTORS : origin = 0x3FFFC2, length = 0x00003E /* part of boot ROM */ PAGE 1 : /* Data Memory */ BOOT_RSVD : origin = 0x000000, length = 0x000050 /* Part of M0, */ RAMM0 : origin = 0x000050, length = 0x0003B0 /* M0 */ RAMM1 : origin = 0x000400, length = 0x000400 /* M1 */ RAML2 : origin = 0x008C00, length = 0x000400 /* L2 */ RAML3 : origin = 0x009000, length = 0x001000 /* L3 */ FLASHB : origin = 0x3F4000, length = 0x002000 /* on-chip FLASH */ } SECTIONS { .cinit : > FLASHA PAGE = 0 .pinit : > FLASHA, PAGE = 0 .text : > FLASHA PAGE = 0 codestart : > BEGIN PAGE = 0 ramfuncs : LOAD = FLASHD, RUN = RAML0, LOAD_START(_RamfuncsLoadStart), LOAD_END(_RamfuncsLoadEnd), RUN_START(_RamfuncsRunStart), PAGE = 0 csmpasswds : > CSM_PWL_P0 PAGE = 0 csm_rsvd : > CSM_RSVD PAGE = 0 /* Allocate uninitalized data sections: */ .stack : > RAMM0 PAGE = 1 .ebss : > RAML2 PAGE = 1 .esysmem : > RAML2 PAGE = 1 /* Initalized sections go in Flash */ .econst : > FLASHA PAGE = 0 .switch : > FLASHA PAGE = 0 /* Allocate IQ math areas: */ IQmath : > FLASHA PAGE = 0 IQmathTables : > IQTABLES, PAGE = 0, TYPE = NOLOAD .reset : > RESET, PAGE = 0, TYPE = DSECT vectors : > VECTORS PAGE = 0, TYPE = DSECT } 1、先看.cinit、.bss和.ebss这三个段。.cinit是已初始化段,.bss和.ebss是未初始化段。
三个段存储内容如下:
.cinit 显式初始化的全局变量和静态变量表 代码
.bss 全局和静态变量 不超过64K长度
.ebss 长调用(far)的全局或静态变量 数据中的任何地方
.cinit: 全局变量和静态变量的C初始化记录,包含未用const声明的外部(extern)或静态(static)数据表。
.bss: 为全局变量和局部变量保留的空间,在程序上电时.cinit空间中的数据复制出来并存储在.bss空间中。
.ebss:为使用大寄存器模式时的全局变量和静态变量预留的空间,在程序上电时,cinit空间中的数据复制出来并存储在.ebss中,与.ebss不同的是.bss分配范围被限制在低64K 16位数据区,而.ebss的分配范围是4M 22位数据区
因为.bss和.ebss基本上是一样的,所以这里只验证.cinit和.ebss。
实验开始:
在main程序中定义未初始化的变量:全局变量global、全局静态变量g_static、局部静态变量local_static。
定义初始化的变量:全局变量g_init、全局静态变量g_static_init、局部静态变量local_static_init。
并把它们相应的存储位置标注在代码后面。

这里写图片描述
编译后,查看map文件,如下(注:为了方便分析,下面的map文件是经过裁剪的,后面的map都是一样。):
这里写图片描述
分析:
可以看到初始化全局变量g_init和未初始化全局变量global都在.ebss段中,地址是8c03和8c05。但是没有看到static变量。
在.cinit段中有存储0c个长度的变量,.ebss中有06个长度的变量,更奇怪的是下面的initialized data中显示是12,uninitialized data显示是6?这是为什么?
现在一个一个解答,从上面程序可以看到我们一共定义了6个变量,在前面已经说了.cinit是存放已初始化的变量的段,.ebss是存放未初始化变量的段,且程序上电后会自动把.cinit上的变量复制并存储到.ebss中。就是说.ebss应该有6个变量才对,所以上面的.ebss显示06,uninitialized data显示是6就很好理解了。
那.cinit段中有存储0c个长度的变量以及initialized data中显示是12怎么理解?
看看手册资料,如下:

这里写图片描述
原来.cinit段变量存储的情况是(3+n)word,即一个变量存储在.cinit中最少占用4个word。
程序中我们一共定义了3个已初始化的变量,也就是3*4 = 12,即0c。所以上面的疑问也得到解答了。
就是说.cinit中存放了3个变量,就是我们定义的那3个已初始化变量。
还有一个问题,如何查看static变量呢?在map文件中无法显示static变量,我们转到程序仿真上查看变量的地址。如下图
可以看到程序所定义的static变量都存放在0x00008c00开始的地址上,而这个地址就是.ebss的起始地址。
这里写图片描述
现在我们来验证外部(extern)变量或外部静态(static)变量是不是也是存放在.cinit段中的。
在main程序中,访问3个extern变量。如下:
这里写图片描述
新建test.c文件并定义一个初始化全局变量extern_g、一个初始化静态全局变量extern_static_g,
一个子函数void test(void),函数内定义一个初始化局部静态变量extern_func_v。
这里写图片描述
编译程序时出错,如下。说main文件中有2个变量extern_func_v,extern_static_g未定义。
这里写图片描述
把main文件的第8行和第9行代码注消。重新编译程序。编译通过了。
细心的人可能注意到了,刚才在main程序中对test.c中的3个变量进行访问,其中报错的是两个static变量,而变量extern_g却没报错,能够通过编译。
这说明了:被static修饰的变量,只限于当前文件或函数访问,外部文件或外部函数是不能够访问的。
现在,来看一下map文件。参考上面的分析,从红 {MOD}框出的部分可以得出结论。
这里写图片描述
接下来仿真调试程序,单步运行程序,结果如下,extern_g的值被修改为10了。说明在main文件中是可以访问test.c文件的全局变量extern_g的。
同时也看到了两个static变量的地址都是在08c00上的。
这里写图片描述
结论:
.cinit存放的是已经初始化的全局变量和已经初始化的static变量(变量表)。程序上电后会复制并存储到.ebss或.bss中。(相当于下图的.data)
.ebss或.bss存放的是未初始化的全局变量和static变量(变量表)。(相当于下图的.bss)
程序、变量的一般存储方式图:
这里写图片描述
2、验证.text段存储的是可执行代码和常数
在main文件上调用了两个函数,如下:
这里写图片描述
编译后查看map文件,可以看到main函数和test函数都是存放在.text段上的。
这里写图片描述
3、验证.stack段
我们都知道局部变量都是放在栈上的。所以在main文件的test函数内定义一个局部变量。并观察变量的存储位置。如下图:
这里写图片描述
因为.stack上的变量在map文件是无法体现的,需要运行程序后变量才会存在。
编译并运行程序后,如下图,可以看到i变量是存放在0x00000057的地址上的。而从上面的CMD文件可以看到
RAMM0 : origin = 0x000050, length = 0x0003B0
.stack : > RAMM0 PAGE = 1
也就是说i变量是存放在.stack段上的。
这里写图片描述