1use rhdl::prelude::*;
24
25use crate::ports::{Axis256, Axis512, idle256, idle512};
26
27#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
29pub struct BroadcastReq {
30 pub start: bool,
32 pub qbase: b24,
34 pub n: b5,
36 pub word: b32,
38 pub len: b16,
41 pub payload: [b64; 8],
43 pub beats: b5,
45 pub from_ram: bool,
47}
48
49#[kernel]
51pub fn idle_bcast_req() -> BroadcastReq {
52 BroadcastReq { start: false, qbase: b24(0), n: b5(0), word: b32(0), len: b16(0), payload: [b64(0); 8], beats: b5(0), from_ram: false }
53}
54
55#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
57pub struct BroadcastIn {
58 pub req: BroadcastReq,
60 pub meta_ready: bool,
62 pub data_ready: bool,
64 pub ram_data: [b64; 8],
66}
67
68#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
70pub struct BroadcastOut {
71 pub busy: bool,
73 pub done: bool,
75 pub meta: Axis256,
77 pub data: Axis512,
79 pub ram_addr: b5,
81}
82
83#[derive(Clone, Copy, Debug, PartialEq, Digital, Default)]
85pub struct BroadcastState {
86 pub busy: bool,
88 pub req: BroadcastReq,
90 pub dest: b5,
92 pub meta_sent: bool,
94 pub data_sent: bool,
96 pub beat: b5,
98 pub stale: bool,
100}
101
102#[kernel]
105pub fn write_meta(qpn: b24, raddr: b48, len: b32) -> [b64; 4] {
106 let lane0 = b64(1) | (qpn.resize::<64>() << b64(3));
109 let lane1 = (raddr.resize::<64>() << b64(11)) | (len.resize::<64>() << b64(59));
110 let lane2 = (len >> b32(5)).resize::<64>();
111 [lane0, lane1, lane2, b64(0)]
112}
113
114#[kernel]
116pub fn keep_bytes(len: b16) -> b64 {
117 if len >= b16(64) { !b64(0) } else { (b64(1) << len.resize::<64>()) - b64(1) }
118}
119
120#[derive(Clone, Debug, Synchronous, SynchronousDQ)]
122pub struct Broadcaster {
123 state: rhdl_fpga::core::dff::DFF<BroadcastState>,
124}
125
126impl Default for Broadcaster {
127 fn default() -> Self {
128 Self { state: rhdl_fpga::core::dff::DFF::new(BroadcastState::default()) }
129 }
130}
131
132impl SynchronousIO for Broadcaster {
133 type I = BroadcastIn;
134 type O = BroadcastOut;
135 type Kernel = broadcast_kernel;
136}
137
138#[kernel]
140pub fn broadcast_kernel(_cr: ClockReset, i: BroadcastIn, q: BroadcasterQ) -> (BroadcastOut, BroadcasterD) {
141 let r = q.state;
142 let mut s = r;
143 let mut o = BroadcastOut { busy: r.busy, done: false, meta: idle256(), data: idle512(), ram_addr: r.beat };
144 if !r.busy && i.req.start && i.req.n == b5(0) {
146 o.done = true;
147 }
148 if !r.busy && i.req.start && i.req.n != b5(0) {
149 s.busy = true;
150 s.req = i.req;
151 s.dest = b5(0);
152 s.meta_sent = false;
153 s.data_sent = false;
154 s.beat = b5(0);
155 s.stale = true;
156 }
157 if r.busy {
158 let qpn = r.req.qbase + r.dest.resize::<24>();
159 let raddr: b48 = (r.req.word.resize::<48>()) << b48(2);
160 o.meta.valid = !r.meta_sent;
161 o.meta.data = write_meta(qpn, raddr, r.req.len.resize());
162 o.meta.last = true;
163 let final_beat = r.beat + b5(1) == r.req.beats;
164 let have = !r.req.from_ram || !r.stale;
166 o.data.valid = !r.data_sent && have;
167 o.data.data = if r.req.from_ram { i.ram_data } else { r.req.payload };
168 o.data.keep = if r.req.from_ram { !b64(0) } else { keep_bytes(r.req.len) };
169 o.data.last = final_beat;
170 s.stale = false;
171 let meta_ok = r.meta_sent || i.meta_ready;
172 s.meta_sent = meta_ok;
173 let mut data_ok = r.data_sent;
174 if !r.data_sent && have && i.data_ready {
175 if final_beat {
176 data_ok = true;
177 } else {
178 s.beat = r.beat + b5(1);
179 s.stale = true;
180 }
181 }
182 s.data_sent = data_ok;
183 if meta_ok && data_ok {
184 s.meta_sent = false;
185 s.data_sent = false;
186 s.beat = b5(0);
187 s.stale = true;
188 s.dest = r.dest + b5(1);
189 if r.dest + b5(1) == r.req.n {
190 s.busy = false;
191 o.done = true;
192 }
193 }
194 }
195 (o, BroadcasterD { state: s })
196}