calyx_opt/passes/
externalize.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
use super::dump_ports;
use crate::traversal::{Action, ConstructVisitor, Named, VisResult, Visitor};
use calyx_ir::{self as ir, LibrarySignatures, RRC};
use calyx_utils::CalyxResult;

/// Externalize input/output ports for cells marked with the `@external(1)` attribute.
/// The ports of these cells are exposed through the ports of the parent
/// component.
///
/// For example:
/// ```
/// component main() -> () {
///     cells {
///         // Inputs: addr0, write_data, write_en
///         // Outputs: read_data, done
///         @external(1) m1 = prim comb_mem_d1(32, 10, 4);
///     }
///     wires {
///         m1.addr0 = 1'd1;
///         x.in = m1.read_data;
///     }
/// }
/// ```
/// is transformed into:
/// ```
/// component main(
///     m1_read_data: 32,
///     m1_done: 1
/// ) -> (m1_add0: 4, m1_write_data: 32, m1_write_en: 1) {
///     cells {
///         // m1 removed.
///     }
///     wires {
///         m1_add0 = 1'd1;
///         x.in = m1_read_data;
///     }
/// }
/// ```
pub struct Externalize;

impl ConstructVisitor for Externalize {
    fn from(_ctx: &ir::Context) -> CalyxResult<Self>
    where
        Self: Sized,
    {
        let externalize = Externalize;
        Ok(externalize)
    }

    fn clear_data(&mut self) {
        //data is shared between components
    }
}

impl Named for Externalize {
    fn name() -> &'static str {
        "externalize"
    }

    fn description() -> &'static str {
        "Externalize the interfaces of cells marked with `@external(1)`"
    }
}

fn has_external_attribute(cr: &RRC<ir::Cell>) -> bool {
    let cell = cr.borrow();
    cell.get_attribute(ir::BoolAttr::External).is_some()
}

impl Visitor for Externalize {
    fn start(
        &mut self,
        comp: &mut ir::Component,
        _ctx: &LibrarySignatures,
        _comps: &[ir::Component],
    ) -> VisResult {
        let dump_ports::DumpResults { cells, rewrites } =
            dump_ports::dump_ports_to_signature(
                comp,
                has_external_attribute,
                false,
            );

        let rw = ir::Rewriter {
            port_map: rewrites,
            ..Default::default()
        };
        comp.for_each_assignment(|assign| {
            rw.rewrite_assign(assign);
        });
        comp.for_each_static_assignment(|assign| {
            rw.rewrite_assign(assign);
        });
        rw.rewrite_control(&mut comp.control.borrow_mut());
        // Don't allow cells to be dropped before this because otherwise rewriting will fail
        drop(cells);

        Ok(Action::Stop)
    }
}