蜂鸟例程的编译与程序的加载
队伍编号:CICC2136
队伍名称:芯如止水
1 例程的编译
1.1 汇编语言程序原理
对于汇编文件(.S),以rv32ui-p-add.S文件为例,编译与执行过程如下:
① 使用命令make dump,make dump命在定义文件夹下的Makefile中,依次执行了clean、elf、dump三个命令。编译过程使用了riscv的toolchain:
② 在vsim文件夹下依次使用命令make clean、make install、make run_test,所有命令都定义在vsim文件夹下的Makefile中:
1.2 高级语言程序
对于C语言文件(.c),以自定义的baremetal/demo_i2c文件夹下的demo_i2c.c文件为例,编译与执行过程如下:
① 使用命令make dasm PROGRAM=demo_i2c,将make dsam命令的定义在hbird_hdk/Build文件夹下的Makefile.rules中,实际上需要依次执行clean、elf、dasm三个命令;而在demo_i2c文件夹下的Makefile,定义了具体路径。编译过程同样使用了riscv的toolchain:
② 在vsim文件夹下依次使用命令make clean、make install、make run_test,所有命令都定义在vsim文件夹下的Makefile中。这一过程与1.1节所述内容一致,只是需要修改TESTCASE为待执行程序对应路径。
2 程序的加载
在仿真的过程中,会首先将前文编译生成的(.verilog)文件通过tb_top.v文件里initial过程块中的readmemh函数读进来,存放在ITCM中:
initial begin
$readmemh({testcase, ".verilog"}, itcm_mem);
for (i=0;i<(`E203_ITCM_RAM_DP);i=i+1) begin
`ITCM.mem_r[i][00+7:00] = itcm_mem[i*8+0];
`ITCM.mem_r[i][08+7:08] = itcm_mem[i*8+1];
`ITCM.mem_r[i][16+7:16] = itcm_mem[i*8+2];
`ITCM.mem_r[i][24+7:24] = itcm_mem[i*8+3];
`ITCM.mem_r[i][32+7:32] = itcm_mem[i*8+4];
`ITCM.mem_r[i][40+7:40] = itcm_mem[i*8+5];
`ITCM.mem_r[i][48+7:48] = itcm_mem[i*8+6];
`ITCM.mem_r[i][56+7:56] = itcm_mem[i*8+7];
end
初始化后,ROM里的上电程序执行完成后会跳转到ITCM的地址(8000_0000),再开始执行ITCM里面的指令,即预先编写的软件代码。在这一过程中,PC值经历了0000_1000到0000_1004到8000_0000的变化过程。
以下是每一步的详细过程:
① PC initial:0000_1000
在e203_cpu_top模块中,定义了PC的初始化信号:
// This signal can be used to indicate the PC value for the core after reset
input [`E203_PC_SIZE-1:0] pc_rtvec,
对信号进行trace-driver,可见在e203_subsys_top即整个系统的互联模块中定义了PC的初始值,也就是ROM的起始地址值:
.pc_rtvec (32'h0000_1000),
② PC:0000_1000 → 0000_1004
在e203_ifu_ifetch模块中进行PC生成,在顺序取指而非流水线冲刷或分支指令的情况下,对32位指令,下一条指令的PC值为当前PC值加4。
③ PC:0000_1004 → 8000_0000
在sirv_mrom模块中,定义了jump_to_ram_gen模块。其含义是PC进入ROM,首先执行auipc t0, 0x7fff指令,该指令将立即数左移12位后,将得到的数字与PC值相加,最后存到t0寄存器中。此时PC=0x0000_1000,与0x7fff_f000相加即得到t0=0x8000_0000。
与此同时,PC自增4,随后在jump_to_ram_gen模块中,第二条指令jr t0被执行,该指令跳转到t0所存地址,即ITCM起始地址0x8000_0000,随后即可按照软件所编写的指令执行。
generate
if(1) begin: jump_to_ram_gen
// Just jump to the ITCM base address
for (i=0;i<1024;i=i+1) begin: rom_gen
if(i==0) begin: rom0_gen
assign mask_rom[i] = 32'h7ffff297; //auipc t0, 0x7ffff
end
else if(i==1) begin: rom1_gen
assign mask_rom[i] = 32'h00028067; //jr t0
end
else begin: rom_non01_gen
assign mask_rom[i] = 32'h00000000;
end
end
end
④ PC:8000_0000 → 8000_0004 → ……
随后可见PC值不断自增。
查看自定义的demo_i2c.c编译得出的(.dump)反汇编文件,可见仿真中初始化后PC的地址变化情况与反汇编程序中PC的变化情况相同,则可说明处理器已经正确地按照预定程序执行:
80000000 <_start>:
80000000: 30047073 csrci mstatus,8
80000004: 10001197 auipc gp,0x10001
80000008: f0418193 addi gp,gp,-252 # 90000f08 <__global_pointer$>
8000000c: 10010117 auipc sp,0x10010
80000010: ff410113 addi sp,sp,-12 # 90010000 <_sp>
80000014: 00000517 auipc a0,0x0
80000018: 08450513 addi a0,a0,132 # 80000098 <_itcm>
......