修改RISCV工具链
第一步是安装RISCV工具链:
$ git clone https://github.com/riscv/riscv-tools.git
$ git submodule update --init --recursive
$ export RISCV=/path/to/install/riscv/toolchain
$ ./build.sh
第二步明确要添加的指令,以mod指令为例:
mod r1, r2, r3
Semantics:
R[r1] = R[r2] % R[r3]
第三步打开 riscv-opcodes/opcodes文件,在这里,将能够看到分配给各种指令的各种操作码和指令位。 为mod指令分配了一条未使用的指令:
sra rd rs1 rs2 31..25=32 14..12=5 6..2=0x0C 1..0=3
or rd rs1 rs2 31..25=0 14..12=6 6..2=0x0C 1..0=3
and rd rs1 rs2 31..25=0 14..12=7 6..2=0x0C 1..0=3
mod rd rs1 rs2 31..25=1 14..12=0 6..2=0x1A 1..0=3
addiw rd rs1 imm12 14..12=0 6..2=0x06 1..0=3
slliw rd rs1 31..25=0 shamtw 14..12=1 6..2=0x06 1..0=3
srliw rd rs1 31..25=0 shamtw 14..12=5 6..2=0x06 1..0=3
sraiw rd rs1 31..25=32 shamtw 14..12=5 6..2=0x06 1..0=3
第四步,运行下面的代码得到MOD的掩码和代码:
cat opcodes-pseudo opcodes opcodes-rvc opcodes-rvc-pseudo opcodes-custom | ./parse-opcodes -c > ~/temp.h
打开 temp.h将看到:
#define MATCH_MOD 0x200006b
#define MASK_MOD 0xfe00707f
第五步,将上面的内容添加到:riscv-gnu-toolchain/riscv-binutils-gdb/include/opcode/riscv-opc.h文件中
第六步,修改riscv-gnu-toolchain/riscv-binutils-gdb/opcodes/riscv-opc.c文件:
const struct riscv_opcode riscv_opcodes[] =
{
/* name, isa, operands, match, mask, match_func, pinfo. */
{"unimp", "C", "", 0, 0xffffU, match_opcode, 0 },
{"unimp", "I", "", MATCH_CSRRW | (CSR_CYCLE << OP_SH_CSR), 0xffffffffU, match_opcode, 0 }, /* csrw cycle, x0 */
{"ebreak", "C", "", MATCH_C_EBREAK, MASK_C_EBREAK, match_opcode, INSN_ALIAS },
{"ebreak", "I", "", MATCH_EBREAK, MASK_EBREAK, match_opcode, 0 },
{"sbreak", "C", "", MATCH_C_EBREAK, MASK_C_EBREAK, match_opcode, INSN_ALIAS },
{"sbreak", "I", "", MATCH_EBREAK, MASK_EBREAK, match_opcode, INSN_ALIAS },
....
....
....
{"mod", "I", "d,s,t", MATCH_MOD, MASK_MOD, match_opcode, 0 }
....
....
第七步,重新编译工具链
第八步,测试,使用下面的代码:
#include <stdio.h>
int main(){
int a,b,c;
a = 5;
b = 2;
asm volatile
(
"mod %[z], %[x], %[y]\n\t"
: [z] "=r" (c)
: [x] "r" (a), [y] "r" (b)
)
if ( c != 1 ){
printf("\n[[FAILED]]\n");
return -1;
}
printf("\n[[PASSED]]\n");
return 0;
}
使用修改过的工具链编译:
$ riscv64-unknown-elf-gcc mod.c -o mod
打开obj dump文件查看指令是否被使用:
$ riscv64-unknown-elf-objdump -dC mod > mod.dump
在gem5中添加指令:
第一步,修改arch/riscv/decoder.isa 文件:0x33是0x10在fun7中预留的指令。
0x33: decode FUNCT3 {
format ROp {
0x0: decode FUNCT7 {
0x0: add({{
Rd = Rs1_sd + Rs2_sd;
}});
0x1: mul({{
Rd = Rs1_sd*Rs2_sd;
}}, IntMultOp);
0x10: mod({{
Rd = Rs1_sd % Rs2_sd;
}});
0x20: sub({{
Rd = Rs1_sd - Rs2_sd;
}});
}
注意汇编器中的指令匹配是这样做的:
请参阅riscv-gnu-toolchain / riscv-binutils -gdb / opcodes / riscv-opc.c中的match_opcode()函数
op-> match和op-> mask是我们定义的MATCH和MASK宏。
((insn ^ op->match) & op->mask) == 0;
这意味着如果你只是在指令中看到MATCH中的1位并翻转它们,然后看到屏蔽位,那么一切都应该是0.MASK告诉哪些位是有意义的,MATCH告诉所需的配置是什么。
在spike ISA simulator中添加指令:
第一步,riscv-isa-sim/riscv/encoding.h中添加:
#define MATCH_MOD 0x200006b
#define MASK_MOD 0xfe00707f
...
DECLARE_INSN(add, MATCH_MOD, MASK_MOD)
第二步,创建如下文件并添加:
riscv-isa-sim/riscv/insns/mod.h
WRITE_RD(sext_xlen(RS1 % RS2));
第三步,在riscv-isa-sim/riscv/riscv.mk.in中添加:
riscv_insn_list = \
...
mod \
...
第四步,riscv-isa-sim/spike_main/disasm.cc中添加:
DEFINE_RTYPE(mod);