1use std::sync::Arc;
5
6use rust_embed::RustEmbed;
7use serde::{Deserialize, Serialize};
8use thiserror::Error;
9
10use super::chip_interface::ChipInterface;
11
12#[derive(Error, Debug)]
13pub enum AxiError {
14 #[error("Invalid path: {key} specifically was not able to find {path}")]
15 InvalidPath { key: String, path: String },
16
17 #[error("Invalid path: {key} specifically was not able to parse {path} as an array def.")]
18 InvalidArrayPath { key: String, path: String },
19
20 #[error("No AXI data table loaded")]
21 NoAxiData,
22
23 #[error("The readbuffer is not large enough to hold the requested data")]
24 ReadBufferTooSmall,
25
26 #[error("The writebuffer is not the same size as the requested field")]
27 WriteBufferMismatch,
28}
29
30#[derive(Clone, Debug, Serialize, Deserialize)]
31pub struct AxiData {
32 pub addr: u64,
33 pub size: u64,
34 pub bits: Option<(u32, u32)>,
35}
36
37#[derive(Debug, Deserialize, Serialize)]
38pub struct MemorySlice {
39 pub name: String,
40 pub offset: u64,
41 pub size: u64,
42 pub array_count: Option<u64>,
43 pub bit_mask: Option<(u32, u32)>,
44 pub children: std::collections::HashMap<String, MemorySlice>,
45}
46
47#[derive(Serialize, Deserialize)]
48pub enum MemorySlices {
49 Flat(std::collections::HashMap<String, AxiData>),
50 Tree(std::collections::HashMap<String, MemorySlice>),
51}
52
53#[derive(RustEmbed)]
54#[folder = "axi-data"]
55struct WHPciData;
56
57pub fn load_axi_table(file: &str, _version: u32) -> MemorySlices {
58 let data = WHPciData::get(file).unwrap();
59 bincode::deserialize(&data.data).unwrap()
60}
61
62pub trait ChipComms {
69 fn axi_translate(&self, addr: &str) -> Result<AxiData, AxiError>;
71 fn axi_read(
73 &self,
74 chip_if: &dyn ChipInterface,
75 addr: u64,
76 data: &mut [u8],
77 ) -> Result<(), Box<dyn std::error::Error>>;
78 fn axi_write(
79 &self,
80 chip_if: &dyn ChipInterface,
81 addr: u64,
82 data: &[u8],
83 ) -> Result<(), Box<dyn std::error::Error>>;
84
85 fn noc_read(
87 &self,
88 chip_if: &dyn ChipInterface,
89 noc_id: u8,
90 x: u8,
91 y: u8,
92 addr: u64,
93 data: &mut [u8],
94 ) -> Result<(), Box<dyn std::error::Error>>;
95 fn noc_write(
96 &self,
97 chip_if: &dyn ChipInterface,
98 noc_id: u8,
99 x: u8,
100 y: u8,
101 addr: u64,
102 data: &[u8],
103 ) -> Result<(), Box<dyn std::error::Error>>;
104 fn noc_multicast(
105 &self,
106 chip_if: &dyn ChipInterface,
107 noc_id: u8,
108 start: (u8, u8),
109 end: (u8, u8),
110 addr: u64,
111 data: &[u8],
112 ) -> Result<(), Box<dyn std::error::Error>>;
113 fn noc_broadcast(
114 &self,
115 chip_if: &dyn ChipInterface,
116 noc_id: u8,
117 addr: u64,
118 data: &[u8],
119 ) -> Result<(), Box<dyn std::error::Error>>;
120
121 fn noc_read32(
123 &self,
124 chip_if: &dyn ChipInterface,
125 noc_id: u8,
126 x: u8,
127 y: u8,
128 addr: u64,
129 ) -> Result<u32, Box<dyn std::error::Error>> {
130 let mut value = [0; 4];
131 self.noc_read(chip_if, noc_id, x, y, addr, &mut value)?;
132 Ok(u32::from_le_bytes(value))
133 }
134
135 fn noc_write32(
136 &self,
137 chip_if: &dyn ChipInterface,
138 noc_id: u8,
139 x: u8,
140 y: u8,
141 addr: u64,
142 value: u32,
143 ) -> Result<(), Box<dyn std::error::Error>> {
144 self.noc_write(chip_if, noc_id, x, y, addr, value.to_le_bytes().as_slice())
145 }
146
147 fn noc_multicast32(
148 &self,
149 chip_if: &dyn ChipInterface,
150 noc_id: u8,
151 start: (u8, u8),
152 end: (u8, u8),
153 addr: u64,
154 value: u32,
155 ) -> Result<(), Box<dyn std::error::Error>> {
156 self.noc_multicast(
157 chip_if,
158 noc_id,
159 start,
160 end,
161 addr,
162 value.to_le_bytes().as_slice(),
163 )
164 }
165
166 fn noc_broadcast32(
167 &self,
168 chip_if: &dyn ChipInterface,
169 noc_id: u8,
170 addr: u64,
171 value: u32,
172 ) -> Result<(), Box<dyn std::error::Error>> {
173 self.noc_broadcast(chip_if, noc_id, addr, value.to_le_bytes().as_slice())
174 }
175
176 fn axi_read32(
177 &self,
178 chip_if: &dyn ChipInterface,
179 addr: u64,
180 ) -> Result<u32, Box<dyn std::error::Error>> {
181 let mut value = [0; 4];
182 self.axi_read(chip_if, addr, &mut value)?;
183 Ok(u32::from_le_bytes(value))
184 }
185
186 fn axi_write32(
187 &self,
188 chip_if: &dyn ChipInterface,
189 addr: u64,
190 value: u32,
191 ) -> Result<(), Box<dyn std::error::Error>> {
192 self.axi_write(chip_if, addr, value.to_le_bytes().as_slice())
193 }
194
195 fn axi_sread32(
196 &self,
197 chip_if: &dyn ChipInterface,
198 addr: &str,
199 ) -> Result<u32, Box<dyn std::error::Error>> {
200 let addr = self.axi_translate(addr.as_ref())?.addr;
201
202 let mut value = [0; 4];
203 self.axi_read(chip_if, addr, &mut value)?;
204 Ok(u32::from_le_bytes(value))
205 }
206
207 fn axi_swrite32(
208 &self,
209 chip_if: &dyn ChipInterface,
210 addr: &str,
211 value: u32,
212 ) -> Result<(), Box<dyn std::error::Error>> {
213 let addr = self.axi_translate(addr.as_ref())?.addr;
214
215 self.axi_write(chip_if, addr, &value.to_le_bytes())?;
216 Ok(())
217 }
218}
219
220pub fn axi_translate_tree(
221 data: &std::collections::HashMap<String, MemorySlice>,
222 addr: &str,
223) -> Result<AxiData, AxiError> {
224 let mut it = data;
225
226 let mut offset = 0;
227 let mut size = 0;
228 let mut bits = None;
229 for key in addr.split('.') {
230 let (slice, index) = if !it.contains_key(key) && key.contains('[') {
231 let mut parts = key.split('[');
232 let key = parts.next().ok_or_else(|| AxiError::InvalidArrayPath {
233 key: key.to_string(),
234 path: addr.to_string(),
235 })?;
236 let index = parts
237 .next()
238 .ok_or_else(|| AxiError::InvalidArrayPath {
239 key: key.to_string(),
240 path: addr.to_string(),
241 })?
242 .trim_end_matches(']')
243 .parse::<u64>()
244 .map_err(|_| AxiError::InvalidArrayPath {
245 key: key.to_string(),
246 path: addr.to_string(),
247 })?;
248
249 (it.get(key), Some(index))
250 } else {
251 (it.get(key), None)
252 };
253
254 if let Some(slice) = slice {
255 it = &slice.children;
256 if let (Some(count), Some(index)) = (slice.array_count, index) {
257 assert!(index < count);
258 } else if index.is_some() ^ slice.array_count.is_some() {
259 dbg!(slice);
260 panic!("Tried to index a non-array or no index for array with {key}")
261 }
262
263 size = slice.size;
264 bits = slice.bit_mask;
265 offset += slice.offset + slice.size * index.unwrap_or(0);
266 } else {
267 return Err(AxiError::InvalidPath {
268 path: addr.to_string(),
269 key: key.to_string(),
270 });
271 }
272 }
273
274 Ok(AxiData {
275 addr: offset,
276 size,
277 bits,
278 })
279}
280
281pub fn axi_translate(data: Option<&MemorySlices>, addr: &str) -> Result<AxiData, AxiError> {
282 match data.ok_or(AxiError::NoAxiData)? {
283 MemorySlices::Flat(data) => {
284 if let Some(data) = data.get(addr) {
285 Ok(data.clone())
286 } else {
287 Err(AxiError::InvalidPath {
288 path: addr.to_string(),
289 key: addr.to_string(),
290 })
291 }
292 }
293 MemorySlices::Tree(data) => axi_translate_tree(data, addr),
294 }
295}
296
297pub struct ArcIf {
298 pub axi_data: MemorySlices,
299}
300
301impl ChipComms for ArcIf {
302 fn axi_translate(&self, addr: &str) -> Result<AxiData, AxiError> {
303 axi_translate(Some(&self.axi_data), addr)
304 }
305
306 fn axi_read(
307 &self,
308 chip_if: &dyn ChipInterface,
309 addr: u64,
310 data: &mut [u8],
311 ) -> Result<(), Box<dyn std::error::Error>> {
312 chip_if.axi_read(addr as u32, data)
313 }
314
315 fn axi_write(
316 &self,
317 chip_if: &dyn ChipInterface,
318 addr: u64,
319 data: &[u8],
320 ) -> Result<(), Box<dyn std::error::Error>> {
321 chip_if.axi_write(addr as u32, data)
322 }
323
324 fn noc_read(
325 &self,
326 chip_if: &dyn ChipInterface,
327 noc_id: u8,
328 x: u8,
329 y: u8,
330 addr: u64,
331 data: &mut [u8],
332 ) -> Result<(), Box<dyn std::error::Error>> {
333 chip_if.noc_read(noc_id, x, y, addr, data)
334 }
335
336 fn noc_write(
337 &self,
338 chip_if: &dyn ChipInterface,
339 noc_id: u8,
340 x: u8,
341 y: u8,
342 addr: u64,
343 data: &[u8],
344 ) -> Result<(), Box<dyn std::error::Error>> {
345 chip_if.noc_write(noc_id, x, y, addr, data)
346 }
347
348 fn noc_multicast(
349 &self,
350 chip_if: &dyn ChipInterface,
351 noc_id: u8,
352 start: (u8, u8),
353 end: (u8, u8),
354 addr: u64,
355 data: &[u8],
356 ) -> Result<(), Box<dyn std::error::Error>> {
357 chip_if.noc_multicast(noc_id, start, end, addr, data)
358 }
359
360 fn noc_broadcast(
361 &self,
362 chip_if: &dyn ChipInterface,
363 noc_id: u8,
364 addr: u64,
365 data: &[u8],
366 ) -> Result<(), Box<dyn std::error::Error>> {
367 chip_if.noc_broadcast(noc_id, addr, data)
368 }
369}
370
371pub struct NocIf {
372 pub axi_data: MemorySlices,
373 pub noc_id: u8,
374 pub x: u8,
375 pub y: u8,
376}
377
378impl ChipComms for NocIf {
379 fn axi_translate(&self, addr: &str) -> Result<AxiData, AxiError> {
380 axi_translate(Some(&self.axi_data), addr)
381 }
382
383 fn axi_read(
384 &self,
385 chip_if: &dyn ChipInterface,
386 addr: u64,
387 data: &mut [u8],
388 ) -> Result<(), Box<dyn std::error::Error>> {
389 chip_if.noc_read(self.noc_id, self.x, self.y, addr, data)
390 }
391
392 fn axi_write(
393 &self,
394 chip_if: &dyn ChipInterface,
395 addr: u64,
396 data: &[u8],
397 ) -> Result<(), Box<dyn std::error::Error>> {
398 chip_if.noc_write(self.noc_id, self.x, self.y, addr, data)
399 }
400
401 fn noc_read(
402 &self,
403 chip_if: &dyn ChipInterface,
404 noc_id: u8,
405 x: u8,
406 y: u8,
407 addr: u64,
408 data: &mut [u8],
409 ) -> Result<(), Box<dyn std::error::Error>> {
410 chip_if.noc_read(noc_id, x, y, addr, data)
411 }
412
413 fn noc_write(
414 &self,
415 chip_if: &dyn ChipInterface,
416 noc_id: u8,
417 x: u8,
418 y: u8,
419 addr: u64,
420 data: &[u8],
421 ) -> Result<(), Box<dyn std::error::Error>> {
422 chip_if.noc_write(noc_id, x, y, addr, data)
423 }
424
425 fn noc_multicast(
426 &self,
427 chip_if: &dyn ChipInterface,
428 noc_id: u8,
429 start: (u8, u8),
430 end: (u8, u8),
431 addr: u64,
432 data: &[u8],
433 ) -> Result<(), Box<dyn std::error::Error>> {
434 chip_if.noc_multicast(noc_id, start, end, addr, data)
435 }
436
437 fn noc_broadcast(
438 &self,
439 chip_if: &dyn ChipInterface,
440 noc_id: u8,
441 addr: u64,
442 data: &[u8],
443 ) -> Result<(), Box<dyn std::error::Error>> {
444 chip_if.noc_broadcast(noc_id, addr, data)
445 }
446}
447
448impl ChipComms for Arc<dyn ChipComms> {
449 fn axi_translate(&self, addr: &str) -> Result<AxiData, AxiError> {
450 self.as_ref().axi_translate(addr)
451 }
452
453 fn axi_read(
454 &self,
455 chip_if: &dyn ChipInterface,
456 addr: u64,
457 data: &mut [u8],
458 ) -> Result<(), Box<dyn std::error::Error>> {
459 self.as_ref().axi_read(chip_if, addr, data)
460 }
461
462 fn axi_write(
463 &self,
464 chip_if: &dyn ChipInterface,
465 addr: u64,
466 data: &[u8],
467 ) -> Result<(), Box<dyn std::error::Error>> {
468 self.as_ref().axi_write(chip_if, addr, data)
469 }
470
471 fn noc_read(
472 &self,
473 chip_if: &dyn ChipInterface,
474 noc_id: u8,
475 x: u8,
476 y: u8,
477 addr: u64,
478 data: &mut [u8],
479 ) -> Result<(), Box<dyn std::error::Error>> {
480 self.as_ref().noc_read(chip_if, noc_id, x, y, addr, data)
481 }
482
483 fn noc_write(
484 &self,
485 chip_if: &dyn ChipInterface,
486 noc_id: u8,
487 x: u8,
488 y: u8,
489 addr: u64,
490 data: &[u8],
491 ) -> Result<(), Box<dyn std::error::Error>> {
492 self.as_ref().noc_write(chip_if, noc_id, x, y, addr, data)
493 }
494
495 fn noc_multicast(
496 &self,
497 chip_if: &dyn ChipInterface,
498 noc_id: u8,
499 start: (u8, u8),
500 end: (u8, u8),
501 addr: u64,
502 data: &[u8],
503 ) -> Result<(), Box<dyn std::error::Error>> {
504 self.as_ref()
505 .noc_multicast(chip_if, noc_id, start, end, addr, data)
506 }
507
508 fn noc_broadcast(
509 &self,
510 chip_if: &dyn ChipInterface,
511 noc_id: u8,
512 addr: u64,
513 data: &[u8],
514 ) -> Result<(), Box<dyn std::error::Error>> {
515 self.as_ref().noc_broadcast(chip_if, noc_id, addr, data)
516 }
517}
518
519impl ChipComms for Arc<dyn ChipComms + Send + Sync> {
520 fn axi_translate(&self, addr: &str) -> Result<AxiData, AxiError> {
521 self.as_ref().axi_translate(addr)
522 }
523
524 fn axi_read(
525 &self,
526 chip_if: &dyn ChipInterface,
527 addr: u64,
528 data: &mut [u8],
529 ) -> Result<(), Box<dyn std::error::Error>> {
530 self.as_ref().axi_read(chip_if, addr, data)
531 }
532
533 fn axi_write(
534 &self,
535 chip_if: &dyn ChipInterface,
536 addr: u64,
537 data: &[u8],
538 ) -> Result<(), Box<dyn std::error::Error>> {
539 self.as_ref().axi_write(chip_if, addr, data)
540 }
541
542 fn noc_read(
543 &self,
544 chip_if: &dyn ChipInterface,
545 noc_id: u8,
546 x: u8,
547 y: u8,
548 addr: u64,
549 data: &mut [u8],
550 ) -> Result<(), Box<dyn std::error::Error>> {
551 self.as_ref().noc_read(chip_if, noc_id, x, y, addr, data)
552 }
553
554 fn noc_write(
555 &self,
556 chip_if: &dyn ChipInterface,
557 noc_id: u8,
558 x: u8,
559 y: u8,
560 addr: u64,
561 data: &[u8],
562 ) -> Result<(), Box<dyn std::error::Error>> {
563 self.as_ref().noc_write(chip_if, noc_id, x, y, addr, data)
564 }
565
566 fn noc_multicast(
567 &self,
568 chip_if: &dyn ChipInterface,
569 noc_id: u8,
570 start: (u8, u8),
571 end: (u8, u8),
572 addr: u64,
573 data: &[u8],
574 ) -> Result<(), Box<dyn std::error::Error>> {
575 self.as_ref()
576 .noc_multicast(chip_if, noc_id, start, end, addr, data)
577 }
578
579 fn noc_broadcast(
580 &self,
581 chip_if: &dyn ChipInterface,
582 noc_id: u8,
583 addr: u64,
584 data: &[u8],
585 ) -> Result<(), Box<dyn std::error::Error>> {
586 self.as_ref().noc_broadcast(chip_if, noc_id, addr, data)
587 }
588}