use super::{register, Dmcontrol, Dmstatus};
use crate::architecture::riscv::{Abstractcs, Command, Data0, Progbuf0, Progbuf1};
use crate::DebugProbeError;
use crate::{Memory, MemoryInterface, Probe};
use crate::{CoreRegisterAddress, Error as ProbeRsError};
use std::cell::RefCell;
use std::rc::Rc;
use std::{
convert::TryInto,
time::{Duration, Instant},
};
use bitfield::bitfield;
use thiserror::Error;
#[derive(Error, Debug)]
pub(crate) enum RiscvError {
#[error("Error during read/write to the DMI register: {0:?}")]
DmiTransfer(DmiOperationStatus),
#[error("Debug Probe Error: {0}")]
DebugProbe(#[from] DebugProbeError),
#[error("Timeout during JTAG register access.")]
Timeout,
#[error("Error occured 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 module is currently not supported.")]
UnsupportedDebugModuleVersion(u8),
}
impl From<RiscvError> for ProbeRsError {
fn from(err: RiscvError) -> Self {
match err {
RiscvError::DebugProbe(e) => e.into(),
other => ProbeRsError::ArchitectureSpecific(Box::new(other)),
}
}
}
#[derive(Debug)]
pub(crate) enum AbstractCommandErrorKind {
None = 0,
Busy = 1,
NotSupported = 2,
Exception = 3,
HaltResume = 4,
Bus = 5,
_Reserved = 6,
Other = 7,
}
impl AbstractCommandErrorKind {
fn parse(value: u8) -> Self {
use AbstractCommandErrorKind::*;
match value {
0 => None,
1 => Busy,
2 => NotSupported,
3 => Exception,
4 => HaltResume,
5 => Bus,
6 => _Reserved,
7 => Other,
_ => panic!("cmderr is a 3 bit value, values higher than 7 should not occur."),
}
}
}
#[allow(dead_code)]
#[derive(Debug, Copy, Clone, PartialEq)]
enum DebugModuleVersion {
NoModule = 0,
Version0_11 = 1,
Version0_13 = 2,
NonConforming = 15,
}
#[derive(Clone, Debug)]
pub struct RiscvCommunicationInterface {
inner: Rc<RefCell<InnerRiscvCommunicationInterface>>,
}
impl RiscvCommunicationInterface {
pub(crate) fn new(probe: Probe) -> Result<Self, RiscvError> {
Ok(Self {
inner: Rc::new(RefCell::new(InnerRiscvCommunicationInterface::build(
probe,
)?)),
})
}
pub(super) fn read_dm_register<R: DebugRegister>(&self) -> Result<R, RiscvError> {
self.inner.borrow_mut().read_dm_register()
}
pub(super) fn write_dm_register(&self, register: impl DebugRegister) -> Result<(), RiscvError> {
self.inner.borrow_mut().write_dm_register(register)
}
pub(crate) fn execute_abstract_command(&self, command: u32) -> Result<(), RiscvError> {
self.inner.borrow_mut().execute_abstract_command(command)
}
pub(crate) fn abstract_cmd_register_read(
&self,
regno: impl Into<CoreRegisterAddress>,
) -> Result<u32, RiscvError> {
self.inner.borrow_mut().abstract_cmd_register_read(regno)
}
pub(crate) fn abstract_cmd_register_write(
&self,
regno: impl Into<CoreRegisterAddress>,
value: u32,
) -> Result<(), RiscvError> {
self.inner
.borrow_mut()
.abstract_cmd_register_write(regno, value)
}
pub fn read_idcode(&self) -> Result<u32, DebugProbeError> {
self.inner.borrow_mut().read_idcode()
}
pub fn close(self) -> Result<Probe, Self> {
Rc::try_unwrap(self.inner)
.map(|cell| cell.into_inner().probe)
.map_err(|e| RiscvCommunicationInterface { inner: e })
}
pub fn memory(&self) -> Memory {
Memory::new(self.clone())
}
}
impl MemoryInterface for RiscvCommunicationInterface {
fn read32(&mut self, address: u32) -> Result<u32, crate::Error> {
self.inner.borrow_mut().read32(address)
}
fn read8(&mut self, address: u32) -> Result<u8, crate::Error> {
self.inner.borrow_mut().read8(address)
}
fn read_block32(&mut self, address: u32, data: &mut [u32]) -> Result<(), crate::Error> {
self.inner.borrow_mut().read_block32(address, data)
}
fn read_block8(&mut self, address: u32, data: &mut [u8]) -> Result<(), crate::Error> {
self.inner.borrow_mut().read_block8(address, data)
}
fn write32(&mut self, addr: u32, data: u32) -> Result<(), crate::Error> {
self.inner.borrow_mut().write32(addr, data)
}
fn write8(&mut self, addr: u32, data: u8) -> Result<(), crate::Error> {
self.inner.borrow_mut().write8(addr, data)
}
fn write_block32(&mut self, addr: u32, data: &[u32]) -> Result<(), crate::Error> {
self.inner.borrow_mut().write_block32(addr, data)
}
fn write_block8(&mut self, addr: u32, data: &[u8]) -> Result<(), crate::Error> {
self.inner.borrow_mut().write_block8(addr, data)
}
}
#[derive(Debug)]
struct InnerRiscvCommunicationInterface {
probe: Probe,
abits: u32,
}
const RISCV_TIMEOUT: Duration = Duration::from_secs(5);
impl InnerRiscvCommunicationInterface {
pub fn build(mut probe: Probe) -> Result<Self, RiscvError> {
log::debug!("Building RISCV interface");
let jtag_interface = probe
.get_interface_jtag_mut()
.ok_or(DebugProbeError::InterfaceNotAvailable("JTAG"))?;
let dtmcs_raw = jtag_interface.read_register(DTMCS_ADDRESS, DTMCS_WIDTH)?;
let dtmcs = Dtmcs(u32::from_le_bytes((&dtmcs_raw[..]).try_into().unwrap()));
log::debug!("Dtmcs: {:?}", dtmcs);
let abits = dtmcs.abits();
let idle_cycles = dtmcs.idle();
jtag_interface.set_idle_cycles(idle_cycles as u8);
let mut interface = InnerRiscvCommunicationInterface { probe, abits };
interface.dmi_reset()?;
let status: Dmstatus = interface.read_dm_register()?;
if status.version() != DebugModuleVersion::Version0_13 as u32 {
return Err(RiscvError::UnsupportedDebugModuleVersion(
status.version() as u8
));
}
log::debug!("dmstatus: {:?}", status);
let mut control = Dmcontrol(0);
control.set_dmactive(true);
interface.write_dm_register(control)?;
Ok(interface)
}
fn dmi_reset(&mut self) -> Result<(), RiscvError> {
let mut dtmcs = Dtmcs(0);
dtmcs.set_dmireset(true);
let Dtmcs(reg_value) = dtmcs;
let bytes = reg_value.to_le_bytes();
let jtag_interface = self
.probe
.get_interface_jtag_mut()
.ok_or(DebugProbeError::InterfaceNotAvailable("JTAG"))?;
jtag_interface.write_register(DTMCS_ADDRESS, &bytes, DTMCS_WIDTH)?;
Ok(())
}
fn read_idcode(&mut self) -> Result<u32, DebugProbeError> {
let jtag_interface = self
.probe
.get_interface_jtag_mut()
.ok_or(DebugProbeError::InterfaceNotAvailable("JTAG"))?;
let value = jtag_interface.read_register(0x1, 32)?;
Ok(u32::from_le_bytes((&value[..]).try_into().unwrap()))
}
fn dmi_register_access(
&mut self,
address: u64,
value: u32,
op: DmiOperation,
) -> Result<u32, RiscvError> {
let register_value: u128 = ((address as u128) << DMI_ADDRESS_BIT_OFFSET)
| ((value as u128) << DMI_VALUE_BIT_OFFSET)
| op as u128;
let bytes = register_value.to_le_bytes();
let bit_size = self.abits + DMI_ADDRESS_BIT_OFFSET;
let jtag_interface = self
.probe
.get_interface_jtag_mut()
.ok_or(DebugProbeError::InterfaceNotAvailable("JTAG"))?;
let response_bytes = jtag_interface.write_register(DMI_ADDRESS, &bytes, bit_size)?;
let response_value: u128 = response_bytes.iter().enumerate().fold(0, |acc, elem| {
let (byte_offset, value) = elem;
acc + ((*value as u128) << (8 * byte_offset))
});
let op = (response_value & DMI_OP_MASK) as u8;
if op != 0 {
return Err(RiscvError::DmiTransfer(
DmiOperationStatus::parse(op).unwrap(),
));
}
let value = (response_value >> 2) as u32;
Ok(value)
}
fn dmi_register_access_with_timeout(
&mut self,
address: u64,
value: u32,
op: DmiOperation,
timeout: Duration,
) -> Result<u32, RiscvError> {
let start_time = Instant::now();
loop {
match self.dmi_register_access(address, value, op) {
Ok(result) => return Ok(result),
Err(RiscvError::DmiTransfer(DmiOperationStatus::RequestInProgress)) => {
self.dmi_reset()?;
}
Err(e) => return Err(e),
}
if start_time.elapsed() > timeout {
return Err(RiscvError::Timeout);
}
}
}
pub(crate) fn read_dm_register<R: DebugRegister>(&mut self) -> Result<R, RiscvError> {
log::debug!("Reading DM register '{}' at {:#010x}", R::NAME, R::ADDRESS);
self.dmi_register_access_with_timeout(
R::ADDRESS as u64,
0,
DmiOperation::Read,
RISCV_TIMEOUT,
)?;
let response =
self.dmi_register_access_with_timeout(0, 0, DmiOperation::NoOp, RISCV_TIMEOUT)?;
log::debug!(
"Read DM register '{}' at {:#010x} = {:#010x}",
R::NAME,
R::ADDRESS,
response
);
Ok(response.into())
}
pub(crate) fn write_dm_register<R: DebugRegister>(
&mut self,
register: R,
) -> Result<(), RiscvError> {
let data = register.into();
log::debug!(
"Write DM register '{}' at {:#010x} = {:#010x}",
R::NAME,
R::ADDRESS,
data
);
self.dmi_register_access_with_timeout(
R::ADDRESS as u64,
data,
DmiOperation::Write,
RISCV_TIMEOUT,
)?;
Ok(())
}
fn perform_memory_read(
&mut self,
address: u32,
width: RiscvBusAccess,
) -> Result<u32, RiscvError> {
let s0 = self.abstract_cmd_register_read(®ister::S0)?;
let mut lw_command: u32 = 0b000000000000_01000_000_01000_0000011;
assert!((width as u32) < 3, "Width larger than 3 not supported yet");
lw_command |= (width as u32) << 12;
let ebreak_cmd = 0b000000000001_00000_000_00000_1110011;
self.write_dm_register(Progbuf0(lw_command))?;
self.write_dm_register(Progbuf1(ebreak_cmd))?;
self.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((register::S0).address.0 as u32);
self.write_dm_register(command)?;
let status: Abstractcs = self.read_dm_register()?;
if status.cmderr() != 0 {
return Err(RiscvError::AbstractCommand(
AbstractCommandErrorKind::parse(status.cmderr() as u8),
));
}
let value = self.abstract_cmd_register_read(®ister::S0)?;
self.abstract_cmd_register_write(®ister::S0, s0)?;
Ok(value)
}
fn perform_memory_write(
&mut self,
address: u32,
width: RiscvBusAccess,
data: u32,
) -> Result<(), RiscvError> {
let s0 = self.abstract_cmd_register_read(®ister::S0)?;
let s1 = self.abstract_cmd_register_read(®ister::S1)?;
let mut sw_command: u32 = 0b0000000_01001_01000_000_00000_0100011;
assert!((width as u32) < 3, "Width larger than 3 not supported yet");
sw_command |= (width as u32) << 12;
let ebreak_cmd = 0b000000000001_00000_000_00000_1110011;
self.write_dm_register(Progbuf0(sw_command))?;
self.write_dm_register(Progbuf1(ebreak_cmd))?;
self.abstract_cmd_register_write(®ister::S0, address)?;
self.write_dm_register(Data0(data))?;
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((register::S1).address.0 as u32);
self.write_dm_register(command)?;
let status: Abstractcs = self.read_dm_register()?;
if status.cmderr() != 0 {
return Err(RiscvError::AbstractCommand(
AbstractCommandErrorKind::parse(status.cmderr() as u8),
));
}
self.abstract_cmd_register_write(®ister::S0, s0)?;
self.abstract_cmd_register_write(®ister::S1, s1)?;
Ok(())
}
pub(crate) fn execute_abstract_command(&mut self, command: u32) -> Result<(), RiscvError> {
let mut dmcontrol = Dmcontrol(0);
dmcontrol.set_haltreq(false);
dmcontrol.set_resumereq(false);
dmcontrol.set_ackhavereset(true);
dmcontrol.set_dmactive(true);
self.write_dm_register(dmcontrol)?;
let abstractcs_prev: Abstractcs = self.read_dm_register()?;
log::debug!("abstractcs: {:?}", abstractcs_prev);
if abstractcs_prev.cmderr() != 0 {
let mut abstractcs_clear = Abstractcs(0);
abstractcs_clear.set_cmderr(0x7);
self.write_dm_register(abstractcs_clear)?;
}
self.write_dm_register(Command(command))?;
let start_time = Instant::now();
let mut abstractcs: Abstractcs;
loop {
abstractcs = self.read_dm_register()?;
if !abstractcs.busy() {
break;
}
if start_time.elapsed() > RISCV_TIMEOUT {
return Err(RiscvError::Timeout);
}
}
log::debug!("abstracts: {:?}", abstractcs);
if abstractcs.cmderr() != 0 {
return Err(RiscvError::AbstractCommand(
AbstractCommandErrorKind::parse(abstractcs.cmderr() as u8),
));
}
Ok(())
}
pub(crate) fn abstract_cmd_register_read(
&mut self,
regno: impl Into<CoreRegisterAddress>,
) -> Result<u32, RiscvError> {
let mut command = AccessRegisterCommand(0);
command.set_cmd_type(0);
command.set_transfer(true);
command.set_aarsize(RiscvBusAccess::A32);
command.set_regno(regno.into().0 as u32);
self.execute_abstract_command(command.0)?;
let register_value: Data0 = self.read_dm_register()?;
Ok(register_value.into())
}
pub(crate) fn abstract_cmd_register_write(
&mut self,
regno: impl Into<CoreRegisterAddress>,
value: u32,
) -> Result<(), RiscvError> {
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_regno(regno.into().0 as u32);
self.write_dm_register(Data0(value))?;
self.execute_abstract_command(command.0)?;
Ok(())
}
}
impl MemoryInterface for InnerRiscvCommunicationInterface {
fn read32(&mut self, address: u32) -> Result<u32, crate::Error> {
let result = self.perform_memory_read(address, RiscvBusAccess::A32)?;
Ok(result)
}
fn read8(&mut self, address: u32) -> Result<u8, crate::Error> {
let value = self.perform_memory_read(address, RiscvBusAccess::A8)?;
Ok((value & 0xff) as u8)
}
fn read_block32(&mut self, address: u32, data: &mut [u32]) -> Result<(), crate::Error> {
for (offset, word) in data.iter_mut().enumerate() {
*word = self.read32(address + ((offset * 4) as u32))?;
}
Ok(())
}
fn read_block8(&mut self, address: u32, data: &mut [u8]) -> Result<(), crate::Error> {
for (offset, byte) in data.iter_mut().enumerate() {
*byte = self.read8(address + (offset as u32))?;
}
Ok(())
}
fn write32(&mut self, address: u32, data: u32) -> Result<(), crate::Error> {
self.perform_memory_write(address, RiscvBusAccess::A32, data)?;
Ok(())
}
fn write8(&mut self, address: u32, data: u8) -> Result<(), crate::Error> {
self.perform_memory_write(address, RiscvBusAccess::A8, data as u32)?;
Ok(())
}
fn write_block32(&mut self, address: u32, data: &[u32]) -> Result<(), crate::Error> {
for (offset, word) in data.iter().enumerate() {
self.write32(address + ((offset * 4) as u32), *word)?;
}
Ok(())
}
fn write_block8(&mut self, address: u32, data: &[u8]) -> Result<(), crate::Error> {
for (offset, byte) in data.iter().enumerate() {
self.write8(address + (offset as u32), *byte)?;
}
Ok(())
}
}
#[derive(Copy, Clone, Debug)]
pub enum RiscvBusAccess {
A8 = 0,
A16 = 1,
A32 = 2,
A64 = 3,
A128 = 4,
}
impl From<RiscvBusAccess> for u8 {
fn from(value: RiscvBusAccess) -> Self {
value as u8
}
}
bitfield! {
struct Dtmcs(u32);
impl Debug;
_, set_dmihardreset: 17;
_, set_dmireset: 16;
idle, _: 14, 12;
dmistat, _: 11,10;
abits, _: 9,4;
version, _: 3,0;
}
const DTMCS_ADDRESS: u32 = 0x10;
const DTMCS_WIDTH: u32 = 32;
const DMI_ADDRESS: u32 = 0x11;
const DMI_ADDRESS_BIT_OFFSET: u32 = 34;
const DMI_VALUE_BIT_OFFSET: u32 = 2;
const DMI_OP_MASK: u128 = 0x3;
bitfield! {
pub struct AccessRegisterCommand(u32);
impl Debug;
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;
}
impl DebugRegister for AccessRegisterCommand {
const ADDRESS: u8 = 0x17;
const NAME: &'static str = "command";
}
impl From<AccessRegisterCommand> for u32 {
fn from(register: AccessRegisterCommand) -> Self {
register.0
}
}
impl From<u32> for AccessRegisterCommand {
fn from(value: u32) -> Self {
Self(value)
}
}
pub(super) trait DebugRegister: Into<u32> + From<u32> {
const ADDRESS: u8;
const NAME: &'static str;
}
bitfield! {
pub struct Sbcs(u32);
impl Debug;
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: 16;
sberror, set_sberror: 14, 12;
sbasize, _: 11, 5;
sbaccess128, _: 4;
sbaccess64, _: 3;
sbaccess32, _: 2;
sbaccess16, _: 1;
sbaccess8, _: 0;
}
impl DebugRegister for Sbcs {
const ADDRESS: u8 = 0x38;
const NAME: &'static str = "sbcs";
}
impl From<Sbcs> for u32 {
fn from(register: Sbcs) -> Self {
register.0
}
}
bitfield! {
pub struct Abstractauto(u32);
impl Debug;
autoexecprogbuf, set_autoexecprogbuf: 31, 16;
autoexecdata, set_autoexecdata: 11, 0;
}
impl DebugRegister for Abstractauto {
const ADDRESS: u8 = 0x38;
const NAME: &'static str = "abstractauto";
}
impl From<Abstractauto> for u32 {
fn from(register: Abstractauto) -> Self {
register.0
}
}
impl From<u32> for Abstractauto {
fn from(value: u32) -> Self {
Self(value)
}
}
impl From<u32> for Sbcs {
fn from(value: u32) -> Self {
Self(value)
}
}
bitfield! {
pub struct AccessMemoryCommand(u32);
impl Debug;
_, 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 DebugRegister for AccessMemoryCommand {
const ADDRESS: u8 = 0x17;
const NAME: &'static str = "command";
}
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)
}
}
data_register! { Sbaddress0, 0x39, "sbaddress0" }
data_register! { Sbaddress1, 0x3a, "sbaddress1" }
data_register! { Sbaddress2, 0x3b, "sbaddress2" }
data_register! { Sbaddress3, 0x37, "sbaddress3" }
data_register! { Sbdata0, 0x3c, "sbdata0" }
data_register! { Sbdata1, 0x3d, "sbdata1" }
data_register! { Sbdata2, 0x3e, "sbdata2" }
data_register! { Sbdata3, 0x3f, "sbdata3" }
#[derive(Debug)]
pub(crate) enum DmiOperationStatus {
Ok = 0,
Reserved = 1,
OperationFailed = 2,
RequestInProgress = 3,
}
impl DmiOperationStatus {
fn parse(value: u8) -> Option<Self> {
use DmiOperationStatus::*;
let status = match value {
0 => Ok,
1 => Reserved,
2 => OperationFailed,
3 => RequestInProgress,
_ => return None,
};
Some(status)
}
}
#[derive(Copy, Clone, Debug)]
enum DmiOperation {
NoOp = 0,
Read = 1,
Write = 2,
_Reserved = 3,
}