1use crate::{self as ir, LibrarySignatures, Nothing, RRC, WRC};
4use calyx_frontend::BoolAttr;
5use calyx_utils::CalyxResult;
6use std::rc::Rc;
7
8use super::{CellType, PortDef};
9
10pub struct Builder<'a> {
18 pub component: &'a mut ir::Component,
20 lib: &'a LibrarySignatures,
22 validate: bool,
25 generated: bool,
27}
28
29impl<'a> Builder<'a> {
30 pub fn new(
32 component: &'a mut ir::Component,
33 lib: &'a LibrarySignatures,
34 ) -> Self {
35 Self {
36 component,
37 lib,
38 validate: false,
39 generated: true,
41 }
42 }
43
44 pub fn validate(mut self) -> Self {
46 self.validate = true;
47 self
48 }
49
50 pub fn not_generated(mut self) -> Self {
52 self.generated = false;
53 self
54 }
55
56 pub fn add_continuous_assignments(
57 &mut self,
58 assigns: Vec<ir::Assignment<Nothing>>,
59 ) {
60 self.component.continuous_assignments.extend(assigns);
61 }
62
63 pub fn add_fsm<S>(&mut self, prefix: S) -> RRC<ir::FSM>
67 where
68 S: Into<ir::Id>,
69 {
70 let prefix: ir::Id = prefix.into();
71 assert!(
72 prefix != "",
73 "Cannot construct group with empty name prefix"
74 );
75 let name = self.component.generate_name(prefix);
76
77 let fsm = ir::rrc(ir::FSM::new(name));
79
80 for (name, width) in &[("start", 1), ("done", 1), ("state", 1)] {
82 let hole = ir::rrc(ir::Port {
83 name: ir::Id::from(*name),
84 width: *width,
85 direction: ir::Direction::Inout,
86 parent: ir::PortParent::FSM(WRC::from(&fsm)),
87 attributes: ir::Attributes::default(),
88 });
89 fsm.borrow_mut().wires.push(hole);
90 }
91
92 self.component.get_fsms_mut().add(Rc::clone(&fsm));
94
95 fsm
96 }
97
98 pub fn add_group<S>(&mut self, prefix: S) -> RRC<ir::Group>
102 where
103 S: Into<ir::Id>,
104 {
105 let prefix: ir::Id = prefix.into();
106 assert!(
107 prefix != "",
108 "Cannot construct group with empty name prefix"
109 );
110 let name = self.component.generate_name(prefix);
111
112 let group = ir::rrc(ir::Group::new(name));
114
115 for (name, width) in &[("go", 1), ("done", 1)] {
117 let hole = ir::rrc(ir::Port {
118 name: ir::Id::from(*name),
119 width: *width,
120 direction: ir::Direction::Inout,
121 parent: ir::PortParent::Group(WRC::from(&group)),
122 attributes: ir::Attributes::default(),
123 });
124 group.borrow_mut().holes.push(hole);
125 }
126
127 self.component.get_groups_mut().add(Rc::clone(&group));
129
130 group
131 }
132
133 pub fn add_static_group<S>(
137 &mut self,
138 prefix: S,
139 latency: u64,
140 ) -> RRC<ir::StaticGroup>
141 where
142 S: Into<ir::Id>,
143 {
144 let prefix: ir::Id = prefix.into();
145 assert!(
146 prefix != "",
147 "Cannot construct group with empty name prefix"
148 );
149 let name = self.component.generate_name(prefix);
150
151 let group = ir::rrc(ir::StaticGroup::new(name, latency));
153
154 let (name, width) = ("go", 1);
158 let hole = ir::rrc(ir::Port {
159 name: ir::Id::from(name),
160 width,
161 direction: ir::Direction::Inout,
162 parent: ir::PortParent::StaticGroup(WRC::from(&group)),
163 attributes: ir::Attributes::default(),
164 });
165 group.borrow_mut().holes.push(hole);
166
167 self.component
169 .get_static_groups_mut()
170 .add(Rc::clone(&group));
171
172 group
173 }
174
175 pub fn add_comb_group<S>(&mut self, prefix: S) -> RRC<ir::CombGroup>
177 where
178 S: Into<ir::Id> + ToString + Clone,
179 {
180 let name = self.component.generate_name(prefix);
181
182 let group = ir::rrc(ir::CombGroup {
184 name,
185 attributes: ir::Attributes::default(),
186 assignments: vec![],
187 });
188
189 self.component.comb_groups.add(Rc::clone(&group));
191
192 group
193 }
194
195 pub fn add_constant(&mut self, val: u64, width: u64) -> RRC<ir::Cell> {
199 assert!(
201 (64 - val.leading_zeros()) as u64 <= width,
206 "Constant value {val} cannot fit in {width} bits"
207 );
208 let name = ir::Cell::constant_name(val, width);
209 if let Some(cell) = self.component.cells.find(name) {
212 return Rc::clone(&cell);
213 }
214
215 let cell = Self::cell_from_signature(
217 name,
218 ir::CellType::Constant { val, width },
219 vec![ir::PortDef::new(
220 ir::Id::from("out"),
221 width,
222 ir::Direction::Output,
223 ir::Attributes::default(),
224 )],
225 );
226
227 self.component.cells.add(Rc::clone(&cell));
229
230 cell
231 }
232
233 pub fn add_primitive<Pre, Prim>(
244 &mut self,
245 prefix: Pre,
246 primitive: Prim,
247 param_values: &[u64],
248 ) -> RRC<ir::Cell>
249 where
250 Pre: Into<ir::Id> + ToString + Clone,
251 Prim: Into<ir::Id>,
252 {
253 self.try_add_primitive(prefix, primitive, param_values)
254 .expect("failed to add primitive:")
255 }
256
257 pub fn try_add_primitive<Pre, Prim>(
259 &mut self,
260 prefix: Pre,
261 primitive: Prim,
262 param_values: &[u64],
263 ) -> CalyxResult<RRC<ir::Cell>>
264 where
265 Pre: Into<ir::Id> + ToString + Clone,
266 Prim: Into<ir::Id>,
267 {
268 let prim_id = primitive.into();
269 let prim = &self.lib.get_primitive(prim_id);
270 let (param_binding, ports) = prim.resolve(param_values)?;
271
272 let name = self.component.generate_name(prefix);
273 let cell = Self::cell_from_signature(
274 name,
275 ir::CellType::Primitive {
276 name: prim_id,
277 param_binding: Box::new(param_binding),
278 is_comb: prim.is_comb,
279 latency: prim.latency,
280 },
281 ports,
282 );
283 if self.generated {
284 cell.borrow_mut().add_attribute(BoolAttr::Generated, 1);
285 }
286 self.component.cells.add(Rc::clone(&cell));
287 Ok(cell)
288 }
289
290 pub fn add_component<Pre>(
293 &mut self,
294 prefix: Pre,
295 component: Pre,
296 sig: Vec<PortDef<u64>>,
297 ) -> RRC<ir::Cell>
298 where
299 Pre: Into<ir::Id> + ToString + Clone,
300 {
301 let name = self.component.generate_name(prefix);
302 let cell = Self::cell_from_signature(
303 name,
304 CellType::Component {
305 name: component.into(),
306 },
307 sig,
308 );
309 if self.generated {
310 cell.borrow_mut().add_attribute(BoolAttr::Generated, 1);
311 }
312 self.component.cells.add(Rc::clone(&cell));
313 cell
314 }
315
316 pub fn build_assignment<T>(
318 &self,
319 dst: RRC<ir::Port>,
320 src: RRC<ir::Port>,
321 guard: ir::Guard<T>,
322 ) -> ir::Assignment<T> {
323 if self.validate {
325 self.is_port_well_formed(&dst.borrow());
326 self.is_port_well_formed(&src.borrow());
327 guard
328 .all_ports()
329 .into_iter()
330 .for_each(|p| self.is_port_well_formed(&p.borrow()));
331 }
332 debug_assert!(
334 src.borrow().width == dst.borrow().width,
335 "Invalid assignment. `{}.{}' and `{}.{}' have different widths",
336 src.borrow().get_parent_name(),
337 src.borrow().name,
338 dst.borrow().get_parent_name(),
339 dst.borrow().name,
340 );
341 debug_assert!(
343 src.borrow().direction != ir::Direction::Input,
345 "Not an ouput port: {}.{}",
346 src.borrow().get_parent_name(),
347 src.borrow().name
348 );
349 debug_assert!(
350 dst.borrow().direction != ir::Direction::Output,
352 "Not an input port: {}.{}",
353 dst.borrow().get_parent_name(),
354 dst.borrow().name
355 );
356
357 ir::Assignment {
358 dst,
359 src,
360 guard: Box::new(guard),
361 attributes: ir::Attributes::default(),
362 }
363 }
364
365 fn is_port_well_formed(&self, port: &ir::Port) {
371 match &port.parent {
372 ir::PortParent::Cell(cell_wref) => {
373 let cell_ref = cell_wref.internal.upgrade().expect("Weak reference to port's parent cell points to nothing. This usually means that the Component did not retain a pointer to the Cell.");
374
375 let cell = &cell_ref.borrow();
376 self.component.find_cell(cell.name()).expect("Port's parent cell not present in the component. Add the cell to the component before using the Port.");
377 }
378 ir::PortParent::Group(group_wref) => {
379 let group_ref = group_wref.internal.upgrade().expect("Weak reference to hole's parent group points to nothing. This usually means that the Component did not retain a pointer to the Group.");
380
381 let group = &group_ref.borrow();
382 self.component.find_group(group.name()).expect("Hole's parent cell not present in the component. Add the group to the component before using the Hole.");
383 }
384 ir::PortParent::FSM(_) => todo!(),
385 ir::PortParent::StaticGroup(group_wref) => {
386 let group_ref = group_wref.internal.upgrade().expect("Weak reference to hole's parent group points to nothing. This usually means that the Component did not retain a pointer to the Group.");
387
388 let group = &group_ref.borrow();
389 self.component.find_static_group(group.name()).expect("Hole's parent cell not present in the component. Add the static group to the component before using the Hole.");
390 }
391 };
392 }
393 pub(super) fn cell_from_signature(
396 name: ir::Id,
397 typ: ir::CellType,
398 ports: Vec<ir::PortDef<u64>>,
399 ) -> RRC<ir::Cell> {
400 let cell = ir::rrc(ir::Cell::new(name, typ));
401 ports.into_iter().for_each(|pd| {
402 let port = ir::rrc(ir::Port {
403 name: pd.name(),
404 width: pd.width,
405 direction: pd.direction,
406 parent: ir::PortParent::Cell(WRC::from(&cell)),
407 attributes: pd.attributes,
408 });
409 cell.borrow_mut().ports.push(port);
410 });
411 cell
412 }
413}