probe_rs/architecture/arm/ap/
mod.rs

1//! Defines types and registers for ADIv5 and ADIv6 access ports (APs).
2
3pub(crate) mod generic_ap;
4pub(crate) mod memory_ap;
5mod registers;
6pub mod v1;
7pub mod v2;
8
9pub use generic_ap::GenericAp;
10pub use memory_ap::MemoryAp;
11pub use memory_ap::MemoryApType;
12pub(crate) use registers::define_ap_register;
13pub use registers::{BASE, BASE2, BD0, BD1, BD2, BD3, CFG, CSW, DRW, IDR, MBT, TAR, TAR2};
14
15use crate::architecture::arm::{
16    ArmError, DapAccess, DebugPortError, FullyQualifiedApAddress, RegisterParseError,
17};
18
19use crate::probe::DebugProbeError;
20
21/// Sum-type of the Memory Access Ports.
22#[derive(Debug)]
23pub enum AccessPort {
24    /// Any memory Access Port.
25    // TODO: Allow each memory by types to be specialised with there specific feature
26    MemoryAp(memory_ap::MemoryAp),
27    /// Other Access Ports not used for memory accesses.
28    Other(GenericAp),
29}
30impl AccessPortType for AccessPort {
31    fn ap_address(&self) -> &FullyQualifiedApAddress {
32        match self {
33            AccessPort::MemoryAp(mem_ap) => mem_ap.ap_address(),
34            AccessPort::Other(o) => o.ap_address(),
35        }
36    }
37}
38
39/// Some error during AP handling occurred.
40#[derive(Debug, thiserror::Error)]
41pub enum AccessPortError {
42    /// An error occurred when trying to read a register.
43    #[error("Failed to read register {name} at address {address:#04x}")]
44    RegisterRead {
45        /// The address of the register.
46        address: u64,
47        /// The name if the register.
48        name: &'static str,
49        /// The underlying root error of this access error.
50        #[source]
51        source: Box<dyn std::error::Error + Send + Sync>,
52    },
53    /// An error occurred when trying to write a register.
54    #[error("Failed to write register {name} at address {address:#04x}")]
55    RegisterWrite {
56        /// The address of the register.
57        address: u64,
58        /// The name if the register.
59        name: &'static str,
60        /// The underlying root error of this access error.
61        #[source]
62        source: Box<dyn std::error::Error + Send + Sync>,
63    },
64    /// Some error with the operation of the APs DP occurred.
65    #[error("Error while communicating with debug port")]
66    DebugPort(#[from] DebugPortError),
67    /// An error occurred when trying to flush batched writes of to the AP.
68    #[error("Failed to flush batched writes")]
69    Flush(#[from] DebugProbeError),
70
71    /// Error while parsing a register
72    #[error("Error parsing a register")]
73    RegisterParse(#[from] RegisterParseError),
74}
75
76impl AccessPortError {
77    /// Constructs a [`AccessPortError::RegisterRead`] from just the source error and the register type.
78    pub fn register_read_error<R: ApRegister, E: std::error::Error + Send + Sync + 'static>(
79        source: E,
80    ) -> Self {
81        AccessPortError::RegisterRead {
82            address: R::ADDRESS,
83            name: R::NAME,
84            source: Box::new(source),
85        }
86    }
87
88    /// Constructs a [`AccessPortError::RegisterWrite`] from just the source error and the register type.
89    pub fn register_write_error<R: ApRegister, E: std::error::Error + Send + Sync + 'static>(
90        source: E,
91    ) -> Self {
92        AccessPortError::RegisterWrite {
93            address: R::ADDRESS,
94            name: R::NAME,
95            source: Box::new(source),
96        }
97    }
98}
99
100/// A trait to be implemented by ports types providing access to a register.
101pub trait ApRegAccess<Reg: ApRegister>: AccessPortType {}
102
103/// A trait to be implemented on access port types.
104pub trait AccessPortType {
105    /// Returns the address of the access port.
106    fn ap_address(&self) -> &FullyQualifiedApAddress;
107}
108
109/// A trait to be implemented by access port drivers to implement access port operations.
110pub trait ApAccess {
111    /// Read a register of the access port.
112    fn read_ap_register<PORT, R>(&mut self, port: &PORT) -> Result<R, ArmError>
113    where
114        PORT: AccessPortType + ApRegAccess<R> + ?Sized,
115        R: ApRegister;
116
117    /// Read a register of the access port using a block transfer.
118    /// This can be used to read multiple values from the same register.
119    fn read_ap_register_repeated<PORT, R>(
120        &mut self,
121        port: &PORT,
122        values: &mut [u32],
123    ) -> Result<(), ArmError>
124    where
125        PORT: AccessPortType + ApRegAccess<R> + ?Sized,
126        R: ApRegister;
127
128    /// Write a register of the access port.
129    fn write_ap_register<PORT, R>(&mut self, port: &PORT, register: R) -> Result<(), ArmError>
130    where
131        PORT: AccessPortType + ApRegAccess<R> + ?Sized,
132        R: ApRegister;
133
134    /// Write a register of the access port using a block transfer.
135    /// This can be used to write multiple values to the same register.
136    fn write_ap_register_repeated<PORT, R>(
137        &mut self,
138        port: &PORT,
139        values: &[u32],
140    ) -> Result<(), ArmError>
141    where
142        PORT: AccessPortType + ApRegAccess<R> + ?Sized,
143        R: ApRegister;
144}
145
146impl<T: DapAccess> ApAccess for T {
147    #[tracing::instrument(skip(self, port), fields(ap = port.ap_address().ap_v1().ok(), register = R::NAME, value))]
148    fn read_ap_register<PORT, R>(&mut self, port: &PORT) -> Result<R, ArmError>
149    where
150        PORT: AccessPortType + ApRegAccess<R> + ?Sized,
151        R: ApRegister,
152    {
153        let raw_value = self.read_raw_ap_register(port.ap_address(), R::ADDRESS)?;
154
155        tracing::Span::current().record("value", raw_value);
156
157        tracing::debug!("Register read succesful");
158
159        Ok(raw_value.try_into()?)
160    }
161
162    fn write_ap_register<PORT, R>(&mut self, port: &PORT, register: R) -> Result<(), ArmError>
163    where
164        PORT: AccessPortType + ApRegAccess<R> + ?Sized,
165        R: ApRegister,
166    {
167        tracing::debug!("Writing AP register {}, value={:x?}", R::NAME, register);
168        self.write_raw_ap_register(port.ap_address(), R::ADDRESS, register.into())
169            .inspect_err(|err| tracing::warn!("Failed to write AP register {}: {}", R::NAME, err))
170    }
171
172    fn write_ap_register_repeated<PORT, R>(
173        &mut self,
174        port: &PORT,
175        values: &[u32],
176    ) -> Result<(), ArmError>
177    where
178        PORT: AccessPortType + ApRegAccess<R> + ?Sized,
179        R: ApRegister,
180    {
181        tracing::debug!(
182            "Writing register {}, block with len={} words",
183            R::NAME,
184            values.len(),
185        );
186        self.write_raw_ap_register_repeated(port.ap_address(), R::ADDRESS, values)
187    }
188
189    fn read_ap_register_repeated<PORT, R>(
190        &mut self,
191        port: &PORT,
192        values: &mut [u32],
193    ) -> Result<(), ArmError>
194    where
195        PORT: AccessPortType + ApRegAccess<R> + ?Sized,
196        R: ApRegister,
197    {
198        tracing::debug!(
199            "Reading register {}, block with len={} words",
200            R::NAME,
201            values.len(),
202        );
203
204        self.read_raw_ap_register_repeated(port.ap_address(), R::ADDRESS, values)
205    }
206}
207
208/// The unit of data that is transferred in one transfer via the DRW commands.
209///
210/// This can be configured with the CSW command.
211///
212/// ALL MCUs support `U32`. All other transfer sizes are optionally implemented.
213#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
214pub enum DataSize {
215    /// 1 byte transfers are supported.
216    U8 = 0b000,
217    /// 2 byte transfers are supported.
218    U16 = 0b001,
219    /// 4 byte transfers are supported.
220    #[default]
221    U32 = 0b010,
222    /// 8 byte transfers are supported.
223    U64 = 0b011,
224    /// 16 byte transfers are supported.
225    U128 = 0b100,
226    /// 32 byte transfers are supported.
227    U256 = 0b101,
228}
229
230impl DataSize {
231    pub(crate) fn to_byte_count(self) -> usize {
232        match self {
233            DataSize::U8 => 1,
234            DataSize::U16 => 2,
235            DataSize::U32 => 4,
236            DataSize::U64 => 8,
237            DataSize::U128 => 16,
238            DataSize::U256 => 32,
239        }
240    }
241}
242
243/// Invalid data size.
244pub struct InvalidDataSizeError;
245
246impl TryFrom<u8> for DataSize {
247    type Error = InvalidDataSizeError;
248    fn try_from(value: u8) -> Result<Self, InvalidDataSizeError> {
249        match value {
250            0b000 => Ok(DataSize::U8),
251            0b001 => Ok(DataSize::U16),
252            0b010 => Ok(DataSize::U32),
253            0b011 => Ok(DataSize::U64),
254            0b100 => Ok(DataSize::U128),
255            0b101 => Ok(DataSize::U256),
256            _ => Err(InvalidDataSizeError),
257        }
258    }
259}
260
261/// The increment to the TAR that is performed after each DRW read or write.
262///
263/// This can be used to avoid successive TAR transfers for writes of consecutive addresses.
264/// This will effectively save half the bandwidth!
265///
266/// Can be configured in the CSW.
267#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
268pub enum AddressIncrement {
269    /// No increments are happening after the DRW access. TAR always stays the same.
270    /// Always supported.
271    Off = 0b00,
272    /// Increments the TAR by the size of the access after each DRW access.
273    /// Always supported.
274    #[default]
275    Single = 0b01,
276    /// Enables packed access to the DRW (see C2.2.7).
277    /// Only available if sub-word access is supported by the core.
278    Packed = 0b10,
279}
280
281impl AddressIncrement {
282    /// Create a new `AddressIncrement` from a u8.
283    pub fn from_u8(value: u8) -> Option<Self> {
284        match value {
285            0b00 => Some(AddressIncrement::Off),
286            0b01 => Some(AddressIncrement::Single),
287            0b10 => Some(AddressIncrement::Packed),
288            _ => None,
289        }
290    }
291}
292
293/// The format of the BASE register (see C2.6.1).
294#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
295pub enum BaseAddrFormat {
296    /// The legacy format of very old cores. Very little cores use this.
297    #[default]
298    Legacy = 0,
299    /// The format all newer MCUs use.
300    ADIv5 = 1,
301}
302
303/// Describes the class of an access port defined in the [`ARM Debug Interface v5.2`](https://developer.arm.com/documentation/ihi0031/f/?lang=en) specification.
304#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
305pub enum ApClass {
306    /// This describes a custom AP that is vendor defined and not defined by ARM
307    #[default]
308    Undefined = 0b0000,
309    /// The standard ARM COM-AP defined in the [`ARM Debug Interface v5.2`](https://developer.arm.com/documentation/ihi0031/f/?lang=en) specification.
310    ComAp = 0b0001,
311    /// The standard ARM MEM-AP defined  in the [`ARM Debug Interface v5.2`](https://developer.arm.com/documentation/ihi0031/f/?lang=en) specification
312    MemAp = 0b1000,
313}
314
315impl ApClass {
316    /// Tries to create an `ApClass` from a given `u8`.
317    pub fn from_u8(value: u8) -> Option<Self> {
318        match value {
319            0b0000 => Some(ApClass::Undefined),
320            0b0001 => Some(ApClass::ComAp),
321            0b1000 => Some(ApClass::MemAp),
322            _ => None,
323        }
324    }
325}
326
327/// The type of AP defined in the [`ARM Debug Interface v5.2`](https://developer.arm.com/documentation/ihi0031/f/?lang=en) specification.
328/// You can find the details in the table C1-2 on page C1-146.
329/// The different types correspond to the different access/memory buses of ARM cores.
330#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
331pub enum ApType {
332    /// This is the most basic AP that is included in most MCUs and uses SWD or JTAG as an access bus.
333    #[default]
334    JtagComAp = 0x0,
335    /// A AMBA based AHB3 AP (see E1.5).
336    AmbaAhb3 = 0x1,
337    /// A AMBA based APB2 and APB3 AP (see E1.8).
338    AmbaApb2Apb3 = 0x2,
339    /// A AMBA based AXI3 and AXI4 AP (see E1.2).
340    AmbaAxi3Axi4 = 0x4,
341    /// A AMBA based AHB5 AP (see E1.6).
342    AmbaAhb5 = 0x5,
343    /// A AMBA based APB4 and APB5 AP (see E1.9).
344    AmbaApb4Apb5 = 0x6,
345    /// A AMBA based AXI5 AP (see E1.4).
346    AmbaAxi5 = 0x7,
347    /// A AMBA based AHB5 AP with enhanced HPROT (see E1.7).
348    AmbaAhb5Hprot = 0x8,
349}
350
351impl ApType {
352    /// Tries to create an `ApType` from a given `u8`.
353    pub fn from_u8(value: u8) -> Option<Self> {
354        match value {
355            0x0 => Some(ApType::JtagComAp),
356            0x1 => Some(ApType::AmbaAhb3),
357            0x2 => Some(ApType::AmbaApb2Apb3),
358            0x4 => Some(ApType::AmbaAxi3Axi4),
359            0x5 => Some(ApType::AmbaAhb5),
360            0x6 => Some(ApType::AmbaApb4Apb5),
361            0x7 => Some(ApType::AmbaAxi5),
362            0x8 => Some(ApType::AmbaAhb5Hprot),
363            _ => None,
364        }
365    }
366}
367/// Base trait for all versions of access port registers
368pub trait ApRegister:
369    Clone + TryFrom<u32, Error = RegisterParseError> + Into<u32> + Sized + std::fmt::Debug
370{
371    /// The address of the register (in bytes).
372    const ADDRESS: u64;
373
374    /// The name of the register as string.
375    const NAME: &'static str;
376}