luwen_api/chip/blackhole/
message.rs1use crate::{chip::AxiData, error::PlatformError};
2
3use super::Blackhole;
4
5#[derive(Debug, thiserror::Error)]
6pub enum MessageError {
7 #[error("Timed out in {phase} after {}s", .timeout.as_secs_f32())]
8 Timeout {
9 phase: String,
10 timeout: std::time::Duration,
11 },
12 #[error("Selected out of range queue ({index} > {queue_count})")]
13 QueueIndexOutOfRange { index: u32, queue_count: u32 },
14}
15
16#[derive(Clone)]
17pub struct MessageQueue<const N: usize> {
18 pub header_size: u32,
19 pub entry_size: u32,
20
21 pub queue_base: u64,
22 pub queue_count: u32,
23
24 pub queue_size: u32,
25
26 pub fw_int: AxiData,
27}
28
29impl<const N: usize> MessageQueue<N> {
30 fn get_base(&self, index: u8) -> u64 {
31 let msg_queue_size = 2 * self.queue_size * (self.entry_size * 4) + (self.header_size * 4);
32 self.queue_base + (index as u64 * msg_queue_size as u64)
33 }
34
35 fn qread32(
36 &self,
37 chip: &Blackhole,
38 index: u8,
39 offset: u32,
40 ) -> Result<u32, Box<dyn std::error::Error>> {
41 chip.arc_if
42 .axi_read32(&chip.chip_if, self.get_base(index) + (4 * offset as u64))
43 }
44
45 fn qwrite32(
46 &self,
47 chip: &Blackhole,
48 index: u8,
49 offset: u32,
50 value: u32,
51 ) -> Result<(), Box<dyn std::error::Error>> {
52 chip.arc_if.axi_write32(
53 &chip.chip_if,
54 self.get_base(index) + (4 * offset as u64),
55 value,
56 )
57 }
58
59 fn trigger_int(&self, chip: &Blackhole) -> Result<bool, PlatformError> {
60 let mut mvalue = vec![0u8; self.fw_int.size as usize];
61 let value =
62 crate::chip::HlCommsInterface::axi_read_field(&chip, &self.fw_int, &mut mvalue)?;
63
64 if value[0] & 1 != 0 {
65 return Ok(false);
66 }
67
68 mvalue[0] |= 1;
69
70 crate::chip::HlCommsInterface::axi_write_field(&chip, &self.fw_int, mvalue.as_slice())?;
71
72 Ok(true)
73 }
74
75 fn push_request(
76 &self,
77 chip: &Blackhole,
78 index: u8,
79 request: &[u32; N],
80 timeout: std::time::Duration,
81 ) -> Result<(), PlatformError> {
82 let request_queue_wptr = self.qread32(chip, index, 0)?;
83
84 let start_time = std::time::Instant::now();
85 loop {
86 let request_queue_rptr = self.qread32(chip, index, 4)?;
87
88 if request_queue_rptr.abs_diff(request_queue_wptr) % (2 * self.queue_size)
90 != self.queue_size
91 {
92 break;
93 }
94
95 let elapsed = start_time.elapsed();
96 if elapsed > timeout {
97 return Err(MessageError::Timeout {
98 phase: "push".to_string(),
99 timeout: elapsed,
100 })?;
101 }
102 }
103
104 let request_entry_offset =
105 self.header_size + (request_queue_wptr % self.queue_size) * N as u32;
106 for (i, &item) in request.iter().enumerate() {
107 self.qwrite32(chip, index, request_entry_offset + i as u32, item)?;
108 }
109
110 let request_queue_wptr = (request_queue_wptr + 1) % (2 * self.queue_size);
111 self.qwrite32(chip, index, 0, request_queue_wptr)?;
112
113 self.trigger_int(chip)?;
114
115 Ok(())
116 }
117
118 fn pop_response(
119 &self,
120 chip: &Blackhole,
121 index: u8,
122 result: &mut [u32; N],
123 timeout: std::time::Duration,
124 ) -> Result<(), PlatformError> {
125 let response_queue_rptr = self.qread32(chip, index, 1)?;
126
127 let start_time = std::time::Instant::now();
128 loop {
129 let response_queue_wptr = self.qread32(chip, index, 5)?;
130
131 if response_queue_wptr != response_queue_rptr {
133 break;
134 }
135
136 let elapsed = start_time.elapsed();
137 if elapsed > timeout {
138 return Err(MessageError::Timeout {
139 phase: "pop".to_string(),
140 timeout: elapsed,
141 })?;
142 }
143 }
144
145 let response_entry_offset = self.header_size
146 + (self.queue_size + (response_queue_rptr % self.queue_size)) * N as u32;
147 for (i, item) in result.iter_mut().enumerate() {
148 *item = self.qread32(chip, index, response_entry_offset + i as u32)?;
149 }
150
151 let response_queue_rptr = (response_queue_rptr + 1) % (2 * self.queue_size);
152 self.qwrite32(chip, index, 1, response_queue_rptr)?;
153
154 Ok(())
155 }
156
157 pub fn send_message(
158 &self,
159 chip: &Blackhole,
160 index: u8,
161 mut request: [u32; N],
162 timeout: std::time::Duration,
163 ) -> Result<[u32; N], PlatformError> {
164 if index as u32 > self.queue_count {
165 return Err(MessageError::QueueIndexOutOfRange {
166 index: index as u32,
167 queue_count: self.queue_count,
168 })?;
169 }
170
171 self.push_request(chip, index, &request, timeout)?;
172 self.pop_response(chip, index, &mut request, timeout)?;
173
174 Ok(request)
175 }
176}
177
178#[derive(Debug)]
179pub struct QueueInfo {
180 pub req_rptr: u32,
181 pub req_wptr: u32,
182 pub resp_rptr: u32,
183 pub resp_wptr: u32,
184}
185
186impl<const N: usize> MessageQueue<N> {
187 pub fn get_queue_info(&self, chip: &Blackhole, index: u8) -> Result<QueueInfo, PlatformError> {
188 if index as u32 > self.queue_count {
189 return Err(MessageError::QueueIndexOutOfRange {
190 index: index as u32,
191 queue_count: self.queue_count,
192 })?;
193 }
194
195 Ok(QueueInfo {
196 req_rptr: self.qread32(chip, index, 4)?,
197 req_wptr: self.qread32(chip, index, 0)?,
198 resp_rptr: self.qread32(chip, index, 1)?,
199 resp_wptr: self.qread32(chip, index, 5)?,
200 })
201 }
202}