calyx_opt/passes/
wrap_main.rs1use std::borrow::BorrowMut;
2
3use crate::traversal::{Action, Named, VisResult, Visitor};
4use calyx_ir as ir;
5use ir::build_assignments;
6
7#[derive(Default)]
8pub struct WrapMain;
14
15impl Named for WrapMain {
16 fn name() -> &'static str {
17 "wrap-main"
18 }
19
20 fn description() -> &'static str {
21 "If the top-level component is not named `main`, adds a new `main` component and makes it the top-level component."
22 }
23}
24
25impl Visitor for WrapMain {
26 fn precondition(ctx: &calyx_ir::Context) -> Option<String>
27 where
28 Self: Sized,
29 {
30 if ctx.entrypoint().name == "main" {
31 Some("Top-level component is already named `main'".to_string())
32 } else {
33 None
34 }
35 }
36
37 fn start_context(&mut self, ctx: &mut ir::Context) -> VisResult {
38 let entry = ctx.entrypoint();
39 let sig = entry.signature.borrow();
40
41 if let Some(p) = sig.ports.iter().find(|p| {
43 let port = p.borrow();
44 let attr = &port.attributes;
45 !(attr.has(ir::BoolAttr::Clk)
46 || attr.has(ir::BoolAttr::Reset)
47 || attr.has(ir::NumAttr::Go)
48 || attr.has(ir::NumAttr::Done))
49 }) {
50 let pn = p.borrow().name;
51 log::warn!(
52 "Entrypoint component `{}' has non-interface port `{}'. Cannot wrap it in `main' component. The component might not simulate with the Calyx test bench or generate results with the synthesis scripts without modification.",
53 entry.name,
54 pn
55 );
56 return Ok(Action::Stop);
57 }
58 let entry_name = entry.name;
59 let mut ports = sig.get_signature();
60 ports
61 .iter_mut()
62 .for_each(|pd| pd.direction = pd.direction.reverse());
63 drop(sig);
64
65 ctx.entrypoint_mut()
67 .attributes
68 .remove(ir::BoolAttr::TopLevel);
69
70 let mut main = ir::Component::new("main", vec![], true, false, None);
72 main.borrow_mut()
73 .attributes
74 .insert(ir::BoolAttr::TopLevel, 1);
75
76 {
78 let mut builder = ir::Builder::new(&mut main, &ctx.lib);
79 let comp = builder.add_component(entry_name, entry_name, ports);
80 let main_sig = builder.component.signature.clone();
81 let cont_assigns = build_assignments!(builder;
82 comp["go"] = ? main_sig["go"];
83 main_sig["done"] = ? comp["done"];
84 );
85 builder
86 .component
87 .continuous_assignments
88 .extend(cont_assigns);
89 }
90
91 ctx.entrypoint = main.name;
93 ctx.components.push(main);
94
95 Ok(Action::Stop)
97 }
98}