新ちゃん 发表于 2020-8-18 16:12:16

如何建立自己的RISC-V编译环境--C_Code?

本帖最后由 新ちゃん 于 2020-8-29 14:35 编辑

如何建立自己的RISC-V编译环境–C_Code?
1.RISC-V编译环境框架这是我RISC-V编译环境的架构:buildcasecommontoolchain

一级目录二级目录说明
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.各目录内容介绍
2.1 toolchain:工具链目录我不打算介绍,如果有不明白的,可以看我的这个博客:
                        rocket-chip工具链的编译与使用
2.2 project:这个目录就是放你的项目代码的。每个项目建立一个目录。在这个例子中,我放的是test目录,test的源代码如下(修改于/riscv-tests/benchmarks/vvadd):#define U32 *(volatile unsigned int *)
#define DATA_SIZE 100

int input1_data =
{
   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 =
{
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 + b;
}

//--------------------------------------------------------------------------
// 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个通用寄存器。
lix1, 0
lix2, 0
lix3, 0
lix4, 0
lix5, 0
lix6, 0
lix7, 0
lix8, 0
lix9, 0
lix10,0
lix11,0
lix12,0
lix13,0
lix14,0
lix15,0
lix16,0
lix17,0
lix18,0
lix19,0
lix20,0
lix21,0
lix22,0
lix23,0
lix24,0
lix25,0
lix26,0
lix27,0
lix28,0
lix29,0
lix30,0
lix31,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 ?= -I ../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本篇完,感谢关注:RISC-V单片机中文网
页: [1]
查看完整版本: 如何建立自己的RISC-V编译环境--C_Code?