Extender el conjunto de instrucciones (ISA) de RISC-V añadiendo instrucciones personalizadas puede aumentar el rendimiento y optimizar para aplicaciones específicas. Este artículo guía sobre cómo añadir una instrucción «módulo» a la ISA de RISC-V, escribir un programa que utilice esta instrucción, integrarla en el compilador RISC-V y ejecutarla en Gem5 y Spike, un simulador de ISA.
Primero, es necesario instalar riscv-tools:
$ git clone https://github.com/riscv/riscv-tools.git
$ git submodule update --init --recursive
$ export RISCV=/path/to/install/riscv/toolchain
$ ./build.sh
Este comando construirá la cadena de herramientas RISC-V. A continuación, añadiremos la instrucción «módulo» con la siguiente sintaxis y semántica:
mod r1, r2, r3
Semantics: R[r1] = R[r2] % R[r3]
Abra el archivo riscv-opcodes/opcodes
y añada la definición para la instrucción mod
:
sra rd rs1 rs2 31..25=32 14..12=5 6..2=0x0C 1..0=3
...
mod rd rs1 rs2 31..25=1 14..12=0 6..2=0x1A 1..0=3
...
Después, ejecute el siguiente comando para generar el archivo temp.h
:
cat opcodes-pseudo opcodes opcodes-rvc opcodes-rvc-pseudo opcodes-custom | ./parse-opcodes -c > ~/temp.h
En el archivo temp.h
, busque las dos líneas siguientes:
#define MATCH_MOD 0x200006b
#define MASK_MOD 0xfe00707f
Añada estas dos líneas a riscv-gnu-toolchain/riscv-binutils-gdb/include/opcode/riscv-opc.h
. Continúe, modifique el archivo riscv-gnu-toolchain/riscv-binutils-gdb/opcodes/riscv-opc.c
y añada la siguiente línea al array riscv_opcodes[]
:
const struct riscv_opcode riscv_opcodes[] = {
...,
{"mod", "I", "rd,rs1,rs2", MATCH_MOD, MASK_MOD, match_opcode, 0},
...
};
Recompile riscv-gnu-toolchain
. Ahora, escriba un programa en C para probar:
#include <stdio.h>
int main() {
int a, b, c;
a = 5;
b = 2;
asm volatile ("mod %[z], %[x], %[y]nt"
: [z] "=r" (c)
: [x] "r" (a), [y] "r" (b));
if (c != 1) {
printf("n[[FAILED]]n");
return -1;
}
printf("n[[PASSED]]n");
return 0;
}
Compile el programa usando el compilador RISC-V modificado:
$ riscv64-unknown-elf-gcc mod.c -o mod
Use objdump
para inspeccionar la instrucción mod
:
$ riscv64-unknown-elf-objdump -dC mod > mod.dump
Para añadir la instrucción a Gem5, edite arch/riscv/decoder.isa
:
0x33: decode FUNCT3 {
format ROp {
0x0: decode FUNCT7 {
0x0: add({{ Rd = Rs1_sd + Rs2_sd; }});
...
0x10: mod({{ Rd = Rs1_sd % Rs2_sd; }});
...
}
...
}
...
}
La coincidencia de instrucciones en el ensamblador se realiza de la siguiente manera:
((insn ^ op->match) & op->mask) == 0;
Finalmente, para añadir la instrucción al simulador Spike, modifique riscv-isa-sim/riscv/encoding.h
:
#define MATCH_MOD 0x200006b
#define MASK_MOD 0xfe00707f
...
DECLARE_INSN(mod, MATCH_MOD, MASK_MOD)
Cree el archivo riscv-isa-sim/riscv/insns/mod.h
con el siguiente contenido:
WRITE_RD(sext_xlen(RS1 % RS2));
Añada este archivo a riscv-isa-sim/riscv/riscv.mk.in
y añada la línea DEFINE_RTYPE(mod);
a riscv-isa-sim/spike_main/disasm.cc
. Después, recompile riscv-tools
. En este punto, la instrucción «mod» se ha añadido al simulador Spike.