riscv: Introduce support for defining instructions
authorAndrew Jones <ajones@ventanamicro.com>
Sun, 2 Oct 2022 04:48:07 +0000 (10:18 +0530)
committerAnup Patel <anup@brainfault.org>
Sun, 2 Oct 2022 04:48:07 +0000 (10:18 +0530)
When compiling with toolchains that haven't yet been taught about
new instructions we need to encode them ourselves. Create a new file
where support for instruction definitions will evolve. We initiate
the file with a macro called INSN_R(), which implements the R-type
instruction encoding. INSN_R() will use the assembler's .insn
directive when available, which should give the assembler a chance
to do some validation. When .insn is not available we fall back to
manual encoding.

Not only should using instruction encoding macros improve readability
and maintainability of code over the alternative of inserting
instructions directly (e.g. '.word 0xc0de'), but we should also gain
potential for more optimized code after compilation because the
compiler will have control over the input and output registers used.

Signed-off-by: Andrew Jones <ajones@ventanamicro.com>
Reviewed-by: Anup Patel <anup@brainfault.org>
Signed-off-by: Anup Patel <anup@brainfault.org>
arch/riscv/Kconfig
arch/riscv/include/asm/insn-def.h [new file with mode: 0644]

index 59d1888..d6b0ffd 100644 (file)
@@ -227,6 +227,9 @@ config RISCV_DMA_NONCOHERENT
        select ARCH_HAS_SETUP_DMA_OPS
        select DMA_DIRECT_REMAP
 
+config AS_HAS_INSN
+       def_bool $(as-instr,.insn r 51$(comma) 0$(comma) 0$(comma) t0$(comma) t0$(comma) zero)
+
 source "arch/riscv/Kconfig.socs"
 source "arch/riscv/Kconfig.erratas"
 
diff --git a/arch/riscv/include/asm/insn-def.h b/arch/riscv/include/asm/insn-def.h
new file mode 100644 (file)
index 0000000..635612e
--- /dev/null
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ASM_INSN_DEF_H
+#define __ASM_INSN_DEF_H
+
+#include <asm/asm.h>
+
+#define INSN_R_FUNC7_SHIFT             25
+#define INSN_R_RS2_SHIFT               20
+#define INSN_R_RS1_SHIFT               15
+#define INSN_R_FUNC3_SHIFT             12
+#define INSN_R_RD_SHIFT                         7
+#define INSN_R_OPCODE_SHIFT             0
+
+#ifdef __ASSEMBLY__
+
+#ifdef CONFIG_AS_HAS_INSN
+
+       .macro insn_r, opcode, func3, func7, rd, rs1, rs2
+       .insn   r \opcode, \func3, \func7, \rd, \rs1, \rs2
+       .endm
+
+#else
+
+#include <asm/gpr-num.h>
+
+       .macro insn_r, opcode, func3, func7, rd, rs1, rs2
+       .4byte  ((\opcode << INSN_R_OPCODE_SHIFT) |             \
+                (\func3 << INSN_R_FUNC3_SHIFT) |               \
+                (\func7 << INSN_R_FUNC7_SHIFT) |               \
+                (.L__gpr_num_\rd << INSN_R_RD_SHIFT) |         \
+                (.L__gpr_num_\rs1 << INSN_R_RS1_SHIFT) |       \
+                (.L__gpr_num_\rs2 << INSN_R_RS2_SHIFT))
+       .endm
+
+#endif
+
+#define __INSN_R(...)  insn_r __VA_ARGS__
+
+#else /* ! __ASSEMBLY__ */
+
+#ifdef CONFIG_AS_HAS_INSN
+
+#define __INSN_R(opcode, func3, func7, rd, rs1, rs2)   \
+       ".insn  r " opcode ", " func3 ", " func7 ", " rd ", " rs1 ", " rs2 "\n"
+
+#else
+
+#include <linux/stringify.h>
+#include <asm/gpr-num.h>
+
+#define DEFINE_INSN_R                                                  \
+       __DEFINE_ASM_GPR_NUMS                                           \
+"      .macro insn_r, opcode, func3, func7, rd, rs1, rs2\n"            \
+"      .4byte  ((\\opcode << " __stringify(INSN_R_OPCODE_SHIFT) ") |"  \
+"               (\\func3 << " __stringify(INSN_R_FUNC3_SHIFT) ") |"    \
+"               (\\func7 << " __stringify(INSN_R_FUNC7_SHIFT) ") |"    \
+"               (.L__gpr_num_\\rd << " __stringify(INSN_R_RD_SHIFT) ") |"    \
+"               (.L__gpr_num_\\rs1 << " __stringify(INSN_R_RS1_SHIFT) ") |"  \
+"               (.L__gpr_num_\\rs2 << " __stringify(INSN_R_RS2_SHIFT) "))\n" \
+"      .endm\n"
+
+#define UNDEFINE_INSN_R                                                        \
+"      .purgem insn_r\n"
+
+#define __INSN_R(opcode, func3, func7, rd, rs1, rs2)                   \
+       DEFINE_INSN_R                                                   \
+       "insn_r " opcode ", " func3 ", " func7 ", " rd ", " rs1 ", " rs2 "\n" \
+       UNDEFINE_INSN_R
+
+#endif
+
+#endif /* ! __ASSEMBLY__ */
+
+#define INSN_R(opcode, func3, func7, rd, rs1, rs2)             \
+       __INSN_R(RV_##opcode, RV_##func3, RV_##func7,           \
+                RV_##rd, RV_##rs1, RV_##rs2)
+
+#define RV_OPCODE(v)           __ASM_STR(v)
+#define RV_FUNC3(v)            __ASM_STR(v)
+#define RV_FUNC7(v)            __ASM_STR(v)
+#define RV_RD(v)               __ASM_STR(v)
+#define RV_RS1(v)              __ASM_STR(v)
+#define RV_RS2(v)              __ASM_STR(v)
+#define __RV_REG(v)            __ASM_STR(x ## v)
+#define RV___RD(v)             __RV_REG(v)
+#define RV___RS1(v)            __RV_REG(v)
+#define RV___RS2(v)            __RV_REG(v)
+
+#endif /* __ASM_INSN_DEF_H */