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 successful");
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,
U16,
#[default]
U32,
U64,
U128,
U256,
Unknown(u8),
}
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,
DataSize::Unknown(bits) => {
unreachable!("byte count requested for unknown data size {bits:#x}")
}
}
}
}
impl From<DataSize> for u8 {
fn from(value: DataSize) -> u8 {
match value {
DataSize::U8 => 0b000,
DataSize::U16 => 0b001,
DataSize::U32 => 0b010,
DataSize::U64 => 0b011,
DataSize::U128 => 0b100,
DataSize::U256 => 0b101,
DataSize::Unknown(bits) => bits,
}
}
}
impl From<u8> for DataSize {
fn from(value: u8) -> Self {
match value {
0b000 => DataSize::U8,
0b001 => DataSize::U16,
0b010 => DataSize::U32,
0b011 => DataSize::U64,
0b100 => DataSize::U128,
0b101 => DataSize::U256,
bits => DataSize::Unknown(bits),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum AddressIncrement {
Off,
#[default]
Single,
Packed,
Unknown(u8),
}
impl From<AddressIncrement> for u8 {
fn from(value: AddressIncrement) -> u8 {
match value {
AddressIncrement::Off => 0b00,
AddressIncrement::Single => 0b01,
AddressIncrement::Packed => 0b10,
AddressIncrement::Unknown(bits) => bits,
}
}
}
impl From<u8> for AddressIncrement {
fn from(value: u8) -> Self {
match value {
0b00 => AddressIncrement::Off,
0b01 => AddressIncrement::Single,
0b10 => AddressIncrement::Packed,
bits => AddressIncrement::Unknown(bits),
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
pub enum BaseAddrFormat {
#[default]
Legacy,
ADIv5,
Unknown(u8),
}
impl From<BaseAddrFormat> for u8 {
fn from(value: BaseAddrFormat) -> u8 {
match value {
BaseAddrFormat::Legacy => 0,
BaseAddrFormat::ADIv5 => 1,
BaseAddrFormat::Unknown(bits) => bits,
}
}
}
impl From<u8> for BaseAddrFormat {
fn from(value: u8) -> Self {
match value {
0 => BaseAddrFormat::Legacy,
1 => BaseAddrFormat::ADIv5,
bits => BaseAddrFormat::Unknown(bits),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ApClass {
#[default]
Undefined,
ComAp,
MemAp,
Unknown(u8),
}
impl From<ApClass> for u8 {
fn from(value: ApClass) -> u8 {
match value {
ApClass::Undefined => 0b0000,
ApClass::ComAp => 0b0001,
ApClass::MemAp => 0b1000,
ApClass::Unknown(bits) => bits,
}
}
}
impl From<u8> for ApClass {
fn from(value: u8) -> Self {
match value {
0b0000 => ApClass::Undefined,
0b0001 => ApClass::ComAp,
0b1000 => ApClass::MemAp,
bits => ApClass::Unknown(bits),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ApType {
#[default]
JtagComAp,
AmbaAhb3,
AmbaApb2Apb3,
AmbaAxi3Axi4,
AmbaAhb5,
AmbaApb4Apb5,
AmbaAxi5,
AmbaAhb5Hprot,
Unknown(u8),
}
impl From<ApType> for u8 {
fn from(value: ApType) -> u8 {
match value {
ApType::JtagComAp => 0x0,
ApType::AmbaAhb3 => 0x1,
ApType::AmbaApb2Apb3 => 0x2,
ApType::AmbaAxi3Axi4 => 0x4,
ApType::AmbaAhb5 => 0x5,
ApType::AmbaApb4Apb5 => 0x6,
ApType::AmbaAxi5 => 0x7,
ApType::AmbaAhb5Hprot => 0x8,
ApType::Unknown(bits) => bits,
}
}
}
impl From<u8> for ApType {
fn from(value: u8) -> Self {
match value {
0x0 => ApType::JtagComAp,
0x1 => ApType::AmbaAhb3,
0x2 => ApType::AmbaApb2Apb3,
0x4 => ApType::AmbaAxi3Axi4,
0x5 => ApType::AmbaAhb5,
0x6 => ApType::AmbaApb4Apb5,
0x7 => ApType::AmbaAxi5,
0x8 => ApType::AmbaAhb5Hprot,
bits => ApType::Unknown(bits),
}
}
}
pub trait ApRegister:
Clone + TryFrom<u32, Error = RegisterParseError> + Into<u32> + Sized + std::fmt::Debug
{
const ADDRESS: u64;
const NAME: &'static str;
}