-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow debug module to be at a base address other than 0 #2649
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
08652d5
Allow debug module to be at a base address other than 0
ernie-sifive 3708173
tabs
ernie-sifive 5065bbc
Merge remote-tracking branch 'origin/master' into debug-not-at-zero
ernie-sifive c80c59e
Add scalafix.
richardxia ebe5421
Remove unused imports.
richardxia e942598
Actually configure CI services to run test bucket 9.
richardxia 2057eea
Allow debug module to be at a base address other than 0
ernie-sifive 742a470
tabs
ernie-sifive cb52db8
Rebase
ernie-sifive 4a29ccb
Merge remote-tracking branch 'origin/master' into debug-not-at-zero
ernie-sifive File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
// See LICENSE.SiFive for license details. | ||
|
||
#include "riscv-pk/encoding.h" | ||
|
||
#ifndef CSR_DSCRATCH1 | ||
#define CSR_DSCRATCH1 (CSR_DSCRATCH + 1) | ||
#endif | ||
|
||
// These are implementation-specific addresses in the Debug Module, relative to entry | ||
#define HALTED -0x700 // 0x100 | ||
#define GOING -0x6FC // 0x104 | ||
#define RESUMING -0x6F8 // 0x108 | ||
#define EXCEPTION -0x6F4 // 0x10C | ||
|
||
// Region of memory where each hart has 1 byte to read. | ||
#define FLAGS -0x400 // 0x400 | ||
#define FLAG_GO 0 | ||
#define FLAG_RESUME 1 | ||
|
||
.option norvc | ||
.global entry | ||
.global exception | ||
|
||
// Entry location on ebreak, Halt, or Breakpoint | ||
// It is the same for all harts. They branch when | ||
// their GO or RESUME bit is set. | ||
|
||
// 0x800 | ||
entry: | ||
csrw CSR_DSCRATCH1, s1 // s1=s1, ds1=s1: Save s1 to use as base pointer | ||
j _entry | ||
|
||
// 0x808 | ||
exception: | ||
csrrw s1, CSR_DSCRATCH1, s1 // s1=base, ds1=s1 | ||
sw zero, EXCEPTION(s1) // Let debug module know you got an exception. | ||
|
||
_entry: | ||
// This fence is required because the execution may have written something | ||
// into the Abstract Data or Program Buffer registers. | ||
fence | ||
csrw CSR_DSCRATCH, s0 // Save s0 to allow signaling MHARTID | ||
la s1, entry // s1 = base (0x800 into debug region) | ||
|
||
// We continue to let the hart know that we are halted in order that | ||
// a DM which was reset is still made aware that a hart is halted. | ||
// We keep checking both whether there is something the debugger wants | ||
// us to do, or whether we should resume. | ||
entry_loop: | ||
csrr s0, CSR_MHARTID | ||
sw s0, HALTED(s1) | ||
add s0, s0, s1 // s0=base + hartid | ||
lbu s0, FLAGS(s0) // 1 byte flag per hart. Only one hart advances here. | ||
andi s0, s0, (1 << FLAG_GO) | (1 << FLAG_RESUME) | ||
beqz s0, entry_loop // Loop until either GO or RESUME is set. | ||
|
||
andi s0, s0, (1 << FLAG_GO) | ||
beqz s0, _resume // If GO is clear at this point, RESUME must be set. | ||
|
||
csrr s0, CSR_DSCRATCH // Restore s0 here | ||
|
||
//TODO: 0x48 is a hack for (icache-entry) constant | ||
jalr zero, 0x48(s1) // Rocket-Chip has a specific hack which is that jalr in | ||
// Debug Mode will flush the I-Cache. We need that so that the | ||
// remainder of the variable instructions will be what Debug Module | ||
// intends. | ||
icache: | ||
sw zero, GOING(s1) // When debug module sees this write, the GO flag is reset. | ||
csrrw s1, CSR_DSCRATCH1, s1 // s1=s1, ds1=base | ||
j whereto | ||
|
||
_resume: | ||
csrr s0, CSR_MHARTID | ||
sw s0, RESUMING(s1) // When Debug Module sees this write, the RESUME flag is reset. | ||
csrr s0, CSR_DSCRATCH // Restore s0 | ||
csrr s1, CSR_DSCRATCH1 // Restore s1 | ||
dret | ||
|
||
// END OF ACTUAL "ROM" CONTENTS. BELOW IS JUST FOR LINKER SCRIPT. | ||
|
||
.section .whereto | ||
whereto: | ||
nop | ||
// Variable "ROM" This is : jal x0 abstract, jal x0 program_buffer, | ||
// or jal x0 resume, as desired. | ||
// Debug Module state machine tracks what is 'desired'. | ||
// We don't need/want to use jalr here because all of the | ||
// Variable ROM contents are set by | ||
// Debug Module before setting the OK_GO byte. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ import chisel3.util._ | |
import freechips.rocketchip.config._ | ||
import freechips.rocketchip.diplomacy._ | ||
import freechips.rocketchip.regmapper._ | ||
import freechips.rocketchip.rocket.Instructions | ||
import freechips.rocketchip.rocket.{CSRs, Instructions} | ||
import freechips.rocketchip.tile.MaxHartIdBits | ||
import freechips.rocketchip.tilelink._ | ||
import freechips.rocketchip.devices.tilelink.{DevNullParams, TLError} | ||
|
@@ -54,8 +54,8 @@ object DsbRegAddrs{ | |
def IMPEBREAK(cfg: DebugModuleParams) = { DATA - 4 } | ||
|
||
// We want abstract to be immediately before PROGBUF | ||
// because we auto-generate 2 instructions. | ||
def ABSTRACT(cfg:DebugModuleParams) = PROGBUF(cfg) - 8 | ||
// because we auto-generate 2 (or 5) instructions. | ||
def ABSTRACT(cfg:DebugModuleParams) = PROGBUF(cfg) - (cfg.nAbstractInstructions * 4) | ||
|
||
def FLAGS = 0x400 | ||
def ROMBASE = 0x800 | ||
|
@@ -101,6 +101,7 @@ object DebugAbstractCommandType extends scala.Enumeration { | |
**/ | ||
|
||
case class DebugModuleParams ( | ||
baseAddress : BigInt = BigInt(0), | ||
nDMIAddrSize : Int = 7, | ||
nProgramBufferWords: Int = 16, | ||
nAbstractDataWords : Int = 4, | ||
|
@@ -130,7 +131,12 @@ case class DebugModuleParams ( | |
// TODO: Check that quick access requirements are met. | ||
} | ||
|
||
def address = AddressSet(0, 0xFFF) // This is required for correct functionality; it's not configurable. | ||
def address = AddressSet(baseAddress, 0xFFF) | ||
def atzero = (baseAddress == 0) | ||
def nAbstractInstructions = if (atzero) 2 else 5 | ||
def debugEntry: BigInt = baseAddress + 0x800 | ||
def debugException: BigInt = baseAddress + 0x808 | ||
def nDscratch: Int = if (atzero) 1 else 2 | ||
} | ||
|
||
object DefaultDebugModuleParams { | ||
|
@@ -363,9 +369,12 @@ class TLDebugModuleOuter(device: Device)(implicit p: Parameters) extends LazyMod | |
} | ||
|
||
//----HARTINFO | ||
// DATA registers are mapped to memory. The dataaddr field of HARTINFO has only | ||
// 12 bits and assumes the DM base is 0. If not at 0, then HARTINFO reads as 0 | ||
// (implying nonexistence according to the Debug Spec). | ||
|
||
val HARTINFORdData = WireInit(0.U.asTypeOf(new HARTINFOFields())) | ||
when (dmAuthenticated) { | ||
if (cfg.atzero) when (dmAuthenticated) { | ||
HARTINFORdData.dataaccess := true.B | ||
HARTINFORdData.datasize := cfg.nAbstractDataWords.U | ||
HARTINFORdData.dataaddr := DsbRegAddrs.DATA.U | ||
|
@@ -510,11 +519,11 @@ class TLDebugModuleOuter(device: Device)(implicit p: Parameters) extends LazyMod | |
)) | ||
|
||
val hartinfoRegFields = RegFieldGroup("dmi_hartinfo", Some("hart information"), Seq( | ||
RegField.r(12, HARTINFORdData.dataaddr, RegFieldDesc("dataaddr", "data address", reset=Some(DsbRegAddrs.DATA))), | ||
RegField.r(4, HARTINFORdData.datasize, RegFieldDesc("datasize", "number of DATA registers", reset=Some(cfg.nAbstractDataWords))), | ||
RegField.r(1, HARTINFORdData.dataaccess, RegFieldDesc("dataaccess", "data access type", reset=Some(1))), | ||
RegField.r(12, HARTINFORdData.dataaddr, RegFieldDesc("dataaddr", "data address", reset=Some(if (cfg.atzero) DsbRegAddrs.DATA else 0))), | ||
RegField.r(4, HARTINFORdData.datasize, RegFieldDesc("datasize", "number of DATA registers", reset=Some(if (cfg.atzero) cfg.nAbstractDataWords else 0))), | ||
RegField.r(1, HARTINFORdData.dataaccess, RegFieldDesc("dataaccess", "data access type", reset=Some(if (cfg.atzero) 1 else 0))), | ||
RegField(3), | ||
RegField.r(4, HARTINFORdData.nscratch, RegFieldDesc("nscratch", "number of scratch registers", reset=Some(cfg.nScratch))) | ||
RegField.r(4, HARTINFORdData.nscratch, RegFieldDesc("nscratch", "number of scratch registers", reset=Some(if (cfg.atzero) cfg.nScratch else 0))) | ||
)) | ||
|
||
//-------------------------------------------------------------- | ||
|
@@ -1429,6 +1438,14 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int, beatBytes: I | |
val opcode = UInt(7.W) | ||
} | ||
|
||
class GeneratedCSR extends Bundle { | ||
val imm = UInt(12.W) | ||
val rs1 = UInt(5.W) | ||
val funct3 = UInt(3.W) | ||
val rd = UInt(5.W) | ||
val opcode = UInt(7.W) | ||
} | ||
|
||
class GeneratedUJ extends Bundle { | ||
val imm3 = UInt(1.W) | ||
val imm0 = UInt(10.W) | ||
|
@@ -1451,41 +1468,87 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int, beatBytes: I | |
} | ||
} | ||
|
||
val abstractGeneratedMem = Reg(Vec(2, (UInt(32.W)))) | ||
val abstractGeneratedI = Wire(new GeneratedI()) | ||
val abstractGeneratedS = Wire(new GeneratedS()) | ||
val nop = Wire(new GeneratedI()) | ||
require((cfg.atzero && cfg.nAbstractInstructions == 2) || (!cfg.atzero && cfg.nAbstractInstructions == 5), | ||
"Mismatch between DebugModuleParams atzero and nAbstractInstructions") | ||
val abstractGeneratedMem = Reg(Vec(cfg.nAbstractInstructions, (UInt(32.W)))) | ||
|
||
def abstractGeneratedI(cfg: DebugModuleParams): UInt = { | ||
val inst = Wire(new GeneratedI()) | ||
val offset = if (cfg.atzero) DATA else (DATA-0x800) & 0xFFF | ||
val base = if (cfg.atzero) 0.U else Mux(accessRegisterCommandReg.regno(0), 8.U, 9.U) | ||
inst.opcode := (Instructions.LW.value.U.asTypeOf(new GeneratedI())).opcode | ||
inst.rd := (accessRegisterCommandReg.regno & 0x1F.U) | ||
inst.funct3 := accessRegisterCommandReg.size | ||
inst.rs1 := base | ||
inst.imm := offset.U | ||
inst.asUInt | ||
} | ||
|
||
abstractGeneratedI.opcode := (Instructions.LW.value.U.asTypeOf(new GeneratedI())).opcode | ||
abstractGeneratedI.rd := (accessRegisterCommandReg.regno & 0x1F.U) | ||
abstractGeneratedI.funct3 := accessRegisterCommandReg.size | ||
abstractGeneratedI.rs1 := 0.U | ||
abstractGeneratedI.imm := DATA.U | ||
def abstractGeneratedS(cfg: DebugModuleParams): UInt = { | ||
val inst = Wire(new GeneratedS()) | ||
val offset = if (cfg.atzero) DATA else (DATA-0x800) & 0xFFF | ||
val base = if (cfg.atzero) 0.U else Mux(accessRegisterCommandReg.regno(0), 8.U, 9.U) | ||
inst.opcode := (Instructions.SW.value.U.asTypeOf(new GeneratedS())).opcode | ||
inst.immlo := (offset & 0x1F).U | ||
inst.funct3 := accessRegisterCommandReg.size | ||
inst.rs1 := base | ||
inst.rs2 := (accessRegisterCommandReg.regno & 0x1F.U) | ||
inst.immhi := (offset >> 5).U | ||
inst.asUInt | ||
} | ||
|
||
abstractGeneratedS.opcode := (Instructions.SW.value.U.asTypeOf(new GeneratedS())).opcode | ||
abstractGeneratedS.immlo := (DATA & 0x1F).U | ||
abstractGeneratedS.funct3 := accessRegisterCommandReg.size | ||
abstractGeneratedS.rs1 := 0.U | ||
abstractGeneratedS.rs2 := (accessRegisterCommandReg.regno & 0x1F.U) | ||
abstractGeneratedS.immhi := (DATA >> 5).U | ||
def abstractGeneratedCSR: UInt = { | ||
val inst = Wire(new GeneratedCSR()) | ||
val base = Mux(accessRegisterCommandReg.regno(0), 8.U, 9.U) // use s0 as base for odd regs, s1 as base for even regs | ||
inst := (Instructions.CSRRW.value.U.asTypeOf(new GeneratedCSR())) | ||
inst.imm := CSRs.dscratch1.U | ||
inst.rs1 := base | ||
inst.rd := base | ||
inst.asUInt | ||
} | ||
|
||
val nop = Wire(new GeneratedI()) | ||
nop := Instructions.ADDI.value.U.asTypeOf(new GeneratedI()) | ||
nop.rd := 0.U | ||
nop.rs1 := 0.U | ||
nop.imm := 0.U | ||
|
||
val isa = Wire(new GeneratedI()) | ||
isa := Instructions.ADDIW.value.U.asTypeOf(new GeneratedI()) | ||
isa.rd := 0.U | ||
isa.rs1 := 0.U | ||
isa.imm := 0.U | ||
|
||
|
||
when (goAbstract) { | ||
abstractGeneratedMem(0) := Mux(accessRegisterCommandReg.transfer, | ||
Mux(accessRegisterCommandReg.write, | ||
// To write a register, we need to do LW. | ||
abstractGeneratedI.asUInt(), | ||
// To read a register, we need to do SW. | ||
abstractGeneratedS.asUInt()), | ||
nop.asUInt() | ||
) | ||
abstractGeneratedMem(1) := Mux(accessRegisterCommandReg.postexec, | ||
nop.asUInt(), | ||
Instructions.EBREAK.value.U) | ||
if (cfg.nAbstractInstructions == 2) { | ||
// ABSTRACT(0): Transfer: LW or SW, else NOP | ||
// ABSTRACT(1): Postexec: NOP else EBREAK | ||
abstractGeneratedMem(0) := Mux(accessRegisterCommandReg.transfer, | ||
Mux(accessRegisterCommandReg.write, abstractGeneratedI(cfg), abstractGeneratedS(cfg)), | ||
nop.asUInt() | ||
) | ||
abstractGeneratedMem(1) := Mux(accessRegisterCommandReg.postexec, | ||
nop.asUInt(), | ||
Instructions.EBREAK.value.U) | ||
} else { | ||
// Entry: All regs in GPRs, dscratch1=offset 0x800 in DM | ||
// ABSTRACT(0): CheckISA: ADDW or NOP (exception here if size=3 and not RV64) | ||
// ABSTRACT(1): CSRRW s1,dscratch1,s1 or CSRRW s0,dscratch1,s0 | ||
// ABSTRACT(2): Transfer: LW, SW, LD, SD else NOP | ||
// ABSTRACT(3): CSRRW s1,dscratch1,s1 or CSRRW s0,dscratch1,s0 | ||
// ABSTRACT(4): Postexec: NOP else EBREAK | ||
abstractGeneratedMem(0) := Mux(accessRegisterCommandReg.transfer && accessRegisterCommandReg.size =/= 2.U, isa.asUInt(), nop.asUInt()) | ||
abstractGeneratedMem(1) := abstractGeneratedCSR | ||
abstractGeneratedMem(2) := Mux(accessRegisterCommandReg.transfer, | ||
Mux(accessRegisterCommandReg.write, abstractGeneratedI(cfg), abstractGeneratedS(cfg)), | ||
nop.asUInt() | ||
) | ||
abstractGeneratedMem(3) := abstractGeneratedCSR | ||
abstractGeneratedMem(4) := Mux(accessRegisterCommandReg.postexec, | ||
nop.asUInt(), | ||
Instructions.EBREAK.value.U) | ||
} | ||
} | ||
|
||
//-------------------------------------------------------------- | ||
|
@@ -1528,7 +1591,8 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int, beatBytes: I | |
flags.zipWithIndex.map{case(x, i) => RegField.r(8, x.asUInt(), RegFieldDesc(s"debug_flags_$i", "", volatile=true))} | ||
}), | ||
ROMBASE -> RegFieldGroup("debug_rom", Some("Debug ROM"), | ||
DebugRomContents().zipWithIndex.map{case (x, i) => RegField.r(8, (x & 0xFF).U(8.W), RegFieldDesc(s"debug_rom_$i", "", reset=Some(x)))}) | ||
(if (cfg.atzero) DebugRomContents() else DebugRomNonzeroContents()).zipWithIndex.map{case (x, i) => | ||
RegField.r(8, (x & 0xFF).U(8.W), RegFieldDesc(s"debug_rom_$i", "", reset=Some(x)))}) | ||
) | ||
|
||
// Override System Bus accesses with dmactive reset. | ||
|
@@ -1579,13 +1643,14 @@ class TLDebugModuleInner(device: Device, getNComponents: () => Int, beatBytes: I | |
val commandWrIsAccessRegister = (COMMANDWrData.cmdtype === DebugAbstractCommandType.AccessRegister.id.U) | ||
val commandRegIsAccessRegister = (COMMANDReg.cmdtype === DebugAbstractCommandType.AccessRegister.id.U) | ||
|
||
val commandWrIsUnsupported = COMMANDWrEn && !commandWrIsAccessRegister; | ||
val commandWrIsUnsupported = COMMANDWrEn && !commandWrIsAccessRegister | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. a semi-colon?! that must be a @mwachs5 2017 original 😂 |
||
|
||
val commandRegIsUnsupported = WireInit(true.B) | ||
val commandRegBadHaltResume = WireInit(false.B) | ||
|
||
// We only support abstract commands for GPRs and any custom registers, if specified. | ||
val accessRegIsGPR = (accessRegisterCommandReg.regno >= 0x1000.U && accessRegisterCommandReg.regno <= 0x101F.U) | ||
val accessRegIsLegalSize = (accessRegisterCommandReg.size === 2.U) || (accessRegisterCommandReg.size === 3.U) | ||
val accessRegIsGPR = (accessRegisterCommandReg.regno >= 0x1000.U && accessRegisterCommandReg.regno <= 0x101F.U) && accessRegIsLegalSize | ||
val accessRegIsCustom = if (needCustom) { | ||
val (custom, customP) = customNode.in.head | ||
customP.addrs.foldLeft(false.B){ | ||
|
20 changes: 20 additions & 0 deletions
20
src/main/scala/devices/debug/DebugRomNonzeroContents.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// This file was auto-generated by 'make publish' in debug/ directory. | ||
|
||
package freechips.rocketchip.devices.debug | ||
|
||
object DebugRomNonzeroContents { | ||
|
||
def apply() : Array[Byte] = { Array ( | ||
0x73, 0x90, 0x34, 0x7b, 0x6f, 0x00, 0xc0, 0x00, 0xf3, 0x94, 0x34, 0x7b, | ||
0x23, 0xa6, 0x04, 0x90, 0x0f, 0x00, 0xf0, 0x0f, 0x73, 0x10, 0x24, 0x7b, | ||
0x97, 0x04, 0x00, 0x00, 0x93, 0x84, 0x84, 0xfe, 0x73, 0x24, 0x40, 0xf1, | ||
0x23, 0xa0, 0x84, 0x90, 0x33, 0x04, 0x94, 0x00, 0x03, 0x44, 0x04, 0xc0, | ||
0x13, 0x74, 0x34, 0x00, 0xe3, 0x06, 0x04, 0xfe, 0x13, 0x74, 0x14, 0x00, | ||
0x63, 0x0c, 0x04, 0x00, 0x73, 0x24, 0x20, 0x7b, 0x67, 0x80, 0x84, 0x04, | ||
0x23, 0xa2, 0x04, 0x90, 0xf3, 0x94, 0x34, 0x7b, 0x6f, 0xf0, 0x1f, 0xab, | ||
0x73, 0x24, 0x40, 0xf1, 0x23, 0xa4, 0x84, 0x90, 0x73, 0x24, 0x20, 0x7b, | ||
0xf3, 0x24, 0x30, 0x7b, 0x73, 0x00, 0x20, 0x7b | ||
).map(_.toByte) } | ||
|
||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder how much work it would be to move these two helpers to
util
so that Rocket and Debug can both depend on them, rather than having a circular dependency between these packages?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Instructions.scala file that has these objects looks like it used to be generated from the
riscv/riscv-opcodes
repository. I ran the chisel generator there, but the result was much different from Instructions.scala, so it's clear the two have diverged at some time in the past. The Spike CSR list used by the Debug ROM code is yet another divergent copy of this info. It makes sense to me to have this info in a foundation likeriscv-opcodes
and generate all uses from there.