Skip to main content

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 successful");
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,
217    /// 2 byte transfers are supported.
218    U16,
219    /// 4 byte transfers are supported.
220    #[default]
221    U32,
222    /// 8 byte transfers are supported.
223    U64,
224    /// 16 byte transfers are supported.
225    U128,
226    /// 32 byte transfers are supported.
227    U256,
228    /// An unknown/reserved encoding read from the target. Holds the raw field bits.
229    Unknown(u8),
230}
231
232impl DataSize {
233    pub(crate) fn to_byte_count(self) -> usize {
234        match self {
235            DataSize::U8 => 1,
236            DataSize::U16 => 2,
237            DataSize::U32 => 4,
238            DataSize::U64 => 8,
239            DataSize::U128 => 16,
240            DataSize::U256 => 32,
241            // Only ever queried for a size probe-rs itself selected, never a raw read-back.
242            DataSize::Unknown(bits) => {
243                unreachable!("byte count requested for unknown data size {bits:#x}")
244            }
245        }
246    }
247}
248
249impl From<DataSize> for u8 {
250    fn from(value: DataSize) -> u8 {
251        match value {
252            DataSize::U8 => 0b000,
253            DataSize::U16 => 0b001,
254            DataSize::U32 => 0b010,
255            DataSize::U64 => 0b011,
256            DataSize::U128 => 0b100,
257            DataSize::U256 => 0b101,
258            DataSize::Unknown(bits) => bits,
259        }
260    }
261}
262
263impl From<u8> for DataSize {
264    fn from(value: u8) -> Self {
265        match value {
266            0b000 => DataSize::U8,
267            0b001 => DataSize::U16,
268            0b010 => DataSize::U32,
269            0b011 => DataSize::U64,
270            0b100 => DataSize::U128,
271            0b101 => DataSize::U256,
272            bits => DataSize::Unknown(bits),
273        }
274    }
275}
276
277/// The increment to the TAR that is performed after each DRW read or write.
278///
279/// This can be used to avoid successive TAR transfers for writes of consecutive addresses.
280/// This will effectively save half the bandwidth!
281///
282/// Can be configured in the CSW.
283#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
284pub enum AddressIncrement {
285    /// No increments are happening after the DRW access. TAR always stays the same.
286    /// Always supported.
287    Off,
288    /// Increments the TAR by the size of the access after each DRW access.
289    /// Always supported.
290    #[default]
291    Single,
292    /// Enables packed access to the DRW (see C2.2.7).
293    /// Only available if sub-word access is supported by the core.
294    Packed,
295    /// An unknown/reserved encoding read from the target. Holds the raw field bits.
296    Unknown(u8),
297}
298
299impl From<AddressIncrement> for u8 {
300    fn from(value: AddressIncrement) -> u8 {
301        match value {
302            AddressIncrement::Off => 0b00,
303            AddressIncrement::Single => 0b01,
304            AddressIncrement::Packed => 0b10,
305            AddressIncrement::Unknown(bits) => bits,
306        }
307    }
308}
309
310impl From<u8> for AddressIncrement {
311    fn from(value: u8) -> Self {
312        match value {
313            0b00 => AddressIncrement::Off,
314            0b01 => AddressIncrement::Single,
315            0b10 => AddressIncrement::Packed,
316            bits => AddressIncrement::Unknown(bits),
317        }
318    }
319}
320
321/// The format of the BASE register (see C2.6.1).
322#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
323pub enum BaseAddrFormat {
324    /// The legacy format of very old cores. Very little cores use this.
325    #[default]
326    Legacy,
327    /// The format all newer MCUs use.
328    ADIv5,
329    /// An unknown/reserved encoding read from the target. Holds the raw field bits.
330    Unknown(u8),
331}
332
333impl From<BaseAddrFormat> for u8 {
334    fn from(value: BaseAddrFormat) -> u8 {
335        match value {
336            BaseAddrFormat::Legacy => 0,
337            BaseAddrFormat::ADIv5 => 1,
338            BaseAddrFormat::Unknown(bits) => bits,
339        }
340    }
341}
342
343impl From<u8> for BaseAddrFormat {
344    fn from(value: u8) -> Self {
345        match value {
346            0 => BaseAddrFormat::Legacy,
347            1 => BaseAddrFormat::ADIv5,
348            bits => BaseAddrFormat::Unknown(bits),
349        }
350    }
351}
352
353/// 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.
354#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
355pub enum ApClass {
356    /// This describes a custom AP that is vendor defined and not defined by ARM
357    #[default]
358    Undefined,
359    /// The standard ARM COM-AP defined in the [`ARM Debug Interface v5.2`](https://developer.arm.com/documentation/ihi0031/f/?lang=en) specification.
360    ComAp,
361    /// The standard ARM MEM-AP defined  in the [`ARM Debug Interface v5.2`](https://developer.arm.com/documentation/ihi0031/f/?lang=en) specification
362    MemAp,
363    /// An unknown/reserved encoding read from the target. Holds the raw field bits.
364    Unknown(u8),
365}
366
367impl From<ApClass> for u8 {
368    fn from(value: ApClass) -> u8 {
369        match value {
370            ApClass::Undefined => 0b0000,
371            ApClass::ComAp => 0b0001,
372            ApClass::MemAp => 0b1000,
373            ApClass::Unknown(bits) => bits,
374        }
375    }
376}
377
378impl From<u8> for ApClass {
379    fn from(value: u8) -> Self {
380        match value {
381            0b0000 => ApClass::Undefined,
382            0b0001 => ApClass::ComAp,
383            0b1000 => ApClass::MemAp,
384            bits => ApClass::Unknown(bits),
385        }
386    }
387}
388
389/// The type of AP defined in the [`ARM Debug Interface v5.2`](https://developer.arm.com/documentation/ihi0031/f/?lang=en) specification.
390/// You can find the details in the table C1-2 on page C1-146.
391/// The different types correspond to the different access/memory buses of ARM cores.
392#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
393pub enum ApType {
394    /// This is the most basic AP that is included in most MCUs and uses SWD or JTAG as an access bus.
395    #[default]
396    JtagComAp,
397    /// A AMBA based AHB3 AP (see E1.5).
398    AmbaAhb3,
399    /// A AMBA based APB2 and APB3 AP (see E1.8).
400    AmbaApb2Apb3,
401    /// A AMBA based AXI3 and AXI4 AP (see E1.2).
402    AmbaAxi3Axi4,
403    /// A AMBA based AHB5 AP (see E1.6).
404    AmbaAhb5,
405    /// A AMBA based APB4 and APB5 AP (see E1.9).
406    AmbaApb4Apb5,
407    /// A AMBA based AXI5 AP (see E1.4).
408    AmbaAxi5,
409    /// A AMBA based AHB5 AP with enhanced HPROT (see E1.7).
410    AmbaAhb5Hprot,
411    /// An unknown/reserved encoding read from the target. Holds the raw field bits.
412    Unknown(u8),
413}
414
415impl From<ApType> for u8 {
416    fn from(value: ApType) -> u8 {
417        match value {
418            ApType::JtagComAp => 0x0,
419            ApType::AmbaAhb3 => 0x1,
420            ApType::AmbaApb2Apb3 => 0x2,
421            ApType::AmbaAxi3Axi4 => 0x4,
422            ApType::AmbaAhb5 => 0x5,
423            ApType::AmbaApb4Apb5 => 0x6,
424            ApType::AmbaAxi5 => 0x7,
425            ApType::AmbaAhb5Hprot => 0x8,
426            ApType::Unknown(bits) => bits,
427        }
428    }
429}
430
431impl From<u8> for ApType {
432    fn from(value: u8) -> Self {
433        match value {
434            0x0 => ApType::JtagComAp,
435            0x1 => ApType::AmbaAhb3,
436            0x2 => ApType::AmbaApb2Apb3,
437            0x4 => ApType::AmbaAxi3Axi4,
438            0x5 => ApType::AmbaAhb5,
439            0x6 => ApType::AmbaApb4Apb5,
440            0x7 => ApType::AmbaAxi5,
441            0x8 => ApType::AmbaAhb5Hprot,
442            bits => ApType::Unknown(bits),
443        }
444    }
445}
446
447/// Base trait for all versions of access port registers
448pub trait ApRegister:
449    Clone + TryFrom<u32, Error = RegisterParseError> + Into<u32> + Sized + std::fmt::Debug
450{
451    /// The address of the register (in bytes).
452    const ADDRESS: u64;
453
454    /// The name of the register as string.
455    const NAME: &'static str;
456}