1#[macro_export]
5macro_rules! value_name {
6 (n($id:expr, $debug_name:expr)) => {
7 spade_mir::ValueName::_test_named($id, $debug_name.to_string())
8 };
9 (e($id:expr)) => {
10 spade_mir::ValueName::Expr(spade_common::id_tracker::ExprID($id))
11 };
12}
13
14#[macro_export]
15macro_rules! if_tracing {
16 () => {None};
17 ($traced_kind:ident $traced_name:tt) => {Some(spade_mir::value_name!($traced_kind $traced_name))}
18}
19
20#[macro_export]
21macro_rules! optional_reset {
22 () => {None};
23 (($rst_trig_kind:ident $rst_trig_name:tt, $rst_val_kind:ident $rst_val_name:tt)) => {
24 Some((
25 spade_mir::value_name!($rst_trig_kind $rst_trig_name),
26 spade_mir::value_name!($rst_val_kind $rst_val_name)
27 ))
28 }
29}
30
31#[macro_export]
32macro_rules! optional_initial {
33 () => {
34 None
35 };
36 (($val:expr)) => {
37 Some($val)
38 };
39}
40
41#[macro_export]
42macro_rules! statement {
43 (
45 const $id:expr; $ty:expr; $value:expr
46 ) => {
47 spade_mir::Statement::Constant(spade_common::id_tracker::ExprID($id), $ty, $value)
48 };
49 (
51 $name_kind:ident $name:tt;
52 $type:expr;
53 $operator:ident $(($operator_args:tt))?$({$operator_struct_args:tt})?;
54 $($arg_kind:ident $arg_name:tt),*
55 ) => {
56 spade_mir::Statement::Binding(spade_mir::Binding {
57 name: spade_mir::value_name!($name_kind $name),
58 operator: spade_mir::Operator::$operator$($operator_args)?,
59 operands: vec![
60 $(spade_mir::value_name!($arg_kind $arg_name)),*
61 ],
62 ty: $type,
63 loc: None,
64 })
65 };
66 (
68 $(traced($traced_kind:ident $traced_name:tt))?
69 reg $name_kind:ident $name:tt;
70 $type:expr;
71 clock ($clk_name_kind:ident $clk_name:tt);
72 $(reset $reset:tt)?
73 $(initial $initial:tt)?;
74 $val_kind:ident $val_name:tt
75 ) => {
76 spade_mir::Statement::Register(spade_mir::Register {
77 name: spade_mir::value_name!($name_kind $name),
78 ty: $type,
79 clock: spade_mir::value_name!($clk_name_kind $clk_name),
80 reset: spade_mir::optional_reset!($($reset)?),
81 initial: spade_mir::optional_initial!($($initial)?),
82 value: spade_mir::value_name!($val_kind $val_name),
83 loc: None,
84 traced: spade_mir::if_tracing!($($traced_kind $traced_name)?)
85 })
86 };
87 (
89 $(traced($traced_kind:ident $traced_name:tt))?
90 reg $name_kind:ident $name:tt;
91 $type:expr;
92 clock ($clk_name_kind:ident $clk_name:tt);
93 $val_kind:ident $val_name:tt
94 ) => {
95 spade_mir::Statement::Register(spade_mir::Register {
96 name: spade_mir::value_name!($name_kind $name),
97 ty: $type,
98 clock: spade_mir::value_name!($clk_name_kind $clk_name),
99 reset: None,
100 initial: None,
101 value: spade_mir::value_name!($val_kind $val_name),
102 loc: None,
103 traced: spade_mir::if_tracing!($($traced_kind $traced_name)?)
104 })
105 };
106 (set; $lhs_kind:ident $lhs_name:tt; $rhs_kind:ident $rhs_name:tt) => {
108 spade_mir::Statement::Set{
109 target: spade_mir::value_name!($lhs_kind $lhs_name).nowhere(),
110 value: spade_mir::value_name!($rhs_kind $rhs_name).nowhere()
111 }
112 };
113 (
114 assert; $name_kind:ident $name:tt
115 ) => {
116 spade_mir::Statement::Assert(spade_mir::value_name!($name_kind $name).nowhere())
117 };
118 (wal_trace ($name_kind:ident $name_name:tt, $val_kind:ident $val_name:tt, $suffix:expr, $ty:expr) ) => {
119 spade_mir::Statement::WalTrace{
120 name: spade_mir::value_name!($name_kind $name_name),
121 val: spade_mir::value_name!($val_kind $val_name),
122 suffix: $suffix.into(),
123 ty: $ty
124 }
125 }
126}
127
128#[macro_export]
140macro_rules! entity {
141 ($name:expr; (
142 $( $arg_name:expr, $arg_intern_kind:ident $arg_intern_name:tt, $arg_type:expr ),* $(,)?
143 ) -> $output_type:expr; {
144 $( $statement:tt );*
145 $(;)?
146 } => $output_name_kind:ident $output_name:tt
147 ) => {
148 spade_mir::Entity {
149 name: spade_mir::unit_name::IntoUnitName::_test_into_unit_name($name),
150 inputs: vec![
151 $(
152 spade_mir::MirInput {
153 name: $arg_name.to_string(),
154 val_name: spade_mir::value_name!($arg_intern_kind $arg_intern_name),
155 ty: $arg_type,
156 no_mangle: None
157 }
158 ),*
159 ],
160 output: spade_mir::value_name!($output_name_kind $output_name),
161 output_type: $output_type,
162 statements: vec![
163 $( spade_mir::statement! $statement ),*
164 ],
165 }
166 }
167}
168
169#[macro_export]
170macro_rules! assert_same_mir {
171 ($got:expr, $expected:expr) => {{
172 let mut var_map = spade_mir::diff::VarMap::new();
173
174 if !spade_mir::diff::compare_entity($got, $expected, &mut var_map) {
175 let (got, expected) =
176 spade_mir::diff_printing::translated_strings($got, $expected, &var_map);
177
178 println!("{}:\n{}", "got".red(), got);
179 println!("{}", "==============================================".red());
180 println!("{}:\n{}", "expected".green(), expected);
181 println!(
182 "{}",
183 "==============================================".green()
184 );
185 println!("{}", prettydiff::diff_chars(&got, &expected));
186 println!(
187 "{}",
188 "==============================================".yellow()
189 );
190 panic!("Code mismatch")
191 }
192 }};
193}
194
195#[cfg(test)]
196mod tests {
197 use spade_common::id_tracker::ExprID;
198 use spade_common::name::{NameID, Path};
199 use spade_mir::unit_name::UnitNameKind;
200
201 use crate::{self as spade_mir, MirInput, UnitName};
202 use crate::{types::Type, Binding, ConstantValue, Operator, Register, Statement, ValueName};
203
204 #[test]
205 fn value_name_parsing_works() {
206 assert_eq!(
207 value_name!(n(0, "test")),
208 ValueName::_test_named(0, "test".to_string())
209 );
210 assert_eq!(value_name!(e(0)), ValueName::Expr(ExprID(0)));
211 }
212
213 #[test]
214 fn binding_parsing_works() {
215 let expected = Statement::Binding(Binding {
216 name: ValueName::Expr(ExprID(0)),
217 operator: Operator::Add,
218 operands: vec![
219 ValueName::Expr(ExprID(1)),
220 ValueName::_test_named(1, "test".to_string()),
221 ],
222 ty: Type::Bool,
223 loc: None,
224 });
225
226 assert_eq!(
227 statement!(e(0); Type::Bool; Add; e(1), n(1, "test")),
228 expected
229 );
230 }
231
232 #[test]
233 fn named_parsing_works() {
234 let expected = Statement::Binding(Binding {
235 name: ValueName::_test_named(0, "string".to_string()),
236 operator: Operator::Add,
237 operands: vec![
238 ValueName::Expr(ExprID(1)),
239 ValueName::_test_named(1, "test".to_string()),
240 ],
241 ty: Type::Bool,
242 loc: None,
243 });
244
245 assert_eq!(
246 statement!(n(0, "string"); Type::Bool; Add; e(1), n(1, "test")),
247 expected
248 );
249 }
250
251 #[test]
252 fn register_parsing_works() {
253 let expected = Statement::Register(Register {
254 name: ValueName::_test_named(0, "test".into()),
255 ty: Type::int(5),
256 clock: ValueName::_test_named(1, "clk".into()),
257 reset: None,
258 initial: None,
259 value: ValueName::Expr(ExprID(0)),
260 loc: None,
261 traced: Some(ValueName::Expr(ExprID(2))),
262 });
263
264 assert_eq!(
265 statement!(traced(e(2)) reg n(0, "test"); Type::int(5); clock (n(1, "clk")); e(0)),
266 expected
267 );
268 }
269
270 #[test]
271 fn register_with_reset_parsing_works() {
272 let expected = Statement::Register(Register {
273 name: ValueName::_test_named(0, "test".into()),
274 ty: Type::int(5),
275 clock: ValueName::_test_named(1, "clk".into()),
276 reset: Some((ValueName::Expr(ExprID(1)), ValueName::Expr(ExprID(2)))),
277 initial: None,
278 value: ValueName::Expr(ExprID(0)),
279 loc: None,
280 traced: None,
281 });
282
283 assert_eq!(
284 statement!(reg n(0, "test"); Type::int(5); clock (n(1, "clk")); reset (e(1), e(2)); e(0)),
285 expected
286 );
287 }
288
289 #[test]
290 fn entity_parsing_works() {
291 let expected = crate::Entity {
292 name: UnitName {
293 kind: UnitNameKind::Escaped {
294 name: "pong".to_string(),
295 path: vec!["pong".to_string()],
296 },
297 source: NameID(0, Path::from_strs(&["pong"])),
298 },
299 inputs: vec![MirInput {
300 name: "_i_clk".to_string(),
301 val_name: ValueName::_test_named(0, "clk".to_string()),
302 ty: Type::Bool,
303 no_mangle: None,
304 }],
305 output: ValueName::_test_named(1, "value".to_string()),
306 output_type: Type::int(6),
307 statements: vec![
308 statement!(e(0); Type::int(6); Add; n(1, "value")),
309 statement!(reg n(1, "value"); Type::int(6); clock (n(0, "clk")); e(0)),
310 ],
311 };
312
313 let result = entity!(&["pong"]; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
314 (e(0); Type::int(6); Add; n(1, "value"));
315 (reg n(1, "value"); Type::int(6); clock (n(0, "clk")); e(0))
316 } => n(1, "value"));
317
318 assert_eq!(result, expected);
319 }
320
321 #[test]
322 fn constant_parsing_works() {
323 let expected = Statement::Constant(ExprID(0), Type::int(10), ConstantValue::int(6));
324
325 let result = statement!(const 0; Type::int(10); ConstantValue::int(6));
326
327 assert_eq!(result, expected);
328 }
329}