1use rhdl::prelude::*;
11
12use crate::ports::{AxiRead, AxiReadResp, Axis512, idle512, idle_read};
13
14#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
16pub struct ShareReq {
17 pub start: bool,
19 pub base: b64,
21 pub word: b32,
23 pub beats: b5,
25}
26
27#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
29pub struct ShareIn {
30 pub req: ShareReq,
32 pub axi: AxiReadResp,
34 pub out_ready: bool,
36}
37
38#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
40pub struct ShareOut {
41 pub busy: bool,
43 pub out: Axis512,
45 pub axi: AxiRead,
47}
48
49#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
51pub struct ShareState {
52 pub phase: b2,
54 pub addr: b64,
56 pub lines: b6,
58 pub ar_lines: b7,
60 pub ar_next: b7,
62 pub beats: b5,
64 pub shift: b6,
66 pub prev: [b64; 8],
68 pub got: b6,
70 pub sent: b5,
72}
73
74#[derive(Clone, Debug, Synchronous, SynchronousDQ)]
76pub struct ShareReader {
77 state: rhdl_fpga::core::dff::DFF<ShareState>,
78}
79
80impl Default for ShareReader {
81 fn default() -> Self {
82 Self { state: rhdl_fpga::core::dff::DFF::new(ShareState::default()) }
83 }
84}
85
86impl SynchronousIO for ShareReader {
87 type I = ShareIn;
88 type O = ShareOut;
89 type Kernel = share_kernel;
90}
91
92#[kernel]
94pub fn align(lo: [b64; 8], hi: [b64; 8], shift: b6) -> [b64; 8] {
95 let mut words = [b32(0); 32];
97 for k in 0..8 {
98 words[2 * k] = lo[k].resize();
99 words[2 * k + 1] = (lo[k] >> b64(32)).resize();
100 words[16 + 2 * k] = hi[k].resize();
101 words[16 + 2 * k + 1] = (hi[k] >> b64(32)).resize();
102 }
103 let off: b4 = (shift >> b6(2)).resize();
104 let mut out = [b64(0); 8];
105 for k in 0..8 {
106 let mut a = b32(0);
107 let mut b = b32(0);
108 for j in 0..16 {
109 if off == b4(j as u128) {
110 a = words[j + 2 * k];
111 b = words[j + 2 * k + 1];
112 }
113 }
114 out[k] = a.resize::<64>() | (b.resize::<64>() << b64(32));
115 }
116 out
117}
118
119#[kernel]
121pub fn share_kernel(_cr: ClockReset, i: ShareIn, q: ShareReaderQ) -> (ShareOut, ShareReaderD) {
122 let r = q.state;
123 let mut s = r;
124 let mut o = ShareOut { busy: r.phase != b2(0), out: idle512(), axi: idle_read() };
125 if r.phase == b2(0) && i.req.start {
126 let byte = i.req.base + (i.req.word.resize::<64>() << b64(2));
127 let shift: b6 = byte.resize();
128 s.addr = byte & !b64(63);
129 s.shift = shift;
130 s.beats = i.req.beats;
131 let lines = i.req.beats.resize::<6>() + (if shift == b6(0) { b6(0) } else { b6(1) });
133 s.lines = lines;
134 let to_boundary: b7 = b7(64) - ((byte >> b64(6)) & b64(63)).resize::<7>();
136 let first = if to_boundary < lines.resize::<7>() { to_boundary } else { lines.resize::<7>() };
137 s.ar_lines = first;
138 s.ar_next = lines.resize::<7>() - first;
139 s.got = b6(0);
140 s.sent = b5(0);
141 s.phase = b2(2);
142 }
143 if r.phase == b2(2) && r.ar_lines != b7(0) {
144 o.axi.ar_valid = true;
145 o.axi.ar_addr = r.addr;
146 o.axi.ar_len = (r.ar_lines - b7(1)).resize();
147 if i.axi.ar_ready {
148 s.addr = r.addr + (r.ar_lines.resize::<64>() << b64(6));
149 s.ar_lines = r.ar_next;
150 s.ar_next = b7(0);
151 }
152 }
153 if r.phase == b2(2) {
154 let aligned = r.shift == b6(0);
155 let priming = !aligned && r.got == b6(0);
158 let beat = if aligned { i.axi.r_data } else { align(r.prev, i.axi.r_data, r.shift) };
159 let emit = i.axi.r_valid && !priming;
160 o.out = Axis512 { valid: emit, data: beat, keep: !b64(0), last: r.sent + b5(1) == r.beats };
161 let take = i.axi.r_valid && (priming || i.out_ready);
163 o.axi.r_ready = priming || i.out_ready;
164 if take {
165 s.prev = i.axi.r_data;
166 s.got = r.got + b6(1);
167 if emit {
168 s.sent = r.sent + b5(1);
169 }
170 if r.got + b6(1) == r.lines {
172 s.phase = b2(0);
173 }
174 }
175 }
176 (o, ShareReaderD { state: s })
177}