use crate::architecture::riscv::dtm::dtm_access::DtmAccess;
use crate::{
architecture::riscv::*, config::Target, memory_mapped_bitfield_register,
probe::DeferredResultIndex, Error as ProbeRsError,
};
use std::any::Any;
use std::collections::HashMap;
#[derive(thiserror::Error, Debug)]
pub enum RiscvError {
#[error("Error during transport")]
DtmOperationFailed,
#[error("Transport operation in progress")]
DtmOperationInProcess,
#[error("Debug Probe Error")]
DebugProbe(#[from] DebugProbeError),
#[error("Timeout during DMI access.")]
Timeout,
#[error("Error occurred during execution of an abstract command: {0:?}")]
AbstractCommand(AbstractCommandErrorKind),
#[error("The core did not acknowledge a request for reset, resume or halt")]
RequestNotAcknowledged,
#[error("The version '{0}' of the debug transport module (DTM) is currently not supported.")]
UnsupportedDebugTransportModuleVersion(u8),
#[error("The version '{0:?}' of the debug module is currently not supported.")]
UnsupportedDebugModuleVersion(DebugModuleVersion),
#[error("CSR at address '{0:x}' is unsupported.")]
UnsupportedCsrAddress(u16),
#[error("Program buffer register '{0}' is currently not supported.")]
UnsupportedProgramBufferRegister(usize),
#[error("Program buffer is too small for supplied program.")]
ProgramBufferTooSmall,
#[error("Memory width larger than 32 bits is not supported yet.")]
UnsupportedBusAccessWidth(RiscvBusAccess),
#[error("Error using system bus")]
SystemBusAccess,
#[error("Unexpected trigger type {0} for address breakpoint.")]
UnexpectedTriggerType(u32),
#[error("Connected target is not a RISC-V device.")]
NoRiscvTarget,
#[error("The target does not support halt after reset.")]
ResetHaltRequestNotSupported,
#[error("The requested data is not available due to a previous error.")]
BatchedResultNotAvailable,
#[error("The requested hart is unavailable.")]
HartUnavailable,
}
impl From<RiscvError> for ProbeRsError {
fn from(err: RiscvError) -> Self {
match err {
RiscvError::DebugProbe(e) => e.into(),
other => ProbeRsError::Riscv(other),
}
}
}
#[derive(Debug)]
pub enum AbstractCommandErrorKind {
Busy = 1,
NotSupported = 2,
Exception = 3,
HaltResume = 4,
Bus = 5,
_Reserved = 6,
Other = 7,
}
impl From<AbstractCommandErrorKind> for RiscvError {
fn from(err: AbstractCommandErrorKind) -> Self {
RiscvError::AbstractCommand(err)
}
}
impl AbstractCommandErrorKind {
fn parse(status: Abstractcs) -> Result<(), Self> {
let err = match status.cmderr() {
0 => return Ok(()),
1 => Self::Busy,
2 => Self::NotSupported,
3 => Self::Exception,
4 => Self::HaltResume,
5 => Self::Bus,
6 => Self::_Reserved,
7 => Self::Other,
_ => unreachable!("cmderr is a 3 bit value, values higher than 7 should not occur."),
};
Err(err)
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum DebugModuleVersion {
NoModule,
Version0_11,
Version0_13,
NonConforming,
Unknown(u8),
}
impl From<u8> for DebugModuleVersion {
fn from(raw: u8) -> Self {
match raw {
0 => Self::NoModule,
1 => Self::Version0_11,
2 => Self::Version0_13,
15 => Self::NonConforming,
other => Self::Unknown(other),
}
}
}
#[derive(Copy, Clone, Debug)]
struct CoreRegisterAbstractCmdSupport(u8);
impl CoreRegisterAbstractCmdSupport {
const READ: Self = Self(1 << 0);
const WRITE: Self = Self(1 << 1);
const BOTH: Self = Self(Self::READ.0 | Self::WRITE.0);
fn supports(&self, o: Self) -> bool {
self.0 & o.0 == o.0
}
fn unset(&mut self, o: Self) {
self.0 &= !(o.0);
}
}
#[derive(Debug, Default)]
struct ScratchState {
stack: Vec<u32>,
}
impl ScratchState {
fn push(&mut self, value: u32) {
self.stack.push(value);
}
fn pop(&mut self) -> Option<u32> {
self.stack.pop()
}
}
#[derive(Debug)]
pub struct RiscvCommunicationInterfaceState {
debug_version: DebugModuleVersion,
progbuf_size: u8,
progbuf_cache: [u32; 16],
implicit_ebreak: bool,
data_register_count: u8,
nscratch: u8,
supports_autoexec: bool,
confstrptr: Option<u128>,
hartsellen: u8,
num_harts: u32,
memory_access_info: HashMap<RiscvBusAccess, MemoryAccessMethod>,
abstract_cmd_register_info: HashMap<RegisterId, CoreRegisterAbstractCmdSupport>,
s0: ScratchState,
s1: ScratchState,
enabled_harts: u32,
last_selected_hart: u32,
hasresethaltreq: Option<bool>,
sysbus_requires_halting: bool,
is_halted: bool,
current_dmcontrol: Dmcontrol,
}
const RISCV_TIMEOUT: Duration = Duration::from_secs(5);
const RISCV_MAX_CSR_ADDR: u16 = 0xFFF;
impl RiscvCommunicationInterfaceState {
pub fn new() -> Self {
RiscvCommunicationInterfaceState {
progbuf_size: 0,
progbuf_cache: [0u32; 16],
debug_version: DebugModuleVersion::NonConforming,
implicit_ebreak: false,
data_register_count: 1,
nscratch: 0,
supports_autoexec: false,
confstrptr: None,
hartsellen: 20,
num_harts: 1,
memory_access_info: HashMap::new(),
abstract_cmd_register_info: HashMap::new(),
s0: ScratchState::default(),
s1: ScratchState::default(),
enabled_harts: 0,
last_selected_hart: 0,
hasresethaltreq: None,
sysbus_requires_halting: false,
is_halted: false,
current_dmcontrol: Dmcontrol(0),
}
}
fn memory_access_method(&mut self, access_width: RiscvBusAccess) -> MemoryAccessMethod {
*self
.memory_access_info
.entry(access_width)
.or_insert(MemoryAccessMethod::ProgramBuffer)
}
}
impl Default for RiscvCommunicationInterfaceState {
fn default() -> Self {
Self::new()
}
}
pub struct RiscvDebugInterfaceState {
pub(super) interface_state: RiscvCommunicationInterfaceState,
pub(super) dtm_state: Box<dyn Any + Send>,
}
impl RiscvDebugInterfaceState {
pub(super) fn new(dtm_state: Box<dyn Any + Send>) -> Self {
Self {
interface_state: RiscvCommunicationInterfaceState::new(),
dtm_state,
}
}
}
pub trait RiscvInterfaceBuilder<'probe> {
fn create_state(&self) -> RiscvDebugInterfaceState;
fn attach<'state>(
self: Box<Self>,
state: &'state mut RiscvDebugInterfaceState,
) -> Result<RiscvCommunicationInterface<'state>, DebugProbeError>
where
'probe: 'state;
fn attach_tunneled<'state>(
self: Box<Self>,
_tunnel_ir_id: u32,
_tunnel_ir_width: u32,
_state: &'state mut RiscvDebugInterfaceState,
) -> Result<RiscvCommunicationInterface<'state>, DebugProbeError>
where
'probe: 'state,
{
Err(DebugProbeError::InterfaceNotAvailable {
interface_name: "Tunneled RISC-V",
})
}
fn attach_auto<'state>(
self: Box<Self>,
target: &Target,
state: &'state mut RiscvDebugInterfaceState,
) -> Result<RiscvCommunicationInterface<'state>, DebugProbeError>
where
'probe: 'state,
{
let maybe_tunnel = target.jtag.as_ref().and_then(|j| j.riscv_tunnel.as_ref());
if let Some(tunnel) = maybe_tunnel {
self.attach_tunneled(tunnel.ir_id, tunnel.ir_width, state)
} else {
self.attach(state)
}
}
}
#[derive(Debug)]
pub struct RiscvCommunicationInterface<'state> {
dtm: Box<dyn DtmAccess + 'state>,
state: &'state mut RiscvCommunicationInterfaceState,
}
impl<'state> RiscvCommunicationInterface<'state> {
pub fn new(
dtm: Box<dyn DtmAccess + 'state>,
state: &'state mut RiscvCommunicationInterfaceState,
) -> Self {
Self { dtm, state }
}
pub fn select_hart(&mut self, hart: u32) -> Result<(), RiscvError> {
if self.state.enabled_harts & (1 << hart) == 0 {
return Err(RiscvError::HartUnavailable);
}
if self.state.last_selected_hart == hart {
return Ok(());
}
let mut control = self.read_dm_register::<Dmcontrol>()?;
control.set_dmactive(true);
control.set_hartsel(hart);
self.schedule_write_dm_register(control)?;
self.state.last_selected_hart = hart;
Ok(())
}
pub fn hart_enabled(&self, hart: u32) -> bool {
self.state.enabled_harts & (1 << hart) != 0
}
pub fn target_reset_assert(&mut self) -> Result<(), DebugProbeError> {
self.dtm.target_reset_assert()
}
pub fn target_reset_deassert(&mut self) -> Result<(), DebugProbeError> {
self.dtm.target_reset_deassert()
}
pub fn read_idcode(&mut self) -> Result<Option<u32>, DebugProbeError> {
self.dtm.read_idcode()
}
fn save_s0(&mut self) -> Result<bool, RiscvError> {
let s0 = self.abstract_cmd_register_read(®isters::S0)?;
self.state.s0.push(s0);
Ok(true)
}
fn restore_s0(&mut self, saved: bool) -> Result<(), RiscvError> {
if saved {
let s0 = self.state.s0.pop().unwrap();
self.abstract_cmd_register_write(®isters::S0, s0)?;
}
Ok(())
}
fn save_s1(&mut self) -> Result<bool, RiscvError> {
let s1 = self.abstract_cmd_register_read(®isters::S1)?;
self.state.s1.push(s1);
Ok(true)
}
fn restore_s1(&mut self, saved: bool) -> Result<(), RiscvError> {
if saved {
let s1 = self.state.s1.pop().unwrap();
self.abstract_cmd_register_write(®isters::S1, s1)?;
}
Ok(())
}
pub(crate) fn enter_debug_mode(&mut self) -> Result<(), RiscvError> {
tracing::debug!("Building RISC-V interface");
self.dtm.init()?;
self.dtm.clear_error_state()?;
let mut control = Dmcontrol(0);
control.set_dmactive(true);
self.schedule_write_dm_register(control)?;
let status: Dmstatus = self.read_dm_register()?;
self.state.progbuf_cache.fill(0);
self.state.memory_access_info.clear();
self.state.debug_version = DebugModuleVersion::from(status.version() as u8);
self.state.is_halted = status.allhalted();
if self.state.debug_version != DebugModuleVersion::Version0_13 {
return Err(RiscvError::UnsupportedDebugModuleVersion(
self.state.debug_version,
));
}
self.state.implicit_ebreak = status.impebreak();
self.state.confstrptr = if status.confstrptrvalid() {
let confstrptr_0: Confstrptr0 = self.read_dm_register()?;
let confstrptr_1: Confstrptr1 = self.read_dm_register()?;
let confstrptr_2: Confstrptr2 = self.read_dm_register()?;
let confstrptr_3: Confstrptr3 = self.read_dm_register()?;
let confstrptr = (u32::from(confstrptr_0) as u128)
| (u32::from(confstrptr_1) as u128) << 8
| (u32::from(confstrptr_2) as u128) << 16
| (u32::from(confstrptr_3) as u128) << 32;
Some(confstrptr)
} else {
None
};
tracing::debug!("dmstatus: {:?}", status);
let mut control = Dmcontrol(0);
control.set_dmactive(true);
control.set_hartsel(0xffff_ffff);
self.schedule_write_dm_register(control)?;
let control = self.read_dm_register::<Dmcontrol>()?;
self.state.hartsellen = control.hartsel().count_ones() as u8;
tracing::debug!("HARTSELLEN: {}", self.state.hartsellen);
let max_hart_index = 2u32.pow(self.state.hartsellen as u32);
let mut num_harts = 1;
self.state.enabled_harts = 1;
let mut control = Dmcontrol(0);
control.set_dmactive(true);
control.set_hartsel(max_hart_index - 1);
self.schedule_write_dm_register(control)?;
let status: Dmstatus = self.read_dm_register()?;
if status.anynonexistent() {
for hart_index in 1..max_hart_index {
let mut control = Dmcontrol(0);
control.set_dmactive(true);
control.set_hartsel(hart_index);
self.schedule_write_dm_register(control)?;
let status: Dmstatus = self.read_dm_register()?;
if status.anynonexistent() {
break;
}
if !status.allunavail() {
self.state.enabled_harts |= 1 << num_harts;
}
num_harts += 1;
}
} else {
tracing::debug!("anynonexistent not supported, assuming only one hart exists")
}
tracing::debug!("Number of harts: {}", num_harts);
self.state.num_harts = num_harts;
let mut control = Dmcontrol(0);
control.set_dmactive(true);
control.set_hartsel(0);
self.schedule_write_dm_register(control)?;
let abstractcs: Abstractcs = self.read_dm_register()?;
self.state.progbuf_size = abstractcs.progbufsize() as u8;
tracing::debug!("Program buffer size: {}", self.state.progbuf_size);
self.state.data_register_count = abstractcs.datacount() as u8;
tracing::debug!(
"Number of data registers: {}",
self.state.data_register_count
);
let hartinfo: Hartinfo = self.read_dm_register()?;
self.state.nscratch = hartinfo.nscratch() as u8;
tracing::debug!("Number of dscratch registers: {}", self.state.nscratch);
let mut abstractauto = Abstractauto(0);
abstractauto.set_autoexecprogbuf(2u32.pow(self.state.progbuf_size as u32) - 1);
abstractauto.set_autoexecdata(2u32.pow(self.state.data_register_count as u32) - 1);
self.schedule_write_dm_register(abstractauto)?;
let abstractauto_readback: Abstractauto = self.read_dm_register()?;
self.state.supports_autoexec = abstractauto_readback == abstractauto;
tracing::debug!("Support for autoexec: {}", self.state.supports_autoexec);
abstractauto = Abstractauto(0);
self.schedule_write_dm_register(abstractauto)?;
let sbcs = self.read_dm_register::<Sbcs>()?;
if sbcs.sbversion() == 1 {
if sbcs.sbaccess8() {
self.state
.memory_access_info
.insert(RiscvBusAccess::A8, MemoryAccessMethod::SystemBus);
}
if sbcs.sbaccess16() {
self.state
.memory_access_info
.insert(RiscvBusAccess::A16, MemoryAccessMethod::SystemBus);
}
if sbcs.sbaccess32() {
self.state
.memory_access_info
.insert(RiscvBusAccess::A32, MemoryAccessMethod::SystemBus);
}
if sbcs.sbaccess64() {
self.state
.memory_access_info
.insert(RiscvBusAccess::A64, MemoryAccessMethod::SystemBus);
}
if sbcs.sbaccess128() {
self.state
.memory_access_info
.insert(RiscvBusAccess::A128, MemoryAccessMethod::SystemBus);
}
} else {
tracing::debug!(
"System bus interface version {} is not supported.",
sbcs.sbversion()
);
}
Ok(())
}
pub(crate) fn disable_debug_module(&mut self) -> Result<(), RiscvError> {
self.debug_on_sw_breakpoint(false)?;
let mut control = Dmcontrol(0);
control.set_dmactive(false);
self.write_dm_register(control)?;
Ok(())
}
pub(crate) fn halt(&mut self, timeout: Duration) -> Result<(), RiscvError> {
let mut dmcontrol = self.state.current_dmcontrol;
tracing::debug!(
"Before requesting halt, the Dmcontrol register value was: {:?}",
dmcontrol
);
dmcontrol.set_dmactive(true);
dmcontrol.set_haltreq(true);
self.schedule_write_dm_register(dmcontrol)?;
let result_status_idx = self.schedule_read_dm_register::<Dmstatus>()?;
dmcontrol.set_haltreq(false);
self.write_dm_register(dmcontrol)?;
let result_status = Dmstatus(self.dtm.read_deferred_result(result_status_idx)?.into_u32());
if result_status.allhalted() {
self.state.is_halted = true;
return Ok(());
}
dmcontrol.set_haltreq(true);
self.write_dm_register(dmcontrol)?;
self.wait_for_core_halted(timeout)?;
dmcontrol.set_haltreq(false);
self.write_dm_register(dmcontrol)?;
Ok(())
}
pub(crate) fn halt_with_previous(&mut self, timeout: Duration) -> Result<bool, RiscvError> {
let was_running = if self.state.is_halted {
false
} else {
let status_idx = self.schedule_read_dm_register::<Dmstatus>()?;
self.halt(timeout)?;
let before_status = Dmstatus(self.dtm.read_deferred_result(status_idx)?.into_u32());
!before_status.allhalted()
};
Ok(was_running)
}
pub(crate) fn core_info(&mut self) -> Result<CoreInformation, RiscvError> {
let pc: u64 = self
.read_csr(super::registers::PC.id().0)
.map(|v| v.into())?;
Ok(CoreInformation { pc })
}
pub(crate) fn core_halted(&mut self) -> Result<bool, RiscvError> {
if !self.state.is_halted {
let dmstatus: Dmstatus = self.read_dm_register()?;
tracing::trace!("{:?}", dmstatus);
self.state.is_halted = dmstatus.allhalted();
}
Ok(self.state.is_halted)
}
pub(crate) fn wait_for_core_halted(&mut self, timeout: Duration) -> Result<(), RiscvError> {
let start = Instant::now();
while !self.core_halted()? {
if start.elapsed() >= timeout {
return Err(RiscvError::Timeout);
}
std::thread::sleep(Duration::from_millis(1));
}
Ok(())
}
pub(crate) fn halted_access<R>(
&mut self,
op: impl FnOnce(&mut Self) -> Result<R, RiscvError>,
) -> Result<R, RiscvError> {
let was_running = self.halt_with_previous(Duration::from_millis(100))?;
let result = op(self);
if was_running {
self.resume_core()?;
}
result
}
pub(super) fn read_csr(&mut self, address: u16) -> Result<u32, RiscvError> {
tracing::debug!("Reading CSR {:#x}", address);
match self.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.read_csr_progbuf(address)
}
other => other,
}
}
pub(crate) fn read_dm_register<R: MemoryMappedRegister<u32>>(
&mut self,
) -> Result<R, RiscvError> {
tracing::debug!(
"Reading DM register '{}' at {:#010x}",
R::NAME,
R::get_mmio_address()
);
let register_value = self.read_dm_register_untyped(R::get_mmio_address())?.into();
tracing::debug!(
"Read DM register '{}' at {:#010x} = {:x?}",
R::NAME,
R::get_mmio_address(),
register_value
);
Ok(register_value)
}
fn read_dm_register_untyped(&mut self, address: u64) -> Result<u32, RiscvError> {
let read_idx = self.schedule_read_dm_register_untyped(address)?;
let register_value = self.dtm.read_deferred_result(read_idx)?.into_u32();
Ok(register_value)
}
pub(crate) fn write_dm_register<R: MemoryMappedRegister<u32>>(
&mut self,
register: R,
) -> Result<(), RiscvError> {
tracing::debug!(
"Write DM register '{}' at {:#010x} = {:x?}",
R::NAME,
R::get_mmio_address(),
register
);
self.write_dm_register_untyped(R::get_mmio_address(), register.into())
}
fn write_dm_register_untyped(&mut self, address: u64, value: u32) -> Result<(), RiscvError> {
self.cache_write(address, value);
self.dtm.write_with_timeout(address, value, RISCV_TIMEOUT)?;
Ok(())
}
fn cache_write(&mut self, address: u64, value: u32) {
if address == Dmcontrol::ADDRESS_OFFSET {
self.state.current_dmcontrol = Dmcontrol(value);
}
}
fn schedule_write_progbuf(&mut self, index: usize, value: u32) -> Result<(), RiscvError> {
match index {
0 => self.schedule_write_dm_register(Progbuf0(value)),
1 => self.schedule_write_dm_register(Progbuf1(value)),
2 => self.schedule_write_dm_register(Progbuf2(value)),
3 => self.schedule_write_dm_register(Progbuf3(value)),
4 => self.schedule_write_dm_register(Progbuf4(value)),
5 => self.schedule_write_dm_register(Progbuf5(value)),
6 => self.schedule_write_dm_register(Progbuf6(value)),
7 => self.schedule_write_dm_register(Progbuf7(value)),
8 => self.schedule_write_dm_register(Progbuf8(value)),
9 => self.schedule_write_dm_register(Progbuf9(value)),
10 => self.schedule_write_dm_register(Progbuf10(value)),
11 => self.schedule_write_dm_register(Progbuf11(value)),
12 => self.schedule_write_dm_register(Progbuf12(value)),
13 => self.schedule_write_dm_register(Progbuf13(value)),
14 => self.schedule_write_dm_register(Progbuf14(value)),
15 => self.schedule_write_dm_register(Progbuf15(value)),
e => Err(RiscvError::UnsupportedProgramBufferRegister(e)),
}
}
pub(crate) fn schedule_setup_program_buffer(&mut self, data: &[u32]) -> Result<(), RiscvError> {
let required_len = if self.state.implicit_ebreak {
data.len()
} else {
data.len() + 1
};
if required_len > self.state.progbuf_size as usize {
return Err(RiscvError::ProgramBufferTooSmall);
}
if data == &self.state.progbuf_cache[..data.len()] {
tracing::debug!("Program buffer is up-to-date, skipping write.");
return Ok(());
}
for (index, word) in data.iter().enumerate() {
self.schedule_write_progbuf(index, *word)?;
}
if !self.state.implicit_ebreak || data.len() < self.state.progbuf_size as usize {
self.schedule_write_progbuf(data.len(), assembly::EBREAK)?;
}
self.state.progbuf_cache[..data.len()].copy_from_slice(data);
Ok(())
}
fn perform_memory_read_sysbus<V: RiscvValue32>(
&mut self,
address: u32,
) -> Result<V, RiscvError> {
let mut sbcs = Sbcs(0);
sbcs.set_sbaccess(V::WIDTH as u32);
sbcs.set_sbreadonaddr(true);
self.schedule_write_dm_register(sbcs)?;
self.schedule_write_dm_register(Sbaddress0(address))?;
let mut results = vec![];
self.schedule_read_large_dtm_register::<V, Sbdata>(&mut results)?;
let sbcs = self.read_dm_register::<Sbcs>()?;
if sbcs.sberror() != 0 {
Err(RiscvError::SystemBusAccess)
} else {
V::read_scheduled_result(self, &mut results)
}
}
fn perform_memory_read_multiple_sysbus<V: RiscvValue32>(
&mut self,
address: u32,
data: &mut [V],
) -> Result<(), RiscvError> {
let mut sbcs = Sbcs(0);
sbcs.set_sbaccess(V::WIDTH as u32);
sbcs.set_sbreadonaddr(true);
sbcs.set_sbreadondata(true);
sbcs.set_sbautoincrement(true);
self.schedule_write_dm_register(sbcs)?;
self.schedule_write_dm_register(Sbaddress0(address))?;
let data_len = data.len();
let mut read_results = Vec::with_capacity(data_len);
for _ in data[..data_len - 1].iter() {
self.schedule_read_large_dtm_register::<V, Sbdata>(&mut read_results)?;
}
self.schedule_write_dm_register(Sbcs(0))?;
self.schedule_read_large_dtm_register::<V, Sbdata>(&mut read_results)?;
let sbcs = self.read_dm_register::<Sbcs>()?;
for out in data.iter_mut() {
*out = V::read_scheduled_result(self, &mut read_results)?;
}
if sbcs.sberror() != 0 {
Err(RiscvError::SystemBusAccess)
} else {
Ok(())
}
}
fn perform_memory_read_progbuf<V: RiscvValue32>(
&mut self,
address: u32,
) -> Result<V, RiscvError> {
self.halted_access(|core| {
let s0 = core.save_s0()?;
let lw_command = assembly::lw(0, 8, V::WIDTH as u8, 8);
core.schedule_setup_program_buffer(&[lw_command])?;
core.schedule_write_dm_register(Data0(address))?;
let mut command = AccessRegisterCommand(0);
command.set_cmd_type(0);
command.set_transfer(true);
command.set_write(true);
command.set_aarsize(RiscvBusAccess::A32);
command.set_postexec(true);
command.set_regno((registers::S0).id.0 as u32);
core.schedule_write_dm_register(command)?;
let abstractcs_idx = core.schedule_read_dm_register::<Abstractcs>()?;
let value = core.abstract_cmd_register_read(®isters::S0)?;
let abstractcs = Abstractcs(core.dtm.read_deferred_result(abstractcs_idx)?.into_u32());
AbstractCommandErrorKind::parse(abstractcs)?;
core.restore_s0(s0)?;
Ok(V::from_register_value(value))
})
}
fn perform_memory_read_multiple_progbuf<V: RiscvValue32>(
&mut self,
address: u32,
data: &mut [V],
) -> Result<(), RiscvError> {
self.halted_access(|core| {
let s0 = core.save_s0()?;
let s1 = core.save_s1()?;
let lw_command: u32 = assembly::lw(0, 8, V::WIDTH as u8, 9);
core.schedule_setup_program_buffer(&[
lw_command,
assembly::addi(8, 8, V::WIDTH.byte_width() as i16),
])?;
core.schedule_write_dm_register(Data0(address))?;
let mut command = AccessRegisterCommand(0);
command.set_cmd_type(0);
command.set_transfer(true);
command.set_write(true);
command.set_aarsize(RiscvBusAccess::A32);
command.set_postexec(true);
command.set_regno((registers::S0).id.0 as u32);
core.schedule_write_dm_register(command)?;
let data_len = data.len();
let mut result_idxs = Vec::with_capacity(data_len - 1);
for out_idx in 0..data_len - 1 {
let mut command = AccessRegisterCommand(0);
command.set_cmd_type(0);
command.set_transfer(true);
command.set_write(false);
command.set_aarsize(RiscvBusAccess::A32);
command.set_postexec(true);
command.set_regno((registers::S1).id.0 as u32);
core.schedule_write_dm_register(command)?;
let value_idx = core.schedule_read_dm_register::<Data0>()?;
result_idxs.push((out_idx, value_idx));
}
let last_value = core.abstract_cmd_register_read(®isters::S1)?;
data[data.len() - 1] = V::from_register_value(last_value);
for (out_idx, value_idx) in result_idxs {
let value = core.dtm.read_deferred_result(value_idx)?.into_u32();
data[out_idx] = V::from_register_value(value);
}
let status: Abstractcs = core.read_dm_register()?;
AbstractCommandErrorKind::parse(status)?;
core.restore_s0(s0)?;
core.restore_s1(s1)?;
Ok(())
})
}
fn perform_memory_write_sysbus<V: RiscvValue>(
&mut self,
address: u32,
data: &[V],
) -> Result<(), RiscvError> {
let mut sbcs = Sbcs(0);
sbcs.set_sbaccess(V::WIDTH as u32);
sbcs.set_sbautoincrement(true);
self.schedule_write_dm_register(sbcs)?;
self.schedule_write_dm_register(Sbaddress0(address))?;
for value in data {
self.schedule_write_large_dtm_register::<V, Sbdata>(*value)?;
}
let sbcs = self.read_dm_register::<Sbcs>()?;
if sbcs.sberror() != 0 {
Err(RiscvError::SystemBusAccess)
} else {
Ok(())
}
}
fn perform_memory_write_progbuf<V: RiscvValue32>(
&mut self,
address: u32,
data: V,
) -> Result<(), RiscvError> {
self.halted_access(|core| {
tracing::debug!(
"Memory write using progbuf - {:#010x} = {:#?}",
address,
data
);
let s0 = core.save_s0()?;
let s1 = core.save_s1()?;
let sw_command = assembly::sw(0, 8, V::WIDTH as u32, 9);
core.schedule_setup_program_buffer(&[sw_command])?;
core.abstract_cmd_register_write(®isters::S0, address)?;
core.schedule_write_dm_register(Data0(data.into()))?;
let mut command = AccessRegisterCommand(0);
command.set_cmd_type(0);
command.set_transfer(true);
command.set_write(true);
command.set_aarsize(RiscvBusAccess::A32);
command.set_postexec(true);
command.set_regno((registers::S1).id.0 as u32);
core.schedule_write_dm_register(command)?;
let status = core.read_dm_register::<Abstractcs>()?;
let error = AbstractCommandErrorKind::parse(status);
if let Err(error) = error {
tracing::error!(
"Executing the abstract command for write_{} failed: {:?} ({:x?})",
V::WIDTH.byte_width() * 8,
error,
status,
);
return Err(RiscvError::AbstractCommand(error));
}
core.restore_s0(s0)?;
core.restore_s1(s1)?;
Ok(())
})
}
fn perform_memory_write_multiple_progbuf<V: RiscvValue32>(
&mut self,
address: u32,
data: &[V],
) -> Result<(), RiscvError> {
self.halted_access(|core| {
let s0 = core.save_s0()?;
let s1 = core.save_s1()?;
core.schedule_setup_program_buffer(&[
assembly::sw(0, 8, V::WIDTH as u32, 9),
assembly::addi(8, 8, V::WIDTH.byte_width() as i16),
])?;
core.abstract_cmd_register_write(®isters::S0, address)?;
for value in data {
core.schedule_write_dm_register(Data0((*value).into()))?;
let mut command = AccessRegisterCommand(0);
command.set_cmd_type(0);
command.set_transfer(true);
command.set_write(true);
command.set_aarsize(RiscvBusAccess::A32);
command.set_postexec(true);
command.set_regno((registers::S1).id.0 as u32);
core.schedule_write_dm_register(command)?;
}
let status = core.read_dm_register::<Abstractcs>()?;
let error = AbstractCommandErrorKind::parse(status);
if let Err(error) = error {
tracing::error!(
"Executing the abstract command for write_multiple_{} failed: {:?} ({:x?})",
V::WIDTH.byte_width() * 8,
error,
status,
);
return Err(RiscvError::AbstractCommand(error));
}
core.restore_s0(s0)?;
core.restore_s1(s1)?;
Ok(())
})
}
pub(crate) fn execute_abstract_command(&mut self, command: u32) -> Result<(), RiscvError> {
let mut dmcontrol = self.state.current_dmcontrol;
dmcontrol.set_dmactive(true);
dmcontrol.set_haltreq(false);
dmcontrol.set_resumereq(false);
dmcontrol.set_ackhavereset(false);
self.schedule_write_dm_register(dmcontrol)?;
fn do_execute_abstract_command(
core: &mut RiscvCommunicationInterface,
command: Command,
) -> Result<(), RiscvError> {
let mut abstractcs_clear = Abstractcs(0);
abstractcs_clear.set_cmderr(0x7);
core.schedule_write_dm_register(abstractcs_clear)?;
core.schedule_write_dm_register(command)?;
let start_time = Instant::now();
let mut abstractcs;
loop {
abstractcs = core.read_dm_register::<Abstractcs>()?;
if !abstractcs.busy() {
break;
}
if start_time.elapsed() > RISCV_TIMEOUT {
return Err(RiscvError::Timeout);
}
}
tracing::debug!("abstracts: {:?}", abstractcs);
AbstractCommandErrorKind::parse(abstractcs)?;
Ok(())
}
match do_execute_abstract_command(self, Command(command)) {
err @ Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::HaltResume)) => {
if !self.core_halted()? {
self.halted_access(|core| do_execute_abstract_command(core, Command(command)))
} else {
err
}
}
other => other,
}
}
fn check_abstract_cmd_register_support(
&self,
regno: RegisterId,
rw: CoreRegisterAbstractCmdSupport,
) -> bool {
if let Some(status) = self.state.abstract_cmd_register_info.get(®no) {
status.supports(rw)
} else {
true
}
}
fn set_abstract_cmd_register_unsupported(
&mut self,
regno: RegisterId,
rw: CoreRegisterAbstractCmdSupport,
) {
let entry = self
.state
.abstract_cmd_register_info
.entry(regno)
.or_insert(CoreRegisterAbstractCmdSupport::BOTH);
entry.unset(rw);
}
pub(crate) fn abstract_cmd_register_read(
&mut self,
regno: impl Into<RegisterId>,
) -> Result<u32, RiscvError> {
let regno = regno.into();
if !self.check_abstract_cmd_register_support(regno, CoreRegisterAbstractCmdSupport::READ) {
return Err(RiscvError::AbstractCommand(
AbstractCommandErrorKind::NotSupported,
));
}
let mut command = AccessRegisterCommand(0);
command.set_cmd_type(0);
command.set_transfer(true);
command.set_aarsize(RiscvBusAccess::A32);
command.set_regno(regno.0 as u32);
match self.execute_abstract_command(command.0) {
Ok(_) => (),
err @ Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::NotSupported)) => {
self.set_abstract_cmd_register_unsupported(
regno,
CoreRegisterAbstractCmdSupport::READ,
);
err?;
}
Err(e) => return Err(e),
}
let register_value: Data0 = self.read_dm_register()?;
Ok(register_value.into())
}
pub(crate) fn abstract_cmd_register_write<V: RiscvValue>(
&mut self,
regno: impl Into<RegisterId>,
value: V,
) -> Result<(), RiscvError> {
let regno = regno.into();
if !self.check_abstract_cmd_register_support(regno, CoreRegisterAbstractCmdSupport::WRITE) {
return Err(RiscvError::AbstractCommand(
AbstractCommandErrorKind::NotSupported,
));
}
let mut command = AccessRegisterCommand(0);
command.set_cmd_type(0);
command.set_transfer(true);
command.set_write(true);
command.set_aarsize(V::WIDTH);
command.set_regno(regno.0 as u32);
self.schedule_write_large_dtm_register::<V, Arg0>(value)?;
match self.execute_abstract_command(command.0) {
Ok(_) => Ok(()),
err @ Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::NotSupported)) => {
self.set_abstract_cmd_register_unsupported(
regno,
CoreRegisterAbstractCmdSupport::WRITE,
);
err
}
Err(e) => Err(e),
}
}
pub fn read_csr_progbuf(&mut self, address: u16) -> Result<u32, RiscvError> {
self.halted_access(|core| {
tracing::debug!("Reading CSR {:#04x}", address);
if address > RISCV_MAX_CSR_ADDR {
return Err(RiscvError::UnsupportedCsrAddress(address));
}
let s0 = core.save_s0()?;
let csrr_cmd = assembly::csrr(8, address);
core.schedule_setup_program_buffer(&[csrr_cmd])?;
let mut postexec_cmd = AccessRegisterCommand(0);
postexec_cmd.set_postexec(true);
core.execute_abstract_command(postexec_cmd.0)?;
let reg_value = core.abstract_cmd_register_read(®isters::S0)?;
core.restore_s0(s0)?;
Ok(reg_value)
})
}
pub fn write_csr_progbuf(&mut self, address: u16, value: u32) -> Result<(), RiscvError> {
self.halted_access(|core| {
tracing::debug!("Writing CSR {:#04x}={}", address, value);
if address > RISCV_MAX_CSR_ADDR {
return Err(RiscvError::UnsupportedCsrAddress(address));
}
let s0 = core.save_s0()?;
core.abstract_cmd_register_write(®isters::S0, value)?;
let csrw_cmd = assembly::csrw(address, 8);
core.schedule_setup_program_buffer(&[csrw_cmd])?;
let mut postexec_cmd = AccessRegisterCommand(0);
postexec_cmd.set_postexec(true);
core.execute_abstract_command(postexec_cmd.0)?;
core.restore_s0(s0)?;
Ok(())
})
}
fn read_word<V: RiscvValue32>(&mut self, address: u32) -> Result<V, crate::Error> {
let result = match self.state.memory_access_method(V::WIDTH) {
MemoryAccessMethod::ProgramBuffer => self.perform_memory_read_progbuf(address)?,
MemoryAccessMethod::SystemBus if self.state.sysbus_requires_halting => {
self.halted_access(|this| this.perform_memory_read_sysbus(address))?
}
MemoryAccessMethod::SystemBus => self.perform_memory_read_sysbus(address)?,
MemoryAccessMethod::AbstractCommand => {
unimplemented!("Memory access using abstract commands is not implemted")
}
};
Ok(result)
}
fn read_multiple<V: RiscvValue32>(
&mut self,
address: u32,
data: &mut [V],
) -> Result<(), crate::Error> {
let access_method = self.state.memory_access_method(V::WIDTH);
tracing::debug!(
"read_multiple({:?}) from {:#08x} using {:?}",
V::WIDTH,
address,
access_method
);
match access_method {
MemoryAccessMethod::ProgramBuffer => {
self.perform_memory_read_multiple_progbuf(address, data)?;
}
MemoryAccessMethod::SystemBus if self.state.sysbus_requires_halting => {
self.halted_access(|this| this.perform_memory_read_multiple_sysbus(address, data))?
}
MemoryAccessMethod::SystemBus => {
self.perform_memory_read_multiple_sysbus(address, data)?;
}
MemoryAccessMethod::AbstractCommand => {
unimplemented!("Memory access using abstract commands is not implemted")
}
};
Ok(())
}
fn write_word<V: RiscvValue32>(&mut self, address: u32, data: V) -> Result<(), crate::Error> {
match self.state.memory_access_method(V::WIDTH) {
MemoryAccessMethod::ProgramBuffer => {
self.perform_memory_write_progbuf(address, data)?
}
MemoryAccessMethod::SystemBus if self.state.sysbus_requires_halting => {
self.halted_access(|this| this.perform_memory_write_sysbus(address, &[data]))?
}
MemoryAccessMethod::SystemBus => self.perform_memory_write_sysbus(address, &[data])?,
MemoryAccessMethod::AbstractCommand => {
unimplemented!("Memory access using abstract commands is not implemted")
}
};
Ok(())
}
fn write_multiple<V: RiscvValue32>(
&mut self,
address: u32,
data: &[V],
) -> Result<(), crate::Error> {
match self.state.memory_access_method(V::WIDTH) {
MemoryAccessMethod::SystemBus if self.state.sysbus_requires_halting => {
self.halted_access(|this| this.perform_memory_write_sysbus(address, data))?
}
MemoryAccessMethod::SystemBus => self.perform_memory_write_sysbus(address, data)?,
MemoryAccessMethod::ProgramBuffer => {
self.perform_memory_write_multiple_progbuf(address, data)?
}
MemoryAccessMethod::AbstractCommand => {
unimplemented!("Memory access using abstract commands is not implemted")
}
}
Ok(())
}
pub(crate) fn schedule_write_dm_register<R: MemoryMappedRegister<u32>>(
&mut self,
register: R,
) -> Result<(), RiscvError> {
tracing::debug!(
"Write DM register '{}' at {:#010x} = {:x?}",
R::NAME,
R::get_mmio_address(),
register
);
self.schedule_write_dm_register_untyped(R::get_mmio_address(), register.into())?;
Ok(())
}
fn schedule_write_dm_register_untyped(
&mut self,
address: u64,
value: u32,
) -> Result<Option<DeferredResultIndex>, RiscvError> {
self.cache_write(address, value);
self.dtm.schedule_write(address, value)
}
pub(super) fn schedule_read_dm_register<R: MemoryMappedRegister<u32>>(
&mut self,
) -> Result<DeferredResultIndex, RiscvError> {
tracing::debug!(
"Reading DM register '{}' at {:#010x}",
R::NAME,
R::get_mmio_address()
);
self.schedule_read_dm_register_untyped(R::get_mmio_address())
}
fn schedule_read_dm_register_untyped(
&mut self,
address: u64,
) -> Result<DeferredResultIndex, RiscvError> {
self.dtm.schedule_read(address)
}
fn schedule_read_large_dtm_register<V, R>(
&mut self,
results: &mut Vec<DeferredResultIndex>,
) -> Result<(), RiscvError>
where
V: RiscvValue,
R: LargeRegister,
{
V::schedule_read_from_register::<R>(self, results)
}
fn schedule_write_large_dtm_register<V, R>(
&mut self,
value: V,
) -> Result<Option<DeferredResultIndex>, RiscvError>
where
V: RiscvValue,
R: LargeRegister,
{
V::schedule_write_to_register::<R>(self, value)
}
pub(crate) fn supports_reset_halt_req(&mut self) -> Result<bool, RiscvError> {
if let Some(has_reset_halt_req) = self.state.hasresethaltreq {
Ok(has_reset_halt_req)
} else {
let dmstatus: Dmstatus = self.read_dm_register()?;
self.state.hasresethaltreq = Some(dmstatus.hasresethaltreq());
Ok(dmstatus.hasresethaltreq())
}
}
pub(crate) fn resume_core(&mut self) -> Result<(), RiscvError> {
self.state.is_halted = false; let mut dmcontrol = self.state.current_dmcontrol;
dmcontrol.set_dmactive(true);
dmcontrol.set_resumereq(true);
self.schedule_write_dm_register(dmcontrol)?;
let status_idx = self.schedule_read_dm_register::<Dmstatus>()?;
dmcontrol.set_resumereq(false);
self.write_dm_register(dmcontrol)?;
let status = Dmstatus(self.dtm.read_deferred_result(status_idx)?.into_u32());
if !status.allresumeack() {
return Err(RiscvError::RequestNotAcknowledged);
}
Ok(())
}
pub(crate) fn reset_hart_and_halt(&mut self, timeout: Duration) -> Result<(), RiscvError> {
tracing::debug!("Resetting core, setting hartreset bit");
let mut dmcontrol = self.state.current_dmcontrol;
dmcontrol.set_dmactive(true);
dmcontrol.set_hartreset(true);
dmcontrol.set_haltreq(true);
self.write_dm_register(dmcontrol)?;
let readback: Dmcontrol = self.read_dm_register()?;
if readback.hartreset() {
tracing::debug!("Clearing hartreset bit");
let mut dmcontrol = readback;
dmcontrol.set_dmactive(true);
dmcontrol.set_hartreset(false);
self.write_dm_register(dmcontrol)?;
} else {
tracing::debug!("Hartreset bit not supported, using ndmreset");
dmcontrol.set_hartreset(false);
dmcontrol.set_ndmreset(true);
dmcontrol.set_haltreq(true);
self.write_dm_register(dmcontrol)?;
tracing::debug!("Clearing ndmreset bit");
dmcontrol.set_ndmreset(false);
dmcontrol.set_haltreq(true);
self.write_dm_register(dmcontrol)?;
}
let start = Instant::now();
loop {
let readback: Dmstatus = self.read_dm_register()?;
if readback.allhavereset() && readback.allhalted() {
break;
}
if start.elapsed() > timeout {
return Err(RiscvError::RequestNotAcknowledged);
}
}
dmcontrol.set_haltreq(false);
dmcontrol.set_ackhavereset(true);
dmcontrol.set_hartreset(false);
dmcontrol.set_ndmreset(false);
self.write_dm_register(dmcontrol)?;
self.debug_on_sw_breakpoint(true)?;
Ok(())
}
pub(crate) fn debug_on_sw_breakpoint(&mut self, enabled: bool) -> Result<(), RiscvError> {
let mut dcsr = Dcsr(self.read_csr(0x7b0)?);
dcsr.set_ebreakm(enabled);
dcsr.set_ebreaks(enabled);
dcsr.set_ebreaku(enabled);
match self.abstract_cmd_register_write(0x7b0, dcsr.0) {
Err(RiscvError::AbstractCommand(AbstractCommandErrorKind::NotSupported)) => {
tracing::debug!("Could not write core register {:#x} with abstract command, falling back to program buffer", 0x7b0);
self.write_csr_progbuf(0x7b0, dcsr.0)
}
other => other,
}
}
pub(crate) fn sysbus_requires_halting(&mut self, en: bool) {
self.state.sysbus_requires_halting = en;
}
}
pub(crate) trait LargeRegister {
const R0_ADDRESS: u8;
const R1_ADDRESS: u8;
const R2_ADDRESS: u8;
const R3_ADDRESS: u8;
}
struct Sbdata {}
impl LargeRegister for Sbdata {
const R0_ADDRESS: u8 = Sbdata0::ADDRESS_OFFSET as u8;
const R1_ADDRESS: u8 = Sbdata1::ADDRESS_OFFSET as u8;
const R2_ADDRESS: u8 = Sbdata2::ADDRESS_OFFSET as u8;
const R3_ADDRESS: u8 = Sbdata3::ADDRESS_OFFSET as u8;
}
struct Arg0 {}
impl LargeRegister for Arg0 {
const R0_ADDRESS: u8 = Data0::ADDRESS_OFFSET as u8;
const R1_ADDRESS: u8 = Data1::ADDRESS_OFFSET as u8;
const R2_ADDRESS: u8 = Data2::ADDRESS_OFFSET as u8;
const R3_ADDRESS: u8 = Data3::ADDRESS_OFFSET as u8;
}
pub(crate) trait RiscvValue32: RiscvValue + Into<u32> {
fn from_register_value(value: u32) -> Self;
}
impl RiscvValue32 for u8 {
fn from_register_value(value: u32) -> Self {
value as u8
}
}
impl RiscvValue32 for u16 {
fn from_register_value(value: u32) -> Self {
value as u16
}
}
impl RiscvValue32 for u32 {
fn from_register_value(value: u32) -> Self {
value
}
}
pub(crate) trait RiscvValue: std::fmt::Debug + Copy + Sized {
const WIDTH: RiscvBusAccess;
fn schedule_read_from_register<R>(
interface: &mut RiscvCommunicationInterface,
results: &mut Vec<DeferredResultIndex>,
) -> Result<(), RiscvError>
where
R: LargeRegister;
fn read_scheduled_result(
interface: &mut RiscvCommunicationInterface,
results: &mut Vec<DeferredResultIndex>,
) -> Result<Self, RiscvError>;
fn schedule_write_to_register<R>(
interface: &mut RiscvCommunicationInterface,
value: Self,
) -> Result<Option<DeferredResultIndex>, RiscvError>
where
R: LargeRegister;
}
impl RiscvValue for u8 {
const WIDTH: RiscvBusAccess = RiscvBusAccess::A8;
fn schedule_read_from_register<R>(
interface: &mut RiscvCommunicationInterface,
results: &mut Vec<DeferredResultIndex>,
) -> Result<(), RiscvError>
where
R: LargeRegister,
{
results.push(interface.schedule_read_dm_register_untyped(R::R0_ADDRESS as u64)?);
Ok(())
}
fn read_scheduled_result(
interface: &mut RiscvCommunicationInterface,
results: &mut Vec<DeferredResultIndex>,
) -> Result<Self, RiscvError> {
let result = interface.dtm.read_deferred_result(results.remove(0))?;
Ok(result.into_u32() as u8)
}
fn schedule_write_to_register<R>(
interface: &mut RiscvCommunicationInterface,
value: Self,
) -> Result<Option<DeferredResultIndex>, RiscvError>
where
R: LargeRegister,
{
interface.schedule_write_dm_register_untyped(R::R0_ADDRESS as u64, value as u32)
}
}
impl RiscvValue for u16 {
const WIDTH: RiscvBusAccess = RiscvBusAccess::A16;
fn schedule_read_from_register<R>(
interface: &mut RiscvCommunicationInterface,
results: &mut Vec<DeferredResultIndex>,
) -> Result<(), RiscvError>
where
R: LargeRegister,
{
results.push(interface.schedule_read_dm_register_untyped(R::R0_ADDRESS as u64)?);
Ok(())
}
fn read_scheduled_result(
interface: &mut RiscvCommunicationInterface,
results: &mut Vec<DeferredResultIndex>,
) -> Result<Self, RiscvError> {
let result = interface.dtm.read_deferred_result(results.remove(0))?;
Ok(result.into_u32() as u16)
}
fn schedule_write_to_register<R>(
interface: &mut RiscvCommunicationInterface,
value: Self,
) -> Result<Option<DeferredResultIndex>, RiscvError>
where
R: LargeRegister,
{
interface.schedule_write_dm_register_untyped(R::R0_ADDRESS as u64, value as u32)
}
}
impl RiscvValue for u32 {
const WIDTH: RiscvBusAccess = RiscvBusAccess::A32;
fn schedule_read_from_register<R>(
interface: &mut RiscvCommunicationInterface,
results: &mut Vec<DeferredResultIndex>,
) -> Result<(), RiscvError>
where
R: LargeRegister,
{
results.push(interface.schedule_read_dm_register_untyped(R::R0_ADDRESS as u64)?);
Ok(())
}
fn read_scheduled_result(
interface: &mut RiscvCommunicationInterface,
results: &mut Vec<DeferredResultIndex>,
) -> Result<Self, RiscvError> {
let result = interface.dtm.read_deferred_result(results.remove(0))?;
Ok(result.into_u32())
}
fn schedule_write_to_register<R>(
interface: &mut RiscvCommunicationInterface,
value: Self,
) -> Result<Option<DeferredResultIndex>, RiscvError>
where
R: LargeRegister,
{
interface.schedule_write_dm_register_untyped(R::R0_ADDRESS as u64, value)
}
}
impl RiscvValue for u64 {
const WIDTH: RiscvBusAccess = RiscvBusAccess::A64;
fn schedule_read_from_register<R>(
interface: &mut RiscvCommunicationInterface,
results: &mut Vec<DeferredResultIndex>,
) -> Result<(), RiscvError>
where
R: LargeRegister,
{
results.push(interface.schedule_read_dm_register_untyped(R::R1_ADDRESS as u64)?);
results.push(interface.schedule_read_dm_register_untyped(R::R0_ADDRESS as u64)?);
Ok(())
}
fn read_scheduled_result(
interface: &mut RiscvCommunicationInterface,
results: &mut Vec<DeferredResultIndex>,
) -> Result<Self, RiscvError> {
let r1 = interface.dtm.read_deferred_result(results.remove(0))?;
let r0 = interface.dtm.read_deferred_result(results.remove(0))?;
Ok(((r1.into_u32() as u64) << 32) | (r0.into_u32() as u64))
}
fn schedule_write_to_register<R>(
interface: &mut RiscvCommunicationInterface,
value: Self,
) -> Result<Option<DeferredResultIndex>, RiscvError>
where
R: LargeRegister,
{
let upper_bits = (value >> 32) as u32;
let lower_bits = (value & 0xffff_ffff) as u32;
interface.schedule_write_dm_register_untyped(R::R1_ADDRESS as u64, upper_bits)?;
interface.schedule_write_dm_register_untyped(R::R0_ADDRESS as u64, lower_bits)
}
}
impl RiscvValue for u128 {
const WIDTH: RiscvBusAccess = RiscvBusAccess::A128;
fn schedule_read_from_register<R>(
interface: &mut RiscvCommunicationInterface,
results: &mut Vec<DeferredResultIndex>,
) -> Result<(), RiscvError>
where
R: LargeRegister,
{
results.push(interface.schedule_read_dm_register_untyped(R::R3_ADDRESS as u64)?);
results.push(interface.schedule_read_dm_register_untyped(R::R2_ADDRESS as u64)?);
results.push(interface.schedule_read_dm_register_untyped(R::R1_ADDRESS as u64)?);
results.push(interface.schedule_read_dm_register_untyped(R::R0_ADDRESS as u64)?);
Ok(())
}
fn read_scheduled_result(
interface: &mut RiscvCommunicationInterface,
results: &mut Vec<DeferredResultIndex>,
) -> Result<Self, RiscvError> {
let r3 = interface.dtm.read_deferred_result(results.remove(0))?;
let r2 = interface.dtm.read_deferred_result(results.remove(0))?;
let r1 = interface.dtm.read_deferred_result(results.remove(0))?;
let r0 = interface.dtm.read_deferred_result(results.remove(0))?;
Ok(((r3.into_u32() as u128) << 96)
| ((r2.into_u32() as u128) << 64)
| ((r1.into_u32() as u128) << 32)
| (r0.into_u32() as u128))
}
fn schedule_write_to_register<R>(
interface: &mut RiscvCommunicationInterface,
value: Self,
) -> Result<Option<DeferredResultIndex>, RiscvError>
where
R: LargeRegister,
{
let bits_3 = (value >> 96) as u32;
let bits_2 = (value >> 64) as u32;
let bits_1 = (value >> 32) as u32;
let bits_0 = (value & 0xffff_ffff) as u32;
interface.schedule_write_dm_register_untyped(R::R3_ADDRESS as u64, bits_3)?;
interface.schedule_write_dm_register_untyped(R::R2_ADDRESS as u64, bits_2)?;
interface.schedule_write_dm_register_untyped(R::R1_ADDRESS as u64, bits_1)?;
interface.schedule_write_dm_register_untyped(R::R0_ADDRESS as u64, bits_0)
}
}
impl MemoryInterface for RiscvCommunicationInterface<'_> {
fn supports_native_64bit_access(&mut self) -> bool {
false
}
fn read_word_64(&mut self, address: u64) -> Result<u64, crate::error::Error> {
let address = valid_32bit_address(address)?;
let mut ret = self.read_word::<u32>(address)? as u64;
ret |= (self.read_word::<u32>(address + 4)? as u64) << 32;
Ok(ret)
}
fn read_word_32(&mut self, address: u64) -> Result<u32, crate::Error> {
let address = valid_32bit_address(address)?;
tracing::debug!("read_word_32 from {:#08x}", address);
self.read_word(address)
}
fn read_word_16(&mut self, address: u64) -> Result<u16, crate::Error> {
let address = valid_32bit_address(address)?;
tracing::debug!("read_word_16 from {:#08x}", address);
self.read_word(address)
}
fn read_word_8(&mut self, address: u64) -> Result<u8, crate::Error> {
let address = valid_32bit_address(address)?;
tracing::debug!("read_word_8 from {:#08x}", address);
self.read_word(address)
}
fn read_64(&mut self, address: u64, data: &mut [u64]) -> Result<(), crate::error::Error> {
let address = valid_32bit_address(address)?;
tracing::debug!("read_64 from {:#08x}", address);
for (i, d) in data.iter_mut().enumerate() {
*d = self.read_word_64((address + (i as u32 * 8)).into())?;
}
Ok(())
}
fn read_32(&mut self, address: u64, data: &mut [u32]) -> Result<(), crate::Error> {
let address = valid_32bit_address(address)?;
tracing::debug!("read_32 from {:#08x}", address);
self.read_multiple(address, data)
}
fn read_16(&mut self, address: u64, data: &mut [u16]) -> Result<(), crate::Error> {
let address = valid_32bit_address(address)?;
tracing::debug!("read_16 from {:#08x}", address);
self.read_multiple(address, data)
}
fn read_8(&mut self, address: u64, data: &mut [u8]) -> Result<(), crate::Error> {
let address = valid_32bit_address(address)?;
tracing::debug!("read_8 from {:#08x}", address);
self.read_multiple(address, data)
}
fn read(&mut self, address: u64, data: &mut [u8]) -> Result<(), crate::Error> {
let address = valid_32bit_address(address)?;
tracing::debug!("read from {:#08x}", address);
self.read_multiple(address, data)
}
fn write_word_64(&mut self, address: u64, data: u64) -> Result<(), crate::error::Error> {
let address = valid_32bit_address(address)?;
let low_word = data as u32;
let high_word = (data >> 32) as u32;
self.write_word(address, low_word)?;
self.write_word(address + 4, high_word)
}
fn write_word_32(&mut self, address: u64, data: u32) -> Result<(), crate::Error> {
let address = valid_32bit_address(address)?;
self.write_word(address, data)
}
fn write_word_16(&mut self, address: u64, data: u16) -> Result<(), crate::Error> {
let address = valid_32bit_address(address)?;
self.write_word(address, data)
}
fn write_word_8(&mut self, address: u64, data: u8) -> Result<(), crate::Error> {
let address = valid_32bit_address(address)?;
self.write_word(address, data)
}
fn write_64(&mut self, address: u64, data: &[u64]) -> Result<(), crate::error::Error> {
let address = valid_32bit_address(address)?;
tracing::debug!("write_64 to {:#08x}", address);
for (i, d) in data.iter().enumerate() {
self.write_word_64((address + (i as u32 * 8)).into(), *d)?;
}
Ok(())
}
fn write_32(&mut self, address: u64, data: &[u32]) -> Result<(), crate::Error> {
let address = valid_32bit_address(address)?;
tracing::debug!("write_32 to {:#08x}", address);
self.write_multiple(address, data)
}
fn write_16(&mut self, address: u64, data: &[u16]) -> Result<(), crate::Error> {
let address = valid_32bit_address(address)?;
tracing::debug!("write_16 to {:#08x}", address);
self.write_multiple(address, data)
}
fn write_8(&mut self, address: u64, data: &[u8]) -> Result<(), crate::Error> {
let address = valid_32bit_address(address)?;
tracing::debug!("write_8 to {:#08x}", address);
self.write_multiple(address, data)
}
fn write(&mut self, address: u64, data: &[u8]) -> Result<(), crate::Error> {
let address = valid_32bit_address(address)?;
self.write_multiple(address, data)
}
fn supports_8bit_transfers(&self) -> Result<bool, crate::Error> {
Ok(true)
}
fn flush(&mut self) -> Result<(), crate::Error> {
Ok(())
}
}
#[derive(Copy, Clone, PartialEq, PartialOrd, Hash, Eq, Debug)]
pub enum RiscvBusAccess {
A8 = 0,
A16 = 1,
A32 = 2,
A64 = 3,
A128 = 4,
}
impl RiscvBusAccess {
const fn byte_width(&self) -> usize {
match self {
RiscvBusAccess::A8 => 1,
RiscvBusAccess::A16 => 2,
RiscvBusAccess::A32 => 4,
RiscvBusAccess::A64 => 8,
RiscvBusAccess::A128 => 16,
}
}
}
impl From<RiscvBusAccess> for u8 {
fn from(value: RiscvBusAccess) -> Self {
value as u8
}
}
#[derive(Debug, Copy, Clone)]
#[allow(dead_code)]
enum MemoryAccessMethod {
ProgramBuffer,
AbstractCommand,
SystemBus,
}
memory_mapped_bitfield_register! {
pub struct AccessRegisterCommand(u32);
0x17, "command",
impl From;
pub _, set_cmd_type: 31, 24;
pub u8, from into RiscvBusAccess, _, set_aarsize: 22, 20;
pub _, set_aarpostincrement: 19;
pub _, set_postexec: 18;
pub _, set_transfer: 17;
pub _, set_write: 16;
pub _, set_regno: 15, 0;
}
memory_mapped_bitfield_register! {
pub struct Sbcs(u32);
0x38, "sbcs",
impl From;
sbversion, _: 31, 29;
sbbusyerror, set_sbbusyerror: 22;
sbbusy, _: 21;
sbreadonaddr, set_sbreadonaddr: 20;
sbaccess, set_sbaccess: 19, 17;
sbautoincrement, set_sbautoincrement: 16;
sbreadondata, set_sbreadondata: 15;
sberror, set_sberror: 14, 12;
sbasize, _: 11, 5;
sbaccess128, _: 4;
sbaccess64, _: 3;
sbaccess32, _: 2;
sbaccess16, _: 1;
sbaccess8, _: 0;
}
memory_mapped_bitfield_register! {
#[derive(Eq, PartialEq)]
pub struct Abstractauto(u32);
0x18, "abstractauto",
impl From;
autoexecprogbuf, set_autoexecprogbuf: 31, 16;
autoexecdata, set_autoexecdata: 11, 0;
}
memory_mapped_bitfield_register! {
pub struct AccessMemoryCommand(u32);
0x17, "command",
_, set_cmd_type: 31, 24;
pub _, set_aamvirtual: 23;
pub _, set_aamsize: 22,20;
pub _, set_aampostincrement: 19;
pub _, set_write: 16;
pub _, set_target_specific: 15, 14;
}
impl From<AccessMemoryCommand> for u32 {
fn from(register: AccessMemoryCommand) -> Self {
let mut reg = register;
reg.set_cmd_type(2);
reg.0
}
}
impl From<u32> for AccessMemoryCommand {
fn from(value: u32) -> Self {
Self(value)
}
}
memory_mapped_bitfield_register! { pub struct Sbaddress0(u32); 0x39, "sbaddress0", impl From; }
memory_mapped_bitfield_register! { pub struct Sbaddress1(u32); 0x3a, "sbaddress1", impl From; }
memory_mapped_bitfield_register! { pub struct Sbaddress2(u32); 0x3b, "sbaddress2", impl From; }
memory_mapped_bitfield_register! { pub struct Sbaddress3(u32); 0x37, "sbaddress3", impl From; }
memory_mapped_bitfield_register! { pub struct Sbdata0(u32); 0x3c, "sbdata0", impl From; }
memory_mapped_bitfield_register! { pub struct Sbdata1(u32); 0x3d, "sbdata1", impl From; }
memory_mapped_bitfield_register! { pub struct Sbdata2(u32); 0x3e, "sbdata2", impl From; }
memory_mapped_bitfield_register! { pub struct Sbdata3(u32); 0x3f, "sbdata3", impl From; }
memory_mapped_bitfield_register! { pub struct Confstrptr0(u32); 0x19, "confstrptr0", impl From; }
memory_mapped_bitfield_register! { pub struct Confstrptr1(u32); 0x1a, "confstrptr1", impl From; }
memory_mapped_bitfield_register! { pub struct Confstrptr2(u32); 0x1b, "confstrptr2", impl From; }
memory_mapped_bitfield_register! { pub struct Confstrptr3(u32); 0x1c, "confstrptr3", impl From; }