Adding Custom Instructions to RISC-V GCC Toolchain

First, clone these repos:

git clone git@github.com:riscv-collab/riscv-gnu-toolchain.git
cd ./riscv-gnu-toolchain/
git submodule update --init --recursive
git clone git@github.com:riscv/riscv-opcodes.git

First, we are going to use riscv-opcodes to generate the encoding of our custom instruction.

Under extensions/unratified/, create a new file for the new instruction. We will use rv_testinst as an example

Inside the file, we have our custom instruction:

testinst    rd rs1 rs2 31..25=1  14..12=0 6..2=0x1A 1..0=3

Then, run the following command to generate C header for this instriction:

uv run riscv_opcodes -c "unratified/rv_testinst"

In the resulting encoding.out.h file, we can see the custom instruction:

encoding.out.h
/* Automatically generated by parse_opcodes. */
#ifndef RISCV_ENCODING_H
#define RISCV_ENCODING_H
#define MATCH_TESTINST 0x200006b
#define MASK_TESTINST 0xfe00707f

Then, we go to riscv-gnu-toolchain repo.

We need to edit the following files:

./binutils/bfd/elfxx-riscv.c

./binutils/include/opcode/riscv-opc.h

./binutils/include/opcode/riscv.h

./gcc/gcc/common/config/riscv/riscv-common.cc

and also the files in ./gdb that is similar to binutils.

./binutils/bfd/elfxx-riscv.c
static struct riscv_supported_ext riscv_supported_vendor_x_ext[] =
{
  {"xcvalu",		ISA_SPEC_CLASS_DRAFT,	1, 0, 0 },
  ...
+  {"xtestinst",		ISA_SPEC_CLASS_DRAFT,	1, 0, 0 },

...

/* Each instuction is belonged to an instruction class INSN_CLASS_*.
   Call riscv_subset_supports to make sure if the instuction is valid.  */

bool
riscv_multi_subset_supports (riscv_parse_subset_t *rps,
			     enum riscv_insn_class insn_class)
{
  switch (insn_class)
    {
    case INSN_CLASS_I:
      return riscv_subset_supports (rps, "i");
    ...
+    case INSN_CLASS_XTESTINST:
+      return riscv_subset_supports (rps, "xtestinst");

...

/* Each instuction is belonged to an instruction class INSN_CLASS_*.
   Call riscv_subset_supports_ext to determine the missing extension.  */

const char *
riscv_multi_subset_supports_ext (riscv_parse_subset_t *rps,
				 enum riscv_insn_class insn_class)
{
  switch (insn_class)
    {
    case INSN_CLASS_I:
      return "i";
    ...
+    case INSN_CLASS_XPENGUIN:
+      return "xpenguin";

./binutils/include/opcode/riscv-opc.h
...
#define MASK_CV_SUB_DIV4           0xfe00707f
#define MASK_CV_SUB_DIV8           0xfe00707f
/* Vendor-specific (UC Berkeley) Xpenguin custom instructions.  */
+ #define MATCH_TESTINST 0x200006b
+ #define MASK_TESTINST 0xfe00707f
...


/* Smrnmi instruction */
DECLARE_INSN(mnret, MATCH_MNRET, MASK_MNRET)
+ /* Vendor-specific (UC Berkeley) Xpenguin custom instructions.  */
+ DECLARE_INSN(testinst, MATCH_TESTINST, MASK_TESTINST)
./binutils/include/opcode/riscv.h

/* All RISC-V instructions belong to at least one of these classes.  */
enum riscv_insn_class
{
  INSN_CLASS_NONE,
  ...
  INSN_CLASS_XCVSIMD,
+  INSN_CLASS_XPENGUIN,
  INSN_CLASS_XTHEADBA,
./binutils/include/opcode/riscv.h
...
{"cv.sub.div8",           0, INSN_CLASS_XCVSIMD, "d,s,t", MATCH_CV_SUB_DIV8, MASK_CV_SUB_DIV8, match_opcode, 0},

+ /* Vendor-specific (UC Berkeley) Xpenguin custom instructions.  */
+ {"testinst", 0, INSN_CLASS_XPENGUIN,       "d,s,t",         MATCH_TESTINST, MASK_TESTINST, match_opcode, 0 },

/* Vendor-specific (T-Head) XTheadBa instructions.  */
{"th.addsl",    0, INSN_CLASS_XTHEADBA,    "d,s,t,Xtu2@25",   MATCH_TH_ADDSL,    MASK_TH_ADDSL,    match_opcode, 0},
...

./gcc/gcc/common/config/riscv/riscv-common.cc

  {"xcvbi", ISA_SPEC_CLASS_NONE, 1, 0},

+  {"xpenguin", ISA_SPEC_CLASS_NONE, 1, 0},

  {"xtheadba", ISA_SPEC_CLASS_NONE, 1, 0},

Build

./configure --prefix=/scratch/tk/Desktop/riscv-matrix/riscv-unknown-elf/
make

Optionally, enable multilib

./configure --prefix=/scratch/tk/Desktop/riscv-matrix/riscv-unknown-elf/ --with-cmodel=medany --enable-multilib

Example program

main.c
#include <stdint.h>
#include <stdio.h>


int main(void) {

  asm volatile("testinst x1, x0, x4\n");
  
  printf("hello\n");

  return 0;
}

riscv64-unknown-elf-gcc main.c -o main.elf

riscv64-unknown-elf-objdump -d main.elf > disassemble.S

Last updated

Was this helpful?