ARM_Cortex-M0 DesignStart系列--3rtl仿真过程的详细分析
- 概述
书接上文《ARM_Cortex-M0 DesignStart系列—2基于xrun的rtl仿真》,本文依然以hello这个test为例,来说明整个rtl仿真的详细过程。通过对整个仿真过程的分析,有助于我们对SoC level仿真的理解以及对整个项目的理解。
让我们沿着,仿真的逻辑顺序以及数据流的方向出发。第一站当然是总的makefile脚本入口处。别忘了我们上文中使用的脚本路径以及脚本命令:
..cortexm0_designstart/systems/cortex_m0_mcu/rtl_sim/makefile
make compile_xm
make sim_xm_indago TESTNAME=hello TOOL_CHAIN=gcc - 仿真主目录下makefile分析(compile+testcode)
编译所有rtl文件

- case中的makefile分析(生成hello.hex)
主要是利用arm自带的c语言编译器(arm-none-eabi-gcc),将hello.c编译成hello.hex文件。目的是,在仿真开始通过initail语句初始化在ROM中,供rtl仿真使用。

将上图中line158的all_gcc展开如下:

3.1 如何查看编译选项的帮助信息

3.2 arm-none-eabi-gcc选项分析
首先是arm-none-elabi-gcc名字的介绍
GNU for ARM编译器的命名规则
arch [-vendor] [-os] [-(gnu)eabi] [-gcc]

编译的时候有两种文件,一种是汇编启动文件,一种是c源文件。首先需要说明一些编译任何一个文件都需要带上的参数:


关于优化等级的选择:
a). gcc中指定优化级别的参数有:-O0、-O1、-O2、-O3、-Og、-Os、-Ofast。
b). 在编译时,如果没有指定上面的任何优化参数,则默认为 -O0,即没有优化。
c). 参数 -O1、-O2、-O3 中,随着数字变大,代码的优化程度也越高,不过这在某种意义上来说,也是以牺牲程序的可调试性为代价的。
d). 参数-Og是在-O1的基础上,去掉了那些影响调试的优化,所以如果最终是为了调试程序,可以使用这个参数。不过光有这个参数也是不行的,这个参数只是告诉编译器,编译后的代码不要影响调试,但调试信息的生成还是靠 -g 参数的。
e). 参数 -Os 是在-O2的基础上,去掉了那些会导致最终可执行程序增大的优化,如果想要更小的可执行程序,可选择这个参数。
f). 参数 -Ofast 是在 -O3 的基础上,添加了一些非常规优化,这些优化是通过打破一些国际标准(比如一些数学函数的实现标准)来实现的,所以一般不推荐使用该参数。
g). 如果想知道上面的优化参数具体做了哪些优化,可以使用 arm-none-eabi-gcc -Q --help=optimizers 命令来查询。
3.3 启动文件编译:
启动文件一般是由汇编写成,汇编文件的格式有.S和.s之分:
.S:表明文件中含有预处理指令(比如#define),需要先进行处理,如果使用的是.S文件,那么需要带上-x assembler-with-cpp参数。
.s:表明文件不需要处理,可以直接编译。本例子是startup_CMSDK_CM0.s;
3.4 链接
链接重要的部分有两点:链接文件和传递给链接器的参数。原理是链接器根据链接文件xx.ld 对hello.o这个文件开始链接,生成包含了调试信息的elf文件。
本例中并没有调用arm-none-eabi-ld这个链接器,所有的都放在编译里面进行了。arm-none-eabi-ld为链接器,即最后链接所有.o文件生成可执行文件elf的工具。一般我们不使用 arm-none-eabi-ld 的指令调用它,而是通过使用arm-none-eabi-gcc 来调用,因为前者对c/cpp文件混合型生成的.o文件们的支持性不好,所以官方的说明书中也推荐使用arm-none-eabi-gcc 指令来代替arm-none-eabi-ld,如下:
arm-none-eabi-gcc -o hello hello.o
3.5 生成bin文件和hex文件
arm-none-eabi-objdump是反汇编指令,参数-S表明尽可能的把本来的代码和反汇编出来的代码一同出现出来,-S参数需求结合arm-linux-gcc编译参数-g,反汇编时一起输出本来的代码。
利用arm-none-eabi-objcopy工具可以将elf文件转化为适合于mcu的bin文件和hex文件,其中参数-O(大写o)用于指定输出文件的格式(默认是bin格式) - 仿真主目录下makefile分析(bootrom)
如下图所示,首先会调用bootloader目录下的make all_gcc,然后把生成的bootloader.hex拷贝到主仿真目录rtl_sim下。

- bootloader目录下makefile分析(bootrom)
如下图所示,由于我们是rtl仿真并没有用到bootloader。所以这一部分不做太多展开。后续FPGA上板调试的时候会用到。

将上面的all_gcc展开后,如下图所示。参考3.的分析,这里就不赘述了。

- 仿真rtl
参考下图中仿真主目录rtl_sim下的makefile,对rtl进行仿真。至此,好像rtl仿真流程上基本结束了。但是这个case(hello)的数据是怎么传入仿真环境的?

- case(hello)的数据是怎么传入仿真的
step1: 如下图所示,在主makefile中调用case hello的makefile,从而产生hello.hex,然后将生成的hello.hex拷贝到主仿真目录,并重新命名为image.hex。

step2: 如下图所示,在文件cmskd_ahb_mcu.v中将image.hex传给了文件cmsdk_ahb_rom.v的filename了。

step3: 如下图所示,在文件cmsdk_ahb_rom.v中,又将image.hex通过filename的形式传给cmsdk_ahb_ram_beh.v了。

step4: 如下图所示,在文件cmsdk_ahb_ram_beh.v中,通过$readmemh这个系统函数,将image.hex以filename的形式传给ram_data这个二维数组了。

step5: 如下图所示,在文件cmsdk_ahb_ram_beh.v中,仿真开始后, ram_data这个二维数组中的数据(image.hex中的内容),被依次放入rdata_out0/1/2/3了。

step6: 如下图所示,在文件cmsdk_ahb_ram_beh.v中,rdata_out0/1/2/3中的数据又被ahb总线读走了。

step7: 如下图所示,HRDATA在文件cmsdk_ahb_ram_beh.v中,rdata_out0/1/2/3中的数据又被ahb总线读走了。

step8, 经过进一步trace,不出所料,通过ahb总线进入cpu core了。

至此,好像rtl仿真流程上基本结束了。但是,其实还有很多工作没做,比如整个mcu(SoC)的架构以及细节都值得研究,比如很多具体case的含义还没有展开,比如FPGA上板调试还没做,比如在目前这颗小的SoC上还可以挂其他外设,比如在它的大哥Cortex-M3上还有更多好玩的,可玩的实在是太多,太多了……
浙公网安备 33010602011771号