calyx_ir/
macros.rs

1/// Parse guard expression into [`ir::Guard`](crate::Guard).
2///
3/// The identifier should either be a [`ir::Group`](crate::Group) or an
4/// [`ir::Cell`](crate::Cell).
5/// Example:
6/// ```
7/// let fsm_out = guard!(fsm["out"] == lb["out"] & g);
8/// ```
9///
10/// The macro supports constructing guards using the following operators:
11/// - Port access: `node[port]`
12/// - Comparison operators: `==`, `>=`, `<=`, `>`, `<`
13/// - Logical operators: `&`, `|`
14/// - Parentheses: `()`
15#[macro_export]
16macro_rules! guard {
17    // Base
18    // Port access
19    ($node:ident[$port:expr]) => {
20        $crate::Guard::from($node.borrow().get($port))
21    };
22    // Parentheses
23    ( ( $($head:tt)* ) ) => {
24        guard!($($head)*)
25    };
26    // A bare name
27    ($e:ident) => { $e };
28
29    // Comparison operators
30    ($node:ident[$port:expr] >= $($tail:tt)*) => {
31        $crate::Guard::from($node.borrow().get($port)).ge(guard!($($tail)*))
32    };
33    ($node:ident[$port:expr] <= $($tail:tt)*) => {
34        $crate::Guard::from($node.borrow().get($port)).le(guard!($($tail)*))
35    };
36    ($node:ident[$port:expr] < $($tail:tt)*) => {
37        $crate::Guard::from($node.borrow().get($port)).lt(guard!($($tail)*))
38    };
39    ($node:ident[$port:expr] > $($tail:tt)*) => {
40        $crate::Guard::from($node.borrow().get($port)).gt(guard!($($tail)*))
41    };
42    ($node:ident[$port:expr] == $($tail:tt)*) => {
43        $crate::Guard::from($node.borrow().get($port)).eq(guard!($($tail)*))
44    };
45    ($node:ident[$port:expr] != $($tail:tt)*) => {
46        $crate::Guard::from($node.borrow().get($port)).neq(guard!($($tail)*))
47    };
48
49    // Logical operators
50    // AND
51    ($node:ident[$port:expr] & $($tail:tt)*) => {
52        $crate::Guard::from($node.borrow().get($port)) & guard!($($tail)*)
53    };
54    ( ( $($head:tt)* ) & $($tail:tt)*) => {
55        guard!($($head)*) & guard!($($tail)*)
56    };
57
58    // OR
59    ($node:ident[$port:expr] | $($tail:tt)*) => {
60        $crate::Guard::from($node.borrow().get($port)) | guard!($($tail)*)
61    };
62    ( ( $($head:tt)* ) | $($tail:tt)*) => {
63        guard!($($head)*) | guard!($($tail)*)
64    };
65}
66
67/// Add primitives and constants to the component and `let`-bind the
68/// references.
69///
70/// Example:
71/// ```
72/// let builder = ir::Builder::from(&mut component, &sigs, validate);
73/// structure!(builder;
74///     let signal_on = constant(1, 32); // Define 32-bit constant 1.
75///     let fsm_reg = prim std_reg(32);  // Define 32-bit register.
76/// )
77/// ```
78#[macro_export]
79macro_rules! structure {
80    ($builder:expr;) => { };
81
82    ($builder:expr;
83     let $var:ident = prim $comp:ident( $($n:expr),* ); $($tail:tt)*) => {
84        let $var = $builder.add_primitive(
85            stringify!($var),
86            stringify!($comp),
87            &[$($n),*]
88        );
89        structure!($builder; $($tail)*)
90    };
91
92    ($builder:expr;
93     let $var:pat = constant($v:expr, $w:expr); $($tail:tt)*) => {
94        let $var = $builder.add_constant($v, $w);
95        structure!($builder; $($tail)*)
96    }
97}
98
99/// Build guarded assignment statements and return a vector containing them.
100///
101/// The macro accepts two forms:
102/// ```
103/// build_assignments!(builder;
104///     group["go"] = ? signal_on["out"]; // no guard
105///     fsm["in"] = guard ? add["out"];
106/// )
107/// ```
108/// **Note**: Guards used in the assignments are `cloned`.
109#[macro_export]
110macro_rules! build_assignments {
111    // Unguarded assignment.
112    (@base $builder:expr;
113     $dst_node:ident[$dst_port:expr] = ? $src_node:ident[$src_port:expr]) => {
114        $builder.build_assignment(
115            $dst_node.borrow().get($dst_port),
116            $src_node.borrow().get($src_port),
117            $crate::Guard::True)
118    };
119
120    // Guarded assignment.
121    (@base $builder:expr;
122     $dst_node:ident[$dst_port:expr] =
123        $guard:ident ?
124        $src_node:ident[$src_port:expr]) => {
125        $builder.build_assignment(
126            $dst_node.borrow().get($dst_port),
127            $src_node.borrow().get($src_port),
128            $guard.clone())
129    };
130
131    ($builder:expr;
132     $($dst_node:ident[$dst_port:expr] =
133         $($guard:ident)? ?
134         $src_node:ident[$src_port:expr];)*)  => {
135        [$(
136            build_assignments!(@base $builder;
137                $dst_node[$dst_port] = $($guard)? ? $src_node[$src_port])
138        ),*]
139
140    };
141}