(原创)构建基于aemb的sopc系统(四)--修改setup文件
现在从读xilinx.ld,crt0.s,crtinit.s开始,构建自己的的setup文件,并实现仿真。
Rom.dump文件真实个非常有用的文件,iprinkf的函数具体怎样调用到outbyte函数的就可以从这个文件中追踪到。
现在可以把crt0.s和rom.dump文件结合着阅读。
_start跳转到_start1
_start1
la r13, r0, _SDA_BASE_ /* Set the Small Data Anchors and the stack pointer */
la r2, r0, _SDA2_BASE_
la r1, r0, _stack-16 /* 16 bytes (4 words are needed by crtinit for args and link reg */
brlid r15, _crtinit /* Initialize BSS and run program */
nop
brlid r15, exit /* Call exit with the return value of main */
addik r5, r3, 0
/* Control does not reach here */
la的命令在《mb_ref_guide》中没有找到,在rom.dump反汇编文件中可以看到
00000050 <_start1>:
50: b0000000 imm 0
54: 31a093a8 addik r13, r0, -27736 // 93a8 <_SDA_BASE_>
58: b0000000 imm 0
5c: 30408e70 addik r2, r0, -29072 // 8e70 <_SDA2_BASE_>
60: b0000000 imm 0
64: 3020d408 addik r1, r0, -11256
68: b9f400e4 brlid r15, 228 // 14c <_crtinit>
6c: 80000000 or r0, r0, r0
70: b9f42818 brlid r15, 10264 // 2888 <exit>
74: 30a30000 addik r5, r3, 0
La对应的指令时addik。在《mb_ref_guide》中可以查到
addik rD, rA, IMM ;Add Immediate and Keep Carry
是个不改变进位标志位的加立即数的指令。R0的作用如下:
Bits | Name | Description | Reset Value | |
0:31 | R0 | R0 is defined to always have the value of zero. Anything written to R0 is discarded. | 0x00000000 |
R0的值始终为零。这条指令的作用就是把_SDA_BASE_的值赋给R13。R13是做什么用的,参见表Register usage conventions。R13用于指定.sdata段,类似的R2指定.sdata2段,R1指定堆栈指针,堆栈中的16个字节用于存储crtinit的参数。
发现了一个还没有解决的问题,就是怎样设置standard output。就是怎样按自己的设置生成C库。在EDK中有一个libgen工具,可以结合mss文件设置。在Nios2中也可以在IDE中设置,但若果用GUN的工具链该怎样操作呢?
brlid r15, _crtinit /* Initialize BSS and run program */
brlid跳转到相对地址_crtinit执行crtinit中的初始化程序。R15就是程序计数器。
当从 _crtinit返回时,就调用了exit
00002888 <exit>:
2888: 3021ffe0 addik r1, r1, -32
288c: 10c00000 addk r6, r0, r0
2890: fa61001c swi r19, r1, 28
2894: f9e10000 swi r15, r1, 0
2898: b9f426d8 brlid r15, 9944 // 4f70 <__call_exitprocs>
289c: 12650000 addk r19, r5, r0
28a0: b0000000 imm 0
28a4: e8a08acc lwi r5, r0, -30004 // 8acc <_global_impure_ptr>
28a8: e8650028 lwi r3, r5, 40
28ac: bc03000c beqi r3, 12 // 28b8
28b0: 99fc1800 brald r15, r3
28b4: 80000000 or r0, r0, r0
28b8: b9f4d7c0 brlid r15, -10304 // 78 <_exit>
28bc: 10b30000 addk r5, r19, r0
exit做了一些收尾的工作就跳到了_exit,一个无限循环
/* _exit Our simple _exit */
.globl _exit
.align 2
.ent _exit
_exit:
bri 0
.end _exit
阅读一下crtinit.s文件
主要做的工作:.sbss段和.bss段清零,调用_program_init程序,调用语言初始化函数__init,调用main函数,调用语言清理函数__finit,调用_program_clean程序,返回crt。
下面按《Embedded System Tools Reference Guide》--GNU Compiler Tools一章中所讲的“Modifying Startup Files”“Compiler Libraries”所讲。
用用户编写的setup文件的方法来编译程序。本文中只是了解这个流程,仍采用link scripts,crtn.s,crtinit.s文件。
在aemb/trunk/sw目录下新建一个custom_crt目录,把EDK软件中的crt0.s,crtinit.s拷贝到这个目录下,把链接脚本文件xilinx.ld文件拷贝到aemb/trunk/sw目录下。然后修改gccrom脚本文件。
修改之后只需在sw文件目录下运行
$ ./gccrom
即可,显示结果与未改之前相同
xgcc=0
dump=0
copy=0
srec=0
sha1=1811964ac2872266f5eda1289c314b8c
主要修改的选项:
CXXFLAGS变量
把”-O0”改成”-Os”,主程序在编译时需设定大于等于-O1的优化选项
添加”-nostartfiles”选项,不适用默认的setup file。
LNKFLAGS变量
添加”-T xilinux.ld”,指定自己修改的脚本文件
添加了INPUT变量,输入的源码文件,在这里,把C run time的文件也当做源码文件输入了。本应该先编译crt文件,再用”-B directory”想指定C run time库的搜索路径的。
修改了crtinit.s中的文件,把
brlid r15, __init /* Invoke language initialization functions */
nop
和
brlid r15, __fini /* Invoke language cleanup functions */
nop
注释掉。可以避免引用重构和结构操作时所产生的额外的代码,减小了代码尺寸。
与采用默认的setup文件相比,减少了1076字节
再进行一下仿真
# AEMB2 32-bit Microprocessor Core Tests
#
# 1. Integer Arithmetic
#
# -PASS-
#
# 2. Integer Factorisation
#
# -PASS-
#
# 3. Floating Point Arithmetic
#
# -PASS-
#
# 4. Memory Allocation
#
# -PASS-
#
# 5. Hardware Interrupts
#
# -PASS-
#
# 6. Accellerator Link
#
# -PASS-
#
# 7. Hardware Exceptions
#
# -PASS-
#
#
# *** EXIT 0018d2d8 ***
# ** Note: $finish : ./verilog/edk63.v(212)
# Time: 1626840 ps Iteration: 0 Instance: /edk63
可以看一下,仿真结果与之前的仿真是相同的。
其实,本次编译与上次编译几乎所有的代码都是一样的,所不一样的是,本次编译过程,是按自行编写C run time文件及link script的步骤操作的,它可以使我们认识带newlib C库时系统的启动过程和自定制地控制代码的编译过程。
以后会继续学习一下Newlib C库。
接下来,开始构建aemb的sopc软硬件系统并作系统仿真。