// Copyright (c) 2026 Petr Balvín (https://petrbalvin.org) // SPDX-License-Identifier: BSD-3-Clause package asm // RISC-V register encoding: maps register names to their 5-bit numbers. // The Go assembler uses the standard RISC-V ABI naming. // riscvRegNum returns the 5-bit register number for a RISC-V register name. // Returns -1 if the register is not recognized. func riscvRegNum(name string) int { switch name { // Numbered integer registers. case "X0", "ZERO": return 0 case "X1", "RA": return 1 case "X2", "SP": return 2 case "X3", "GP": return 3 case "X4", "TP": return 4 case "X5", "T0", "LR": return 5 case "X6", "T1", "TMP": return 6 case "X7", "T2": return 7 case "X8", "S0", "FP": return 8 case "X9", "S1": return 9 case "X10", "A0": return 10 case "X11", "A1": return 11 case "X12", "A2": return 12 case "X13", "A3": return 13 case "X14", "A4": return 14 case "X15", "A5": return 15 case "X16", "A6": return 16 case "X17", "A7": return 17 case "X18", "S2": return 18 case "X19", "S3": return 19 case "X20", "S4": return 20 case "X21", "S5": return 21 case "X22", "S6": return 22 case "X23", "S7": return 23 case "X24", "S8": return 24 case "X25", "S9": return 25 case "X26", "S10": return 26 case "X27", "S11": return 27 case "X28", "T3": return 28 case "X29", "T4": return 29 case "X30", "T5": return 30 case "X31", "T6": return 31 // Floating-point registers (F0-F31). case "F0", "FT0": return 0 case "F1", "FT1": return 1 case "F2", "FT2": return 2 case "F3", "FT3": return 3 case "F4", "FT4": return 4 case "F5", "FT5": return 5 case "F6", "FT6": return 6 case "F7", "FT7": return 7 case "F8", "FS0": return 8 case "F9", "FS1": return 9 case "F10", "FA0": return 10 case "F11", "FA1": return 11 case "F12", "FA2": return 12 case "F13", "FA3": return 13 case "F14", "FA4": return 14 case "F15", "FA5": return 15 case "F16", "FA6": return 16 case "F17", "FA7": return 17 case "F18", "FS2": return 18 case "F19", "FS3": return 19 case "F20", "FS4": return 20 case "F21", "FS5": return 21 case "F22", "FS6": return 22 case "F23", "FS7": return 23 case "F24", "FS8": return 24 case "F25", "FS9": return 25 case "F26", "FS10": return 26 case "F27", "FS11": return 27 case "F28", "FT8": return 28 case "F29", "FT9": return 29 case "F30", "FT10": return 30 case "F31", "FT11": return 31 default: return -1 } } // RISC-V instruction encoding parameters. type riscvEnc struct { opcode uint32 // bits [6:0] funct3 uint32 // bits [14:12] funct7 uint32 // bits [31:25] } // riscvInstrTable maps RISC-V mnemonics to their encoding. var riscvInstrTable = map[string]riscvEnc{ // RV64I — R-type arithmetic/logic. "ADD": {0x33, 0x0, 0x00}, "SUB": {0x33, 0x0, 0x20}, "SLL": {0x33, 0x1, 0x00}, "SLT": {0x33, 0x2, 0x00}, "SLTU": {0x33, 0x3, 0x00}, "XOR": {0x33, 0x4, 0x00}, "SRL": {0x33, 0x5, 0x00}, "SRA": {0x33, 0x5, 0x20}, "OR": {0x33, 0x6, 0x00}, "AND": {0x33, 0x7, 0x00}, // RV64I — 32-bit variants (W suffix). "ADDW": {0x3B, 0x0, 0x00}, "SUBW": {0x3B, 0x0, 0x20}, "SLLW": {0x3B, 0x1, 0x00}, "SRLW": {0x3B, 0x5, 0x00}, "SRAW": {0x3B, 0x5, 0x20}, // RV64M — multiply/divide. "MUL": {0x33, 0x0, 0x01}, "MULH": {0x33, 0x1, 0x01}, "MULHSU": {0x33, 0x2, 0x01}, "MULHU": {0x33, 0x3, 0x01}, "DIV": {0x33, 0x4, 0x01}, "DIVU": {0x33, 0x5, 0x01}, "REM": {0x33, 0x6, 0x01}, "REMU": {0x33, 0x7, 0x01}, // RV64M — 32-bit variants. "MULW": {0x3B, 0x0, 0x01}, "DIVW": {0x3B, 0x4, 0x01}, "DIVUW": {0x3B, 0x5, 0x01}, "REMW": {0x3B, 0x6, 0x01}, "REMUW": {0x3B, 0x7, 0x01}, // RV64I — I-type arithmetic. "ADDI": {0x13, 0x0, 0x00}, "ADDIW": {0x1B, 0x0, 0x00}, "SLTI": {0x13, 0x2, 0x00}, "SLTIU": {0x13, 0x3, 0x00}, "XORI": {0x13, 0x4, 0x00}, "ORI": {0x13, 0x6, 0x00}, "ANDI": {0x13, 0x7, 0x00}, // Loads (I-type). "LB": {0x03, 0x0, 0x00}, "LH": {0x03, 0x1, 0x00}, "LW": {0x03, 0x2, 0x00}, "LD": {0x03, 0x3, 0x00}, "LBU": {0x03, 0x4, 0x00}, "LHU": {0x03, 0x5, 0x00}, "LWU": {0x03, 0x6, 0x00}, // Stores (S-type). "SB": {0x23, 0x0, 0x00}, "SH": {0x23, 0x1, 0x00}, "SW": {0x23, 0x2, 0x00}, "SD": {0x23, 0x3, 0x00}, // Branches (B-type). "BEQ": {0x63, 0x0, 0x00}, "BNE": {0x63, 0x1, 0x00}, "BLT": {0x63, 0x4, 0x00}, "BGE": {0x63, 0x5, 0x00}, "BLTU": {0x63, 0x6, 0x00}, "BGEU": {0x63, 0x7, 0x00}, // U-type. "LUI": {0x37, 0x0, 0x00}, "AUIPC": {0x17, 0x0, 0x00}, // System. "ECALL": {0x73, 0x0, 0x00}, "EBREAK": {0x73, 0x0, 0x00}, "FENCE": {0x0F, 0x0, 0x00}, } // riscvRType encodes an R-type instruction: funct7 | rs2 | rs1 | funct3 | rd | opcode. func riscvRType(enc riscvEnc, rd, rs1, rs2 int) uint32 { return (enc.funct7 << 25) | (uint32(rs2) << 20) | (uint32(rs1) << 15) | (enc.funct3 << 12) | (uint32(rd) << 7) | enc.opcode } // riscvIType encodes an I-type instruction: imm[11:0] | rs1 | funct3 | rd | opcode. func riscvIType(enc riscvEnc, rd, rs1 int, imm int32) uint32 { return (uint32(imm&0xFFF) << 20) | (uint32(rs1) << 15) | (enc.funct3 << 12) | (uint32(rd) << 7) | enc.opcode } // riscvSType encodes an S-type instruction: imm[11:5] | rs2 | rs1 | funct3 | imm[4:0] | opcode. func riscvSType(enc riscvEnc, rs1, rs2 int, imm int32) uint32 { immU := uint32(imm) & 0xFFF return ((immU >> 5) << 25) | (uint32(rs2) << 20) | (uint32(rs1) << 15) | (enc.funct3 << 12) | ((immU & 0x1F) << 7) | enc.opcode } // riscvBType encodes a B-type instruction (branches). func riscvBType(enc riscvEnc, rs1, rs2 int, offset int32) uint32 { imm := uint32(offset) & 0x1FFE // bits [12:1], bit 0 is always 0 return (((imm >> 12) & 1) << 31) | // imm[12] (((imm >> 5) & 0x3F) << 25) | // imm[10:5] (uint32(rs2) << 20) | (uint32(rs1) << 15) | (enc.funct3 << 12) | (((imm >> 1) & 0xF) << 8) | // imm[4:1] (((imm >> 11) & 1) << 7) | // imm[11] enc.opcode } // riscvUType encodes a U-type instruction: imm[31:12] | rd | opcode. func riscvUType(enc riscvEnc, rd int, imm int32) uint32 { return (uint32(imm) & 0xFFFFF000) | (uint32(rd) << 7) | enc.opcode } // riscvJType encodes a J-type instruction (JAL). func riscvJType(rd int, offset int32) uint32 { imm := uint32(offset) & 0x1FFFFE // bits [20:1] return (((imm >> 20) & 1) << 31) | // imm[20] (((imm >> 1) & 0x3FF) << 21) | // imm[10:1] (((imm >> 11) & 1) << 20) | // imm[11] (((imm >> 12) & 0xFF) << 12) | // imm[19:12] (uint32(rd) << 7) | 0x6F // JAL opcode }