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

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

1.RISC-V编译环境框架

这是我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.各目录内容介绍

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

你可能感兴趣的:(RISC-V,&,rocket-chip)