rexcode: riscv INSTRUCTION_TABLE which includes the clobber information

This commit is contained in:
gingerBill
2026-08-20 11:43:26 +01:00
parent 21f48c9a9b
commit f3899c1825
7 changed files with 1255 additions and 457 deletions

View File

@@ -0,0 +1,47 @@
package rexcode_riscv
// Operand slots (indices into the Encoding operand list) that are read/written.
// Max 4 operands (R4-type FMA: rd, rs1, rs2, rs3).
Operand_Set :: distinct bit_set[0..<4; u8]
FFlags :: distinct bit_set[FFlag; u8]
// fcsr accrued exception flags. This is the ONLY flag state in RISC-V — there
// are no integer condition codes, so there is no EFLAGS-style triad here.
FFlag :: enum u8 {
NV, // invalid operation
DZ, // divide by zero
OF, // overflow
UF, // underflow
NX, // inexact
}
Clobber_Regs :: distinct bit_set[Clobber_Reg; u8]
// Implicitly-touched registers that are NOT distinct operands. RISC-V's base
// ISA has almost none of these (unlike x86's RAX/RDX/RSP-heavy encodings) —
// only the compressed link/stack forms.
Clobber_Reg :: enum u8 {
RA, // x1, implicit link on C.JAL / C.JALR
SP, // x2, implicit base on the *SP compressed forms
}
Side_Effects :: distinct bit_set[Side_Effect; u8]
Side_Effect :: enum u8 {
CONTROL, // writes pc: branches, jumps, and trap redirects
TRAP, // synchronous environment trap (ECALL / EBREAK)
FENCE, // explicit memory-ordering barrier (FENCE)
IFENCE, // instruction-fetch synchronization (FENCE.I)
ATOMIC, // indivisible memory RMW (AMO*, and the LR/SC pair)
RESERVATION, // sets or tests an LR/SC reservation
}
Clobber :: struct {
written: Operand_Set, // operand slots whose register/CSR is written
read: Operand_Set, // operand slots whose register/CSR/mem-base is read
implicit_wr: Clobber_Regs, // implicit reg writes (ra on C.JAL/C.JALR)
implicit_rd: Clobber_Regs, // implicit reg reads (sp on the *SP forms)
fflags_wr: FFlags, // accrued exception flags this op may raise
reads_frm: bool, // consumes the dynamic rounding mode from fcsr
writes_mem: bool,
reads_mem: bool,
side_effects: Side_Effects,
}

View File

@@ -1,432 +0,0 @@
// rexcode · Brendan Punsky (dotbmp@github), original author
package rexcode_riscv_tablegen
// =============================================================================
// RISC-V ENCODING_TABLE
// =============================================================================
//
// (bits, mask) model -- same shape as MIPS. `bits` carries the static
// opcode/funct3/funct7 pattern; `mask` covers exactly the bits that are
// fixed. Operand-driven fields (rd, rs1, rs2, immediates, rounding mode,
// aq/rl) land in zero positions of `bits` and are ORed in by the encoder.
//
// Sections:
// §1 RV32I + RV64I base
// §2 Zicsr (CSR access) + Zifencei (FENCE.I)
// §3 M extension
// §4 A extension (atomics)
// §5 F extension (single-precision FP)
// §6 D extension (double-precision FP)
@(rodata)
ENCODING_TABLE:= #partial [Mnemonic][]Encoding{
.INVALID = {},
// =========================================================================
// §1 RV32I / RV64I base
// =========================================================================
// ---- Upper-immediate ----------------------------------------------------
.LUI = { {.LUI, {.GPR,.IMM20,.NONE,.NONE}, {.RD,.IMM_U,.NONE,.NONE}, 0x00000037, MASK_U, .I, {}} },
.AUIPC = { {.AUIPC, {.GPR,.IMM20,.NONE,.NONE}, {.RD,.IMM_U,.NONE,.NONE}, 0x00000017, MASK_U, .I, {}} },
// ---- Jumps --------------------------------------------------------------
.JAL = { {.JAL, {.GPR,.REL21,.NONE,.NONE}, {.RD,.IMM_J,.NONE,.NONE}, 0x0000006F, MASK_J, .I, {branch=true}} },
.JALR = { {.JALR, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00000067, MASK_OPCODE | MASK_FUNCT3, .I, {branch=true}} },
// ---- Branches (B-type) --------------------------------------------------
.BEQ = { {.BEQ, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00000063, MASK_B, .I, {branch=true}} },
.BNE = { {.BNE, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00001063, MASK_B, .I, {branch=true}} },
.BLT = { {.BLT, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00004063, MASK_B, .I, {branch=true}} },
.BGE = { {.BGE, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00005063, MASK_B, .I, {branch=true}} },
.BLTU = { {.BLTU, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00006063, MASK_B, .I, {branch=true}} },
.BGEU = { {.BGEU, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00007063, MASK_B, .I, {branch=true}} },
// ---- Loads (I-type) -----------------------------------------------------
.LB = { {.LB, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00000003, MASK_I, .I, {}} },
.LH = { {.LH, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00001003, MASK_I, .I, {}} },
.LW = { {.LW, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00002003, MASK_I, .I, {}} },
.LBU = { {.LBU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00004003, MASK_I, .I, {}} },
.LHU = { {.LHU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00005003, MASK_I, .I, {}} },
.LWU = { {.LWU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00006003, MASK_I, .I, {rv64_only=true}} },
.LD = { {.LD, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00003003, MASK_I, .I, {rv64_only=true}} },
// ---- Stores (S-type) ----------------------------------------------------
.SB = { {.SB, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00000023, MASK_S, .I, {}} },
.SH = { {.SH, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00001023, MASK_S, .I, {}} },
.SW = { {.SW, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00002023, MASK_S, .I, {}} },
.SD = { {.SD, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00003023, MASK_S, .I, {rv64_only=true}} },
// ---- Integer reg-imm (I-type ALU) ---------------------------------------
.ADDI = { {.ADDI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00000013, MASK_I, .I, {}} },
.SLTI = { {.SLTI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00002013, MASK_I, .I, {}} },
.SLTIU = { {.SLTIU, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00003013, MASK_I, .I, {}} },
.XORI = { {.XORI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00004013, MASK_I, .I, {}} },
.ORI = { {.ORI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00006013, MASK_I, .I, {}} },
.ANDI = { {.ANDI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00007013, MASK_I, .I, {}} },
// I-type shifts. RV32 uses 5-bit shamt + funct7; RV64 widens to 6-bit
// shamt + funct6. We list the RV64-compatible mask (funct6 fixed,
// shamt[5] operand-driven); on RV32 the user must keep shamt < 32.
.SLLI = { {.SLLI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x00001013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .I, {}} },
.SRLI = { {.SRLI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x00005013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .I, {}} },
.SRAI = { {.SRAI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x40005013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .I, {}} },
// RV64 OP-IMM-32 (operates on low 32 bits, sign-extends result)
.ADDIW = { {.ADDIW, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x0000001B, MASK_I, .I, {rv64_only=true}} },
.SLLIW = { {.SLLIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x0000101B, MASK_R, .I, {rv64_only=true}} },
.SRLIW = { {.SRLIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x0000501B, MASK_R, .I, {rv64_only=true}} },
.SRAIW = { {.SRAIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x4000501B, MASK_R, .I, {rv64_only=true}} },
// ---- Integer reg-reg (R-type) -------------------------------------------
.ADD = { {.ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00000033, MASK_R, .I, {}} },
.SUB = { {.SUB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40000033, MASK_R, .I, {}} },
.SLL = { {.SLL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00001033, MASK_R, .I, {}} },
.SLT = { {.SLT, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00002033, MASK_R, .I, {}} },
.SLTU = { {.SLTU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00003033, MASK_R, .I, {}} },
.XOR = { {.XOR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00004033, MASK_R, .I, {}} },
.SRL = { {.SRL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00005033, MASK_R, .I, {}} },
.SRA = { {.SRA, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40005033, MASK_R, .I, {}} },
.OR = { {.OR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00006033, MASK_R, .I, {}} },
.AND = { {.AND, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00007033, MASK_R, .I, {}} },
// RV64 OP-32
.ADDW = { {.ADDW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000003B, MASK_R, .I, {rv64_only=true}} },
.SUBW = { {.SUBW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x4000003B, MASK_R, .I, {rv64_only=true}} },
.SLLW = { {.SLLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000103B, MASK_R, .I, {rv64_only=true}} },
.SRLW = { {.SRLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000503B, MASK_R, .I, {rv64_only=true}} },
.SRAW = { {.SRAW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x4000503B, MASK_R, .I, {rv64_only=true}} },
// ---- Memory ordering ----------------------------------------------------
// FENCE encodes pred/succ in bits 27-24 / 23-20. The opcode reserves
// these as operand-driven; mask covers opcode + funct3.
.FENCE = { {.FENCE, {.FENCE_FLAGS,.FENCE_FLAGS,.NONE,.NONE}, {.FENCE_PRED,.FENCE_SUCC,.NONE,.NONE}, 0x0000000F, MASK_I, .I, {}} },
.FENCE_I = { {.FENCE_I, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x0000100F, 0xFFFFFFFF, .ZIFENCEI, {}} },
// ---- System -------------------------------------------------------------
.ECALL = { {.ECALL, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00000073, 0xFFFFFFFF, .I, {branch=true}} },
.EBREAK = { {.EBREAK, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00100073, 0xFFFFFFFF, .I, {branch=true}} },
// =========================================================================
// §2 Zicsr (CSR access)
// =========================================================================
// CSRRW rd, csr, rs1
// CSRRWI rd, csr, zimm5 (zimm5 lives in the RS1 field)
.CSRRW = { {.CSRRW, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00001073, MASK_I, .ZICSR, {}} },
.CSRRS = { {.CSRRS, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00002073, MASK_I, .ZICSR, {}} },
.CSRRC = { {.CSRRC, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00003073, MASK_I, .ZICSR, {}} },
.CSRRWI = { {.CSRRWI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00005073, MASK_I, .ZICSR, {}} },
.CSRRSI = { {.CSRRSI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00006073, MASK_I, .ZICSR, {}} },
.CSRRCI = { {.CSRRCI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00007073, MASK_I, .ZICSR, {}} },
// =========================================================================
// §3 M extension (RV32M / RV64M)
// =========================================================================
// All share opcode 0x33 and funct7 = 0x01.
.MUL = { {.MUL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02000033, MASK_R, .M, {}} },
.MULH = { {.MULH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02001033, MASK_R, .M, {}} },
.MULHSU = { {.MULHSU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02002033, MASK_R, .M, {}} },
.MULHU = { {.MULHU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02003033, MASK_R, .M, {}} },
.DIV = { {.DIV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02004033, MASK_R, .M, {}} },
.DIVU = { {.DIVU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02005033, MASK_R, .M, {}} },
.REM = { {.REM, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02006033, MASK_R, .M, {}} },
.REMU = { {.REMU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02007033, MASK_R, .M, {}} },
// RV64 M-32 variants (opcode 0x3B)
.MULW = { {.MULW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200003B, MASK_R, .M, {rv64_only=true}} },
.DIVW = { {.DIVW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200403B, MASK_R, .M, {rv64_only=true}} },
.DIVUW = { {.DIVUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200503B, MASK_R, .M, {rv64_only=true}} },
.REMW = { {.REMW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200603B, MASK_R, .M, {rv64_only=true}} },
.REMUW = { {.REMUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200703B, MASK_R, .M, {rv64_only=true}} },
// =========================================================================
// §4 A extension (atomics)
// =========================================================================
// opcode 0x2F; funct3 = 2 for .W and 3 for .D; funct5 (bits 31-27)
// picks the op; bits 26-25 are aq/rl (operand). Mask = opcode +
// funct3 + funct5 = 0xF800707F.
//
// LR.W/LR.D take only one register addr (rd, rs1); rs2 must be 0
// and is part of the static mask.
//
// The address operand uses OFFSET_BASE_A (rs1 only; disp must be 0).
.LR_W = { {.LR_W, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_A,.NONE,.NONE}, 0x1000202F, 0xF9F0707F, .A, {}} },
.SC_W = { {.SC_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x1800202F, 0xF800707F, .A, {}} },
.AMOSWAP_W = { {.AMOSWAP_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0800202F, 0xF800707F, .A, {}} },
.AMOADD_W = { {.AMOADD_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0000202F, 0xF800707F, .A, {}} },
.AMOXOR_W = { {.AMOXOR_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x2000202F, 0xF800707F, .A, {}} },
.AMOAND_W = { {.AMOAND_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x6000202F, 0xF800707F, .A, {}} },
.AMOOR_W = { {.AMOOR_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x4000202F, 0xF800707F, .A, {}} },
.AMOMIN_W = { {.AMOMIN_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x8000202F, 0xF800707F, .A, {}} },
.AMOMAX_W = { {.AMOMAX_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xA000202F, 0xF800707F, .A, {}} },
.AMOMINU_W = { {.AMOMINU_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xC000202F, 0xF800707F, .A, {}} },
.AMOMAXU_W = { {.AMOMAXU_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xE000202F, 0xF800707F, .A, {}} },
.LR_D = { {.LR_D, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_A,.NONE,.NONE}, 0x1000302F, 0xF9F0707F, .A, {rv64_only=true}} },
.SC_D = { {.SC_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x1800302F, 0xF800707F, .A, {rv64_only=true}} },
.AMOSWAP_D = { {.AMOSWAP_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0800302F, 0xF800707F, .A, {rv64_only=true}} },
.AMOADD_D = { {.AMOADD_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0000302F, 0xF800707F, .A, {rv64_only=true}} },
.AMOXOR_D = { {.AMOXOR_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x2000302F, 0xF800707F, .A, {rv64_only=true}} },
.AMOAND_D = { {.AMOAND_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x6000302F, 0xF800707F, .A, {rv64_only=true}} },
.AMOOR_D = { {.AMOOR_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x4000302F, 0xF800707F, .A, {rv64_only=true}} },
.AMOMIN_D = { {.AMOMIN_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x8000302F, 0xF800707F, .A, {rv64_only=true}} },
.AMOMAX_D = { {.AMOMAX_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xA000302F, 0xF800707F, .A, {rv64_only=true}} },
.AMOMINU_D = { {.AMOMINU_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xC000302F, 0xF800707F, .A, {rv64_only=true}} },
.AMOMAXU_D = { {.AMOMAXU_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xE000302F, 0xF800707F, .A, {rv64_only=true}} },
// =========================================================================
// §5 F extension (single-precision)
// =========================================================================
//
// OP-FP opcode = 0x53. funct7 selects op family. funct3 is normally the
// FP rounding mode (operand-driven, fp_round flag) but is fixed for a
// few ops (FMV/FCLASS/FEQ/FLT/FLE/FSGNJ*).
//
// Masks include opcode + funct7 always. funct3 is included only when
// it's a fixed selector rather than a rounding mode. rs2 is included
// when it's a fixed selector (FCVT/FMV/FCLASS/FSQRT).
//
// MASK macros used below:
// M_OP_F7 :: opcode + funct7
// M_OP_F7_RS2 :: + rs2
// M_OP_F7_F3 :: + funct3
// M_OP_F7_F3_RS2 :: + both
.FLW = { {.FLW, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00002007, MASK_I, .F, {}} },
.FSW = { {.FSW, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00002027, MASK_S, .F, {}} },
// R4-type FMA: opcode + fmt (bits 26-25); fmt=00 for .S
.FMADD_S = { {.FMADD_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x00000043, 0x0600007F, .F, {fp_round=true}} },
.FMSUB_S = { {.FMSUB_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x00000047, 0x0600007F, .F, {fp_round=true}} },
.FNMSUB_S = { {.FNMSUB_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0000004B, 0x0600007F, .F, {fp_round=true}} },
.FNMADD_S = { {.FNMADD_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0000004F, 0x0600007F, .F, {fp_round=true}} },
// R-type with rm
.FADD_S = { {.FADD_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}} },
.FSUB_S = { {.FSUB_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x08000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}} },
.FMUL_S = { {.FMUL_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x10000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}} },
.FDIV_S = { {.FDIV_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x18000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}} },
.FSQRT_S = { {.FSQRT_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x58000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}} },
// FSGNJ family: funct7 fixed (0x10), funct3 selects sub-op (no rm)
.FSGNJ_S = { {.FSGNJ_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20000053, MASK_R, .F, {}} },
.FSGNJN_S = { {.FSGNJN_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20001053, MASK_R, .F, {}} },
.FSGNJX_S = { {.FSGNJX_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20002053, MASK_R, .F, {}} },
// FMIN/FMAX: funct7=0x14, funct3 selects min(0)/max(1)
.FMIN_S = { {.FMIN_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28000053, MASK_R, .F, {}} },
.FMAX_S = { {.FMAX_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28001053, MASK_R, .F, {}} },
// FP -> int convert: rs2 is the type selector
.FCVT_W_S = { {.FCVT_W_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}} },
.FCVT_WU_S = { {.FCVT_WU_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}} },
.FCVT_L_S = { {.FCVT_L_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}} },
.FCVT_LU_S = { {.FCVT_LU_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}} },
// FP <- int convert
.FCVT_S_W = { {.FCVT_S_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}} },
.FCVT_S_WU = { {.FCVT_S_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}} },
.FCVT_S_L = { {.FCVT_S_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}} },
.FCVT_S_LU = { {.FCVT_S_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}} },
// FMV / FCLASS: funct3 fixed (000 for FMV, 001 for FCLASS), rs2=0
.FMV_X_W = { {.FMV_X_W, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .F, {}} },
.FMV_W_X = { {.FMV_W_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .F, {}} },
.FCLASS_S = { {.FCLASS_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE0001053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .F, {}} },
// FP compare: funct7=0x50, funct3 selects EQ(2)/LT(1)/LE(0)
.FEQ_S = { {.FEQ_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0002053, MASK_R, .F, {}} },
.FLT_S = { {.FLT_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0001053, MASK_R, .F, {}} },
.FLE_S = { {.FLE_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0000053, MASK_R, .F, {}} },
// =========================================================================
// §6 D extension (double-precision)
// =========================================================================
//
// Same pattern as F but funct7 low bit = 1 (fmt=01 = D).
.FLD = { {.FLD, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00003007, MASK_I, .D, {}} },
.FSD = { {.FSD, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00003027, MASK_S, .D, {}} },
.FMADD_D = { {.FMADD_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x02000043, 0x0600007F, .D, {fp_round=true}} },
.FMSUB_D = { {.FMSUB_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x02000047, 0x0600007F, .D, {fp_round=true}} },
.FNMSUB_D = { {.FNMSUB_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0200004B, 0x0600007F, .D, {fp_round=true}} },
.FNMADD_D = { {.FNMADD_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0200004F, 0x0600007F, .D, {fp_round=true}} },
.FADD_D = { {.FADD_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}} },
.FSUB_D = { {.FSUB_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}} },
.FMUL_D = { {.FMUL_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x12000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}} },
.FDIV_D = { {.FDIV_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x1A000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}} },
.FSQRT_D = { {.FSQRT_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x5A000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}} },
.FSGNJ_D = { {.FSGNJ_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22000053, MASK_R, .D, {}} },
.FSGNJN_D = { {.FSGNJN_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22001053, MASK_R, .D, {}} },
.FSGNJX_D = { {.FSGNJX_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22002053, MASK_R, .D, {}} },
.FMIN_D = { {.FMIN_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2A000053, MASK_R, .D, {}} },
.FMAX_D = { {.FMAX_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2A001053, MASK_R, .D, {}} },
// FCVT between S and D
.FCVT_S_D = { {.FCVT_S_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x40100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}} },
.FCVT_D_S = { {.FCVT_D_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x42000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}} },
// FP -> int (double-source)
.FCVT_W_D = { {.FCVT_W_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}} },
.FCVT_WU_D = { {.FCVT_WU_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}} },
.FCVT_L_D = { {.FCVT_L_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}} },
.FCVT_LU_D = { {.FCVT_LU_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}} },
// FP <- int
.FCVT_D_W = { {.FCVT_D_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}} },
.FCVT_D_WU = { {.FCVT_D_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}} },
.FCVT_D_L = { {.FCVT_D_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}} },
.FCVT_D_LU = { {.FCVT_D_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}} },
// FMV / FCLASS double
.FMV_X_D = { {.FMV_X_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .D, {rv64_only=true}} },
.FMV_D_X = { {.FMV_D_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .D, {rv64_only=true}} },
.FCLASS_D = { {.FCLASS_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE2001053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .D, {}} },
// FP compare double
.FEQ_D = { {.FEQ_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2002053, MASK_R, .D, {}} },
.FLT_D = { {.FLT_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2001053, MASK_R, .D, {}} },
.FLE_D = { {.FLE_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2000053, MASK_R, .D, {}} },
// =========================================================================
// C extension (16-bit compressed)
// =========================================================================
//
// bits/mask use only the low 16 bits; the encoder writes 2 bytes for any
// form whose (bits & 3) != 3. The constant-bit pattern places the C
// dispatch fields (funct + op) in the low half-word.
// ---- Quadrant 0 (op = 00) ----------------------------------------------
// C.ADDI4SPN rd', sp, imm = 000 imm[5:4] imm[9:6] imm[2] imm[3] rd' 00
// funct3=000, op=00 -> static bits 0x0000, mask covers funct3+op only
// so the imm fields and rd' are operand-driven.
.C_ADDI4SPN = { {.C_ADDI4SPN, {.GPR_C, .GPR_SP, .IMM_C8U, .NONE}, {.C_RD_PRIMED, .NONE, .C_IMM_CIW, .NONE}, 0x0000, 0xE003, .C, {}} },
// C.FLD rd', imm(rs1') = 001 imm[5:3] rs1' imm[7:6] rd' 00 (D)
.C_FLD = { {.C_FLD, {.FPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0x2000, 0xE003, .D, {}} },
// C.LW rd', imm(rs1') = 010 imm[5:3] rs1' imm[2,6] rd' 00
.C_LW = { {.C_LW, {.GPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0x4000, 0xE003, .C, {}} },
// C.LD rd', imm(rs1') = 011 imm[5:3] rs1' imm[7:6] rd' 00 (RV64-only)
.C_LD = { {.C_LD, {.GPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0x6000, 0xE003, .C, {rv64_only=true}} },
// C.FSD rs2', imm(rs1') = 101 imm[5:3] rs1' imm[7:6] rs2' 00
.C_FSD = { {.C_FSD, {.FPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0xA000, 0xE003, .D, {}} },
// C.SW rs2', imm(rs1') = 110 imm[5:3] rs1' imm[2,6] rs2' 00
.C_SW = { {.C_SW, {.GPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0xC000, 0xE003, .C, {}} },
// C.SD rs2', imm(rs1') = 111 imm[5:3] rs1' imm[7:6] rs2' 00 (RV64-only)
.C_SD = { {.C_SD, {.GPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0xE000, 0xE003, .C, {rv64_only=true}} },
// C.FLW rd', imm(rs1') = 011 imm[5:3] rs1' imm[2,6] rd' 00 (RV32-only)
.C_FLW = { {.C_FLW, {.FPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0x6000, 0xE003, .F, {rv32_only=true}} },
// C.FSW rs2', imm(rs1') = 111 imm[5:3] rs1' imm[2,6] rs2' 00 (RV32-only)
.C_FSW = { {.C_FSW, {.FPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0xE000, 0xE003, .F, {rv32_only=true}} },
// ---- Quadrant 1 (op = 01) ----------------------------------------------
// C.NOP = 0x0001 = C.ADDI x0, 0 (fully fixed encoding).
.C_NOP = { {.C_NOP, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x0001, 0xFFFF, .C, {}} },
// C.ADDI rd, imm = 000 imm[5] rd!=0 imm[4:0] 01
.C_ADDI = { {.C_ADDI, {.GPR_NONZERO, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_S, .NONE, .NONE}, 0x0001, 0xE003, .C, {}} },
// C.JAL imm = 001 imm[11:1] 01 (RV32-only)
.C_JAL = { {.C_JAL, {.REL12, .NONE, .NONE, .NONE}, {.C_BRANCH12, .NONE, .NONE, .NONE}, 0x2001, 0xE003, .C, {rv32_only=true, branch=true}} },
// C.ADDIW rd, imm = 001 imm[5] rd!=0 imm[4:0] 01 (RV64-only)
.C_ADDIW = { {.C_ADDIW, {.GPR_NONZERO, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_S, .NONE, .NONE}, 0x2001, 0xE003, .C, {rv64_only=true}} },
// C.LI rd, imm = 010 imm[5] rd!=0 imm[4:0] 01
.C_LI = { {.C_LI, {.GPR_NONZERO, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_S, .NONE, .NONE}, 0x4001, 0xE003, .C, {}} },
// C.ADDI16SP sp, imm = 011 imm[9] 00010 imm[4,6,8:7,5] 01
// rd is fixed at 2 (sp); ensure the form discriminates by checking rd=2.
.C_ADDI16SP = { {.C_ADDI16SP, {.GPR_SP, .IMM_C10S, .NONE, .NONE}, {.NONE, .C_IMM_ADDI16SP, .NONE, .NONE}, 0x6101, 0xEF83, .C, {}} },
// C.LUI rd, imm = 011 imm[17] rd!=0,2 imm[16:12] 01
.C_LUI = { {.C_LUI, {.GPR_NONZERO, .IMM_C18S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_LUI, .NONE, .NONE}, 0x6001, 0xE003, .C, {}} },
// C.SRLI rd', shamt = 100 shamt[5] 00 rd' shamt[4:0] 01
.C_SRLI = { {.C_SRLI, {.GPR_C, .IMM_C6U, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_IMM_CI_U, .NONE, .NONE}, 0x8001, 0xEC03, .C, {}} },
// C.SRAI rd', shamt = 100 shamt[5] 01 rd' shamt[4:0] 01
.C_SRAI = { {.C_SRAI, {.GPR_C, .IMM_C6U, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_IMM_CI_U, .NONE, .NONE}, 0x8401, 0xEC03, .C, {}} },
// C.ANDI rd', imm = 100 imm[5] 10 rd' imm[4:0] 01
.C_ANDI = { {.C_ANDI, {.GPR_C, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_IMM_CI_S, .NONE, .NONE}, 0x8801, 0xEC03, .C, {}} },
// CA-format reg-reg (op=01, funct6=100011 / 100111 + funct2 picks op):
// C.SUB rd', rs2' = 100011 rd' 00 rs2' 01
// C.XOR rd', rs2' = 100011 rd' 01 rs2' 01
// C.OR rd', rs2' = 100011 rd' 10 rs2' 01
// C.AND rd', rs2' = 100011 rd' 11 rs2' 01
// C.SUBW rd', rs2' = 100111 rd' 00 rs2' 01 (RV64)
// C.ADDW rd', rs2' = 100111 rd' 01 rs2' 01 (RV64)
.C_SUB = { {.C_SUB, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C01, 0xFC63, .C, {}} },
.C_XOR = { {.C_XOR, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C21, 0xFC63, .C, {}} },
.C_OR = { {.C_OR, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C41, 0xFC63, .C, {}} },
.C_AND = { {.C_AND, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C61, 0xFC63, .C, {}} },
.C_SUBW = { {.C_SUBW, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x9C01, 0xFC63, .C, {rv64_only=true}} },
.C_ADDW = { {.C_ADDW, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x9C21, 0xFC63, .C, {rv64_only=true}} },
// C.J offset = 101 offset[11:1] 01
.C_J = { {.C_J, {.REL12, .NONE, .NONE, .NONE}, {.C_BRANCH12, .NONE, .NONE, .NONE}, 0xA001, 0xE003, .C, {branch=true}} },
// C.BEQZ rs1', offset[8:1] = 110 offset[8,4:3] rs1' offset[7:6,2:1,5] 01
.C_BEQZ = { {.C_BEQZ, {.GPR_C, .REL9, .NONE, .NONE}, {.C_RS1_PRIMED, .C_BRANCH9, .NONE, .NONE}, 0xC001, 0xE003, .C, {branch=true}} },
// C.BNEZ rs1', offset[8:1] = 111 offset[8,4:3] rs1' offset[7:6,2:1,5] 01
.C_BNEZ = { {.C_BNEZ, {.GPR_C, .REL9, .NONE, .NONE}, {.C_RS1_PRIMED, .C_BRANCH9, .NONE, .NONE}, 0xE001, 0xE003, .C, {branch=true}} },
// ---- Quadrant 2 (op = 10) ----------------------------------------------
// C.SLLI rd, shamt = 000 shamt[5] rd!=0 shamt[4:0] 10
.C_SLLI = { {.C_SLLI, {.GPR_NONZERO, .IMM_C6U, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_U, .NONE, .NONE}, 0x0002, 0xE003, .C, {}} },
// C.FLDSP rd, imm = 001 imm[5] rd imm[4:3,8:6] 10
.C_FLDSP = { {.C_FLDSP, {.FPR, .MEM_C_SP_D, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_D, .NONE, .NONE}, 0x2002, 0xE003, .D, {}} },
// C.LWSP rd, imm = 010 imm[5] rd!=0 imm[4:2,7:6] 10
.C_LWSP = { {.C_LWSP, {.GPR_NONZERO, .MEM_C_SP_W, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_W, .NONE, .NONE}, 0x4002, 0xE003, .C, {}} },
// C.LDSP rd, imm = 011 imm[5] rd!=0 imm[4:3,8:6] 10 (RV64)
.C_LDSP = { {.C_LDSP, {.GPR_NONZERO, .MEM_C_SP_D, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_D, .NONE, .NONE}, 0x6002, 0xE003, .C, {rv64_only=true}} },
// CR-format funct4=1000 / 1001 with rd!=0:
// C.JR rs1 = 1000 rs1!=0 00000 10 (rs2=0)
// C.MV rd, rs2 = 1000 rd!=0 rs2!=0 10
// C.EBREAK = 1001 00000 00000 10 (fully fixed 0x9002)
// C.JALR rs1 = 1001 rs1!=0 00000 10 (rs2=0)
// C.ADD rd, rs2 = 1001 rd!=0 rs2!=0 10
.C_JR = { {.C_JR, {.GPR_NONZERO, .NONE, .NONE, .NONE}, {.C_RD_RS1, .NONE, .NONE, .NONE}, 0x8002, 0xF07F, .C, {branch=true}} },
.C_MV = { {.C_MV, {.GPR_NONZERO, .GPR_NONZERO, .NONE, .NONE}, {.C_RD_RS1, .C_RS2, .NONE, .NONE}, 0x8002, 0xF003, .C, {}} },
.C_EBREAK = { {.C_EBREAK, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x9002, 0xFFFF, .C, {}} },
.C_JALR = { {.C_JALR, {.GPR_NONZERO, .NONE, .NONE, .NONE}, {.C_RD_RS1, .NONE, .NONE, .NONE}, 0x9002, 0xF07F, .C, {branch=true}} },
.C_ADD = { {.C_ADD, {.GPR_NONZERO, .GPR_NONZERO, .NONE, .NONE}, {.C_RD_RS1, .C_RS2, .NONE, .NONE}, 0x9002, 0xF003, .C, {}} },
// C.FSDSP rs2, imm = 101 imm[5:3,8:6] rs2 10
.C_FSDSP = { {.C_FSDSP, {.FPR, .MEM_C_SP_D, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_D, .NONE, .NONE}, 0xA002, 0xE003, .D, {}} },
// C.SWSP rs2, imm = 110 imm[5:2,7:6] rs2 10
.C_SWSP = { {.C_SWSP, {.GPR, .MEM_C_SP_W, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_W, .NONE, .NONE}, 0xC002, 0xE003, .C, {}} },
// C.SDSP rs2, imm = 111 imm[5:3,8:6] rs2 10 (RV64)
.C_SDSP = { {.C_SDSP, {.GPR, .MEM_C_SP_D, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_D, .NONE, .NONE}, 0xE002, 0xE003, .C, {rv64_only=true}} },
// C.FLWSP rd, imm = 011 imm[5] rd imm[4:2,7:6] 10 (RV32-only)
.C_FLWSP = { {.C_FLWSP, {.FPR, .MEM_C_SP_W, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_W, .NONE, .NONE}, 0x6002, 0xE003, .F, {rv32_only=true}} },
// C.FSWSP rs2, imm = 111 imm[5:2,7:6] rs2 10 (RV32-only)
.C_FSWSP = { {.C_FSWSP, {.FPR, .MEM_C_SP_W, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_W, .NONE, .NONE}, 0xE002, 0xE003, .F, {rv32_only=true}} },
}

View File

@@ -34,6 +34,7 @@ import lib "../"
// Package-scope aliases so the moved SoT resolves Mnemonic/Encoding unqualified.
Encoding :: lib.Encoding
Mnemonic :: lib.Mnemonic
Clobber :: lib.Clobber
// The SoT's bit/mask literals reference these field-mask constants.
MASK_OPCODE :: lib.MASK_OPCODE
@@ -55,12 +56,13 @@ MASK_J :: lib.MASK_J
Blob :: struct { global, file, typ: string }
BLOBS := [?]Blob{
{"ENCODE_FORMS", "riscv.encode_forms.bin", "Encoding"},
{"ENCODE_RUNS", "riscv.encode_runs.bin", "Encode_Run"},
{"DECODE_ENTRIES", "riscv.entries.bin", "Decode_Entry"},
{"DECODE_INDEX_OPCODE", "riscv.idx_opcode.bin", "Decode_Index"},
{"DECODE_INDEX_OP_FP", "riscv.idx_op_fp.bin", "Decode_Index"},
{"DECODE_INDEX_RVC", "riscv.idx_rvc.bin", "Decode_Index"},
{"ENCODE_FORMS", "riscv.encode_forms.bin", "Encoding"},
{"ENCODE_RUNS", "riscv.encode_runs.bin", "Encode_Run"},
{"DECODE_ENTRIES", "riscv.entries.bin", "Decode_Entry"},
{"DECODE_INDEX_OPCODE", "riscv.idx_opcode.bin", "Decode_Index"},
{"DECODE_INDEX_OP_FP", "riscv.idx_op_fp.bin", "Decode_Index"},
{"DECODE_INDEX_RVC", "riscv.idx_rvc.bin", "Decode_Index"},
{"CLOBBER_FORMS", "riscv.clobber_forms.bin", "Clobber"},
}
DIR_GEN :: #directory + "/generated/"
@@ -98,30 +100,43 @@ emit_encode_tables :: proc() -> (total: int) {
sb := strings.builder_make()
strings.write_string(&sb, "package rexcode_riscv_generated\n\n")
strings.write_string(&sb, "// GENERATED by ../gen.odin -- DO NOT EDIT.\n")
strings.write_string(&sb, "// Flattened encode forms + per-mnemonic run index (source: ENCODING_TABLE).\n\n")
strings.write_string(&sb, "// Flattened encode forms + per-mnemonic run index (source: INSTRUCTION_TABLE).\n\n")
strings.write_string(&sb, "import lib \"../..\"\n\n")
for m in Mnemonic { total += len(ENCODING_TABLE[m]) }
for m in Mnemonic { total += len(INSTRUCTION_TABLE[m]) }
strings.write_string(&sb, "@(rodata)\n")
fmt.sbprintfln(&sb, "ENCODE_FORMS := [%d]lib.Encoding{{", total)
for m in Mnemonic {
forms := ENCODING_TABLE[m]
forms := INSTRUCTION_TABLE[m]
if len(forms) == 0 { continue }
fmt.sbprintfln(&sb, "\t// .%v", m)
for f in forms {
for &form in forms {
f := &form.encoding
write_row(&sb, f.mnemonic, f.ops, f.enc, f.bits, f.mask, f.feature, f.flags)
}
}
strings.write_string(&sb, "}\n\n")
strings.write_string(&sb, "@(rodata)\n")
fmt.sbprintfln(&sb, "CLOBBER_FORMS := [%d]lib.Clobber{{", total)
for m in Mnemonic {
forms := INSTRUCTION_TABLE[m]
if len(forms) == 0 { continue }
fmt.sbprintfln(&sb, "\t// .%v", m)
for &form in forms {
write_clobber_row(&sb, form.clobber)
}
}
strings.write_string(&sb, "}\n\n")
run_w := 0
for m in Mnemonic { run_w = max(run_w, len(reflect.enum_string(m))) }
strings.write_string(&sb, "@(rodata)\n")
strings.write_string(&sb, "ENCODE_RUNS := [lib.Mnemonic]lib.Encode_Run{\n")
start := 0
for m in Mnemonic {
c := len(ENCODING_TABLE[m])
c := len(INSTRUCTION_TABLE[m])
name := reflect.enum_string(m)
fmt.sbprintf(&sb, "\t.%s", name)
for _ in 0..<run_w-len(name) { strings.write_byte(&sb, ' ') }
@@ -141,7 +156,8 @@ emit_decode_tables :: proc() -> (total: int) {
all: [dynamic]Entry
defer delete(all)
for m in Mnemonic {
for f in ENCODING_TABLE[m] {
for &form in INSTRUCTION_TABLE[m] {
f := &form.encoding
e := Entry{
mnemonic = f.mnemonic,
ops = f.ops,
@@ -235,6 +251,64 @@ write_row :: proc(sb: ^strings.Builder, mn: lib.Mnemonic, ops: [4]lib.Operand_Ty
mn, ops[0], ops[1], ops[2], ops[3], enc[0], enc[1], enc[2], enc[3], bits, mask, feature, flags_lit(flags))
}
write_clobber_row :: proc(sb: ^strings.Builder, c: lib.Clobber) {
write_set :: proc(sb: ^strings.Builder, name: string, set: $T) {
strings.write_string(sb, name)
strings.write_string(sb, "=")
strings.write_string(sb, "{")
i := 0
for elem in set {
if i > 0 { strings.write_string(sb, ", ") }
strings.write_string(sb, ".")
fmt.sbprintf(sb, "%s", elem)
i += 1
}
strings.write_string(sb, "}")
}
strings.write_string(sb, "\t{")
defer strings.write_string(sb, "},\n")
i := -1
if c.written != nil {
if i += 1; i > 0 { strings.write_string(sb, ", ") }
strings.write_string(sb, "written=")
fmt.sbprintf(sb, "%w", c.written)
}
if c.read != nil {
if i += 1; i > 0 { strings.write_string(sb, ", ") }
strings.write_string(sb, "read=")
fmt.sbprintf(sb, "%w", c.read)
}
if c.implicit_wr != nil {
if i += 1; i > 0 { strings.write_string(sb, ", ") }
write_set(sb, "implicit_wr", c.implicit_wr)
}
if c.implicit_rd != nil {
if i += 1; i > 0 { strings.write_string(sb, ", ") }
write_set(sb, "implicit_rd", c.implicit_rd)
}
if c.fflags_wr != nil {
if i += 1; i > 0 { strings.write_string(sb, ", ") }
write_set(sb, "fflags_wr", c.fflags_wr)
}
if c.reads_frm {
if i += 1; i > 0 { strings.write_string(sb, ", ") }
fmt.sbprintf(sb, "reads_frm=true")
}
if c.writes_mem {
if i += 1; i > 0 { strings.write_string(sb, ", ") }
fmt.sbprintf(sb, "writes_mem=true")
}
if c.reads_mem {
if i += 1; i > 0 { strings.write_string(sb, ", ") }
fmt.sbprintf(sb, "reads_mem=true")
}
if c.side_effects != nil {
if i += 1; i > 0 { strings.write_string(sb, ", ") }
write_set(sb, "side_effects", c.side_effects)
}
}
flags_lit :: proc(f: lib.Encoding_Flags) -> string {
parts: [dynamic]string
defer delete(parts)
@@ -268,7 +342,8 @@ emit_writer :: proc() {
emit_file(DIR_GEN + "writer.odin", &sb)
}
LOADER_TYPES :: `// -----------------------------------------------------------------------------
LOADER_TYPES :: ```
// -----------------------------------------------------------------------------
// Subsidiary table types (generated scaffolding)
// -----------------------------------------------------------------------------
@@ -294,9 +369,10 @@ Decode_Index :: struct #packed {
count: u16,
}
#assert(size_of(Decode_Index) == 4)
`
```
LOADER_ACCESSORS :: `// -----------------------------------------------------------------------------
LOADER_ACCESSORS :: ```
// -----------------------------------------------------------------------------
// Accessors
// -----------------------------------------------------------------------------
@@ -307,7 +383,15 @@ encoding_forms :: #force_inline proc "contextless" (m: Mnemonic) -> []Encoding {
r := ENCODE_RUNS[u16(m)]
return ENCODE_FORMS[r.start:][:r.count]
}
`
// Per-mnemonic clobber forms: the run of CLOBBER_FORMS belonging to ` + "`m`" + `.
// Replaces the old ENCODING_TABLE[m] slice; the returned view is into rodata.
@(private, require_results)
clobber_forms :: #force_inline proc "contextless" (m: Mnemonic) -> []Clobber {
r := ENCODE_RUNS[u16(m)]
return CLOBBER_FORMS[r.start:][:r.count]
}
```
emit_loader :: proc() {
sb := strings.builder_make()

View File

@@ -3,7 +3,7 @@
package rexcode_riscv_generated
// GENERATED by ../gen.odin -- DO NOT EDIT.
// Flattened encode forms + per-mnemonic run index (source: ENCODING_TABLE).
// Flattened encode forms + per-mnemonic run index (source: INSTRUCTION_TABLE).
import lib "../.."
@@ -407,6 +407,406 @@ ENCODE_FORMS := [198]lib.Encoding{
{ .C_FSWSP, {.FPR,.MEM_C_SP_W,.NONE,.NONE}, {.C_RS2,.C_IMM_CSS_W,.NONE,.NONE}, 0x0000E002, 0x0000E003, .F, {rv32_only=true} },
}
@(rodata)
CLOBBER_FORMS := [198]lib.Clobber{
// .LUI
{written={0}},
// .AUIPC
{written={0}},
// .JAL
{written={0}, side_effects={.CONTROL}},
// .JALR
{written={0}, read={1}, side_effects={.CONTROL}},
// .BEQ
{read={0, 1}, side_effects={.CONTROL}},
// .BNE
{read={0, 1}, side_effects={.CONTROL}},
// .BLT
{read={0, 1}, side_effects={.CONTROL}},
// .BGE
{read={0, 1}, side_effects={.CONTROL}},
// .BLTU
{read={0, 1}, side_effects={.CONTROL}},
// .BGEU
{read={0, 1}, side_effects={.CONTROL}},
// .LB
{written={0}, read={1}, reads_mem=true},
// .LH
{written={0}, read={1}, reads_mem=true},
// .LW
{written={0}, read={1}, reads_mem=true},
// .LBU
{written={0}, read={1}, reads_mem=true},
// .LHU
{written={0}, read={1}, reads_mem=true},
// .SB
{read={0, 1}, writes_mem=true},
// .SH
{read={0, 1}, writes_mem=true},
// .SW
{read={0, 1}, writes_mem=true},
// .LWU
{written={0}, read={1}, reads_mem=true},
// .LD
{written={0}, read={1}, reads_mem=true},
// .SD
{read={0, 1}, writes_mem=true},
// .ADDI
{written={0}, read={1}},
// .SLTI
{written={0}, read={1}},
// .SLTIU
{written={0}, read={1}},
// .XORI
{written={0}, read={1}},
// .ORI
{written={0}, read={1}},
// .ANDI
{written={0}, read={1}},
// .SLLI
{written={0}, read={1}},
// .SRLI
{written={0}, read={1}},
// .SRAI
{written={0}, read={1}},
// .ADDIW
{written={0}, read={1}},
// .SLLIW
{written={0}, read={1}},
// .SRLIW
{written={0}, read={1}},
// .SRAIW
{written={0}, read={1}},
// .ADD
{written={0}, read={1, 2}},
// .SUB
{written={0}, read={1, 2}},
// .SLL
{written={0}, read={1, 2}},
// .SLT
{written={0}, read={1, 2}},
// .SLTU
{written={0}, read={1, 2}},
// .XOR
{written={0}, read={1, 2}},
// .SRL
{written={0}, read={1, 2}},
// .SRA
{written={0}, read={1, 2}},
// .OR
{written={0}, read={1, 2}},
// .AND
{written={0}, read={1, 2}},
// .ADDW
{written={0}, read={1, 2}},
// .SUBW
{written={0}, read={1, 2}},
// .SLLW
{written={0}, read={1, 2}},
// .SRLW
{written={0}, read={1, 2}},
// .SRAW
{written={0}, read={1, 2}},
// .FENCE
{side_effects={.FENCE}},
// .FENCE_I
{side_effects={.IFENCE}},
// .ECALL
{side_effects={.CONTROL, .TRAP}},
// .EBREAK
{side_effects={.CONTROL, .TRAP}},
// .CSRRW
{written={0, 1}, read={1, 2}},
// .CSRRS
{written={0, 1}, read={1, 2}},
// .CSRRC
{written={0, 1}, read={1, 2}},
// .CSRRWI
{written={0, 1}, read={1}},
// .CSRRSI
{written={0, 1}, read={1}},
// .CSRRCI
{written={0, 1}, read={1}},
// .MUL
{written={0}, read={1, 2}},
// .MULH
{written={0}, read={1, 2}},
// .MULHSU
{written={0}, read={1, 2}},
// .MULHU
{written={0}, read={1, 2}},
// .DIV
{written={0}, read={1, 2}},
// .DIVU
{written={0}, read={1, 2}},
// .REM
{written={0}, read={1, 2}},
// .REMU
{written={0}, read={1, 2}},
// .MULW
{written={0}, read={1, 2}},
// .DIVW
{written={0}, read={1, 2}},
// .DIVUW
{written={0}, read={1, 2}},
// .REMW
{written={0}, read={1, 2}},
// .REMUW
{written={0}, read={1, 2}},
// .LR_W
{written={0}, read={1}, reads_mem=true, side_effects={.ATOMIC, .RESERVATION}},
// .SC_W
{written={0}, read={1, 2}, writes_mem=true, side_effects={.ATOMIC, .RESERVATION}},
// .AMOSWAP_W
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOADD_W
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOXOR_W
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOAND_W
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOOR_W
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOMIN_W
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOMAX_W
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOMINU_W
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOMAXU_W
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .LR_D
{written={0}, read={1}, reads_mem=true, side_effects={.ATOMIC, .RESERVATION}},
// .SC_D
{written={0}, read={1, 2}, writes_mem=true, side_effects={.ATOMIC, .RESERVATION}},
// .AMOSWAP_D
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOADD_D
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOXOR_D
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOAND_D
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOOR_D
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOMIN_D
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOMAX_D
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOMINU_D
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .AMOMAXU_D
{written={0}, read={1, 2}, writes_mem=true, reads_mem=true, side_effects={.ATOMIC}},
// .FLW
{written={0}, read={1}, reads_mem=true},
// .FSW
{read={0, 1}, writes_mem=true},
// .FMADD_S
{written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FMSUB_S
{written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FNMSUB_S
{written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FNMADD_S
{written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FADD_S
{written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FSUB_S
{written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FMUL_S
{written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FDIV_S
{written={0}, read={1, 2}, fflags_wr={.NV, .DZ, .OF, .UF, .NX}, reads_frm=true},
// .FSQRT_S
{written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true},
// .FSGNJ_S
{written={0}, read={1, 2}},
// .FSGNJN_S
{written={0}, read={1, 2}},
// .FSGNJX_S
{written={0}, read={1, 2}},
// .FMIN_S
{written={0}, read={1, 2}, fflags_wr={.NV}},
// .FMAX_S
{written={0}, read={1, 2}, fflags_wr={.NV}},
// .FCVT_W_S
{written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true},
// .FCVT_WU_S
{written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true},
// .FMV_X_W
{written={0}, read={1}},
// .FEQ_S
{written={0}, read={1, 2}, fflags_wr={.NV}},
// .FLT_S
{written={0}, read={1, 2}, fflags_wr={.NV}},
// .FLE_S
{written={0}, read={1, 2}, fflags_wr={.NV}},
// .FCLASS_S
{written={0}, read={1}},
// .FCVT_S_W
{written={0}, read={1}, fflags_wr={.NX}, reads_frm=true},
// .FCVT_S_WU
{written={0}, read={1}, fflags_wr={.NX}, reads_frm=true},
// .FMV_W_X
{written={0}, read={1}},
// .FCVT_L_S
{written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true},
// .FCVT_LU_S
{written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true},
// .FCVT_S_L
{written={0}, read={1}, fflags_wr={.NX}, reads_frm=true},
// .FCVT_S_LU
{written={0}, read={1}, fflags_wr={.NX}, reads_frm=true},
// .FLD
{written={0}, read={1}, reads_mem=true},
// .FSD
{read={0, 1}, writes_mem=true},
// .FMADD_D
{written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FMSUB_D
{written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FNMSUB_D
{written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FNMADD_D
{written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FADD_D
{written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FSUB_D
{written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FMUL_D
{written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FDIV_D
{written={0}, read={1, 2}, fflags_wr={.NV, .DZ, .OF, .UF, .NX}, reads_frm=true},
// .FSQRT_D
{written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true},
// .FSGNJ_D
{written={0}, read={1, 2}},
// .FSGNJN_D
{written={0}, read={1, 2}},
// .FSGNJX_D
{written={0}, read={1, 2}},
// .FMIN_D
{written={0}, read={1, 2}, fflags_wr={.NV}},
// .FMAX_D
{written={0}, read={1, 2}, fflags_wr={.NV}},
// .FCVT_S_D
{written={0}, read={1}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true},
// .FCVT_D_S
{written={0}, read={1}, fflags_wr={.NV}, reads_frm=true},
// .FEQ_D
{written={0}, read={1, 2}, fflags_wr={.NV}},
// .FLT_D
{written={0}, read={1, 2}, fflags_wr={.NV}},
// .FLE_D
{written={0}, read={1, 2}, fflags_wr={.NV}},
// .FCLASS_D
{written={0}, read={1}},
// .FCVT_W_D
{written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true},
// .FCVT_WU_D
{written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true},
// .FCVT_D_W
{written={0}, read={1}, reads_frm=true},
// .FCVT_D_WU
{written={0}, read={1}, reads_frm=true},
// .FCVT_L_D
{written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true},
// .FCVT_LU_D
{written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true},
// .FCVT_D_L
{written={0}, read={1}, fflags_wr={.NX}, reads_frm=true},
// .FCVT_D_LU
{written={0}, read={1}, fflags_wr={.NX}, reads_frm=true},
// .FMV_X_D
{written={0}, read={1}},
// .FMV_D_X
{written={0}, read={1}},
// .C_NOP
{},
// .C_EBREAK
{side_effects={.CONTROL, .TRAP}},
// .C_ADDI4SPN
{written={0}, read={1}},
// .C_LW
{written={0}, read={1}, reads_mem=true},
// .C_LD
{written={0}, read={1}, reads_mem=true},
// .C_SW
{read={0, 1}, writes_mem=true},
// .C_SD
{read={0, 1}, writes_mem=true},
// .C_FLW
{written={0}, read={1}, reads_mem=true},
// .C_FSW
{read={0, 1}, writes_mem=true},
// .C_FLD
{written={0}, read={1}, reads_mem=true},
// .C_FSD
{read={0, 1}, writes_mem=true},
// .C_ADDI
{written={0}, read={0}},
// .C_ADDIW
{written={0}, read={0}},
// .C_LI
{written={0}},
// .C_LUI
{written={0}},
// .C_ADDI16SP
{written={0}, read={0}},
// .C_SRLI
{written={0}, read={0}},
// .C_SRAI
{written={0}, read={0}},
// .C_ANDI
{written={0}, read={0}},
// .C_SUB
{written={0}, read={0, 1}},
// .C_XOR
{written={0}, read={0, 1}},
// .C_OR
{written={0}, read={0, 1}},
// .C_AND
{written={0}, read={0, 1}},
// .C_SUBW
{written={0}, read={0, 1}},
// .C_ADDW
{written={0}, read={0, 1}},
// .C_J
{side_effects={.CONTROL}},
// .C_JAL
{implicit_wr={.RA}, side_effects={.CONTROL}},
// .C_BEQZ
{read={0}, side_effects={.CONTROL}},
// .C_BNEZ
{read={0}, side_effects={.CONTROL}},
// .C_SLLI
{written={0}, read={0}},
// .C_LWSP
{written={0}, implicit_rd={.SP}, reads_mem=true},
// .C_LDSP
{written={0}, implicit_rd={.SP}, reads_mem=true},
// .C_SWSP
{read={0}, implicit_rd={.SP}, writes_mem=true},
// .C_SDSP
{read={0}, implicit_rd={.SP}, writes_mem=true},
// .C_FLDSP
{written={0}, implicit_rd={.SP}, reads_mem=true},
// .C_FSDSP
{read={0}, implicit_rd={.SP}, writes_mem=true},
// .C_JR
{read={0}, side_effects={.CONTROL}},
// .C_JALR
{read={0}, implicit_wr={.RA}, side_effects={.CONTROL}},
// .C_MV
{written={0}, read={1}},
// .C_ADD
{written={0}, read={0, 1}},
// .C_FLWSP
{written={0}, implicit_rd={.SP}, reads_mem=true},
// .C_FSWSP
{read={0}, implicit_rd={.SP}, writes_mem=true},
}
@(rodata)
ENCODE_RUNS := [lib.Mnemonic]lib.Encode_Run{
.INVALID = { 0, 0},

View File

@@ -28,4 +28,5 @@ main :: proc() {
w(TABLES + "riscv.idx_opcode.bin", raw(&DECODE_INDEX_OPCODE, size_of(DECODE_INDEX_OPCODE)))
w(TABLES + "riscv.idx_op_fp.bin", raw(&DECODE_INDEX_OP_FP, size_of(DECODE_INDEX_OP_FP)))
w(TABLES + "riscv.idx_rvc.bin", raw(&DECODE_INDEX_RVC, size_of(DECODE_INDEX_RVC)))
w(TABLES + "riscv.clobber_forms.bin", raw(&CLOBBER_FORMS, size_of(CLOBBER_FORMS)))
}

View File

@@ -0,0 +1,690 @@
package rexcode_riscv_tablegen
// Form couples one encoding shape with its architectural effects.
// `using encoding` keeps existing field access (form.opcode, form.ops,
// form.flags, ...) working unchanged when code moves from []Encoding to []Form.
Form :: struct {
using encoding: Encoding,
clobber: Clobber,
}
@(rodata)
INSTRUCTION_TABLE := [Mnemonic][]Form{
.INVALID = {},
// =========================================================================
// §1 RV32I / RV64I base
// =========================================================================
// Upper-immediate
.LUI = {
{{.LUI, {.GPR,.IMM20,.NONE,.NONE}, {.RD,.IMM_U,.NONE,.NONE}, 0x00000037, MASK_U, .I, {}}, {written={0}}},
},
.AUIPC = {
{{.AUIPC, {.GPR,.IMM20,.NONE,.NONE}, {.RD,.IMM_U,.NONE,.NONE}, 0x00000017, MASK_U, .I, {}}, {written={0}}},
},
// Jumps
.JAL = {
{{.JAL, {.GPR,.REL21,.NONE,.NONE}, {.RD,.IMM_J,.NONE,.NONE}, 0x0000006F, MASK_J, .I, {branch=true}}, {written={0}, side_effects={.CONTROL}}},
},
.JALR = {
{{.JALR, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00000067, MASK_OPCODE | MASK_FUNCT3, .I, {branch=true}}, {written={0}, read={1}, side_effects={.CONTROL}}},
},
// Branches (B-type)
.BEQ = {
{{.BEQ, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00000063, MASK_B, .I, {branch=true}}, {read={0, 1}, side_effects={.CONTROL}}},
},
.BNE = {
{{.BNE, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00001063, MASK_B, .I, {branch=true}}, {read={0, 1}, side_effects={.CONTROL}}},
},
.BLT = {
{{.BLT, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00004063, MASK_B, .I, {branch=true}}, {read={0, 1}, side_effects={.CONTROL}}},
},
.BGE = {
{{.BGE, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00005063, MASK_B, .I, {branch=true}}, {read={0, 1}, side_effects={.CONTROL}}},
},
.BLTU = {
{{.BLTU, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00006063, MASK_B, .I, {branch=true}}, {read={0, 1}, side_effects={.CONTROL}}},
},
.BGEU = {
{{.BGEU, {.GPR,.GPR,.REL13,.NONE}, {.RS1,.RS2,.IMM_B,.NONE}, 0x00007063, MASK_B, .I, {branch=true}}, {read={0, 1}, side_effects={.CONTROL}}},
},
// Loads (I-type)
.LB = {
{{.LB, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00000003, MASK_I, .I, {}}, {written={0}, read={1}, reads_mem=true}},
},
.LH = {
{{.LH, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00001003, MASK_I, .I, {}}, {written={0}, read={1}, reads_mem=true}},
},
.LW = {
{{.LW, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00002003, MASK_I, .I, {}}, {written={0}, read={1}, reads_mem=true}},
},
.LBU = {
{{.LBU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00004003, MASK_I, .I, {}}, {written={0}, read={1}, reads_mem=true}},
},
.LHU = {
{{.LHU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00005003, MASK_I, .I, {}}, {written={0}, read={1}, reads_mem=true}},
},
.LWU = {
{{.LWU, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00006003, MASK_I, .I, {rv64_only=true}}, {written={0}, read={1}, reads_mem=true}},
},
.LD = {
{{.LD, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00003003, MASK_I, .I, {rv64_only=true}}, {written={0}, read={1}, reads_mem=true}},
},
// Stores (S-type)
.SB = {
{{.SB, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00000023, MASK_S, .I, {}}, {read={0, 1}, writes_mem=true}},
},
.SH = {
{{.SH, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00001023, MASK_S, .I, {}}, {read={0, 1}, writes_mem=true}},
},
.SW = {
{{.SW, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00002023, MASK_S, .I, {}}, {read={0, 1}, writes_mem=true}},
},
.SD = {
{{.SD, {.GPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00003023, MASK_S, .I, {rv64_only=true}}, {read={0, 1}, writes_mem=true}},
},
// Integer reg-imm (I-type ALU)
.ADDI = {
{{.ADDI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00000013, MASK_I, .I, {}}, {written={0}, read={1}}},
},
.SLTI = {
{{.SLTI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00002013, MASK_I, .I, {}}, {written={0}, read={1}}},
},
.SLTIU = {
{{.SLTIU, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00003013, MASK_I, .I, {}}, {written={0}, read={1}}},
},
.XORI = {
{{.XORI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00004013, MASK_I, .I, {}}, {written={0}, read={1}}},
},
.ORI = {
{{.ORI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00006013, MASK_I, .I, {}}, {written={0}, read={1}}},
},
.ANDI = {
{{.ANDI, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x00007013, MASK_I, .I, {}}, {written={0}, read={1}}},
},
.SLLI = {
{{.SLLI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x00001013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .I, {}}, {written={0}, read={1}}},
},
.SRLI = {
{{.SRLI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x00005013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .I, {}}, {written={0}, read={1}}},
},
.SRAI = {
{{.SRAI, {.GPR,.GPR,.IMM6,.NONE}, {.RD,.RS1,.SHAMT6,.NONE}, 0x40005013, MASK_OPCODE | MASK_FUNCT3 | 0xFC000000, .I, {}}, {written={0}, read={1}}},
},
.ADDIW = {
{{.ADDIW, {.GPR,.GPR,.IMM12,.NONE}, {.RD,.RS1,.IMM_I,.NONE}, 0x0000001B, MASK_I, .I, {rv64_only=true}}, {written={0}, read={1}}},
},
.SLLIW = {
{{.SLLIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x0000101B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1}}},
},
.SRLIW = {
{{.SRLIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x0000501B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1}}},
},
.SRAIW = {
{{.SRAIW, {.GPR,.GPR,.IMM5,.NONE}, {.RD,.RS1,.SHAMT5,.NONE}, 0x4000501B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1}}},
},
// Integer reg-reg (R-type)
.ADD = {
{{.ADD, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00000033, MASK_R, .I, {}}, {written={0}, read={1, 2}}},
},
.SUB = {
{{.SUB, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40000033, MASK_R, .I, {}}, {written={0}, read={1, 2}}},
},
.SLL = {
{{.SLL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00001033, MASK_R, .I, {}}, {written={0}, read={1, 2}}},
},
.SLT = {
{{.SLT, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00002033, MASK_R, .I, {}}, {written={0}, read={1, 2}}},
},
.SLTU = {
{{.SLTU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00003033, MASK_R, .I, {}}, {written={0}, read={1, 2}}},
},
.XOR = {
{{.XOR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00004033, MASK_R, .I, {}}, {written={0}, read={1, 2}}},
},
.SRL = {
{{.SRL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00005033, MASK_R, .I, {}}, {written={0}, read={1, 2}}},
},
.SRA = {
{{.SRA, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x40005033, MASK_R, .I, {}}, {written={0}, read={1, 2}}},
},
.OR = {
{{.OR, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00006033, MASK_R, .I, {}}, {written={0}, read={1, 2}}},
},
.AND = {
{{.AND, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00007033, MASK_R, .I, {}}, {written={0}, read={1, 2}}},
},
.ADDW = {
{{.ADDW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000003B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1, 2}}},
},
.SUBW = {
{{.SUBW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x4000003B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1, 2}}},
},
.SLLW = {
{{.SLLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000103B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1, 2}}},
},
.SRLW = {
{{.SRLW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0000503B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1, 2}}},
},
.SRAW = {
{{.SRAW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x4000503B, MASK_R, .I, {rv64_only=true}}, {written={0}, read={1, 2}}},
},
// Memory ordering
.FENCE = {
{{.FENCE, {.FENCE_FLAGS,.FENCE_FLAGS,.NONE,.NONE}, {.FENCE_PRED,.FENCE_SUCC,.NONE,.NONE}, 0x0000000F, MASK_I, .I, {}}, {side_effects={.FENCE}}},
},
.FENCE_I = {
{{.FENCE_I, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x0000100F, 0xFFFFFFFF, .ZIFENCEI, {}}, {side_effects={.IFENCE}}},
},
// System
.ECALL = {
{{.ECALL, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00000073, 0xFFFFFFFF, .I, {branch=true}}, {side_effects={.TRAP, .CONTROL}}},
},
.EBREAK = {
{{.EBREAK, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x00100073, 0xFFFFFFFF, .I, {branch=true}}, {side_effects={.TRAP, .CONTROL}}},
},
// =========================================================================
// §2 Zicsr (CSR access) — csr operand (slot 1) marked r+w conservatively
// =========================================================================
.CSRRW = {
{{.CSRRW, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00001073, MASK_I, .ZICSR, {}}, {written={0, 1}, read={1, 2}}},
},
.CSRRS = {
{{.CSRRS, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00002073, MASK_I, .ZICSR, {}}, {written={0, 1}, read={1, 2}}},
},
.CSRRC = {
{{.CSRRC, {.GPR,.CSR,.GPR,.NONE}, {.RD,.CSR_FIELD,.RS1,.NONE}, 0x00003073, MASK_I, .ZICSR, {}}, {written={0, 1}, read={1, 2}}},
},
.CSRRWI = {
{{.CSRRWI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00005073, MASK_I, .ZICSR, {}}, {written={0, 1}, read={1}}},
},
.CSRRSI = {
{{.CSRRSI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00006073, MASK_I, .ZICSR, {}}, {written={0, 1}, read={1}}},
},
.CSRRCI = {
{{.CSRRCI, {.GPR,.CSR,.ZIMM5,.NONE}, {.RD,.CSR_FIELD,.ZIMM_FIELD,.NONE}, 0x00007073, MASK_I, .ZICSR, {}}, {written={0, 1}, read={1}}},
},
// =========================================================================
// §3 M extension — pure dataflow; no trap, no flags (incl. DIV/REM by 0)
// =========================================================================
.MUL = {
{{.MUL, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02000033, MASK_R, .M, {}}, {written={0}, read={1, 2}}},
},
.MULH = {
{{.MULH, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02001033, MASK_R, .M, {}}, {written={0}, read={1, 2}}},
},
.MULHSU = {
{{.MULHSU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02002033, MASK_R, .M, {}}, {written={0}, read={1, 2}}},
},
.MULHU = {
{{.MULHU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02003033, MASK_R, .M, {}}, {written={0}, read={1, 2}}},
},
.DIV = {
{{.DIV, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02004033, MASK_R, .M, {}}, {written={0}, read={1, 2}}},
},
.DIVU = {
{{.DIVU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02005033, MASK_R, .M, {}}, {written={0}, read={1, 2}}},
},
.REM = {
{{.REM, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02006033, MASK_R, .M, {}}, {written={0}, read={1, 2}}},
},
.REMU = {
{{.REMU, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02007033, MASK_R, .M, {}}, {written={0}, read={1, 2}}},
},
.MULW = {
{{.MULW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200003B, MASK_R, .M, {rv64_only=true}}, {written={0}, read={1, 2}}},
},
.DIVW = {
{{.DIVW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200403B, MASK_R, .M, {rv64_only=true}}, {written={0}, read={1, 2}}},
},
.DIVUW = {
{{.DIVUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200503B, MASK_R, .M, {rv64_only=true}}, {written={0}, read={1, 2}}},
},
.REMW = {
{{.REMW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200603B, MASK_R, .M, {rv64_only=true}}, {written={0}, read={1, 2}}},
},
.REMUW = {
{{.REMUW, {.GPR,.GPR,.GPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0200703B, MASK_R, .M, {rv64_only=true}}, {written={0}, read={1, 2}}},
},
// =========================================================================
// §4 A extension (atomics)
// =========================================================================
.LR_W = {
{{.LR_W, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_A,.NONE,.NONE}, 0x1000202F, 0xF9F0707F, .A, {}}, {written={0}, read={1}, reads_mem=true, side_effects={.ATOMIC, .RESERVATION}}},
},
.SC_W = {
{{.SC_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x1800202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, writes_mem=true, side_effects={.ATOMIC, .RESERVATION}}},
},
.AMOSWAP_W = {
{{.AMOSWAP_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0800202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOADD_W = {
{{.AMOADD_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOXOR_W = {
{{.AMOXOR_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x2000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOAND_W = {
{{.AMOAND_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x6000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOOR_W = {
{{.AMOOR_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x4000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOMIN_W = {
{{.AMOMIN_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x8000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOMAX_W = {
{{.AMOMAX_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xA000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOMINU_W = {
{{.AMOMINU_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xC000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOMAXU_W = {
{{.AMOMAXU_W, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xE000202F, 0xF800707F, .A, {}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.LR_D = {
{{.LR_D, {.GPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_A,.NONE,.NONE}, 0x1000302F, 0xF9F0707F, .A, {rv64_only=true}}, {written={0}, read={1}, reads_mem=true, side_effects={.ATOMIC, .RESERVATION}}},
},
.SC_D = {
{{.SC_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x1800302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, writes_mem=true, side_effects={.ATOMIC, .RESERVATION}}},
},
.AMOSWAP_D = {
{{.AMOSWAP_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0800302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOADD_D = {
{{.AMOADD_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x0000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOXOR_D = {
{{.AMOXOR_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x2000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOAND_D = {
{{.AMOAND_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x6000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOOR_D = {
{{.AMOOR_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x4000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOMIN_D = {
{{.AMOMIN_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0x8000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOMAX_D = {
{{.AMOMAX_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xA000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOMINU_D = {
{{.AMOMINU_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xC000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
.AMOMAXU_D = {
{{.AMOMAXU_D, {.GPR,.GPR,.MEM,.NONE}, {.RD,.RS2,.OFFSET_BASE_A,.NONE}, 0xE000302F, 0xF800707F, .A, {rv64_only=true}}, {written={0}, read={1, 2}, reads_mem=true, writes_mem=true, side_effects={.ATOMIC}}},
},
// =========================================================================
// §5 F extension (single-precision) — reads_frm == encoding fp_round
// =========================================================================
.FLW = {
{{.FLW, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00002007, MASK_I, .F, {}}, {written={0}, read={1}, reads_mem=true}},
},
.FSW = {
{{.FSW, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00002027, MASK_S, .F, {}}, {read={0, 1}, writes_mem=true}},
},
.FMADD_S = {
{{.FMADD_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x00000043, 0x0600007F, .F, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FMSUB_S = {
{{.FMSUB_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x00000047, 0x0600007F, .F, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FNMSUB_S = {
{{.FNMSUB_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0000004B, 0x0600007F, .F, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FNMADD_S = {
{{.FNMADD_S, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0000004F, 0x0600007F, .F, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FADD_S = {
{{.FADD_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x00000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FSUB_S = {
{{.FSUB_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x08000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FMUL_S = {
{{.FMUL_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x10000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FDIV_S = {
{{.FDIV_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x18000053, MASK_OPCODE | MASK_FUNCT7, .F, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .DZ, .OF, .UF, .NX}, reads_frm=true}},
},
.FSQRT_S = {
{{.FSQRT_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x58000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}},
},
.FSGNJ_S = {
{{.FSGNJ_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20000053, MASK_R, .F, {}}, {written={0}, read={1, 2}}},
},
.FSGNJN_S = {
{{.FSGNJN_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20001053, MASK_R, .F, {}}, {written={0}, read={1, 2}}},
},
.FSGNJX_S = {
{{.FSGNJX_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x20002053, MASK_R, .F, {}}, {written={0}, read={1, 2}}},
},
.FMIN_S = {
{{.FMIN_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28000053, MASK_R, .F, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}},
},
.FMAX_S = {
{{.FMAX_S, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x28001053, MASK_R, .F, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}},
},
.FCVT_W_S = {
{{.FCVT_W_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}},
},
.FCVT_WU_S = {
{{.FCVT_WU_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}},
},
.FCVT_L_S = {
{{.FCVT_L_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}},
},
.FCVT_LU_S = {
{{.FCVT_LU_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC0300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}},
},
.FCVT_S_W = {
{{.FCVT_S_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}},
},
.FCVT_S_WU = {
{{.FCVT_S_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}},
},
.FCVT_S_L = {
{{.FCVT_S_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}},
},
.FCVT_S_LU = {
{{.FCVT_S_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD0300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .F, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}},
},
.FMV_X_W = {
{{.FMV_X_W, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .F, {}}, {written={0}, read={1}}},
},
.FMV_W_X = {
{{.FMV_W_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF0000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .F, {}}, {written={0}, read={1}}},
},
.FCLASS_S = {
{{.FCLASS_S, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE0001053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .F, {}}, {written={0}, read={1}}},
},
.FEQ_S = {
{{.FEQ_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0002053, MASK_R, .F, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}},
},
.FLT_S = {
{{.FLT_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0001053, MASK_R, .F, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}},
},
.FLE_S = {
{{.FLE_S, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA0000053, MASK_R, .F, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}},
},
// =========================================================================
// §6 D extension (double-precision)
// =========================================================================
.FLD = {
{{.FLD, {.FPR,.MEM,.NONE,.NONE}, {.RD,.OFFSET_BASE_I,.NONE,.NONE}, 0x00003007, MASK_I, .D, {}}, {written={0}, read={1}, reads_mem=true}},
},
.FSD = {
{{.FSD, {.FPR,.MEM,.NONE,.NONE}, {.RS2,.OFFSET_BASE_S,.NONE,.NONE}, 0x00003027, MASK_S, .D, {}}, {read={0, 1}, writes_mem=true}},
},
.FMADD_D = {
{{.FMADD_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x02000043, 0x0600007F, .D, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FMSUB_D = {
{{.FMSUB_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x02000047, 0x0600007F, .D, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FNMSUB_D = {
{{.FNMSUB_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0200004B, 0x0600007F, .D, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FNMADD_D = {
{{.FNMADD_D, {.FPR,.FPR,.FPR,.FPR}, {.RD,.RS1,.RS2,.RS3}, 0x0200004F, 0x0600007F, .D, {fp_round=true}}, {written={0}, read={1, 2, 3}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FADD_D = {
{{.FADD_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x02000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FSUB_D = {
{{.FSUB_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x0A000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FMUL_D = {
{{.FMUL_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x12000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FDIV_D = {
{{.FDIV_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x1A000053, MASK_OPCODE | MASK_FUNCT7, .D, {fp_round=true}}, {written={0}, read={1, 2}, fflags_wr={.NV, .DZ, .OF, .UF, .NX}, reads_frm=true}},
},
.FSQRT_D = {
{{.FSQRT_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x5A000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}},
},
.FSGNJ_D = {
{{.FSGNJ_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22000053, MASK_R, .D, {}}, {written={0}, read={1, 2}}},
},
.FSGNJN_D = {
{{.FSGNJN_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22001053, MASK_R, .D, {}}, {written={0}, read={1, 2}}},
},
.FSGNJX_D = {
{{.FSGNJX_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x22002053, MASK_R, .D, {}}, {written={0}, read={1, 2}}},
},
.FMIN_D = {
{{.FMIN_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2A000053, MASK_R, .D, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}},
},
.FMAX_D = {
{{.FMAX_D, {.FPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0x2A001053, MASK_R, .D, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}},
},
.FCVT_S_D = {
{{.FCVT_S_D, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x40100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .OF, .UF, .NX}, reads_frm=true}},
},
.FCVT_D_S = {
{{.FCVT_D_S, {.FPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0x42000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV}, reads_frm=true}},
},
.FCVT_W_D = {
{{.FCVT_W_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}},
},
.FCVT_WU_D = {
{{.FCVT_WU_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}},
},
.FCVT_L_D = {
{{.FCVT_L_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}},
},
.FCVT_LU_D = {
{{.FCVT_LU_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xC2300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NV, .NX}, reads_frm=true}},
},
// FCVT_D_W / FCVT_D_WU are always exact (32-bit int fits a double), so no
// fflags — but reads_frm follows the fp_round flag for class-uniformity.
.FCVT_D_W = {
{{.FCVT_D_W, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}}, {written={0}, read={1}, reads_frm=true}},
},
.FCVT_D_WU = {
{{.FCVT_D_WU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2100053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true}}, {written={0}, read={1}, reads_frm=true}},
},
.FCVT_D_L = {
{{.FCVT_D_L, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2200053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}},
},
.FCVT_D_LU = {
{{.FCVT_D_LU, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xD2300053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2, .D, {fp_round=true, rv64_only=true}}, {written={0}, read={1}, fflags_wr={.NX}, reads_frm=true}},
},
.FMV_X_D = {
{{.FMV_X_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .D, {rv64_only=true}}, {written={0}, read={1}}},
},
.FMV_D_X = {
{{.FMV_D_X, {.FPR,.GPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xF2000053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .D, {rv64_only=true}}, {written={0}, read={1}}},
},
.FCLASS_D = {
{{.FCLASS_D, {.GPR,.FPR,.NONE,.NONE}, {.RD,.RS1,.NONE,.NONE}, 0xE2001053, MASK_OPCODE | MASK_FUNCT7 | MASK_RS2 | MASK_FUNCT3, .D, {}}, {written={0}, read={1}}},
},
.FEQ_D = {
{{.FEQ_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2002053, MASK_R, .D, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}},
},
.FLT_D = {
{{.FLT_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2001053, MASK_R, .D, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}},
},
.FLE_D = {
{{.FLE_D, {.GPR,.FPR,.FPR,.NONE}, {.RD,.RS1,.RS2,.NONE}, 0xA2000053, MASK_R, .D, {}}, {written={0}, read={1, 2}, fflags_wr={.NV}}},
},
// =========================================================================
// C extension: Quadrant 0 (op = 00)
// =========================================================================
.C_ADDI4SPN = {
{{.C_ADDI4SPN, {.GPR_C, .GPR_SP, .IMM_C8U, .NONE}, {.C_RD_PRIMED, .NONE, .C_IMM_CIW, .NONE}, 0x0000, 0xE003, .C, {}}, {written={0}, read={1}}},
},
.C_FLD = {
{{.C_FLD, {.FPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0x2000, 0xE003, .D, {}}, {written={0}, read={1}, reads_mem=true}},
},
.C_LW = {
{{.C_LW, {.GPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0x4000, 0xE003, .C, {}}, {written={0}, read={1}, reads_mem=true}},
},
.C_LD = {
{{.C_LD, {.GPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0x6000, 0xE003, .C, {rv64_only=true}}, {written={0}, read={1}, reads_mem=true}},
},
.C_FSD = {
{{.C_FSD, {.FPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0xA000, 0xE003, .D, {}}, {read={0, 1}, writes_mem=true}},
},
.C_SW = {
{{.C_SW, {.GPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0xC000, 0xE003, .C, {}}, {read={0, 1}, writes_mem=true}},
},
.C_SD = {
{{.C_SD, {.GPR_C, .MEM_C_D, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_D, .NONE, .NONE}, 0xE000, 0xE003, .C, {rv64_only=true}}, {read={0, 1}, writes_mem=true}},
},
// C.FLW / C.FSW — RV32-only, share the C.LD / C.SD slots
.C_FLW = {
{{.C_FLW, {.FPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RD_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0x6000, 0xE003, .F, {rv32_only=true}}, {written={0}, read={1}, reads_mem=true}},
},
.C_FSW = {
{{.C_FSW, {.FPR_C, .MEM_C_W, .NONE, .NONE}, {.C_RS2_PRIMED, .C_OFFSET_BASE_W, .NONE, .NONE}, 0xE000, 0xE003, .F, {rv32_only=true}}, {read={0, 1}, writes_mem=true}},
},
// =========================================================================
// C extension: Quadrant 1 (op = 01)
// =========================================================================
.C_NOP = {
{{.C_NOP, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x0001, 0xFFFF, .C, {}}, {}},
},
.C_ADDI = {
{{.C_ADDI, {.GPR_NONZERO, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_S, .NONE, .NONE}, 0x0001, 0xE003, .C, {}}, {written={0}, read={0}}},
},
.C_JAL = {
{{.C_JAL, {.REL12, .NONE, .NONE, .NONE}, {.C_BRANCH12, .NONE, .NONE, .NONE}, 0x2001, 0xE003, .C, {rv32_only=true, branch=true}}, {implicit_wr={.RA}, side_effects={.CONTROL}}},
},
.C_ADDIW = {
{{.C_ADDIW, {.GPR_NONZERO, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_S, .NONE, .NONE}, 0x2001, 0xE003, .C, {rv64_only=true}}, {written={0}, read={0}}},
},
.C_LI = {
{{.C_LI, {.GPR_NONZERO, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_S, .NONE, .NONE}, 0x4001, 0xE003, .C, {}}, {written={0}}},
},
.C_ADDI16SP = {
{{.C_ADDI16SP, {.GPR_SP, .IMM_C10S, .NONE, .NONE}, {.NONE, .C_IMM_ADDI16SP, .NONE, .NONE}, 0x6101, 0xEF83, .C, {}}, {written={0}, read={0}}},
},
.C_LUI = {
{{.C_LUI, {.GPR_NONZERO, .IMM_C18S, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_LUI, .NONE, .NONE}, 0x6001, 0xE003, .C, {}}, {written={0}}},
},
.C_SRLI = {
{{.C_SRLI, {.GPR_C, .IMM_C6U, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_IMM_CI_U, .NONE, .NONE}, 0x8001, 0xEC03, .C, {}}, {written={0}, read={0}}},
},
.C_SRAI = {
{{.C_SRAI, {.GPR_C, .IMM_C6U, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_IMM_CI_U, .NONE, .NONE}, 0x8401, 0xEC03, .C, {}}, {written={0}, read={0}}},
},
.C_ANDI = {
{{.C_ANDI, {.GPR_C, .IMM_C6S, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_IMM_CI_S, .NONE, .NONE}, 0x8801, 0xEC03, .C, {}}, {written={0}, read={0}}},
},
.C_SUB = {
{{.C_SUB, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C01, 0xFC63, .C, {}}, {written={0}, read={0, 1}}},
},
.C_XOR = {
{{.C_XOR, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C21, 0xFC63, .C, {}}, {written={0}, read={0, 1}}},
},
.C_OR = {
{{.C_OR, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C41, 0xFC63, .C, {}}, {written={0}, read={0, 1}}},
},
.C_AND = {
{{.C_AND, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x8C61, 0xFC63, .C, {}}, {written={0}, read={0, 1}}},
},
.C_SUBW = {
{{.C_SUBW, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x9C01, 0xFC63, .C, {rv64_only=true}}, {written={0}, read={0, 1}}},
},
.C_ADDW = {
{{.C_ADDW, {.GPR_C, .GPR_C, .NONE, .NONE}, {.C_RD_RS1_PRIMED, .C_RS2_PRIMED, .NONE, .NONE}, 0x9C21, 0xFC63, .C, {rv64_only=true}}, {written={0}, read={0, 1}}},
},
.C_J = {
{{.C_J, {.REL12, .NONE, .NONE, .NONE}, {.C_BRANCH12, .NONE, .NONE, .NONE}, 0xA001, 0xE003, .C, {branch=true}}, {side_effects={.CONTROL}}},
},
.C_BEQZ = {
{{.C_BEQZ, {.GPR_C, .REL9, .NONE, .NONE}, {.C_RS1_PRIMED, .C_BRANCH9, .NONE, .NONE}, 0xC001, 0xE003, .C, {branch=true}}, {read={0}, side_effects={.CONTROL}}},
},
.C_BNEZ = {
{{.C_BNEZ, {.GPR_C, .REL9, .NONE, .NONE}, {.C_RS1_PRIMED, .C_BRANCH9, .NONE, .NONE}, 0xE001, 0xE003, .C, {branch=true}}, {read={0}, side_effects={.CONTROL}}},
},
// =========================================================================
// C extension: Quadrant 2 (op = 10)
// =========================================================================
.C_SLLI = {
{{.C_SLLI, {.GPR_NONZERO, .IMM_C6U, .NONE, .NONE}, {.C_RD_RS1, .C_IMM_CI_U, .NONE, .NONE}, 0x0002, 0xE003, .C, {}}, {written={0}, read={0}}},
},
.C_FLDSP = {
{{.C_FLDSP, {.FPR, .MEM_C_SP_D, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_D, .NONE, .NONE}, 0x2002, 0xE003, .D, {}}, {written={0}, implicit_rd={.SP}, reads_mem=true}},
},
.C_LWSP = {
{{.C_LWSP, {.GPR_NONZERO, .MEM_C_SP_W, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_W, .NONE, .NONE}, 0x4002, 0xE003, .C, {}}, {written={0}, implicit_rd={.SP}, reads_mem=true}},
},
.C_LDSP = {
{{.C_LDSP, {.GPR_NONZERO, .MEM_C_SP_D, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_D, .NONE, .NONE}, 0x6002, 0xE003, .C, {rv64_only=true}}, {written={0}, implicit_rd={.SP}, reads_mem=true}},
},
.C_JR = {
{{.C_JR, {.GPR_NONZERO, .NONE, .NONE, .NONE}, {.C_RD_RS1, .NONE, .NONE, .NONE}, 0x8002, 0xF07F, .C, {branch=true}}, {read={0}, side_effects={.CONTROL}}},
},
.C_MV = {
{{.C_MV, {.GPR_NONZERO, .GPR_NONZERO, .NONE, .NONE}, {.C_RD_RS1, .C_RS2, .NONE, .NONE}, 0x8002, 0xF003, .C, {}}, {written={0}, read={1}}},
},
.C_EBREAK = {
{{.C_EBREAK, {.NONE,.NONE,.NONE,.NONE}, {.NONE,.NONE,.NONE,.NONE}, 0x9002, 0xFFFF, .C, {}}, {side_effects={.TRAP, .CONTROL}}},
},
.C_JALR = {
{{.C_JALR, {.GPR_NONZERO, .NONE, .NONE, .NONE}, {.C_RD_RS1, .NONE, .NONE, .NONE}, 0x9002, 0xF07F, .C, {branch=true}}, {read={0}, implicit_wr={.RA}, side_effects={.CONTROL}}},
},
.C_ADD = {
{{.C_ADD, {.GPR_NONZERO, .GPR_NONZERO, .NONE, .NONE}, {.C_RD_RS1, .C_RS2, .NONE, .NONE}, 0x9002, 0xF003, .C, {}}, {written={0}, read={0, 1}}},
},
.C_FSDSP = {
{{.C_FSDSP, {.FPR, .MEM_C_SP_D, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_D, .NONE, .NONE}, 0xA002, 0xE003, .D, {}}, {read={0}, implicit_rd={.SP}, writes_mem=true}},
},
.C_SWSP = {
{{.C_SWSP, {.GPR, .MEM_C_SP_W, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_W, .NONE, .NONE}, 0xC002, 0xE003, .C, {}}, {read={0}, implicit_rd={.SP}, writes_mem=true}},
},
.C_SDSP = {
{{.C_SDSP, {.GPR, .MEM_C_SP_D, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_D, .NONE, .NONE}, 0xE002, 0xE003, .C, {rv64_only=true}}, {read={0}, implicit_rd={.SP}, writes_mem=true}},
},
// C.FLWSP / C.FSWSP — RV32-only, share the C.LDSP / C.SDSP slots
.C_FLWSP = {
{{.C_FLWSP, {.FPR, .MEM_C_SP_W, .NONE, .NONE}, {.C_RD_RS1, .C_SP_OFFSET_W, .NONE, .NONE}, 0x6002, 0xE003, .F, {rv32_only=true}}, {written={0}, implicit_rd={.SP}, reads_mem=true}},
},
.C_FSWSP = {
{{.C_FSWSP, {.FPR, .MEM_C_SP_W, .NONE, .NONE}, {.C_RS2, .C_IMM_CSS_W, .NONE, .NONE}, 0xE002, 0xE003, .F, {rv32_only=true}}, {read={0}, implicit_rd={.SP}, writes_mem=true}},
},
}

View File

@@ -39,26 +39,34 @@ Decode_Index :: struct #packed {
count: u16,
}
#assert(size_of(Decode_Index) == 4)
// -----------------------------------------------------------------------------
// Loaded tables (rodata, embedded from tables/*.bin at compile time)
// -----------------------------------------------------------------------------
@(rodata) ENCODE_FORMS := #load("tables/riscv.encode_forms.bin", []Encoding)
@(rodata) ENCODE_RUNS := #load("tables/riscv.encode_runs.bin", []Encode_Run)
@(rodata) DECODE_ENTRIES := #load("tables/riscv.entries.bin", []Decode_Entry)
@(rodata) DECODE_INDEX_OPCODE := #load("tables/riscv.idx_opcode.bin", []Decode_Index)
@(rodata) DECODE_INDEX_OP_FP := #load("tables/riscv.idx_op_fp.bin", []Decode_Index)
@(rodata) DECODE_INDEX_RVC := #load("tables/riscv.idx_rvc.bin", []Decode_Index)
@(rodata) ENCODE_FORMS := #load("tables/riscv.encode_forms.bin", []Encoding)
@(rodata) ENCODE_RUNS := #load("tables/riscv.encode_runs.bin", []Encode_Run)
@(rodata) DECODE_ENTRIES := #load("tables/riscv.entries.bin", []Decode_Entry)
@(rodata) DECODE_INDEX_OPCODE := #load("tables/riscv.idx_opcode.bin", []Decode_Index)
@(rodata) DECODE_INDEX_OP_FP := #load("tables/riscv.idx_op_fp.bin", []Decode_Index)
@(rodata) DECODE_INDEX_RVC := #load("tables/riscv.idx_rvc.bin", []Decode_Index)
@(rodata) CLOBBER_FORMS := #load("tables/riscv.clobber_forms.bin", []Clobber)
// -----------------------------------------------------------------------------
// Accessors
// -----------------------------------------------------------------------------
// Per-mnemonic encode forms: the run of ENCODE_FORMS belonging to `m`.
// Per-mnemonic encode forms: the run of ENCODE_FORMS belonging to ` + "`m`" + `.
// Replaces the old ENCODING_TABLE[m] slice; the returned view is into rodata.
@(private, require_results)
encoding_forms :: #force_inline proc "contextless" (m: Mnemonic) -> []Encoding {
r := ENCODE_RUNS[u16(m)]
return ENCODE_FORMS[r.start:][:r.count]
}
// Per-mnemonic clobber forms: the run of CLOBBER_FORMS belonging to ` + "`m`" + `.
// Replaces the old ENCODING_TABLE[m] slice; the returned view is into rodata.
@(private, require_results)
clobber_forms :: #force_inline proc "contextless" (m: Mnemonic) -> []Clobber {
r := ENCODE_RUNS[u16(m)]
return CLOBBER_FORMS[r.start:][:r.count]
}