1use std::cmp::min;
11use std::fmt::Display;
12
13use gwr_engine::port::PortStateResult;
14use gwr_engine::traits::{Routable, SimObject};
15use gwr_engine::types::SimResult;
16use gwr_track::entity::GetEntity;
17
18pub trait Fabric<T>: GetEntity + Display
19where
20 T: SimObject + Routable,
21{
22 fn connect_port_egress_i(&self, i: usize, port_state: PortStateResult<T>) -> SimResult;
23 fn port_ingress_i(&self, i: usize) -> PortStateResult<T>;
24 fn col_row_port_to_fabric_port_index(&self, col: usize, row: usize, port: usize) -> usize;
25}
26
27pub struct FabricConfig {
29 num_columns: usize,
31
32 num_rows: usize,
34
35 num_ports_per_node: usize,
37
38 ports_per_node_limit: Option<usize>,
42
43 cycles_per_hop: usize,
45
46 cycles_overhead: usize,
48
49 rx_buffer_bytes: usize,
51
52 tx_buffer_bytes: usize,
54
55 port_bits_per_tick: usize,
57
58 fabric_port_indices: Vec<usize>,
60}
61
62#[must_use]
63fn col_row_port_to_fabric_port_index(
64 num_rows: usize,
65 num_ports_per_node: usize,
66 col: usize,
67 row: usize,
68 port: usize,
69) -> usize {
70 port + row * num_ports_per_node + col * num_rows * num_ports_per_node
71}
72
73#[must_use]
74fn num_x_y_ports(num_columns: usize, num_rows: usize, col: usize, row: usize) -> usize {
75 let mut num_ports = 4;
76 if col == 0 || col == num_columns - 1 {
77 num_ports -= 1;
79 }
80 if row == 0 || row == num_rows - 1 {
81 num_ports -= 1;
83 }
84 num_ports
85}
86
87#[must_use]
90fn node_num_ingress_egress_ports(
91 num_columns: usize,
92 num_rows: usize,
93 num_ports_per_node: usize,
94 ports_per_node_limit: Option<usize>,
95 col: usize,
96 row: usize,
97) -> usize {
98 match ports_per_node_limit {
99 None => num_ports_per_node,
100 Some(ports_per_node_limit) => {
101 let num_x_y_ports = num_x_y_ports(num_columns, num_rows, col, row);
102 let max_ingress_egress_ports = ports_per_node_limit.saturating_sub(num_x_y_ports);
103 min(max_ingress_egress_ports, num_ports_per_node)
104 }
105 }
106}
107
108fn create_populated_indices(
109 num_columns: usize,
110 num_rows: usize,
111 num_ports_per_node: usize,
112 ports_per_node_limit: Option<usize>,
113) -> Vec<usize> {
114 let mut fabric_indices = Vec::new();
115 for col in 0..num_columns {
116 for row in 0..num_rows {
117 let num_ports = node_num_ingress_egress_ports(
118 num_columns,
119 num_rows,
120 num_ports_per_node,
121 ports_per_node_limit,
122 col,
123 row,
124 );
125 for port in 0..num_ports {
126 fabric_indices.push(col_row_port_to_fabric_port_index(
127 num_rows,
128 num_ports_per_node,
129 col,
130 row,
131 port,
132 ));
133 }
134 }
135 }
136 fabric_indices
137}
138
139impl FabricConfig {
140 #[expect(clippy::too_many_arguments)]
141 #[must_use]
142 pub fn new(
143 num_columns: usize,
144 num_rows: usize,
145 num_ports_per_node: usize,
146 ports_per_node_limit: Option<usize>,
147 cycles_per_hop: usize,
148 cycles_overhead: usize,
149 rx_buffer_bytes: usize,
150 tx_buffer_bytes: usize,
151 port_bits_per_tick: usize,
152 ) -> Self {
153 let fabric_port_indices = create_populated_indices(
154 num_columns,
155 num_rows,
156 num_ports_per_node,
157 ports_per_node_limit,
158 );
159 Self {
160 num_columns,
161 num_rows,
162 num_ports_per_node,
163 ports_per_node_limit,
164 cycles_per_hop,
165 cycles_overhead,
166 rx_buffer_bytes,
167 tx_buffer_bytes,
168 port_bits_per_tick,
169 fabric_port_indices,
170 }
171 }
172
173 #[must_use]
175 pub fn max_num_ports(&self) -> usize {
176 self.num_columns * self.num_rows * self.num_ports_per_node
177 }
178
179 #[must_use]
181 pub fn num_ports(&self) -> usize {
182 self.fabric_port_indices.len()
183 }
184
185 #[must_use]
187 pub fn port_indices(&self) -> &Vec<usize> {
188 &self.fabric_port_indices
189 }
190
191 #[must_use]
197 pub fn col_row_port_to_fabric_port_index(&self, col: usize, row: usize, port: usize) -> usize {
198 col_row_port_to_fabric_port_index(self.num_rows, self.num_ports_per_node, col, row, port)
199 }
200
201 #[must_use]
202 pub fn fabric_port_index_to_col_row_port(
203 &self,
204 fabric_port_index: usize,
205 ) -> (usize, usize, usize) {
206 let col = fabric_port_index / self.num_ports_per_node / self.num_rows;
207 let row = (fabric_port_index / self.num_ports_per_node) % self.num_rows;
208 let port = fabric_port_index % self.num_ports_per_node;
209 (col, row, port)
210 }
211
212 #[must_use]
213 pub fn node_num_ingress_egress_ports(&self, col: usize, row: usize) -> usize {
214 node_num_ingress_egress_ports(
215 self.num_columns,
216 self.num_rows,
217 self.num_ports_per_node,
218 self.ports_per_node_limit,
219 col,
220 row,
221 )
222 }
223
224 #[must_use]
225 pub fn max_x(&self) -> usize {
226 self.num_columns - 1
227 }
228
229 #[must_use]
230 pub fn max_y(&self) -> usize {
231 self.num_rows - 1
232 }
233
234 #[must_use]
235 pub fn num_columns(&self) -> usize {
236 self.num_columns
237 }
238
239 #[must_use]
240 pub fn num_rows(&self) -> usize {
241 self.num_rows
242 }
243
244 #[must_use]
245 pub fn num_ports_per_node(&self) -> usize {
246 self.num_ports_per_node
247 }
248
249 #[must_use]
250 pub fn cycles_per_hop(&self) -> usize {
251 self.cycles_per_hop
252 }
253
254 #[must_use]
255 pub fn cycles_overhead(&self) -> usize {
256 self.cycles_overhead
257 }
258
259 #[must_use]
260 pub fn port_bits_per_tick(&self) -> usize {
261 self.port_bits_per_tick
262 }
263}
264
265pub mod functional;
266pub mod node;
267pub mod routed;
268
269#[test]
270fn port_index() {
271 let config: FabricConfig = FabricConfig::new(3, 4, 2, None, 1, 1, 1, 1, 1);
272
273 assert_eq!(config.col_row_port_to_fabric_port_index(0, 0, 0), 0);
274 assert_eq!(config.fabric_port_index_to_col_row_port(0), (0, 0, 0));
275
276 assert_eq!(config.col_row_port_to_fabric_port_index(0, 0, 1), 1);
277 assert_eq!(config.fabric_port_index_to_col_row_port(1), (0, 0, 1));
278
279 assert_eq!(config.col_row_port_to_fabric_port_index(0, 1, 0), 2);
280 assert_eq!(config.fabric_port_index_to_col_row_port(2), (0, 1, 0));
281
282 assert_eq!(config.col_row_port_to_fabric_port_index(0, 1, 1), 3);
283 assert_eq!(config.fabric_port_index_to_col_row_port(3), (0, 1, 1));
284
285 assert_eq!(config.col_row_port_to_fabric_port_index(1, 0, 0), 8);
286 assert_eq!(config.fabric_port_index_to_col_row_port(8), (1, 0, 0));
287
288 assert_eq!(config.col_row_port_to_fabric_port_index(1, 3, 0), 14);
289 assert_eq!(config.fabric_port_index_to_col_row_port(14), (1, 3, 0));
290
291 assert_eq!(config.col_row_port_to_fabric_port_index(2, 1, 1), 19);
292 assert_eq!(config.fabric_port_index_to_col_row_port(19), (2, 1, 1));
293}