1use rhdl::prelude::*;
40
41use crate::ports::{AxiLiteIn, AxiLiteOut, CfgWrite, idle_lite_out, regs};
42
43pub const MAGIC: u32 = 0x3142_5552;
45
46#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
48pub struct Args {
49 pub network_ptr: b64,
51 pub message_ptr: b64,
53 pub node_num: b32,
55 pub id: b32,
57 pub execution_cycles: b32,
59 pub wait: b32,
61 pub sk: [b64; 4],
63 pub session: b64,
65}
66
67#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
69pub struct Status {
70 pub finished: bool,
72 pub shape: b32,
74 pub decided: b32,
76 pub fast: b32,
78 pub slow: b32,
80 pub views: b32,
82 pub cycles: b32,
84 pub first: b32,
86 pub last: b32,
88 pub slot_min: b32,
90 pub slot_max: b32,
92 pub slot_sum: b64,
94 pub verified: b32,
96 pub rejected: b32,
98 pub state: b32,
100 pub fault: b32,
105}
106
107#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
109pub struct ControlIn {
110 pub axi: AxiLiteIn,
112 pub status: Status,
114}
115
116#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
118pub struct ControlOut {
119 pub axi: AxiLiteOut,
121 pub args: Args,
123 pub running: bool,
125 pub start: bool,
127 pub cfg: CfgWrite,
129}
130
131#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
133pub struct ControlState {
134 pub args: Args,
136 pub running: bool,
138 pub start: bool,
140 pub done: bool,
142 pub gie: bool,
144 pub ier: bool,
146 pub isr: bool,
148 pub aw_have: bool,
150 pub aw_addr: b12,
152 pub w_have: bool,
154 pub w_data: b32,
156 pub b_valid: bool,
158 pub r_valid: bool,
160 pub r_data: b32,
162}
163
164#[derive(Clone, Debug, Synchronous, SynchronousDQ)]
166pub struct Control {
167 state: rhdl_fpga::core::dff::DFF<ControlState>,
168}
169
170impl Default for Control {
171 fn default() -> Self {
172 Self { state: rhdl_fpga::core::dff::DFF::new(ControlState::default()) }
173 }
174}
175
176impl SynchronousIO for Control {
177 type I = ControlIn;
178 type O = ControlOut;
179 type Kernel = control_kernel;
180}
181
182#[kernel]
185pub fn arg64_word(v: b64, at: b12, base: b12) -> (bool, b32) {
186 if at == base {
187 (true, v.resize())
188 } else if at == base + b12(4) {
189 (true, (v >> b64(32)).resize())
190 } else {
191 (false, b32(0))
192 }
193}
194
195#[kernel]
198pub fn set_arg64(v: b64, at: b12, base: b12, data: b32) -> b64 {
199 if at == base {
200 (v & (b64(0xffff_ffff) << b64(32))) | data.resize::<64>()
201 } else if at == base + b12(4) {
202 (v & b64(0xffff_ffff)) | (data.resize::<64>() << b64(32))
203 } else {
204 v
205 }
206}
207
208#[kernel]
210pub fn control_kernel(_cr: ClockReset, i: ControlIn, q: ControlQ) -> (ControlOut, ControlD) {
211 let r = q.state;
212 let mut s = r;
213 let mut o = ControlOut {
214 axi: idle_lite_out(),
215 args: r.args,
216 running: false,
217 start: false,
218 cfg: CfgWrite { valid: false, addr: b12(0), data: b32(0) },
219 };
220 s.start = false;
221 if r.running && i.status.finished {
222 s.running = false;
223 s.done = true;
224 s.isr = true;
225 }
226
227 o.axi.aw_ready = !r.aw_have && !r.b_valid;
229 o.axi.w_ready = !r.w_have && !r.b_valid;
230 if i.axi.aw_valid && !r.aw_have && !r.b_valid {
231 s.aw_have = true;
232 s.aw_addr = i.axi.aw_addr;
233 }
234 if i.axi.w_valid && !r.w_have && !r.b_valid {
235 s.w_have = true;
236 s.w_data = i.axi.w_data;
237 }
238 if r.aw_have && r.w_have {
239 let a = r.aw_addr;
240 let d = r.w_data;
241 s.aw_have = false;
242 s.w_have = false;
243 s.b_valid = true;
244 if a == b12(regs::AP_CTRL as u128) && (d & b32(1)) == b32(1) && !r.running {
245 s.running = true;
246 s.start = true;
247 }
248 if a == b12(regs::GIE as u128) {
249 s.gie = (d & b32(1)) == b32(1);
250 }
251 if a == b12(regs::IER as u128) {
252 s.ier = (d & b32(1)) == b32(1);
253 }
254 if a == b12(regs::ISR as u128) && (d & b32(1)) == b32(1) {
255 s.isr = false;
256 }
257 if !r.running && a >= b12(0x800) {
259 o.cfg = CfgWrite { valid: true, addr: a - b12(0x800), data: d };
260 }
261 if !r.running {
263 s.args.network_ptr = set_arg64(r.args.network_ptr, a, b12(regs::NETWORK_PTR as u128), d);
264 s.args.message_ptr = set_arg64(r.args.message_ptr, a, b12(regs::MESSAGE_PTR as u128), d);
265 if a == b12(regs::NODE_NUM as u128) {
266 s.args.node_num = d;
267 }
268 if a == b12(regs::ID as u128) {
269 s.args.id = d;
270 }
271 if a == b12(regs::EXECUTION_CYCLES as u128) {
272 s.args.execution_cycles = d;
273 }
274 if a == b12(regs::WAIT as u128) {
275 s.args.wait = d;
276 }
277 for k in 0..4 {
278 s.args.sk[k] = set_arg64(r.args.sk[k], a, b12((regs::SK0 + 12 * k) as u128), d);
279 }
280 s.args.session = set_arg64(r.args.session, a, b12(regs::SESSION as u128), d);
281 }
282 }
283 o.axi.b_valid = r.b_valid;
284 if r.b_valid && i.axi.b_ready {
285 s.b_valid = false;
286 }
287
288 o.axi.ar_ready = !r.r_valid;
290 if i.axi.ar_valid && !r.r_valid {
291 let a = i.axi.ar_addr;
292 let st = i.status;
293 let mut v = b32(0);
294 if a == b12(regs::AP_CTRL as u128) {
295 v = (if r.start || r.running { b32(1) } else { b32(0) })
296 | (if r.done { b32(2) } else { b32(0) })
297 | (if !r.running { b32(4) } else { b32(0) })
298 | (if r.done { b32(8) } else { b32(0) });
299 s.done = false;
300 }
301 if a == b12(regs::GIE as u128) {
302 v = if r.gie { b32(1) } else { b32(0) };
303 }
304 if a == b12(regs::IER as u128) {
305 v = if r.ier { b32(1) } else { b32(0) };
306 }
307 if a == b12(regs::ISR as u128) {
308 v = if r.isr { b32(1) } else { b32(0) };
309 }
310 let (h0, w0) = arg64_word(r.args.network_ptr, a, b12(regs::NETWORK_PTR as u128));
311 if h0 {
312 v = w0;
313 }
314 let (h1, w1) = arg64_word(r.args.message_ptr, a, b12(regs::MESSAGE_PTR as u128));
315 if h1 {
316 v = w1;
317 }
318 let (h2, w2) = arg64_word(r.args.session, a, b12(regs::SESSION as u128));
319 if h2 {
320 v = w2;
321 }
322 if a == b12(regs::NODE_NUM as u128) {
323 v = r.args.node_num;
324 }
325 if a == b12(regs::ID as u128) {
326 v = r.args.id;
327 }
328 if a == b12(regs::EXECUTION_CYCLES as u128) {
329 v = r.args.execution_cycles;
330 }
331 if a == b12(regs::WAIT as u128) {
332 v = r.args.wait;
333 }
334 let words = [
336 b32(0x3142_5552),
337 st.shape,
338 st.decided,
339 st.fast,
340 st.slow,
341 st.views,
342 st.cycles,
343 st.first,
344 st.last,
345 st.slot_min,
346 st.slot_max,
347 st.slot_sum.resize(),
348 (st.slot_sum >> b64(32)).resize(),
349 st.verified,
350 st.rejected,
351 st.state,
352 st.fault,
353 ];
354 for k in 0..17 {
355 if a == b12((regs::STATUS + 4 * k) as u128) {
356 v = words[k];
357 }
358 }
359 s.r_valid = true;
360 s.r_data = v;
361 }
362 o.axi.r_valid = r.r_valid;
363 o.axi.r_data = r.r_data;
364 if r.r_valid && i.axi.r_ready {
365 s.r_valid = false;
366 }
367 o.axi.interrupt = r.gie && r.ier && r.isr;
368 o.args = r.args;
369 o.running = r.running;
370 o.start = r.start;
371 (o, ControlD { state: s })
372}