1use crate::codegen_sva::pdk_target::UserArea;
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub struct MacroPort {
25 pub name: &'static str,
26 pub width: u32,
27 pub is_input: bool,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq)]
32pub struct ShuttleMacro {
33 pub name: &'static str,
34 pub width_um: f64,
36 pub height_um: f64,
37 pub ports: &'static [MacroPort],
39 pub has_rst: bool,
41}
42
43impl ShuttleMacro {
44 pub fn area_mm2(&self) -> f64 {
45 self.width_um * self.height_um / 1.0e6
46 }
47 pub fn in_words(&self) -> u32 {
49 self.ports
50 .iter()
51 .filter(|p| p.is_input)
52 .map(|p| p.width.div_ceil(32))
53 .sum()
54 }
55 pub fn out_words(&self) -> u32 {
56 self.ports
57 .iter()
58 .filter(|p| !p.is_input)
59 .map(|p| p.width.div_ceil(32))
60 .sum()
61 }
62}
63
64#[derive(Debug, Clone, PartialEq)]
66pub struct Placement {
67 pub name: &'static str,
68 pub x_um: f64,
69 pub y_um: f64,
70 pub base: u32,
72}
73
74#[derive(Debug, Clone, PartialEq)]
76pub enum ShuttleUnplaceable {
77 AreaExceeded { needed_mm2: f64, available_mm2: f64 },
79 MacroTooLarge { name: &'static str, w: f64, h: f64 },
81 DoesNotPack {
83 placed: usize,
84 total: usize,
85 keepout_um: f64,
86 },
87 AddressOverflow {
89 name: &'static str,
90 words: u32,
91 per_macro_words: u32,
92 },
93}
94
95pub const MACRO_KEEPOUT_UM: f64 = 50.0;
103
104pub const MACRO_ADDR_STRIDE: u32 = 0x100;
107const WB_BASE: u32 = 0x3000_0000;
108
109pub fn plan_shuttle(
116 macros: &[ShuttleMacro],
117 area: UserArea,
118) -> Result<Vec<Placement>, ShuttleUnplaceable> {
119 let avail = area.mm2();
120 let needed: f64 = macros.iter().map(|m| m.area_mm2()).sum();
121 if needed > avail {
122 return Err(ShuttleUnplaceable::AreaExceeded {
123 needed_mm2: needed,
124 available_mm2: avail,
125 });
126 }
127 let (aw, ah) = (area.width_um, area.height_um);
128 for m in macros {
129 if m.width_um + 2.0 * MACRO_KEEPOUT_UM > aw || m.height_um + 2.0 * MACRO_KEEPOUT_UM > ah {
130 return Err(ShuttleUnplaceable::MacroTooLarge {
131 name: m.name,
132 w: m.width_um,
133 h: m.height_um,
134 });
135 }
136 }
137 for (i, m) in macros.iter().enumerate() {
138 let words = m.in_words().max(m.out_words());
139 let per = MACRO_ADDR_STRIDE / 4;
140 if words > per {
141 return Err(ShuttleUnplaceable::AddressOverflow {
142 name: m.name,
143 words,
144 per_macro_words: per,
145 });
146 }
147 let _ = i;
148 }
149
150 let mut order: Vec<&ShuttleMacro> = macros.iter().collect();
151 order.sort_by(|a, b| b.height_um.total_cmp(&a.height_um).then(a.name.cmp(b.name)));
152
153 let mut out = Vec::new();
154 let (mut x, mut y, mut shelf_h) = (MACRO_KEEPOUT_UM, MACRO_KEEPOUT_UM, 0.0f64);
155 for m in &order {
156 let (w, h) = (m.width_um, m.height_um);
157 if x + w + MACRO_KEEPOUT_UM > aw {
158 x = MACRO_KEEPOUT_UM;
159 y += shelf_h + MACRO_KEEPOUT_UM;
160 shelf_h = 0.0;
161 }
162 if y + h + MACRO_KEEPOUT_UM > ah {
163 return Err(ShuttleUnplaceable::DoesNotPack {
164 placed: out.len(),
165 total: macros.len(),
166 keepout_um: MACRO_KEEPOUT_UM,
167 });
168 }
169 let idx = macros
172 .iter()
173 .position(|c| c.name == m.name)
174 .expect("macro in the input set");
175 out.push(Placement {
176 name: m.name,
177 x_um: x,
178 y_um: y,
179 base: WB_BASE + (idx as u32) * MACRO_ADDR_STRIDE,
180 });
181 x += w + MACRO_KEEPOUT_UM;
182 shelf_h = shelf_h.max(h);
183 }
184 Ok(out)
185}
186
187pub fn emit_macro_cfg(placed: &[Placement]) -> String {
189 let mut s = String::new();
190 for p in placed {
191 s.push_str(&format!("{}_i {:.0} {:.0} N\n", p.name, p.x_um, p.y_um));
192 }
193 s
194}
195
196pub fn emit_pdn_hooks(placed: &[Placement]) -> String {
199 placed
200 .iter()
201 .map(|p| format!("{}_i vccd1 vssd1 vccd1 vssd1", p.name))
202 .collect::<Vec<_>>()
203 .join(", ")
204}
205
206const fn i(name: &'static str, width: u32) -> MacroPort {
207 MacroPort {
208 name,
209 width,
210 is_input: true,
211 }
212}
213const fn o(name: &'static str, width: u32) -> MacroPort {
214 MacroPort {
215 name,
216 width,
217 is_input: false,
218 }
219}
220
221pub const CLEAN_MACROS: &[ShuttleMacro] = &[
228 ShuttleMacro {
229 name: "systolic_pipe8_realbist",
230 width_um: 1062.6,
231 height_um: 1073.3,
232 ports: &[o("sig", 1)],
233 has_rst: true,
234 },
235 ShuttleMacro {
236 name: "fabric_horner_seq",
237 width_um: 1028.8,
238 height_um: 1039.5,
239 ports: &[i("in0", 64), o("result", 64), o("done", 1)],
240 has_rst: true,
241 },
242 ShuttleMacro {
243 name: "fabric_soc",
244 width_um: 783.2,
245 height_um: 793.9,
246 ports: &[i("in0", 64), o("result", 64), o("done", 1)],
247 has_rst: true,
248 },
249 ShuttleMacro {
250 name: "soft_core_scalar",
251 width_um: 649.0,
252 height_um: 659.7,
253 ports: &[i("start", 1), o("result", 64), o("done", 1)],
254 has_rst: true,
255 },
256 ShuttleMacro {
257 name: "systolic_tile_realbist",
258 width_um: 602.0,
259 height_um: 612.7,
260 ports: &[o("sig", 1)],
261 has_rst: true,
262 },
263 ShuttleMacro {
264 name: "gpu_simt",
265 width_um: 591.0,
266 height_um: 601.7,
267 ports: &[i("in0", 64), o("result", 64), o("done", 1)],
268 has_rst: true,
269 },
270 ShuttleMacro {
271 name: "gemm_mac_realbist",
272 width_um: 529.5,
273 height_um: 540.2,
274 ports: &[o("sig", 1)],
275 has_rst: true,
276 },
277 ShuttleMacro {
278 name: "infinichip",
279 width_um: 350.0,
280 height_um: 350.0,
281 ports: &[i("in0", 64), o("result", 64), o("done", 1)],
282 has_rst: true,
283 },
284 ShuttleMacro {
285 name: "dpu_ingest",
286 width_um: 320.0,
287 height_um: 320.0,
288 ports: &[i("in0", 64), o("result", 64), o("done", 1)],
289 has_rst: true,
290 },
291 ShuttleMacro {
292 name: "dram_executor_wb",
293 width_um: 300.0,
294 height_um: 300.0,
295 ports: &[i("cmd", 64), o("la", 64)],
296 has_rst: true,
297 },
298 ShuttleMacro {
299 name: "nested_tri",
300 width_um: 204.8,
301 height_um: 215.5,
302 ports: &[i("in0", 64), o("result", 64), o("done", 1)],
303 has_rst: true,
304 },
305 ShuttleMacro {
306 name: "cgra_sumto",
307 width_um: 187.2,
308 height_um: 198.0,
309 ports: &[i("in0", 64), o("result", 64), o("done", 1)],
310 has_rst: true,
311 },
312 ShuttleMacro {
313 name: "decision_hft_realbist",
314 width_um: 178.6,
315 height_um: 189.3,
316 ports: &[o("sig", 1)],
317 has_rst: true,
318 },
319 ShuttleMacro {
320 name: "decision_hft_bist",
321 width_um: 159.1,
322 height_um: 169.8,
323 ports: &[o("sig", 1)],
324 has_rst: true,
325 },
326 ShuttleMacro {
327 name: "rev_alu_core",
328 width_um: 150.9,
329 height_um: 161.6,
330 ports: &[i("op", 3), o("a", 32), o("b", 32)],
331 has_rst: false,
332 },
333 ShuttleMacro {
334 name: "dram_executor",
335 width_um: 132.4,
336 height_um: 143.1,
337 ports: &[
338 i("cmd_word", 64),
339 i("cmd_valid", 1),
340 o("issue", 1),
341 o("op", 3),
342 o("bank", 5),
343 o("row", 32),
344 ],
345 has_rst: true,
346 },
347];