riscv gcc中添加自定义的csr支持

2021-08-20 15:14:22 浏览数 (1)

riscv gcc中添加自定义的csr支持

  • 1.概述
  • 2.不改变编译工具链实现CSR添加
  • 3.在编译器中集成CSR名称
  • 4.编译开发riscv gcc相关
  • 5.小结

1.概述

由于RISCV的模块化的指令集的定义,各家都有着自己的实现方式。从当前看来,除了标准的CSR外,很多都实现了自己的CSR指令扩展。如何自定义CSR并且让编译器能够识别,本文将进行一定的分析,同时从riscv gcc开发的角度出发,来分析编译器开发的流程。

2.不改变编译工具链实现CSR添加

如果想读写CSR,可以使用汇编指令进行操作。

代码语言:javascript复制
void test_csr()
{
  int a = 0x00200;
  asm volatile("csrw 0x307,%0"::"r"(a));
}

通过反汇编

代码语言:javascript复制
riscv32-unknown-elf-objdump -D virt_test.elf > 1.txt

得到该函数的汇编代码

由于编号为0x307的CSR没有标准定义,所以会直接会体现在汇编函数中。但是这样并不会影响功能的使用。

对于这些非标准的CSR的读写操作,RISCV GCC并不会根据特定的编码序号生成相应的名称。

比如芯来科技为其eclic定义的一条CSR。

如果用标准的GCC进行编译,那么需要给定CSR地址(0x7ed)。

这样的实现,在写汇编函数的时候,给定CSR的地址即可,不能写名字。比如:

代码语言:javascript复制
csrw 0x7ed,zero

通过上述的方式,可以完成不改变编译器的情况下,实现非标准的CSR的操作。

3.在编译器中集成CSR名称

往往通过汇编去查看时,若没有CSR名称,直接去查看CSR的地址,有时候还需要通过CSR的地址,查阅相关的寄存器手册,才能明白读写哪个寄存器。为了简化这种操作,可以将CSR的名称添加到gcc中。这里借用玄铁C906上的扩展指令进行实验。

如果不想改变gcc,那么实现上直接可以通过内联汇编。

代码语言:javascript复制
void test_csr()
{
  int a = 0x00200;
  asm volatile("csrw 0x7c0,%0"::"r"(a));
}

那么最后反汇编得到结果如下:

这显然还是不够直观。

为了让其更加的直观,可以修改RISCV工具链。

这里使用的是riscv-gnu-toolchain,目前做编译器开发需要对该仓库的使用非常熟悉。

代码语言:javascript复制
https://github.com/riscv/riscv-gnu-toolchain.git

将代码进行clone后,更新子模块。

代码语言:javascript复制
git submodule init
git submodule update

其中需要修改的是riscv-gnu-toolchain/riscv-binutils/include/opcode/riscv-opc.h

同时将MXSTATUS的地址添加进去。

这样就能够,编译工具链,用生成的编译工具链去编译代码,就能够正常的看到反汇编的执行效果了。

这样,无论是传递地址csrw 0x7c0,zero,还是传递名称csrw mxstatus,zero,汇编器都能够正常的输出CSR名称。

通过对编译器的修改,也是非常的简单的实现了这个功能。

4.编译开发riscv gcc相关

如果要研究riscv gcc的开发工作,搭建环境,加快编译效率很关键。由于编译工具链很大,涉及到的模块很多,而且编译的过程很复杂,为了节省编译的时间,可以通过编译选项来进行约束。

通常情况下,编译全功能的gcc,可以采用

代码语言:javascript复制
./configure --prefix=$PREFIX --enable-multilib --with-cmodel=medany

当使能了--enable-multilib,就能够编译很多版本的lib库。

代码语言:javascript复制
./riscv64-unknown-elf-gcc --print-multi-lib
.;
rv32i/ilp32;@march=rv32i@mabi=ilp32
rv32ic/ilp32;@march=rv32ic@mabi=ilp32
rv32im/ilp32;@march=rv32im@mabi=ilp32
rv32imc/ilp32;@march=rv32imc@mabi=ilp32
rv32iac/ilp32;@march=rv32iac@mabi=ilp32
rv32imac/ilp32;@march=rv32imac@mabi=ilp32
rv32imafc/ilp32f;@march=rv32imafc@mabi=ilp32f
rv32imafdc/ilp32d;@march=rv32imafdc@mabi=ilp32d
rv32e/ilp32e;@march=rv32e@mabi=ilp32e
rv32ec/ilp32e;@march=rv32ec@mabi=ilp32e
rv32emc/ilp32e;@march=rv32emc@mabi=ilp32e
rv32ema/ilp32e;@march=rv32ema@mabi=ilp32e
rv32emac/ilp32e;@march=rv32emac@mabi=ilp32e
rv32eac/ilp32e;@march=rv32eac@mabi=ilp32e
rv64i/lp64;@march=rv64i@mabi=lp64
rv64im/lp64;@march=rv64im@mabi=lp64
rv64imc/lp64;@march=rv64imc@mabi=lp64
rv64imac/lp64;@march=rv64imac@mabi=lp64
rv64imafc/lp64f;@march=rv64imafc@mabi=lp64f

这样实际上也是消耗了很多时间,为了解决这个问题,可以指定特定的march和mabi进行编译和测试,待开发完成后,发布时在进行整体编译。这样开发效率会高出很多。

代码语言:javascript复制
make clean
./configure --prefix=$RISCV/0727/rv32 --with-arch=rv32gc  --with-abi=ilp32d --disable-gdb
make -j8

例如上面的命令,只编译march为rv32gc,abi为ilp32d的gcc模型。省略掉很多库的编译,让编译的时间缩短了不少。

5.小结

为自己的处理器添加特定的CSR支持,一种情况下可以使用CSR的地址进行,另外一种就是修改汇编器,前一种方法比较直观,适合使用riscv通用编译器的开发方式进行开发,但是不够直观。后一种则需要修改汇编器,并且需要自己编译工具链,比较复杂,但是使用起来直观,简单。

0 人点赞