这是我RISC-V编译环境的架构:
build case common toolchain
一级目录 | 二级目录 | 说明 |
---|---|---|
build | - | xx.hex、xx.bin、xx.dump & xx.elf生成的目录。 |
- | Makefile | 编译脚本。 |
- | test | 生成文件,根据test.c生成的xx.hex、xx.bin、xx.dump & xx.elf |
project | - | 各个目录的源代码。 |
- | test | 放test项目的全部H文件&C文件。 |
common | - | 各个项目公用的文件。 |
- | encoding.h | /riscv-tests/env目录中的H文件。 |
- | program.ld | 类似/riscv-tests/benchmarks/common/test.ld的文件,用于链接物理地址、汇编和C语言代码。 |
- | program.S | 最底层的汇编。 |
toolchain | - | 工具链。我在/riscv-tools/riscv-gnu-toolchain/的工具链上提取了对我有用的部分。 |
2.1 toolchain:工具链目录我不打算介绍,如果有不明白的,可以看我的这个博客:
rocket-chip工具链的编译与使用(https://blog.csdn.net/a_weiming/article/details/84801051)
2.2 project:这个目录就是放你的项目代码的。每个项目建立一个目录。在这个例子中,我放的是test目录,test的源代码如下(修改于/riscv-tests/benchmarks/vvadd):
#define U32 *(volatile unsigned int *)
#define DATA_SIZE 100
int input1_data[DATA_SIZE] =
{
41, 833, 564, 187, 749, 350, 132, 949, 584, 805, 621, 6, 931, 890, 392, 694, 961, 110, 116, 296,
426, 314, 659, 774, 319, 678, 875, 376, 474, 938, 539, 569, 203, 280, 759, 606, 511, 657, 195, 81,
267, 229, 337, 944, 902, 241, 913, 826, 933, 985, 195, 960, 566, 350, 649, 657, 181, 111, 859, 65,
288, 349, 141, 905, 886, 264, 576, 979, 761, 241, 478, 499, 403, 222, 444, 721, 676, 317, 224, 937,
288, 119, 615, 606, 389, 351, 455, 278, 367, 358, 584, 62, 985, 403, 346, 517, 559, 908, 775, 255
};
int input2_data[DATA_SIZE] =
{
454, 335, 1, 989, 365, 572, 64, 153, 216, 140, 210, 572, 339, 593, 898, 228, 12, 883, 750, 646,
500, 436, 701, 812, 981, 150, 696, 564, 272, 258, 647, 509, 88, 703, 669, 375, 551, 936, 592, 569,
952, 800, 584, 643, 368, 489, 328, 313, 592, 388, 543, 649, 979, 997, 814, 79, 208, 998, 629, 847,
704, 997, 253, 715, 430, 415, 538, 700, 4, 494, 100, 864, 693, 416, 296, 285, 620, 78, 351, 540,
646, 169, 527, 289, 796, 801, 720, 758, 745, 92, 989, 271, 853, 788, 531, 222, 461, 241, 358, 332
};
//--------------------------------------------------------------------------
// handle_trap function
void handle_trap()
{
while(1);
}
//--------------------------------------------------------------------------
// test function
void test( int n, int a[], int b[])
{
int i;
for ( i = 0; i < n; i++ )
U32(0x20800000+4*i) = a[i] + b[i];
}
//--------------------------------------------------------------------------
// Main
void main()
{
test( DATA_SIZE, input1_data, input2_data);
}
2.3 common:这个目录比较重要,而且改动的地方比较多。
2.3.1 encoding.h:这个目录不解释,就是RISC-V各重要CSR寄存器的定义。
2.3.2 program.ld:这个文件是修改于/riscv-tests/benchmarks/common/test.ld。
修改点:
1)修改了代码的启始地址。
/* text: test code section */
. = 0x80000000;
2)去除了这个一大段的空白空间。
/*. = ALIGN(0x1000);*/
2.3.3 program.S:这个文件改动比较大(修改于/riscv-tests/benchmarks/common/crt.S),这个文件改动需要注意以下几点:
1)扩展名必须为大写的S,大写的S可以使gcc自动识别汇编程序中的C预处理命令,像#include、#define、#ifdef、 #endif等,也就是说,使用gcc进行编译,你可以在汇编程序中使用C的预处理命令。
2)因为我生成的rocket-chip是不使用浮点的,不使用虚拟内存,不使用ROCC的,所以很多内容我直接删改了,而且栈和异常入口都是根据我生成的rocket-chip来设定的,大家可以根据自己的情况进行修改。
代码:
#include "encoding.h"
#define LREG lw
#define SREG sw
#define REGBYTES 4
.section ".text.init"
.globl _start
_start:
#####我是注释,下面的操作是清除32个通用寄存器。
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
#####我是注释,下面的操作是配置异常入口,异常入口为trap_entry这个标志。
# initialize trap vector
la t0, trap_entry
csrw mtvec, t0
# initialize global pointer
.option push
.option norelax
la gp, __global_pointer$
.option pop
#####我是注释,下面的操作是配置栈的地址。
li sp, 0x80F00000
#####我是注释,下面的操作跳到我test项目中的main函数中。
j main
#####我是注释,下面的是trap_entry这个函数的内容,申请栈空间,压栈,保存
#####mcasue&mepc,跳到handle_trap函数中(上面的test.c有这个函数),处理完后
#####还原MSTATUS_MPP的模式,出栈,跳出trap_entry函数。
.align 2
trap_entry:
addi sp, sp, -272
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)
csrr a0, mcause
csrr a1, mepc
SREG a1, 32*REGBYTES(sp)
mv a2, sp
jal handle_trap
LREG a1, 32*REGBYTES(sp)
csrw mepc, a1
# Remain in M-mode after eret
li t0, MSTATUS_MPP
csrs mstatus, t0
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:
2.4 bulid:这个目录最主要的是Makefile脚本,用于调用工具链编译project。我只贴部分代码,是生成elf的代码,生成bin、hex和dump的方法大家参考/riscv-tests/benchmarks/Makefile。
部分代码:
#--------------------------------------------------------------------
# author : xhunter
# data : 2019.4.2
# name : project compiler for rocket-chip
#--------------------------------------------------------------------
proj_name ?= test
#--------------------------------------------------------------------
# Build rules
#--------------------------------------------------------------------
RISCV_PREFIX ?= ../toolchain/bin/riscv32-unknown-elf-
RISCV_GCC ?= $(RISCV_PREFIX)gcc
RISCV_GCC_OPTS ?= -DPREALLOCATE=1 -mcmodel=medany -static -std=gnu99 -O2 -ffast-math -fno-common -fno-builtin-printf
RISCV_LINK_OPTS ?= -static -nostdlib -nostartfiles -lm -lgcc -T ../common/program.ld
SOURCE_FILE ?= ../common/*.h ../common/*.S ../project/$(proj_name)/*.c
#--------------------------------------------------------------------
# Object
#--------------------------------------------------------------------
default:
make all
elf:
$(RISCV_GCC) $(RISCV_GCC_OPTS) -o $(proj_name)/$(proj_name).elf $(SOURCE_FILE) $(RISCV_LINK_OPTS)
all: elf