# Adding Custom Instructions to RISC-V GCC Toolchain

First, clone these repos:

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

```bash
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:

```bash
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:

```bash
uv run riscv_opcodes -c "unratified/rv_testinst"
```

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

{% code title="encoding.out.h" %}

```c
/* Automatically generated by parse_opcodes. */
#ifndef RISCV_ENCODING_H
#define RISCV_ENCODING_H
#define MATCH_TESTINST 0x200006b
#define MASK_TESTINST 0xfe00707f

```

{% endcode %}

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.

{% code title="./binutils/bfd/elfxx-riscv.c" %}

```diff
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";
```

{% endcode %}

{% code title="./binutils/include/opcode/riscv-opc.h" %}

```diff
...
#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)
```

{% endcode %}

{% code title="./binutils/include/opcode/riscv.h" %}

```diff

/* 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,
```

{% endcode %}

{% code title="./binutils/include/opcode/riscv.h" %}

```diff
...
{"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},
...
```

{% endcode %}

{% code title="./gcc/gcc/common/config/riscv/riscv-common.cc" %}

```diff

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

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

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

{% endcode %}

Build

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

Optionally, enable multilib

{% code overflow="wrap" %}

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

{% endcode %}

Example program

{% code title="main.c" %}

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


int main(void) {

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

  return 0;
}

```

{% endcode %}

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

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

{% embed url="<https://medium.com/@viveksgt/adding-custom-instructions-compilation-support-to-riscv-toolchain-78ce1b6efcf4>" %}

{% embed url="<https://hsandid.github.io/posts/risc-v-custom-instruction/#installing-the-risc-v-gnugcc-toolchain>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://tk233.gitbook.io/notes/risc-v-soc/adding-custom-instructions-to-risc-v-gcc-toolchain.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
