如何在玄铁gcc工具链中添加自定义指令
需要用到的工具
- 玄铁gcc工具链源码
- riscv-opcodes工具
获取玄铁工具链源码
因为需要魔改编译器,所以不能用他提供的预编译版本:
git clone .git
将文件夹下的.gitmodules
中的内容换成以下镜像站:
[submodule "riscv-binutils"]path = riscv-binutilsurl = .git
[submodule "riscv-gcc"]path = riscv-gccurl = ../gcc.git
[submodule "riscv-glibc"]path = riscv-glibcurl = .git
[submodule "riscv-dejagnu"]path = riscv-dejagnuurl = .gitbranch = riscv-dejagnu-1.6
[submodule "riscv-newlib"]path = riscv-newliburl = .git
[submodule "riscv-gdb"]path = riscv-gdburl = .git
[submodule "qemu"]path = qemuurl = .git
然后初始化项目仓库(根据网速大概10min?):
git submodule update --init
使用riscv-opcodes工具创建自定义指令
获取工具:
git clone git@github:riscv/riscv-opcodes.git
cd riscv-opcodes
code rv_test
根据模版,编辑rv_test内容如下:
cube rd rs1 rs2 31..25=0x0c 14..12=0x6 6..2=0x1e 1..0=3
随后make
一下就可以得到encoding.out.h
文件,可以找一下刚刚加的指令相关的关键字:
//可以找到两行define
#define MATCH_CUBE 0x1800607b
#define MASK_CUBE 0xfe00707f//以及一个宏
DECLARE_INSN(cube, MATCH_CUBE, MASK_CUBE)
接下来,要利用gcc工具链的binutils
工具把我们的自定义指令正式加入到gcc工具链中,打开riscv-binutils/include/opcode/riscv-opc.h
,加入上面的几行代码。其中,DECLARE_INSN
宏要加在#ifdef DECLARE_INSN
和#endif
中间。
另外,我们还要在riscv-binutils/opcodes/riscv-opc.c
文件中,加入我们自定义指令的机器码格式。
可以看到这里有一个结构体常量数组定义了所有opcodes:
const struct riscv_opcode riscv_opcodes[] =
{
/* name, xlen, isa, operands, match, mask, match_func, pinfo. */
我们仿照其它I-Type的指令格式编写我们的指令的该结构体下的定义:
{"cube", 0, INSN_CLASS_I, "d,s,t", MATCH_CUBE, MASK_CUBE, match_opcode, 0 },
参考如下:
{"hinval.gvma", 0, INSN_CLASS_SVINVAL, "s,t", MATCH_HINVAL_GVMA, MASK_HINVAL_GVMA, match_opcode, 0 },{"cube", 0, INSN_CLASS_I, "d,s,t", MATCH_CUBE, MASK_CUBE, match_opcode, 0 },
/* Terminate the list. */
{0, 0, INSN_CLASS_NONE, 0, 0, 0, 0, 0}
};
其中INSN_CLASS_I
代表指令为基础整数指令集(也有其他扩展指令集:A(原子指令集)、M(乘法指令集)、C(压缩指令集)、F(单精度浮点)等,如下图),MATCH_CUBE
和MASK_CUBE
来自刚刚riscv-opcodes工具生成的宏定义,match_opcode
表示指令通过opcode
匹配(即32位指令的低7位)。
到此,一条自定义指令便在gcc工具链中添加成功了,另外,我们也可以在刚才的两个文件中看到平头哥自定义指令集的相关内容,接下来,我们还需要重新编译一下工具链:
#--prefix就是安装目录自己定好即可,待会还要用到
./configure --prefix=/home/qw/xuantie-test-gcc
#-j几根据自己电脑来,我大概花了一个小时才编译完
make -j8
在C910项目中实验自己定义的指令
在smart_run/setup/example_setup.csh
中设置刚刚gcc工具链的安装位置:
setenv TOOL_EXTENSION /自己的/安装/路径/bin
然后,在smart_run/tests/cases/hello_world/hello_world.c
这个测试中,添加以下内容,cube即我们刚刚添加的自定义指令:
asm volatile("lable_test: \n""cube a0,a1,zero\n");
然后编译hello_world测试用例:
make buildcase CASE=hello_world
然后,打开smart_run/work/hello_world.obj
这个反汇编文件,就能看到我们添加的label以及指令了:
0000000000000708 <lable_test>:708: 1805e57b cube x10,x11,x0
当然,因为还没有在硬件上提供这条指令的相关支持,目前我们还没发真正的在C910上运行这条指令(还要魔改C910源码,悲)。
参考
cyy大佬文章
b乎上的文章
如何在玄铁gcc工具链中添加自定义指令
需要用到的工具
- 玄铁gcc工具链源码
- riscv-opcodes工具
获取玄铁工具链源码
因为需要魔改编译器,所以不能用他提供的预编译版本:
git clone .git
将文件夹下的.gitmodules
中的内容换成以下镜像站:
[submodule "riscv-binutils"]path = riscv-binutilsurl = .git
[submodule "riscv-gcc"]path = riscv-gccurl = ../gcc.git
[submodule "riscv-glibc"]path = riscv-glibcurl = .git
[submodule "riscv-dejagnu"]path = riscv-dejagnuurl = .gitbranch = riscv-dejagnu-1.6
[submodule "riscv-newlib"]path = riscv-newliburl = .git
[submodule "riscv-gdb"]path = riscv-gdburl = .git
[submodule "qemu"]path = qemuurl = .git
然后初始化项目仓库(根据网速大概10min?):
git submodule update --init
使用riscv-opcodes工具创建自定义指令
获取工具:
git clone git@github:riscv/riscv-opcodes.git
cd riscv-opcodes
code rv_test
根据模版,编辑rv_test内容如下:
cube rd rs1 rs2 31..25=0x0c 14..12=0x6 6..2=0x1e 1..0=3
随后make
一下就可以得到encoding.out.h
文件,可以找一下刚刚加的指令相关的关键字:
//可以找到两行define
#define MATCH_CUBE 0x1800607b
#define MASK_CUBE 0xfe00707f//以及一个宏
DECLARE_INSN(cube, MATCH_CUBE, MASK_CUBE)
接下来,要利用gcc工具链的binutils
工具把我们的自定义指令正式加入到gcc工具链中,打开riscv-binutils/include/opcode/riscv-opc.h
,加入上面的几行代码。其中,DECLARE_INSN
宏要加在#ifdef DECLARE_INSN
和#endif
中间。
另外,我们还要在riscv-binutils/opcodes/riscv-opc.c
文件中,加入我们自定义指令的机器码格式。
可以看到这里有一个结构体常量数组定义了所有opcodes:
const struct riscv_opcode riscv_opcodes[] =
{
/* name, xlen, isa, operands, match, mask, match_func, pinfo. */
我们仿照其它I-Type的指令格式编写我们的指令的该结构体下的定义:
{"cube", 0, INSN_CLASS_I, "d,s,t", MATCH_CUBE, MASK_CUBE, match_opcode, 0 },
参考如下:
{"hinval.gvma", 0, INSN_CLASS_SVINVAL, "s,t", MATCH_HINVAL_GVMA, MASK_HINVAL_GVMA, match_opcode, 0 },{"cube", 0, INSN_CLASS_I, "d,s,t", MATCH_CUBE, MASK_CUBE, match_opcode, 0 },
/* Terminate the list. */
{0, 0, INSN_CLASS_NONE, 0, 0, 0, 0, 0}
};
其中INSN_CLASS_I
代表指令为基础整数指令集(也有其他扩展指令集:A(原子指令集)、M(乘法指令集)、C(压缩指令集)、F(单精度浮点)等,如下图),MATCH_CUBE
和MASK_CUBE
来自刚刚riscv-opcodes工具生成的宏定义,match_opcode
表示指令通过opcode
匹配(即32位指令的低7位)。
到此,一条自定义指令便在gcc工具链中添加成功了,另外,我们也可以在刚才的两个文件中看到平头哥自定义指令集的相关内容,接下来,我们还需要重新编译一下工具链:
#--prefix就是安装目录自己定好即可,待会还要用到
./configure --prefix=/home/qw/xuantie-test-gcc
#-j几根据自己电脑来,我大概花了一个小时才编译完
make -j8
在C910项目中实验自己定义的指令
在smart_run/setup/example_setup.csh
中设置刚刚gcc工具链的安装位置:
setenv TOOL_EXTENSION /自己的/安装/路径/bin
然后,在smart_run/tests/cases/hello_world/hello_world.c
这个测试中,添加以下内容,cube即我们刚刚添加的自定义指令:
asm volatile("lable_test: \n""cube a0,a1,zero\n");
然后编译hello_world测试用例:
make buildcase CASE=hello_world
然后,打开smart_run/work/hello_world.obj
这个反汇编文件,就能看到我们添加的label以及指令了:
0000000000000708 <lable_test>:708: 1805e57b cube x10,x11,x0
当然,因为还没有在硬件上提供这条指令的相关支持,目前我们还没发真正的在C910上运行这条指令(还要魔改C910源码,悲)。
参考
cyy大佬文章
b乎上的文章
发布评论