101 lines
4.9 KiB
Go
101 lines
4.9 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|||
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
||
|
|
|
||
|
|
package arch
|
||
|
|
|
||
|
|
import "fmt"
|
||
|
|
|
||
|
|
func buildRISCV() *Table {
|
||
|
|
return newTable(RISCV, riscvRegisters(), relaxCounts(mergedInstrs(riscvSummaries(), commonGeneratedInstrs, riscvGeneratedInstrs)))
|
||
|
|
}
|
||
|
|
|
||
|
|
func riscvSummaries() map[string]Instr { return toMap(riscvCurated()) }
|
||
|
|
|
||
|
|
// riscvRegisters builds the RISC-V register file: the numbered integer (X) and
|
||
|
|
// floating-point (F) registers plus their standard ABI aliases.
|
||
|
|
func riscvRegisters() []Register {
|
||
|
|
var regs []Register
|
||
|
|
add := func(name string, class RegClass, desc string) {
|
||
|
|
regs = append(regs, Register{Name: name, Class: class, Desc: desc})
|
||
|
|
}
|
||
|
|
for i := 0; i <= 31; i++ {
|
||
|
|
add(fmt.Sprintf("X%d", i), GPR, "integer register")
|
||
|
|
}
|
||
|
|
for i := 0; i <= 31; i++ {
|
||
|
|
add(fmt.Sprintf("F%d", i), Float, "floating-point register")
|
||
|
|
}
|
||
|
|
// Integer ABI aliases.
|
||
|
|
for _, n := range []string{"ZERO", "RA", "SP", "GP", "TP", "FP", "LR", "TMP"} {
|
||
|
|
add(n, GPR, "integer ABI alias")
|
||
|
|
}
|
||
|
|
for i := 0; i <= 6; i++ {
|
||
|
|
add(fmt.Sprintf("T%d", i), GPR, "temporary")
|
||
|
|
}
|
||
|
|
for i := 0; i <= 11; i++ {
|
||
|
|
add(fmt.Sprintf("S%d", i), GPR, "saved register")
|
||
|
|
}
|
||
|
|
for i := 0; i <= 7; i++ {
|
||
|
|
add(fmt.Sprintf("A%d", i), GPR, "argument/result register")
|
||
|
|
}
|
||
|
|
// Floating-point ABI aliases.
|
||
|
|
for i := 0; i <= 11; i++ {
|
||
|
|
add(fmt.Sprintf("FT%d", i), Float, "FP temporary")
|
||
|
|
}
|
||
|
|
for i := 0; i <= 11; i++ {
|
||
|
|
add(fmt.Sprintf("FS%d", i), Float, "FP saved register")
|
||
|
|
}
|
||
|
|
for i := 0; i <= 7; i++ {
|
||
|
|
add(fmt.Sprintf("FA%d", i), Float, "FP argument/result register")
|
||
|
|
}
|
||
|
|
return regs
|
||
|
|
}
|
||
|
|
|
||
|
|
// riscvCurated is a hand-written subset of common RISC-V instructions carrying
|
||
|
|
// summaries. The authoritative, complete set is riscvGeneratedInstrs.
|
||
|
|
func riscvCurated() []Instr {
|
||
|
|
return []Instr{
|
||
|
|
ic("ADD", "Integer add", 3, 3), ic("ADDI", "Add immediate", 3, 3),
|
||
|
|
ic("ADDIW", "Add immediate (32-bit)", 3, 3), ic("ADDW", "Add (32-bit)", 3, 3),
|
||
|
|
ic("SUB", "Integer subtract", 3, 3), ic("SUBW", "Subtract (32-bit)", 3, 3),
|
||
|
|
ic("AND", "Bitwise AND", 3, 3), ic("ANDI", "AND immediate", 3, 3),
|
||
|
|
ic("OR", "Bitwise OR", 3, 3), ic("ORI", "OR immediate", 3, 3),
|
||
|
|
ic("XOR", "Bitwise XOR", 3, 3), ic("XORI", "XOR immediate", 3, 3),
|
||
|
|
ic("SLL", "Shift left logical", 3, 3), ic("SLLI", "Shift left logical immediate", 3, 3),
|
||
|
|
ic("SRL", "Shift right logical", 3, 3), ic("SRLI", "Shift right logical immediate", 3, 3),
|
||
|
|
ic("SRA", "Shift right arithmetic", 3, 3), ic("SRAI", "Shift right arithmetic immediate", 3, 3),
|
||
|
|
ic("SLT", "Set if less than", 3, 3), ic("SLTI", "Set if less than immediate", 3, 3),
|
||
|
|
ic("SLTU", "Set if less than unsigned", 3, 3), ic("SLTIU", "Set if less than unsigned immediate", 3, 3),
|
||
|
|
ic("MUL", "Multiply", 3, 3), ic("MULH", "Multiply high", 3, 3),
|
||
|
|
ic("MULHU", "Multiply high unsigned", 3, 3), ic("MULHSU", "Multiply high signed/unsigned", 3, 3),
|
||
|
|
ic("DIV", "Divide", 3, 3), ic("DIVU", "Divide unsigned", 3, 3),
|
||
|
|
ic("REM", "Remainder", 3, 3), ic("REMU", "Remainder unsigned", 3, 3),
|
||
|
|
ic("MULW", "Multiply (32-bit)", 3, 3), ic("DIVW", "Divide (32-bit)", 3, 3),
|
||
|
|
ic("LB", "Load byte", 2, 2), ic("LBU", "Load byte unsigned", 2, 2),
|
||
|
|
ic("LH", "Load halfword", 2, 2), ic("LHU", "Load halfword unsigned", 2, 2),
|
||
|
|
ic("LW", "Load word", 2, 2), ic("LWU", "Load word unsigned", 2, 2),
|
||
|
|
ic("LD", "Load doubleword", 2, 2),
|
||
|
|
ic("SB", "Store byte", 2, 2), ic("SH", "Store halfword", 2, 2),
|
||
|
|
ic("SW", "Store word", 2, 2), ic("SD", "Store doubleword", 2, 2),
|
||
|
|
ic("LUI", "Load upper immediate", 2, 2), ic("AUIPC", "Add upper immediate to PC", 2, 2),
|
||
|
|
ic("BEQ", "Branch if equal", 3, 3), ic("BNE", "Branch if not equal", 3, 3),
|
||
|
|
ic("BLT", "Branch if less than", 3, 3), ic("BGE", "Branch if greater or equal", 3, 3),
|
||
|
|
ic("BLTU", "Branch if less than unsigned", 3, 3), ic("BGEU", "Branch if greater or equal unsigned", 3, 3),
|
||
|
|
ic("JAL", "Jump and link", 1, 2), ic("JALR", "Jump and link register", 1, 3),
|
||
|
|
i("JMP", "Unconditional jump"), i("CALL", "Call subroutine"),
|
||
|
|
ic("RET", "Return", 0, 1), i("ECALL", "Environment call"), i("EBREAK", "Breakpoint"),
|
||
|
|
i("FENCE", "Memory barrier"), i("CSR", "Control/status register access"),
|
||
|
|
// Floating point.
|
||
|
|
ic("FADDS", "FP add (single)", 3, 3), ic("FADDD", "FP add (double)", 3, 3),
|
||
|
|
ic("FSUBS", "FP subtract (single)", 3, 3), ic("FSUBD", "FP subtract (double)", 3, 3),
|
||
|
|
ic("FMULS", "FP multiply (single)", 3, 3), ic("FMULD", "FP multiply (double)", 3, 3),
|
||
|
|
ic("FDIVS", "FP divide (single)", 3, 3), ic("FDIVD", "FP divide (double)", 3, 3),
|
||
|
|
ic("FLW", "FP load word", 2, 2), ic("FLD", "FP load doubleword", 2, 2),
|
||
|
|
ic("FSW", "FP store word", 2, 2), ic("FSD", "FP store doubleword", 2, 2),
|
||
|
|
// Atomics.
|
||
|
|
i("LRW", "Load-reserved word"), i("LRD", "Load-reserved doubleword"),
|
||
|
|
i("SCW", "Store-conditional word"), i("SCD", "Store-conditional doubleword"),
|
||
|
|
i("AMOSWAPW", "Atomic swap word"), i("AMOSWAPD", "Atomic swap doubleword"),
|
||
|
|
i("AMOADDW", "Atomic add word"), i("AMOADDD", "Atomic add doubleword"),
|
||
|
|
}
|
||
|
|
}
|