3.4.1 riscv-tests目录的作用。
riscv-tests目录放的是isa、debug、mt和benchmarks的测试文件、底层相关驱动、及其编译的文件,用于测试rocket-chip cpu的性能,可以适当地理解为系统验证,即通过编写C/汇编实现cpu性能的评估。riscv-tests目录的编译依赖于riscv-gnu-toolchain目录,因为C/汇编编译至bin/hex文件都需要用到工具链,同时反汇编的dump文件也需要用到工具链。一般比较常用的是:riscv$(XLEN)-unknown-elf-gcc、riscv$ (XLEN)-unknown-elf-objdump和riscv$ (XLEN)-unknown-elf-objcopy,$ (XLEN)是rocket-chip cpu的处理位数,有32和64两种。
3.4.2 riscv-tests目录的详细说明。
3.4.3 riscv-tests目录使用例子。 (1) 新建C程序目录,在riscv-tests/benchmarks中新建test目录。 - cd benchmarks && mkdir test
复制代码(2) 编写C语言程序,并保存为test.c。
test.c: - #define U32 *(volatile unsigned int *)
- //--------------------------------------------------------------------------
- // Main
- void main()
- {
- int i;
- for ( i = 0; i < 10; i++ )
- U32(0x20400000+4*i) = i;
- }
复制代码(3) 由于我生成的rocket-chip memory_port是从0x2000_0000开始的,所有我需要修改链接文件,告诉gcc工具链,我希望代码从0x2000_0000开始。所以需要修改riscv-tests/benchmarks/common目录下的test.ld。 - /* . = 0x80000000; */
- . = 0x20000000;
- .text.init : { *(.text.init) }
复制代码(4) 再次编译riscv-tests目录,然后在riscv-tests/build/benchmarks目录中能找到编译出来的test.riscv(elf文件) & test.riscv.dump(反汇编文件)。
(5) 最后对riscv-tests/benchmarks/common目录下的crt.S(汇编代码文件)做分析,每个benchmarks目录下的程序都会用到这个文件,#中文的就是注释。 我只对这个文件做初步分析,很多关键字各位可以自行百度或可以关注公众号:硅农亚历山大,阅读其发表的文章《编译过程简介》。 - #关键字段
- .section ".text.init"
- .globl _start
- #最开始的代码,将32个通用寄存器置0。
- _start:
- li x1, 0
- li x2, 0
- li x3, 0
- li x4, 0
- li x5, 0
- li x6, 0
- li x7, 0
- li x8, 0
- li x9, 0
- li x10,0
- li x11,0
- li x12,0
- li x13,0
- li x14,0
- li x15,0
- li x16,0
- li x17,0
- li x18,0
- li x19,0
- li x20,0
- li x21,0
- li x22,0
- li x23,0
- li x24,0
- li x25,0
- li x26,0
- li x27,0
- li x28,0
- li x29,0
- li x30,0
- li x31,0
- #使用浮点或ROCC,必须置位。
- # enable FPU and accelerator if present
- li t0, MSTATUS_FS | MSTATUS_XS
- csrs mstatus, t0
- # make sure XLEN agrees with compilation choice
- li t0, 1
- slli t0, t0, 31
- #if __riscv_xlen == 64
- bgez t0, 1f
- #else
- bltz t0, 1f
- #endif
- 2:
- li a0, 1
- sw a0, tohost, t0
- j 2b
- 1:
- #如果生成的rocket-chip支持浮点操作,则需要将浮点的32个通用寄存器置0。
- #ifdef __riscv_flen
- # initialize FPU if we have one
- la t0, 1f
- csrw mtvec, t0
- fssr x0
- fmv.s.x f0, x0
- fmv.s.x f1, x0
- fmv.s.x f2, x0
- fmv.s.x f3, x0
- fmv.s.x f4, x0
- fmv.s.x f5, x0
- fmv.s.x f6, x0
- fmv.s.x f7, x0
- fmv.s.x f8, x0
- fmv.s.x f9, x0
- fmv.s.x f10,x0
- fmv.s.x f11,x0
- fmv.s.x f12,x0
- fmv.s.x f13,x0
- fmv.s.x f14,x0
- fmv.s.x f15,x0
- fmv.s.x f16,x0
- fmv.s.x f17,x0
- fmv.s.x f18,x0
- fmv.s.x f19,x0
- fmv.s.x f20,x0
- fmv.s.x f21,x0
- fmv.s.x f22,x0
- fmv.s.x f23,x0
- fmv.s.x f24,x0
- fmv.s.x f25,x0
- fmv.s.x f26,x0
- fmv.s.x f27,x0
- fmv.s.x f28,x0
- fmv.s.x f29,x0
- fmv.s.x f30,x0
- fmv.s.x f31,x0
- 1:
- #endif
- #将trap_entry函数的地址付给mtvec CSR寄存器,发生中断或异常时,PC将会跳至mtvec的地址。
- # initialize trap vector
- la t0, trap_entry
- csrw mtvec, t0
- #初始化全局点,设置堆栈的位置
- # initialize global pointer
- .option push
- .option norelax
- la gp, __global_pointer$
- .option pop
- la tp, _end + 63
- and tp, tp, -64
- # get core id
- csrr a0, mhartid
- # for now, assume only 1 core
- li a1, 1
- 1:bgeu a0, a1, 1b
- # give each core 128KB of stack + TLS
- #define STKSHIFT 17
- sll a2, a0, STKSHIFT
- add tp, tp, a2
- add sp, a0, 1
- sll sp, sp, STKSHIFT
- add sp, sp, tp
- #跳至_init的函数中。
- j _init
- #对齐位置,接下来是trap_entry函数的汇编代码。
- .align 2
- trap_entry:
- addi sp, sp, -272
- #异常/中断发生时,保护现场,将32个通用寄存器的值存到某个地方。
- SREG x1, 1*REGBYTES(sp)
- SREG x2, 2*REGBYTES(sp)
- SREG x3, 3*REGBYTES(sp)
- SREG x4, 4*REGBYTES(sp)
- SREG x5, 5*REGBYTES(sp)
- SREG x6, 6*REGBYTES(sp)
- SREG x7, 7*REGBYTES(sp)
- SREG x8, 8*REGBYTES(sp)
- SREG x9, 9*REGBYTES(sp)
- SREG x10, 10*REGBYTES(sp)
- SREG x11, 11*REGBYTES(sp)
- SREG x12, 12*REGBYTES(sp)
- SREG x13, 13*REGBYTES(sp)
- SREG x14, 14*REGBYTES(sp)
- SREG x15, 15*REGBYTES(sp)
- SREG x16, 16*REGBYTES(sp)
- SREG x17, 17*REGBYTES(sp)
- SREG x18, 18*REGBYTES(sp)
- SREG x19, 19*REGBYTES(sp)
- SREG x20, 20*REGBYTES(sp)
- SREG x21, 21*REGBYTES(sp)
- SREG x22, 22*REGBYTES(sp)
- SREG x23, 23*REGBYTES(sp)
- SREG x24, 24*REGBYTES(sp)
- SREG x25, 25*REGBYTES(sp)
- SREG x26, 26*REGBYTES(sp)
- SREG x27, 27*REGBYTES(sp)
- SREG x28, 28*REGBYTES(sp)
- SREG x29, 29*REGBYTES(sp)
- SREG x30, 30*REGBYTES(sp)
- SREG x31, 31*REGBYTES(sp)
- #存好一些特殊的CSR寄存器值,并跳至handle_trap函数中。
- csrr a0, mcause
- csrr a1, mepc
- mv a2, sp
- jal handle_trap
- csrw mepc, a0
- #返回之前的工作模式
- # Remain in M-mode after eret
- li t0, MSTATUS_MPP
- csrs mstatus, t0
- #恢复现场,将之前保存的32个通用寄存器的值返回。
- LREG x1, 1*REGBYTES(sp)
- LREG x2, 2*REGBYTES(sp)
- LREG x3, 3*REGBYTES(sp)
- LREG x4, 4*REGBYTES(sp)
- LREG x5, 5*REGBYTES(sp)
- LREG x6, 6*REGBYTES(sp)
- LREG x7, 7*REGBYTES(sp)
- LREG x8, 8*REGBYTES(sp)
- LREG x9, 9*REGBYTES(sp)
- LREG x10, 10*REGBYTES(sp)
- LREG x11, 11*REGBYTES(sp)
- LREG x12, 12*REGBYTES(sp)
- LREG x13, 13*REGBYTES(sp)
- LREG x14, 14*REGBYTES(sp)
- LREG x15, 15*REGBYTES(sp)
- LREG x16, 16*REGBYTES(sp)
- LREG x17, 17*REGBYTES(sp)
- LREG x18, 18*REGBYTES(sp)
- LREG x19, 19*REGBYTES(sp)
- LREG x20, 20*REGBYTES(sp)
- LREG x21, 21*REGBYTES(sp)
- LREG x22, 22*REGBYTES(sp)
- LREG x23, 23*REGBYTES(sp)
- LREG x24, 24*REGBYTES(sp)
- LREG x25, 25*REGBYTES(sp)
- LREG x26, 26*REGBYTES(sp)
- LREG x27, 27*REGBYTES(sp)
- LREG x28, 28*REGBYTES(sp)
- LREG x29, 29*REGBYTES(sp)
- LREG x30, 30*REGBYTES(sp)
- LREG x31, 31*REGBYTES(sp)
- addi sp, sp, 272
- mret
- .section ".tdata.begin"
- .globl _tdata_begin
- _tdata_begin:
- .section ".tdata.end"
- .globl _tdata_end
- _tdata_end:
- .section ".tbss.end"
- .globl _tbss_end
- _tbss_end:
- .section ".tohost","aw",@progbits
- .align 6
- .globl tohost
- tohost: .dword 0
- .align 6
- .globl fromhost
- fromhost: .dword 0
复制代码
---------------------
作者:a_weiming
来源:CSDN
|