From b2a0e3ae4d5316c368b7b47bf30ac65d3de6c572 Mon Sep 17 00:00:00 2001 From: Parth Sarkar Date: Tue, 19 Nov 2024 00:45:54 -0500 Subject: [PATCH] impld wire inliner wrt fsm compilation - need to instantiate wire for start/done signals for FSM - right now, they can't be translated easily to verilog i don't think; they will probably need primitive std_wire instantiations to map easily to verilog logic variables, right? --- calyx-ir/src/printer.rs | 3 +- calyx-opt/src/passes/wire_inliner.rs | 100 +++++++++++++++++++-------- 2 files changed, 74 insertions(+), 29 deletions(-) diff --git a/calyx-ir/src/printer.rs b/calyx-ir/src/printer.rs index f24f0ca5dc..dc9e44caed 100644 --- a/calyx-ir/src/printer.rs +++ b/calyx-ir/src/printer.rs @@ -370,6 +370,7 @@ impl Printer { if !matches!(&*assign.guard, ir::Guard::True) { write!(f, "{} ? ", Self::guard_str(&assign.guard.clone()))?; } + write!(f, "{};", Self::port_to_str(&assign.src.borrow())) } @@ -459,7 +460,7 @@ impl Printer { writeln!(f, "{{")?; for assign in assigns { Self::write_assignment(assign, indent_level + 4, f)?; - writeln!(f)?; + writeln!(f, "")?; } write!(f, "{}", " ".repeat(indent_level + 2))?; write!(f, "}} => ")?; diff --git a/calyx-opt/src/passes/wire_inliner.rs b/calyx-opt/src/passes/wire_inliner.rs index b6ca13d683..4e6b943858 100644 --- a/calyx-opt/src/passes/wire_inliner.rs +++ b/calyx-opt/src/passes/wire_inliner.rs @@ -22,28 +22,59 @@ impl Named for WireInliner { } } -fn rewrite_assign(map: &HoleMapping, assign: &mut ir::Assignment) { - let rewrite = |port: &RRC| -> Option> { - if let ir::PortParent::Group(g) = &port.borrow().parent { - let (go, done) = &map[&g.upgrade().borrow().name()]; - let cell = if port.borrow().name == "go" { go } else { done }; - Some(Rc::clone(cell)) - } else { - None - } - }; +fn rewrite(map: &HoleMapping, port: &RRC) -> Option> { + if let ir::PortParent::Group(g) = &port.borrow().parent { + let (go, done) = &map[&g.upgrade().borrow().name()]; + let cell = if port.borrow().name == "go" { go } else { done }; + Some(Rc::clone(cell)) + } else { + None + } +} - if let Some(cell) = rewrite(&assign.dst) { +fn rewrite_assign(map: &HoleMapping, assign: &mut ir::Assignment) { + if let Some(cell) = rewrite(map, &assign.dst) { assign.dst = cell.borrow().get("in"); } - if let Some(cell) = rewrite(&assign.src) { + if let Some(cell) = rewrite(map, &assign.src) { assign.src = cell.borrow().get("out"); } assign.guard.for_each(&mut |port| { - rewrite(&port).map(|cell| ir::Guard::port(cell.borrow().get("out"))) + rewrite(map, &port) + .map(|cell| ir::Guard::port(cell.borrow().get("out"))) }); } +fn rewrite_guard(map: &HoleMapping, guard: &mut ir::Guard) { + match guard { + ir::Guard::True | ir::Guard::Info(_) => (), + // update the port of a port guard to read from appropriate + // group wire, if it is dependent on a group's port in the first place + ir::Guard::Port(p) => { + if let Some(cell) = rewrite(map, p) { + guard.update(|_| ir::Guard::port(cell.borrow().get("out"))); + } + } + // update the ports of a port-comparison guard to read from appropriate + // group wire, if these are dependent on groups' ports in the first place + ir::Guard::CompOp(_, p1, p2) => { + if let Some(cell) = rewrite(map, p1) { + let _ = std::mem::replace(p1, cell.borrow().get("out")); + } + if let Some(cell) = rewrite(map, p2) { + let _ = std::mem::replace(p2, cell.borrow().get("out")); + } + } + ir::Guard::Not(b) => { + rewrite_guard(map, &mut *b); + } + ir::Guard::And(b1, b2) | ir::Guard::Or(b1, b2) => { + rewrite_guard(map, &mut *b1); + rewrite_guard(map, &mut *b2); + } + } +} + impl Visitor for WireInliner { fn start( &mut self, @@ -51,34 +82,26 @@ impl Visitor for WireInliner { sigs: &LibrarySignatures, _comps: &[ir::Component], ) -> VisResult { + // trigger start of component FSM based on component's go signal + // trigger done of component based on FSM's done signal let control_ref = Rc::clone(&comp.control); let control = control_ref.borrow(); - // Don't compile if the control program is empty - // if let ir::Control::Empty(..) = &*control { - // return Ok(Action::Stop); - // } - match &*control { - ir::Control::Enable(data) => { + ir::Control::FSMEnable(fsm_en) => { let this = Rc::clone(&comp.signature); let mut builder = ir::Builder::new(comp, sigs); - let group = &data.group; + let comp_fsm = &fsm_en.fsm; let this_go_port = this .borrow() .find_unique_with_attr(ir::NumAttr::Go)? .unwrap(); - let this_done_port = this - .borrow() - .find_unique_with_attr(ir::NumAttr::Done)? - .unwrap(); - structure!(builder; let one = constant(1, 1); ); - let group_done = guard!(group[this_done_port.borrow().name]); + let fsm_done = guard!(comp_fsm["done"]); let assigns = build_assignments!(builder; - group["go"] = ? this[this_go_port.borrow().name]; - this["done"] = group_done ? one["out"]; + comp_fsm["start"] = ? this[this_go_port.borrow().name]; + this["done"] = fsm_done ? one["out"]; ); comp.continuous_assignments.extend(assigns); } @@ -127,6 +150,27 @@ impl Visitor for WireInliner { gr.borrow_mut().assignments = assigns; }); + comp.get_fsms_mut().iter_mut().for_each(|fsm| { + // rewrite all assignments at each state within every fsm + for assigns_at_state in fsm.borrow_mut().assignments.iter_mut() { + for asgn in assigns_at_state.iter_mut() { + rewrite_assign(&hole_map, asgn); + } + } + // rewrite all guards in transitions that depend on group port values + for trans_at_state in fsm.borrow_mut().transitions.iter_mut() { + if let ir::Transition::Conditional(cond_trans_at_state) = + trans_at_state + { + for (cond_trans, _) in cond_trans_at_state { + rewrite_guard(&hole_map, cond_trans) + } + } + } + }); + + // rewrite all transitions as well + comp.continuous_assignments .iter_mut() .for_each(|assign| rewrite_assign(&hole_map, assign));