1use std::cell::RefCell;
22use std::collections::VecDeque;
23use std::rc::Rc;
24
25use async_trait::async_trait;
26use gwr_components::flow_controls::limiter::Limiter;
27use gwr_components::router::{DefaultAlgorithm, Route};
28use gwr_components::store::{ByteStore, Store};
29use gwr_components::{connect_port, rc_limiter};
30use gwr_engine::engine::Engine;
31use gwr_engine::events::repeated::Repeated;
32use gwr_engine::executor::Spawner;
33use gwr_engine::port::{InPort, OutPort, PortStateResult};
34use gwr_engine::sim_error;
35use gwr_engine::time::clock::{Clock, ClockTick};
36use gwr_engine::traits::{Event, Routable, Runnable, SimObject};
37use gwr_engine::types::{SimError, SimResult};
38use gwr_model_builder::{EntityDisplay, EntityGet};
39use gwr_track::build_aka;
40use gwr_track::entity::Entity;
41use gwr_track::tracker::aka::Aka;
42
43use crate::fabric::{Fabric, FabricConfig};
44
45#[must_use]
47fn manhatten_rx_to_tx_cycles(
48 config: &FabricConfig,
49 rx_port_index: usize,
50 tx_port_index: usize,
51) -> usize {
52 let (rx_col, rx_row, _) = config.fabric_port_index_to_col_row_port(rx_port_index);
53 let (tx_col, tx_row, _) = config.fabric_port_index_to_col_row_port(tx_port_index);
54 let horizontal_hops = rx_col.abs_diff(tx_col);
55 let vertical_hops = rx_row.abs_diff(tx_row);
56
57 (horizontal_hops + vertical_hops) * config.cycles_per_hop + config.cycles_overhead
60}
61
62#[derive(EntityGet, EntityDisplay)]
63pub struct FunctionalFabric<T>
64where
65 T: SimObject + Routable,
66{
67 entity: Rc<Entity>,
68 rx_buffer_limiters: Vec<Rc<Limiter<T>>>,
69 internal_rx: RefCell<Vec<InPort<T>>>,
70 tx_buffers: Vec<Rc<Store<T>>>,
71 internal_tx: RefCell<Vec<OutPort<T>>>,
72 config: Rc<FabricConfig>,
73 clock: Clock,
74 spawner: Spawner,
75}
76
77impl<T> FunctionalFabric<T>
78where
79 T: SimObject + Routable,
80{
81 pub fn new_and_register_with_renames(
86 engine: &Engine,
87 clock: &Clock,
88 parent: &Rc<Entity>,
89 name: &str,
90 aka: Option<&Aka>,
91 config: Rc<FabricConfig>,
92 ) -> Result<Rc<Self>, SimError> {
93 let entity = Rc::new(Entity::new(parent, name));
94 let spawner = engine.spawner();
95
96 let num_ports = config.num_columns * config.num_rows * config.num_ports_per_node;
97 if num_ports < 2 {
98 return sim_error!("Cannot create fabric with less than 2 ports");
99 }
100
101 let mut rx_buffer_limiters = Vec::with_capacity(num_ports);
102 let mut internal_rx = Vec::with_capacity(num_ports);
103 let mut tx_buffers = Vec::with_capacity(num_ports);
104 let mut internal_tx = Vec::with_capacity(num_ports);
105
106 let port_limiter = rc_limiter!(clock, config.port_bits_per_tick);
107
108 for i in 0..num_ports {
109 let rx_buffer_limiter_aka =
111 build_aka!(aka, &entity, &[(&format!("ingress_{i}"), "rx")]);
112 let rx_buffer_limiter = Limiter::new_and_register_with_renames(
113 engine,
114 clock,
115 &entity,
116 &format!("limit_rx_{i}"),
117 Some(&rx_buffer_limiter_aka),
118 port_limiter.clone(),
119 );
120 let rx_buffer = ByteStore::new_and_register(
121 engine,
122 clock,
123 &entity,
124 &format!("rx_buf_{i}"),
125 config.rx_buffer_bytes,
126 )?;
127 connect_port!(rx_buffer_limiter, tx => rx_buffer, rx)
128 .expect("Internal ports should connect without error");
129
130 let internal_rx_port = InPort::new(engine, clock, &entity, &format!("internal_rx_{i}"));
132 rx_buffer
133 .connect_port_tx(internal_rx_port.state())
134 .expect("Internal ports should connect without error");
135
136 rx_buffer_limiters.push(rx_buffer_limiter);
137 internal_rx.push(internal_rx_port);
138
139 let tx_buffer_limiter = Limiter::new_and_register(
141 engine,
142 clock,
143 &entity,
144 &format!("limit_tx_{i}"),
145 port_limiter.clone(),
146 );
147
148 let tx_buffer_aka = build_aka!(aka, &entity, &[(&format!("egress_{i}"), "tx")]);
149 let tx_buffer = ByteStore::new_and_register_with_renames(
150 engine,
151 clock,
152 &entity,
153 &format!("tx_buf_{i}"),
154 Some(&tx_buffer_aka),
155 config.tx_buffer_bytes,
156 )?;
157 connect_port!(tx_buffer_limiter, tx => tx_buffer, rx)
158 .expect("Internal ports should connect without error");
159
160 let mut internal_tx_port = OutPort::new(&entity, &format!("internal_tx_{i}"));
162 internal_tx_port
163 .connect(tx_buffer_limiter.port_rx())
164 .expect("Internal ports should connect without error");
165
166 tx_buffers.push(tx_buffer);
167 internal_tx.push(internal_tx_port);
168 }
169
170 let rc_self = Rc::new(Self {
171 entity,
172 rx_buffer_limiters,
173 internal_rx: RefCell::new(internal_rx),
174 tx_buffers,
175 internal_tx: RefCell::new(internal_tx),
176 config,
177 clock: clock.clone(),
178 spawner,
179 });
180 engine.register(rc_self.clone());
181 Ok(rc_self)
182 }
183
184 pub fn new_and_register(
189 engine: &Engine,
190 clock: &Clock,
191 parent: &Rc<Entity>,
192 name: &str,
193 config: Rc<FabricConfig>,
194 ) -> Result<Rc<Self>, SimError> {
195 Self::new_and_register_with_renames(engine, clock, parent, name, None, config)
196 }
197}
198
199impl<T> Fabric<T> for FunctionalFabric<T>
200where
201 T: SimObject + Routable,
202{
203 fn connect_port_egress_i(&self, i: usize, port_state: PortStateResult<T>) -> SimResult {
204 self.tx_buffers[i].connect_port_tx(port_state)
205 }
206
207 fn port_ingress_i(&self, i: usize) -> PortStateResult<T> {
208 self.rx_buffer_limiters[i].port_rx()
209 }
210
211 fn col_row_port_to_fabric_port_index(&self, col: usize, row: usize, port: usize) -> usize {
212 self.config
213 .col_row_port_to_fabric_port_index(col, row, port)
214 }
215}
216
217#[async_trait(?Send)]
218impl<T> Runnable for FunctionalFabric<T>
219where
220 T: SimObject + Routable,
221{
222 async fn run(&self) -> SimResult {
223 let num_ports = self.config.max_num_ports();
224 let mut port_states = Vec::with_capacity(num_ports);
225 for _ in 0..num_ports {
226 port_states.push(PortState::default());
227 }
228 let port_states = Rc::new(port_states);
229
230 let routing_algorithm: Rc<Box<dyn Route<T>>> = Rc::new(Box::new(DefaultAlgorithm {}));
231
232 for (i, internal_rx) in self.internal_rx.borrow_mut().drain(..).enumerate() {
233 let entity = self.entity.clone();
234 let clock = self.clock.clone();
235 let port_states = port_states.clone();
236 let routing_algorithm = routing_algorithm.clone();
237 let config = self.config.clone();
238
239 self.spawner.spawn(async move {
240 run_rx(
241 entity,
242 clock,
243 i,
244 internal_rx,
245 port_states,
246 routing_algorithm,
247 config,
248 )
249 .await
250 });
251 }
252
253 for (i, internal_tx) in self.internal_tx.borrow_mut().drain(..).enumerate() {
254 let entity = self.entity.clone();
255 let clock = self.clock.clone();
256 let port_states = port_states.clone();
257
258 self.spawner
259 .spawn(async move { run_tx(entity, clock, i, internal_tx, port_states).await });
260 }
261
262 Ok(())
263 }
264}
265
266struct PortState<T> {
270 data_for_tx: RefCell<VecDeque<(T, ClockTick)>>,
271 data_for_tx_bytes: RefCell<usize>,
272 waiting_for_data: Repeated<()>,
273 waiting_for_room: Repeated<()>,
274 inputs_waiting_for_room: RefCell<VecDeque<usize>>,
275}
276
277impl<T> Default for PortState<T> {
278 fn default() -> Self {
279 Self {
280 data_for_tx: RefCell::new(VecDeque::new()),
281 data_for_tx_bytes: RefCell::new(0),
282 waiting_for_data: Repeated::default(),
283 waiting_for_room: Repeated::default(),
284 inputs_waiting_for_room: RefCell::new(VecDeque::new()),
285 }
286 }
287}
288
289async fn run_rx<T>(
290 entity: Rc<Entity>,
291 clock: Clock,
292 port_index: usize,
293 mut internal_rx: InPort<T>,
294 port_states: Rc<Vec<PortState<T>>>,
295 routing_algorithm: Rc<Box<dyn Route<T>>>,
296 config: Rc<FabricConfig>,
297) -> SimResult
298where
299 T: SimObject + Routable,
300{
301 let max_internal_buffer_bytes = config.tx_buffer_bytes;
303
304 loop {
305 let value = internal_rx.get()?.await;
306 let value_id = value.id();
307 entity.track_enter(value_id);
308 let value_bytes = value.total_bytes();
309
310 let dest_index = routing_algorithm.route(&value)?;
311 let delay_ticks = manhatten_rx_to_tx_cycles(&config, port_index, dest_index);
312
313 let mut tick = clock.tick_now();
314 tick.set_tick(tick.tick() + delay_ticks as u64);
315
316 while *port_states[dest_index].data_for_tx_bytes.borrow() + value_bytes
318 > max_internal_buffer_bytes
319 {
320 port_states[dest_index]
321 .inputs_waiting_for_room
322 .borrow_mut()
323 .push_back(port_index);
324 port_states[port_index].waiting_for_room.listen().await;
325 }
326 *port_states[dest_index].data_for_tx_bytes.borrow_mut() += value_bytes;
327 port_states[dest_index]
328 .data_for_tx
329 .borrow_mut()
330 .push_back((value, tick));
331 port_states[dest_index].waiting_for_data.notify();
332 }
333}
334
335async fn run_tx<T>(
336 entity: Rc<Entity>,
337 clock: Clock,
338 port_index: usize,
339 mut internal_tx: OutPort<T>,
340 port_states: Rc<Vec<PortState<T>>>,
341) -> SimResult
342where
343 T: SimObject + Routable,
344{
345 loop {
346 let next = port_states[port_index].data_for_tx.borrow_mut().pop_front();
347
348 if let Some((value, _)) = &next {
349 *port_states[port_index].data_for_tx_bytes.borrow_mut() -= value.total_bytes();
350 }
351
352 if let Some(waiting_input) = port_states[port_index]
353 .inputs_waiting_for_room
354 .borrow_mut()
355 .pop_front()
356 {
357 port_states[waiting_input].waiting_for_room.notify();
358 }
359
360 match next {
361 Some((value, tick)) => {
362 let tick_now = clock.tick_now();
363 if tick_now.tick() < tick.tick() {
364 clock.wait_ticks(tick.tick() - tick_now.tick()).await;
366 }
367
368 entity.track_exit(value.id());
369 internal_tx.put(value)?.await;
370 }
371 None => {
372 port_states[port_index].waiting_for_data.listen().await;
373 }
374 }
375 }
376}