probe_rs/architecture/arm/ap/
mod.rs#[macro_use]
pub mod register_generation;
pub(crate) mod generic_ap;
pub(crate) mod memory_ap;
use crate::architecture::arm::dp::DebugPortError;
use crate::probe::DebugProbeError;
pub use generic_ap::{ApClass, ApType, IDR};
use super::{
communication_interface::RegisterParseError, ArmError, DapAccess, DpAddress,
FullyQualifiedApAddress, Register,
};
#[derive(Debug, thiserror::Error)]
pub enum AccessPortError {
#[error("Failed to read register {name} at address {address:#04x}")]
RegisterRead {
address: u8,
name: &'static str,
#[source]
source: Box<dyn std::error::Error + Send + Sync>,
},
#[error("Failed to write register {name} at address {address:#04x}")]
RegisterWrite {
address: u8,
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: Register, 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: Register, 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: Register>: 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: Register;
fn read_ap_register_repeated<PORT, R>(
&mut self,
port: &PORT,
values: &mut [u32],
) -> Result<(), ArmError>
where
PORT: AccessPortType + ApRegAccess<R> + ?Sized,
R: Register;
fn write_ap_register<PORT, R>(&mut self, port: &PORT, register: R) -> Result<(), ArmError>
where
PORT: AccessPortType + ApRegAccess<R> + ?Sized,
R: Register;
fn write_ap_register_repeated<PORT, R>(
&mut self,
port: &PORT,
values: &[u32],
) -> Result<(), ArmError>
where
PORT: AccessPortType + ApRegAccess<R> + ?Sized,
R: Register;
}
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: Register,
{
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: Register,
{
tracing::debug!("Writing register {}, value={:x?}", R::NAME, register);
self.write_raw_ap_register(port.ap_address(), R::ADDRESS, register.into())
}
fn write_ap_register_repeated<PORT, R>(
&mut self,
port: &PORT,
values: &[u32],
) -> Result<(), ArmError>
where
PORT: AccessPortType + ApRegAccess<R> + ?Sized,
R: Register,
{
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: Register,
{
tracing::debug!(
"Reading register {}, block with len={} words",
R::NAME,
values.len(),
);
self.read_raw_ap_register_repeated(port.ap_address(), R::ADDRESS, values)
}
}
pub fn access_port_is_valid<AP>(
debug_port: &mut AP,
access_port: &FullyQualifiedApAddress,
) -> Option<IDR>
where
AP: DapAccess,
{
let idr_result: Result<IDR, _> = debug_port
.read_raw_ap_register(access_port, IDR::ADDRESS)
.and_then(|idr| Ok(IDR::try_from(idr)?));
match idr_result {
Ok(idr) if u32::from(idr) != 0 => Some(idr),
Ok(_) => {
tracing::debug!("AP {} is not valid, IDR = 0", access_port.ap());
None
}
Err(e) => {
tracing::debug!(
"Error reading IDR register from AP {}: {}",
access_port.ap(),
e
);
None
}
}
}
#[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(),
}
}
}
#[tracing::instrument(skip(debug_port))]
pub(crate) fn valid_access_ports<DP>(
debug_port: &mut DP,
dp: DpAddress,
) -> Vec<FullyQualifiedApAddress>
where
DP: DapAccess,
{
valid_access_ports_allowlist(debug_port, dp, 0..=255)
}
#[tracing::instrument(skip(debug_port, allowed_aps))]
pub(crate) fn valid_access_ports_allowlist<DP>(
debug_port: &mut DP,
dp: DpAddress,
allowed_aps: impl IntoIterator<Item = u8>,
) -> Vec<FullyQualifiedApAddress>
where
DP: DapAccess,
{
allowed_aps
.into_iter()
.map_while(|ap| {
let ap = FullyQualifiedApAddress::v1_with_dp(dp, ap);
access_port_is_valid(debug_port, &ap).map(|_| ap)
})
.collect()
}
pub fn get_ap_by_idr<AP, P>(debug_port: &mut AP, dp: DpAddress, f: P) -> Option<GenericAp>
where
AP: ApAccess,
P: Fn(IDR) -> bool,
{
(0..=255)
.map(|ap| GenericAp::new(FullyQualifiedApAddress::v1_with_dp(dp, ap)))
.find(|ap| {
if let Ok(idr) = debug_port.read_ap_register(ap) {
f(idr)
} else {
false
}
})
}
define_ap!(
GenericAp
);
impl ApRegAccess<IDR> for GenericAp {}