1use rhdl::prelude::*;
19
20use crate::ports::{AxiRead, AxiReadResp, idle_read};
21
22#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
25pub struct FetchReq {
26 pub start: bool,
28 pub base: b64,
30 pub word: b32,
32 pub count: b6,
34}
35
36#[kernel]
38pub fn idle_fetch_req() -> FetchReq {
39 FetchReq { start: false, base: b64(0), word: b32(0), count: b6(0) }
40}
41
42#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
44pub struct FetchIn {
45 pub req: FetchReq,
47 pub axi: AxiReadResp,
49}
50
51#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
53pub struct FetchOut {
54 pub busy: bool,
56 pub done: bool,
58 pub words: [b32; 32],
61 pub axi: AxiRead,
63}
64
65#[derive(Clone, Copy, Debug, PartialEq, Digital)]
67pub struct FetchState {
68 pub phase: b2,
70 pub addr: b64,
72 pub total: b2,
74 pub ar_beats: b2,
76 pub ar_next: b2,
78 pub offset: b4,
80 pub got: b2,
82 pub buf: [b32; 48],
84}
85
86impl Default for FetchState {
87 fn default() -> Self {
88 Self { phase: b2(0), addr: b64(0), total: b2(0), ar_beats: b2(0), ar_next: b2(0), offset: b4(0), got: b2(0), buf: [b32(0); 48] }
89 }
90}
91
92#[derive(Clone, Debug, Synchronous, SynchronousDQ)]
94pub struct Fetcher {
95 state: rhdl_fpga::core::dff::DFF<FetchState>,
96}
97
98impl Default for Fetcher {
99 fn default() -> Self {
100 Self { state: rhdl_fpga::core::dff::DFF::new(FetchState::default()) }
101 }
102}
103
104impl SynchronousIO for Fetcher {
105 type I = FetchIn;
106 type O = FetchOut;
107 type Kernel = fetch_kernel;
108}
109
110#[kernel]
112pub fn fetch_kernel(_cr: ClockReset, i: FetchIn, q: FetcherQ) -> (FetchOut, FetcherD) {
113 let r = q.state;
114 let mut s = r;
115 let mut o = FetchOut { busy: false, done: false, words: [b32(0); 32], axi: idle_read() };
116 o.busy = r.phase != b2(0);
117 if r.phase == b2(0) && i.req.start {
118 let byte = i.req.base + (i.req.word.resize::<64>() << b64(2));
120 let offset: b4 = (byte >> b64(2)).resize();
121 s.addr = byte & !b64(63);
122 s.offset = offset;
123 let end: b7 = offset.resize::<7>() + i.req.count.resize::<7>();
125 let total = if end > b7(32) { b2(3) } else if end > b7(16) { b2(2) } else { b2(1) };
126 s.total = total;
127 let to_boundary: b7 = b7(64) - ((byte >> b64(6)) & b64(63)).resize::<7>();
130 let first = if to_boundary < total.resize::<7>() { to_boundary.resize::<2>() } else { total };
131 s.ar_beats = first;
132 s.ar_next = total - first;
133 s.got = b2(0);
134 s.phase = b2(2);
135 }
136 if r.phase == b2(2) {
137 if r.ar_beats != b2(0) {
139 o.axi.ar_valid = true;
140 o.axi.ar_addr = r.addr;
141 o.axi.ar_len = (r.ar_beats - b2(1)).resize();
142 if i.axi.ar_ready {
143 s.addr = r.addr + (r.ar_beats.resize::<64>() << b64(6));
144 s.ar_beats = r.ar_next;
145 s.ar_next = b2(0);
146 }
147 }
148 o.axi.r_ready = true;
151 if i.axi.r_valid {
152 for k in 0..8 {
153 let lo: b32 = i.axi.r_data[k].resize();
154 let hi: b32 = (i.axi.r_data[k] >> b64(32)).resize();
155 if r.got == b2(0) {
156 s.buf[2 * k] = lo;
157 s.buf[2 * k + 1] = hi;
158 } else if r.got == b2(1) {
159 s.buf[16 + 2 * k] = lo;
160 s.buf[16 + 2 * k + 1] = hi;
161 } else {
162 s.buf[32 + 2 * k] = lo;
163 s.buf[32 + 2 * k + 1] = hi;
164 }
165 }
166 s.got = r.got + b2(1);
167 if r.got + b2(1) == r.total {
168 s.phase = b2(3);
169 }
170 }
171 }
172 if r.phase == b2(3) {
173 o.done = true;
174 s.phase = b2(0);
175 }
176 for k in 0..32 {
178 let mut w = b32(0);
179 for j in 0..16 {
180 if r.offset == b4(j as u128) {
181 w = r.buf[j + k];
182 }
183 }
184 o.words[k] = w;
185 }
186 (o, FetcherD { state: s })
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192 use crate::ports::AxiReadResp;
193
194 fn fetch(word: u32, count: u32) -> Vec<u32> {
197 let f = Fetcher::default();
198 let mut st = f.init();
199 let cr = |level| rhdl::core::clock_reset(rhdl::core::clock::clock(level), rhdl::core::types::reset::reset(false));
200 let mut queue: std::collections::VecDeque<(u64, u64)> = Default::default();
201 let mut start = true;
202 for _ in 0..200 {
203 let mut resp = AxiReadResp { ar_ready: true, ..Default::default() };
204 if let Some(&(addr, left)) = queue.front() {
205 resp.r_valid = true;
206 resp.r_data = std::array::from_fn(|k| {
207 let w = addr / 4 + 2 * k as u64;
208 b64(u128::from(w) | (u128::from(w + 1) << 32))
209 });
210 resp.r_last = left == 0;
211 }
212 let i = FetchIn { req: FetchReq { start, base: b64(0), word: b32(word.into()), count: b6(count.into()) }, axi: resp };
213 let o = f.sim(cr(false), i, &mut st);
214 if o.done {
215 return o.words[..count as usize].iter().map(|w| w.raw() as u32).collect();
216 }
217 if o.axi.ar_valid {
218 let (addr, beats) = (o.axi.ar_addr.raw() as u64, o.axi.ar_len.raw() as u64 + 1);
219 assert_eq!(addr / 4096, (addr + 64 * beats - 1) / 4096, "burst at {addr:#x} of {beats} beats crosses 4 KiB");
220 for b in 0..beats {
221 queue.push_back((addr + 64 * b, beats - 1 - b));
222 }
223 }
224 if resp.r_valid && o.axi.r_ready {
225 queue.pop_front();
226 }
227 f.sim(cr(true), i, &mut st);
228 start = false;
229 }
230 panic!("fetch of word {word} count {count} never finished");
231 }
232
233 #[test]
236 fn fetches_never_cross_4_kib() {
237 for word in 1000..1030u32 {
238 for count in [1u32, 2, 5, 16, 17, 32] {
239 let got = fetch(word, count);
240 assert_eq!(got, (word..word + count).collect::<Vec<_>>(), "word {word} count {count}");
241 }
242 }
243 }
244}