DDR引发的问题(上)

背景

在C6455上有一片外挂DDR2,型号是MICRON的MT47H128M16RT-25EIT:C,容量为256MB,16位数据位宽,设计接口时钟250MHz,接口速率500MHz,地址范围是0xE0000000~0xEFFFFFFF。

问题描述

现在需要将一段初始化的数据定义到DDR中,因此我们将链接文件写成这样:

MEMORY
{
    IRAM (RWX) : org = 0x800000, len = 0x1fbc00
    DDR2 (RWX) : org = 0xe0000000, len = 0x10000000
}
SECTIONS
{
    .slowdata: load > IRAM, run > DDR2
}

在代码中变量定义为

#pragma DATA_SECTION(foo, ".slowdata");
char data[1024*1024] = {
//一些无规律的初值
...
};

链接出错,提示

linker.cmd”, line 148: error #10099-D: program will not fit into available memory. placement with alignment fails for section “.cinit” size 0xfddc3 .

问题分析

既然是链接问题,那么就要分析编译链接的细节。

编译、链接生成的目标文件包含若干个段,其中有些属于未初始化的段,有些为初始化段。未初始化段只保留RAM空间,不占有目标文件空间。初始化段既占用RAM空间也存储在目标文件里。我们关心的初始化全局变量被C/C++编译器生成一个表,存储在.cinit段中。
所有C/C++程序都要与一个bootstrap例程(boot.obj)相链接来执行初始化,该目标文件中定义了_c_int00符号作为整个代码的入口地址。这个目标文件中还包含了用于初始化运行时环境的代码和数据,如设置系统栈、配置寄存器、处理.cinit初始化表、禁止中断,调用_main等。

若链接时设置了运行时初始化,则初始化过程如图所示。加载器先将.cinit段加载到内存中,再在运行时由启动例程拷贝到运行地址。当指定了某些链接选项时,C6000编译器生成的.init段还会以RLE等格式压缩以节省空间,在运行时先解压缩再拷贝。
DDR引发的问题(上)_第1张图片

若链接时设置了加载时初始化,则初始化过程如图所示。加载器不把.cinit段加载到内存中,而是直接解析并拷贝到运行地址。
DDR引发的问题(上)_第2张图片

在我们的工程中,链接选项配置为默认值–rom_model即运行时初始化,从map文件可以看出其中有一个.cinit段,长度近1MB,即需要占用RAM中的1MB空间。我们的RAM总共2MB大小,加上其他的代码和数据,剩余空间明显不足以容纳下这个段。

解决方案

找到了问题原因,就有了解决方法,即把链接选项配置为–ram_model,加载时初始化。这样链接后发现map文件中的.cinit段消失,链接成功。

然后用仿真器加载并运行,结果出现问题——数据并未初始化为指定值。
解决这一问题又要涉及到芯片启动过程,下次再分析。

你可能感兴趣的:(链接)