#![allow(clippy::inconsistent_digit_grouping)]
use self::registers::*;
use crate::{
core::{
Architecture, BreakpointCause, CoreInformation, CoreRegisters, RegisterId, RegisterValue,
},
memory::valid_32bit_address,
memory_mapped_bitfield_register, CoreInterface, CoreRegister, CoreStatus, CoreType, Error,
HaltReason, InstructionSet, MemoryInterface,
};
use anyhow::{anyhow, Result};
use bitfield::bitfield;
use communication_interface::{AbstractCommandErrorKind, RiscvCommunicationInterface, RiscvError};
use registers::RISCV_CORE_REGSISTERS;
use std::time::{Duration, Instant};
#[macro_use]
pub(crate) mod registers;
pub use registers::PC;
pub(crate) mod assembly;
mod dtm;
pub mod communication_interface;
pub mod sequences;
pub struct Riscv32<'probe> {
interface: &'probe mut RiscvCommunicationInterface,
state: &'probe mut RiscVState,
id: usize,
}
impl<'probe> Riscv32<'probe> {
pub fn new(
interface: &'probe mut RiscvCommunicationInterface,
state: &'probe mut RiscVState,
id: usize,
) -> Self {
Self {
interface,
state,
id,
}
}
fn read_csr(&mut self, address: u16) -> Result<u32, RiscvError> {
tracing::debug!("Reading CSR {:#x}", address);
match self.interface.abstract_cmd_register_read(address) {
Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::NotSupported)) => {
tracing::debug!("Could not read core register {:#x} with abstract command, falling back to program buffer", address);
self.interface.read_csr_progbuf(address)
}
other => other,
}
}
fn write_csr(&mut self, address: u16, value: u32) -> Result<(), RiscvError> {
tracing::debug!("Writing CSR {:#x}", address);
match self.interface.abstract_cmd_register_write(address, value) {
Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::NotSupported)) => {
tracing::debug!("Could not write core register {:#x} with abstract command, falling back to program buffer", address);
self.interface.write_csr_progbuf(address, value)
}
other => other,
}
}
fn resume_core(&mut self) -> Result<(), crate::Error> {
let mut dmcontrol = Dmcontrol(0);
dmcontrol.set_resumereq(true);
dmcontrol.set_dmactive(true);
self.interface.write_dm_register(dmcontrol)?;
let status: Dmstatus = self.interface.read_dm_register()?;
if !status.allresumeack() {
return Err(RiscvError::RequestNotAcknowledged.into());
};
let mut dmcontrol = Dmcontrol(0);
dmcontrol.set_dmactive(true);
self.interface.write_dm_register(dmcontrol)?;
Ok(())
}
fn supports_reset_halt_req(&mut self) -> Result<bool, crate::Error> {
if let Some(has_reset_halt_req) = self.state.hasresethaltreq {
Ok(has_reset_halt_req)
} else {
let dmstatus: Dmstatus = self.interface.read_dm_register()?;
self.state.hasresethaltreq = Some(dmstatus.hasresethaltreq());
Ok(dmstatus.hasresethaltreq())
}
}
}
impl<'probe> CoreInterface for Riscv32<'probe> {
fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), crate::Error> {
let start = Instant::now();
while start.elapsed() < timeout {
let dmstatus: Dmstatus = self.interface.read_dm_register()?;
tracing::trace!("{:?}", dmstatus);
if dmstatus.allhalted() {
return Ok(());
}
}
Err(Error::Riscv(RiscvError::Timeout))
}
fn core_halted(&mut self) -> Result<bool, crate::Error> {
let dmstatus: Dmstatus = self.interface.read_dm_register()?;
Ok(dmstatus.allhalted())
}
fn status(&mut self) -> Result<crate::core::CoreStatus, crate::Error> {
let status: Dmstatus = self.interface.read_dm_register()?;
if status.allhalted() {
let dcsr = Dcsr(self.read_core_reg(RegisterId::from(0x7b0))?.try_into()?);
let reason = match dcsr.cause() {
1 => HaltReason::Breakpoint(BreakpointCause::Software),
2 => HaltReason::Breakpoint(BreakpointCause::Hardware),
3 => HaltReason::Request,
4 => HaltReason::Step,
5 => HaltReason::Exception,
_ => HaltReason::Unknown,
};
Ok(CoreStatus::Halted(reason))
} else if status.allrunning() {
Ok(CoreStatus::Running)
} else {
Err(
anyhow!("Some cores are running while some are halted, this should not happen.")
.into(),
)
}
}
fn halt(&mut self, timeout: Duration) -> Result<CoreInformation, crate::Error> {
tracing::debug!(
"Before requesting halt, the Dmcontrol register value was: {:?}",
self.interface.read_dm_register::<Dmcontrol>()?
);
let mut dmcontrol = Dmcontrol(0);
dmcontrol.set_haltreq(true);
dmcontrol.set_dmactive(true);
self.interface.write_dm_register(dmcontrol)?;
self.wait_for_core_halted(timeout)?;
let mut dmcontrol = Dmcontrol(0);
dmcontrol.set_dmactive(true);
self.interface.write_dm_register(dmcontrol)?;
let pc = self.read_core_reg(self.program_counter().into())?;
Ok(CoreInformation { pc: pc.try_into()? })
}
fn run(&mut self) -> Result<(), crate::Error> {
self.step()?;
self.resume_core()?;
Ok(())
}
fn reset(&mut self) -> Result<(), crate::Error> {
match self.reset_and_halt(Duration::from_millis(500)) {
Ok(_) => self.resume_core()?,
Err(error) => {
return Err(RiscvError::DebugProbe(crate::DebugProbeError::Other(
anyhow::anyhow!("Error during reset : {:?}", error),
))
.into());
}
}
Ok(())
}
fn reset_and_halt(
&mut self,
_timeout: Duration,
) -> Result<crate::core::CoreInformation, crate::Error> {
tracing::debug!("Resetting core, setting hartreset bit");
self.reset_catch_set()?;
let mut dmcontrol = Dmcontrol(0);
dmcontrol.set_dmactive(true);
dmcontrol.set_hartreset(true);
dmcontrol.set_haltreq(true);
self.interface.write_dm_register(dmcontrol)?;
let readback: Dmcontrol = self.interface.read_dm_register()?;
if readback.hartreset() {
tracing::debug!("Clearing hartreset bit");
let mut dmcontrol = readback;
dmcontrol.set_dmactive(true);
dmcontrol.set_hartreset(false);
self.interface.write_dm_register(dmcontrol)?;
} else {
tracing::debug!("Hartreset bit not supported, using ndmreset");
let mut dmcontrol = Dmcontrol(0);
dmcontrol.set_dmactive(true);
dmcontrol.set_ndmreset(true);
dmcontrol.set_haltreq(true);
self.interface.write_dm_register(dmcontrol)?;
tracing::debug!("Clearing ndmreset bit");
let mut dmcontrol = Dmcontrol(0);
dmcontrol.set_dmactive(true);
dmcontrol.set_ndmreset(false);
dmcontrol.set_haltreq(true);
self.interface.write_dm_register(dmcontrol)?;
}
let readback: Dmstatus = self.interface.read_dm_register()?;
if !(readback.allhavereset() && readback.allhalted()) {
return Err(RiscvError::RequestNotAcknowledged.into());
}
let mut dmcontrol = Dmcontrol(0);
dmcontrol.set_dmactive(true);
dmcontrol.set_ackhavereset(true);
self.interface.write_dm_register(dmcontrol)?;
self.reset_catch_clear()?;
let pc = self.read_core_reg(RegisterId(0x7b1))?;
Ok(CoreInformation { pc: pc.try_into()? })
}
fn step(&mut self) -> Result<crate::core::CoreInformation, crate::Error> {
let halt_reason = self.status()?;
if matches!(
halt_reason,
CoreStatus::Halted(HaltReason::Breakpoint(BreakpointCause::Software))
) && self.state.hw_breakpoints_enabled
{
let mut debug_pc = self.read_core_reg(RegisterId(0x7b1))?;
if matches!(self.instruction_set()?, InstructionSet::RV32C) {
debug_pc.increment_address(2)?;
} else {
debug_pc.increment_address(4)?;
}
self.write_core_reg(RegisterId(0x7b1), debug_pc)?;
return Ok(CoreInformation {
pc: debug_pc.try_into()?,
});
} else if matches!(
halt_reason,
CoreStatus::Halted(HaltReason::Breakpoint(BreakpointCause::Hardware))
) {
self.enable_breakpoints(false)?;
}
let mut dcsr = Dcsr(self.read_core_reg(RegisterId(0x7b0))?.try_into()?);
dcsr.set_step(true);
dcsr.set_stepie(false);
dcsr.set_stopcount(true);
self.write_csr(0x7b0, dcsr.0)?;
self.resume_core()?;
self.wait_for_core_halted(Duration::from_millis(100))?;
let pc = self.read_core_reg(RegisterId(0x7b1))?;
let mut dcsr = Dcsr(self.read_core_reg(RegisterId(0x7b0))?.try_into()?);
dcsr.set_step(false);
dcsr.set_stepie(true);
dcsr.set_stopcount(false);
self.write_csr(0x7b0, dcsr.0)?;
if matches!(
halt_reason,
CoreStatus::Halted(HaltReason::Breakpoint(BreakpointCause::Hardware))
) {
self.enable_breakpoints(true)?;
}
Ok(CoreInformation { pc: pc.try_into()? })
}
fn read_core_reg(&mut self, address: RegisterId) -> Result<RegisterValue, crate::Error> {
self.read_csr(address.0)
.map(|v| v.into())
.map_err(|e| e.into())
}
fn write_core_reg(
&mut self,
address: RegisterId,
value: RegisterValue,
) -> Result<(), crate::Error> {
let value: u32 = value.try_into()?;
self.write_csr(address.0, value).map_err(|e| e.into())
}
fn available_breakpoint_units(&mut self) -> Result<u32, crate::Error> {
tracing::debug!("Determining number of HW breakpoints supported");
let tselect = 0x7a0;
let tdata1 = 0x7a1;
let tinfo = 0x7a4;
let mut tselect_index = 0;
loop {
tracing::debug!("Trying tselect={}", tselect_index);
if let Err(e) = self.write_csr(tselect, tselect_index) {
match e {
RiscvError::AbstractCommand(AbstractCommandErrorKind::Exception) => break,
other_error => return Err(other_error.into()),
}
}
let readback = self.read_csr(tselect)?;
if readback != tselect_index {
break;
}
match self.read_csr(tinfo) {
Ok(tinfo_val) => {
if tinfo_val & 0xffff == 1 {
break;
} else {
tracing::info!(
"Discovered trigger with index {} and type {}",
tselect_index,
tinfo_val & 0xffff
);
}
}
Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::Exception)) => {
let tdata_val = self.read_csr(tdata1)?;
let misa_value = Misa(self.read_csr(0x301)?);
let xlen = u32::pow(2, misa_value.mxl() + 4);
let trigger_type = tdata_val >> (xlen - 4);
if trigger_type == 0 {
break;
}
tracing::info!(
"Discovered trigger with index {} and type {}",
tselect_index,
trigger_type,
);
}
Err(other) => return Err(other.into()),
}
tselect_index += 1;
}
tracing::debug!("Target supports {} breakpoints.", tselect_index);
Ok(tselect_index)
}
fn hw_breakpoints(&mut self) -> Result<Vec<Option<u64>>, Error> {
let tselect = 0x7a0;
let tdata1 = 0x7a1;
let tdata2 = 0x7a2;
let mut breakpoints = vec![];
let num_hw_breakpoints = self.available_breakpoint_units()? as usize;
for bp_unit_index in 0..num_hw_breakpoints {
self.write_csr(tselect, bp_unit_index as u32)?;
let tdata_value = Mcontrol(self.read_csr(tdata1)?);
tracing::warn!("Breakpoint {}: {:?}", bp_unit_index, tdata_value);
let trigger_any_mode_active = tdata_value.m() || tdata_value.s() || tdata_value.u();
let trigger_any_action_enabled =
tdata_value.execute() || tdata_value.store() || tdata_value.load();
if tdata_value.type_() == 0b10
&& tdata_value.action() == 1
&& tdata_value.match_() == 0
&& trigger_any_mode_active
&& trigger_any_action_enabled
{
let breakpoint = self.read_csr(tdata2)?;
breakpoints.push(Some(breakpoint as u64));
} else {
breakpoints.push(None);
}
}
Ok(breakpoints)
}
fn enable_breakpoints(&mut self, state: bool) -> Result<(), crate::Error> {
let tselect = 0x7a0;
let tdata1 = 0x7a1;
for bp_unit_index in 0..self.available_breakpoint_units()? as usize {
self.write_csr(tselect, bp_unit_index as u32)?;
let mut tdata_value = Mcontrol(self.read_csr(tdata1)?);
if tdata_value.type_() == 0b10
&& tdata_value.action() == 1
&& tdata_value.match_() == 0
&& tdata_value.execute()
&& ((tdata_value.m() && tdata_value.u()) || (!tdata_value.m() && !tdata_value.u()))
{
tracing::debug!(
"Will modify breakpoint enabled={} for {}: {:?}",
state,
bp_unit_index,
tdata_value
);
tdata_value.set_m(state);
tdata_value.set_u(state);
self.write_csr(tdata1, tdata_value.0)?;
}
}
self.state.hw_breakpoints_enabled = state;
Ok(())
}
fn set_hw_breakpoint(&mut self, bp_unit_index: usize, addr: u64) -> Result<(), crate::Error> {
let addr = valid_32bit_address(addr)?;
if !self.hw_breakpoints_enabled() {
self.enable_breakpoints(true)?;
}
let tselect = 0x7a0;
let tdata1 = 0x7a1;
let tdata2 = 0x7a2;
tracing::warn!("Setting breakpoint {}", bp_unit_index);
self.write_csr(tselect, bp_unit_index as u32)?;
let tdata_value = Mcontrol(self.read_csr(tdata1)?);
let trigger_type = tdata_value.type_();
if trigger_type != 0b10 {
return Err(RiscvError::UnexpectedTriggerType(trigger_type).into());
}
let mut instruction_breakpoint = Mcontrol(0);
instruction_breakpoint.set_action(1);
instruction_breakpoint.set_match(0);
instruction_breakpoint.set_m(true);
instruction_breakpoint.set_u(true);
instruction_breakpoint.set_execute(true);
instruction_breakpoint.set_dmode(true);
instruction_breakpoint.set_select(false);
self.write_csr(tdata1, instruction_breakpoint.0)?;
self.write_csr(tdata2, addr)?;
Ok(())
}
fn clear_hw_breakpoint(&mut self, unit_index: usize) -> Result<(), crate::Error> {
let tselect = 0x7a0;
let tdata1 = 0x7a1;
let tdata2 = 0x7a2;
self.write_csr(tselect, unit_index as u32)?;
self.write_csr(tdata1, 0)?;
self.write_csr(tdata2, 0)?;
Ok(())
}
fn registers(&self) -> &'static CoreRegisters {
&RISCV_CORE_REGSISTERS
}
fn program_counter(&self) -> &'static CoreRegister {
&PC
}
fn frame_pointer(&self) -> &'static CoreRegister {
&FP
}
fn stack_pointer(&self) -> &'static CoreRegister {
&SP
}
fn return_address(&self) -> &'static CoreRegister {
&RA
}
fn hw_breakpoints_enabled(&self) -> bool {
self.state.hw_breakpoints_enabled
}
fn debug_on_sw_breakpoint(&mut self, enabled: bool) -> Result<(), crate::error::Error> {
let mut dcsr = Dcsr(self.read_core_reg(RegisterId(0x7b0))?.try_into()?);
dcsr.set_ebreakm(enabled);
dcsr.set_ebreaks(enabled);
dcsr.set_ebreaku(enabled);
self.write_csr(0x7b0, dcsr.0).map_err(|e| e.into())
}
fn architecture(&self) -> Architecture {
Architecture::Riscv
}
fn core_type(&self) -> CoreType {
CoreType::Riscv
}
fn instruction_set(&mut self) -> Result<InstructionSet, Error> {
let misa_value = Misa(self.read_csr(0x301)?);
if misa_value.extensions() & (1 << 2) != 0 {
Ok(InstructionSet::RV32C)
} else {
Ok(InstructionSet::RV32)
}
}
fn fpu_support(&mut self) -> Result<bool, crate::error::Error> {
Err(crate::error::Error::Other(anyhow::anyhow!(
"Fpu detection not yet implemented"
)))
}
fn id(&self) -> usize {
self.id
}
fn reset_catch_set(&mut self) -> Result<(), Error> {
if !self.supports_reset_halt_req()? {
return Err(Error::Riscv(RiscvError::ResetHaltRequestNotSupported));
}
let mut dmcontrol: Dmcontrol = self.interface.read_dm_register()?;
dmcontrol.set_resethaltreq(true);
self.interface.write_dm_register(dmcontrol)?;
Ok(())
}
fn reset_catch_clear(&mut self) -> Result<(), Error> {
if !self.supports_reset_halt_req()? {
return Err(Error::Riscv(RiscvError::ResetHaltRequestNotSupported));
}
let mut dmcontrol: Dmcontrol = self.interface.read_dm_register()?;
dmcontrol.set_clrresethaltreq(true);
self.interface.write_dm_register(dmcontrol)?;
Ok(())
}
fn debug_core_stop(&mut self) -> Result<(), Error> {
self.debug_on_sw_breakpoint(false)?;
Ok(())
}
}
impl<'probe> MemoryInterface for Riscv32<'probe> {
fn supports_native_64bit_access(&mut self) -> bool {
self.interface.supports_native_64bit_access()
}
fn read_word_64(&mut self, address: u64) -> Result<u64, crate::error::Error> {
self.interface.read_word_64(address)
}
fn read_word_32(&mut self, address: u64) -> Result<u32, Error> {
self.interface.read_word_32(address)
}
fn read_word_8(&mut self, address: u64) -> Result<u8, Error> {
self.interface.read_word_8(address)
}
fn read_64(&mut self, address: u64, data: &mut [u64]) -> Result<(), Error> {
self.interface.read_64(address, data)
}
fn read_32(&mut self, address: u64, data: &mut [u32]) -> Result<(), Error> {
self.interface.read_32(address, data)
}
fn read_8(&mut self, address: u64, data: &mut [u8]) -> Result<(), Error> {
self.interface.read_8(address, data)
}
fn write_word_64(&mut self, address: u64, data: u64) -> Result<(), Error> {
self.interface.write_word_64(address, data)
}
fn write_word_32(&mut self, address: u64, data: u32) -> Result<(), Error> {
self.interface.write_word_32(address, data)
}
fn write_word_8(&mut self, address: u64, data: u8) -> Result<(), Error> {
self.interface.write_word_8(address, data)
}
fn write_64(&mut self, address: u64, data: &[u64]) -> Result<(), Error> {
self.interface.write_64(address, data)
}
fn write_32(&mut self, address: u64, data: &[u32]) -> Result<(), Error> {
self.interface.write_32(address, data)
}
fn write_8(&mut self, address: u64, data: &[u8]) -> Result<(), Error> {
self.interface.write_8(address, data)
}
fn write(&mut self, address: u64, data: &[u8]) -> Result<(), Error> {
self.interface.write(address, data)
}
fn supports_8bit_transfers(&self) -> Result<bool, Error> {
self.interface.supports_8bit_transfers()
}
fn flush(&mut self) -> Result<(), Error> {
self.interface.flush()
}
}
#[derive(Debug)]
pub struct RiscVState {
hw_breakpoints_enabled: bool,
hasresethaltreq: Option<bool>,
}
impl RiscVState {
pub(crate) fn new() -> Self {
Self {
hw_breakpoints_enabled: false,
hasresethaltreq: None,
}
}
}
memory_mapped_bitfield_register! {
pub struct Dmcontrol(u32);
0x10, "dmcontrol",
impl From;
_, set_haltreq: 31;
_, set_resumereq: 30;
hartreset, set_hartreset: 29;
_, set_ackhavereset: 28;
hasel, set_hasel: 26;
hartsello, set_hartsello: 25, 16;
hartselhi, set_hartselhi: 15, 6;
_, set_resethaltreq: 3;
_, set_clrresethaltreq: 2;
ndmreset, set_ndmreset: 1;
dmactive, set_dmactive: 0;
}
impl Dmcontrol {
fn hartsel(&self) -> u32 {
self.hartselhi() << 10 | self.hartsello()
}
fn set_hartsel(&mut self, value: u32) {
self.set_hartsello(value & 0x3ff);
self.set_hartselhi((value >> 10) & 0x3ff);
}
}
memory_mapped_bitfield_register! {
pub struct Dmstatus(u32);
0x11, "dmstatus",
impl From;
impebreak, _: 22;
allhavereset, _: 19;
anyhavereset, _: 18;
allresumeack, _: 17;
anyresumeack, _: 16;
allnonexistent, _: 15;
anynonexistent, _: 14;
allunavail, _: 13;
anyunavail, _: 12;
allrunning, _: 11;
anyrunning, _: 10;
allhalted, _: 9;
anyhalted, _: 8;
authenticated, _: 7;
authbusy, _: 6;
hasresethaltreq, _: 5;
confstrptrvalid, _: 4;
version, _: 3, 0;
}
bitfield! {
struct Dcsr(u32);
impl Debug;
xdebugver, _: 31, 28;
ebreakm, set_ebreakm: 15;
ebreaks, set_ebreaks: 13;
ebreaku, set_ebreaku: 12;
stepie, set_stepie: 11;
stopcount, set_stopcount: 10;
stoptime, set_stoptime: 9;
cause, set_cause: 8, 6;
mprven, set_mprven: 4;
nmip, _: 3;
step, set_step: 2;
prv, set_prv: 1,0;
}
memory_mapped_bitfield_register! {
pub struct Abstractcs(u32);
0x16, "abstractcs",
impl From;
progbufsize, _: 28, 24;
busy, _: 12;
cmderr, set_cmderr: 10, 8;
datacount, _: 3, 0;
}
memory_mapped_bitfield_register! {
pub struct Hartinfo(u32);
0x12, "hartinfo",
impl From;
nscratch, _: 23, 20;
dataaccess, _: 16;
datasize, _: 15, 12;
dataaddr, _: 11, 0;
}
memory_mapped_bitfield_register! { pub struct Data0(u32); 0x04, "data0", impl From; }
memory_mapped_bitfield_register! { pub struct Data1(u32); 0x05, "data1", impl From; }
memory_mapped_bitfield_register! { pub struct Data2(u32); 0x06, "data2", impl From; }
memory_mapped_bitfield_register! { pub struct Data3(u32); 0x07, "data3", impl From; }
memory_mapped_bitfield_register! { pub struct Data4(u32); 0x08, "data4", impl From; }
memory_mapped_bitfield_register! { pub struct Data5(u32); 0x09, "data5", impl From; }
memory_mapped_bitfield_register! { pub struct Data6(u32); 0x0A, "data6", impl From; }
memory_mapped_bitfield_register! { pub struct Data7(u32); 0x0B, "data7", impl From; }
memory_mapped_bitfield_register! { pub struct Data8(u32); 0x0C, "data8", impl From; }
memory_mapped_bitfield_register! { pub struct Data9(u32); 0x0D, "data9", impl From; }
memory_mapped_bitfield_register! { pub struct Data10(u32); 0x0E, "data10", impl From; }
memory_mapped_bitfield_register! { pub struct Data11(u32); 0x0f, "data11", impl From; }
memory_mapped_bitfield_register! { struct Command(u32); 0x17, "command", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf0(u32); 0x20, "progbuf0", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf1(u32); 0x21, "progbuf1", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf2(u32); 0x22, "progbuf2", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf3(u32); 0x23, "progbuf3", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf4(u32); 0x24, "progbuf4", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf5(u32); 0x25, "progbuf5", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf6(u32); 0x26, "progbuf6", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf7(u32); 0x27, "progbuf7", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf8(u32); 0x28, "progbuf8", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf9(u32); 0x29, "progbuf9", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf10(u32); 0x2A, "progbuf10", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf11(u32); 0x2B, "progbuf11", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf12(u32); 0x2C, "progbuf12", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf13(u32); 0x2D, "progbuf13", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf14(u32); 0x2E, "progbuf14", impl From; }
memory_mapped_bitfield_register! { pub struct Progbuf15(u32); 0x2F, "progbuf15", impl From; }
bitfield! {
struct Mcontrol(u32);
impl Debug;
type_, set_type: 31, 28;
dmode, set_dmode: 27;
maskmax, _: 26, 21;
hit, set_hit: 20;
select, set_select: 19;
timing, set_timing: 18;
sizelo, set_sizelo: 17, 16;
action, set_action: 15, 12;
chain, set_chain: 11;
match_, set_match: 10, 7;
m, set_m: 6;
s, set_s: 4;
u, set_u: 3;
execute, set_execute: 2;
store, set_store: 1;
load, set_load: 0;
}
bitfield! {
pub struct Misa(u32);
impl Debug;
mxl, _: 31, 30;
extensions, _: 25, 0;
}