1pub(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#[derive(Debug)]
23pub enum AccessPort {
24 MemoryAp(memory_ap::MemoryAp),
27 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#[derive(Debug, thiserror::Error)]
41pub enum AccessPortError {
42 #[error("Failed to read register {name} at address {address:#04x}")]
44 RegisterRead {
45 address: u64,
47 name: &'static str,
49 #[source]
51 source: Box<dyn std::error::Error + Send + Sync>,
52 },
53 #[error("Failed to write register {name} at address {address:#04x}")]
55 RegisterWrite {
56 address: u64,
58 name: &'static str,
60 #[source]
62 source: Box<dyn std::error::Error + Send + Sync>,
63 },
64 #[error("Error while communicating with debug port")]
66 DebugPort(#[from] DebugPortError),
67 #[error("Failed to flush batched writes")]
69 Flush(#[from] DebugProbeError),
70
71 #[error("Error parsing a register")]
73 RegisterParse(#[from] RegisterParseError),
74}
75
76impl AccessPortError {
77 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 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
100pub trait ApRegAccess<Reg: ApRegister>: AccessPortType {}
102
103pub trait AccessPortType {
105 fn ap_address(&self) -> &FullyQualifiedApAddress;
107}
108
109pub trait ApAccess {
111 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 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 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 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
214pub enum DataSize {
215 U8 = 0b000,
217 U16 = 0b001,
219 #[default]
221 U32 = 0b010,
222 U64 = 0b011,
224 U128 = 0b100,
226 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
243pub 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
268pub enum AddressIncrement {
269 Off = 0b00,
272 #[default]
275 Single = 0b01,
276 Packed = 0b10,
279}
280
281impl AddressIncrement {
282 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#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
295pub enum BaseAddrFormat {
296 #[default]
298 Legacy = 0,
299 ADIv5 = 1,
301}
302
303#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
305pub enum ApClass {
306 #[default]
308 Undefined = 0b0000,
309 ComAp = 0b0001,
311 MemAp = 0b1000,
313}
314
315impl ApClass {
316 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#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
331pub enum ApType {
332 #[default]
334 JtagComAp = 0x0,
335 AmbaAhb3 = 0x1,
337 AmbaApb2Apb3 = 0x2,
339 AmbaAxi3Axi4 = 0x4,
341 AmbaAhb5 = 0x5,
343 AmbaApb4Apb5 = 0x6,
345 AmbaAxi5 = 0x7,
347 AmbaAhb5Hprot = 0x8,
349}
350
351impl ApType {
352 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}
367pub trait ApRegister:
369 Clone + TryFrom<u32, Error = RegisterParseError> + Into<u32> + Sized + std::fmt::Debug
370{
371 const ADDRESS: u64;
373
374 const NAME: &'static str;
376}