pub(crate) mod generic_ap;
pub(crate) mod memory_ap;
mod registers;
pub mod v1;
pub mod v2;
pub use generic_ap::GenericAp;
pub use memory_ap::MemoryAp;
pub use memory_ap::MemoryApType;
pub(crate) use registers::define_ap_register;
pub use registers::{BASE, BASE2, BD0, BD1, BD2, BD3, CFG, CSW, DRW, IDR, MBT, TAR, TAR2};
use crate::architecture::arm::{
ArmError, DapAccess, DebugPortError, FullyQualifiedApAddress, RegisterParseError,
};
use crate::probe::DebugProbeError;
#[derive(Debug)]
pub enum AccessPort {
MemoryAp(memory_ap::MemoryAp),
Other(GenericAp),
}
impl AccessPortType for AccessPort {
fn ap_address(&self) -> &FullyQualifiedApAddress {
match self {
AccessPort::MemoryAp(mem_ap) => mem_ap.ap_address(),
AccessPort::Other(o) => o.ap_address(),
}
}
}
#[derive(Debug, thiserror::Error)]
pub enum AccessPortError {
#[error("Failed to read register {name} at address {address:#04x}")]
RegisterRead {
address: u64,
name: &'static str,
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("Failed to write register {name} at address {address:#04x}")]
RegisterWrite {
address: u64,
name: &'static str,
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("Error while communicating with debug port")]
DebugPort(#[from] DebugPortError),
#[error("Failed to flush batched writes")]
Flush(#[from] DebugProbeError),
#[error("Error parsing a register")]
RegisterParse(#[from] RegisterParseError),
}
impl AccessPortError {
pub fn register_read_error<R: ApRegister, E: std::error::Error + Send + Sync + 'static>(
source: E,
) -> Self {
AccessPortError::RegisterRead {
address: R::ADDRESS,
name: R::NAME,
source: Box::new(source),
}
}
pub fn register_write_error<R: ApRegister, E: std::error::Error + Send + Sync + 'static>(
source: E,
) -> Self {
AccessPortError::RegisterWrite {
address: R::ADDRESS,
name: R::NAME,
source: Box::new(source),
}
}
}
pub trait ApRegAccess<Reg: ApRegister>: AccessPortType {}
pub trait AccessPortType {
fn ap_address(&self) -> &FullyQualifiedApAddress;
}
pub trait ApAccess {
fn read_ap_register<PORT, R>(&mut self, port: &PORT) -> Result<R, ArmError>
where
PORT: AccessPortType + ApRegAccess<R> + ?Sized,
R: ApRegister;
fn read_ap_register_repeated<PORT, R>(
&mut self,
port: &PORT,
values: &mut [u32],
) -> Result<(), ArmError>
where
PORT: AccessPortType + ApRegAccess<R> + ?Sized,
R: ApRegister;
fn write_ap_register<PORT, R>(&mut self, port: &PORT, register: R) -> Result<(), ArmError>
where
PORT: AccessPortType + ApRegAccess<R> + ?Sized,
R: ApRegister;
fn write_ap_register_repeated<PORT, R>(
&mut self,
port: &PORT,
values: &[u32],
) -> Result<(), ArmError>
where
PORT: AccessPortType + ApRegAccess<R> + ?Sized,
R: ApRegister;
}
impl<T: DapAccess> ApAccess for T {
#[tracing::instrument(skip(self, port), fields(ap = port.ap_address().ap_v1().ok(), register = R::NAME, value))]
fn read_ap_register<PORT, R>(&mut self, port: &PORT) -> Result<R, ArmError>
where
PORT: AccessPortType + ApRegAccess<R> + ?Sized,
R: ApRegister,
{
let raw_value = self.read_raw_ap_register(port.ap_address(), R::ADDRESS)?;
tracing::Span::current().record("value", raw_value);
tracing::debug!("Register read succesful");
Ok(raw_value.try_into()?)
}
fn write_ap_register<PORT, R>(&mut self, port: &PORT, register: R) -> Result<(), ArmError>
where
PORT: AccessPortType + ApRegAccess<R> + ?Sized,
R: ApRegister,
{
tracing::debug!("Writing AP register {}, value={:x?}", R::NAME, register);
self.write_raw_ap_register(port.ap_address(), R::ADDRESS, register.into())
.inspect_err(|err| tracing::warn!("Failed to write AP register {}: {}", R::NAME, err))
}
fn write_ap_register_repeated<PORT, R>(
&mut self,
port: &PORT,
values: &[u32],
) -> Result<(), ArmError>
where
PORT: AccessPortType + ApRegAccess<R> + ?Sized,
R: ApRegister,
{
tracing::debug!(
"Writing register {}, block with len={} words",
R::NAME,
values.len(),
);
self.write_raw_ap_register_repeated(port.ap_address(), R::ADDRESS, values)
}
fn read_ap_register_repeated<PORT, R>(
&mut self,
port: &PORT,
values: &mut [u32],
) -> Result<(), ArmError>
where
PORT: AccessPortType + ApRegAccess<R> + ?Sized,
R: ApRegister,
{
tracing::debug!(
"Reading register {}, block with len={} words",
R::NAME,
values.len(),
);
self.read_raw_ap_register_repeated(port.ap_address(), R::ADDRESS, values)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum DataSize {
U8 = 0b000,
U16 = 0b001,
#[default]
U32 = 0b010,
U64 = 0b011,
U128 = 0b100,
U256 = 0b101,
}
impl DataSize {
pub(crate) fn to_byte_count(self) -> usize {
match self {
DataSize::U8 => 1,
DataSize::U16 => 2,
DataSize::U32 => 4,
DataSize::U64 => 8,
DataSize::U128 => 16,
DataSize::U256 => 32,
}
}
}
pub struct InvalidDataSizeError;
impl TryFrom<u8> for DataSize {
type Error = InvalidDataSizeError;
fn try_from(value: u8) -> Result<Self, InvalidDataSizeError> {
match value {
0b000 => Ok(DataSize::U8),
0b001 => Ok(DataSize::U16),
0b010 => Ok(DataSize::U32),
0b011 => Ok(DataSize::U64),
0b100 => Ok(DataSize::U128),
0b101 => Ok(DataSize::U256),
_ => Err(InvalidDataSizeError),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum AddressIncrement {
Off = 0b00,
#[default]
Single = 0b01,
Packed = 0b10,
}
impl AddressIncrement {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0b00 => Some(AddressIncrement::Off),
0b01 => Some(AddressIncrement::Single),
0b10 => Some(AddressIncrement::Packed),
_ => None,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
pub enum BaseAddrFormat {
#[default]
Legacy = 0,
ADIv5 = 1,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ApClass {
#[default]
Undefined = 0b0000,
ComAp = 0b0001,
MemAp = 0b1000,
}
impl ApClass {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0b0000 => Some(ApClass::Undefined),
0b0001 => Some(ApClass::ComAp),
0b1000 => Some(ApClass::MemAp),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ApType {
#[default]
JtagComAp = 0x0,
AmbaAhb3 = 0x1,
AmbaApb2Apb3 = 0x2,
AmbaAxi3Axi4 = 0x4,
AmbaAhb5 = 0x5,
AmbaApb4Apb5 = 0x6,
AmbaAxi5 = 0x7,
AmbaAhb5Hprot = 0x8,
}
impl ApType {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0x0 => Some(ApType::JtagComAp),
0x1 => Some(ApType::AmbaAhb3),
0x2 => Some(ApType::AmbaApb2Apb3),
0x4 => Some(ApType::AmbaAxi3Axi4),
0x5 => Some(ApType::AmbaAhb5),
0x6 => Some(ApType::AmbaApb4Apb5),
0x7 => Some(ApType::AmbaAxi5),
0x8 => Some(ApType::AmbaAhb5Hprot),
_ => None,
}
}
}
pub trait ApRegister:
Clone + TryFrom<u32, Error = RegisterParseError> + Into<u32> + Sized + std::fmt::Debug
{
const ADDRESS: u64;
const NAME: &'static str;
}