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 verilog_attr_groups: vec![],
166 }
167 }
168}
169
170#[macro_export]
171macro_rules! assert_same_mir {
172 ($got:expr, $expected:expr) => {{
173 let mut var_map = spade_mir::diff::VarMap::new();
174
175 if !spade_mir::diff::compare_entity($got, $expected, &mut var_map) {
176 let (got, expected) =
177 spade_mir::diff_printing::translated_strings($got, $expected, &var_map);
178
179 println!("{}:\n{}", "got".red(), got);
180 println!("{}", "==============================================".red());
181 println!("{}:\n{}", "expected".green(), expected);
182 println!(
183 "{}",
184 "==============================================".green()
185 );
186 println!("{}", prettydiff::diff_chars(&got, &expected));
187 println!(
188 "{}",
189 "==============================================".yellow()
190 );
191 panic!("Code mismatch")
192 }
193 }};
194}
195
196#[cfg(test)]
197mod tests {
198 use spade_common::id_tracker::ExprID;
199 use spade_common::name::{NameID, Path};
200 use spade_mir::unit_name::UnitNameKind;
201
202 use crate::{self as spade_mir, MirInput, UnitName};
203 use crate::{types::Type, Binding, ConstantValue, Operator, Register, Statement, ValueName};
204
205 #[test]
206 fn value_name_parsing_works() {
207 assert_eq!(
208 value_name!(n(0, "test")),
209 ValueName::_test_named(0, "test".to_string())
210 );
211 assert_eq!(value_name!(e(0)), ValueName::Expr(ExprID(0)));
212 }
213
214 #[test]
215 fn binding_parsing_works() {
216 let expected = Statement::Binding(Binding {
217 name: ValueName::Expr(ExprID(0)),
218 operator: Operator::Add,
219 operands: vec![
220 ValueName::Expr(ExprID(1)),
221 ValueName::_test_named(1, "test".to_string()),
222 ],
223 ty: Type::Bool,
224 loc: None,
225 });
226
227 assert_eq!(
228 statement!(e(0); Type::Bool; Add; e(1), n(1, "test")),
229 expected
230 );
231 }
232
233 #[test]
234 fn named_parsing_works() {
235 let expected = Statement::Binding(Binding {
236 name: ValueName::_test_named(0, "string".to_string()),
237 operator: Operator::Add,
238 operands: vec![
239 ValueName::Expr(ExprID(1)),
240 ValueName::_test_named(1, "test".to_string()),
241 ],
242 ty: Type::Bool,
243 loc: None,
244 });
245
246 assert_eq!(
247 statement!(n(0, "string"); Type::Bool; Add; e(1), n(1, "test")),
248 expected
249 );
250 }
251
252 #[test]
253 fn register_parsing_works() {
254 let expected = Statement::Register(Register {
255 name: ValueName::_test_named(0, "test".into()),
256 ty: Type::int(5),
257 clock: ValueName::_test_named(1, "clk".into()),
258 reset: None,
259 initial: None,
260 value: ValueName::Expr(ExprID(0)),
261 loc: None,
262 traced: Some(ValueName::Expr(ExprID(2))),
263 });
264
265 assert_eq!(
266 statement!(traced(e(2)) reg n(0, "test"); Type::int(5); clock (n(1, "clk")); e(0)),
267 expected
268 );
269 }
270
271 #[test]
272 fn register_with_reset_parsing_works() {
273 let expected = Statement::Register(Register {
274 name: ValueName::_test_named(0, "test".into()),
275 ty: Type::int(5),
276 clock: ValueName::_test_named(1, "clk".into()),
277 reset: Some((ValueName::Expr(ExprID(1)), ValueName::Expr(ExprID(2)))),
278 initial: None,
279 value: ValueName::Expr(ExprID(0)),
280 loc: None,
281 traced: None,
282 });
283
284 assert_eq!(
285 statement!(reg n(0, "test"); Type::int(5); clock (n(1, "clk")); reset (e(1), e(2)); e(0)),
286 expected
287 );
288 }
289
290 #[test]
291 fn entity_parsing_works() {
292 let expected = crate::Entity {
293 name: UnitName {
294 kind: UnitNameKind::Escaped {
295 name: "pong".to_string(),
296 path: vec!["pong".to_string()],
297 },
298 source: NameID(0, Path::from_strs(&["pong"])),
299 },
300 inputs: vec![MirInput {
301 name: "_i_clk".to_string(),
302 val_name: ValueName::_test_named(0, "clk".to_string()),
303 ty: Type::Bool,
304 no_mangle: None,
305 }],
306 output: ValueName::_test_named(1, "value".to_string()),
307 output_type: Type::int(6),
308 statements: vec![
309 statement!(e(0); Type::int(6); Add; n(1, "value")),
310 statement!(reg n(1, "value"); Type::int(6); clock (n(0, "clk")); e(0)),
311 ],
312 verilog_attr_groups: vec![],
313 };
314
315 let result = entity!(&["pong"]; ("_i_clk", n(0, "clk"), Type::Bool) -> Type::int(6); {
316 (e(0); Type::int(6); Add; n(1, "value"));
317 (reg n(1, "value"); Type::int(6); clock (n(0, "clk")); e(0))
318 } => n(1, "value"));
319
320 assert_eq!(result, expected);
321 }
322
323 #[test]
324 fn constant_parsing_works() {
325 let expected = Statement::Constant(ExprID(0), Type::int(10), ConstantValue::int(6));
326
327 let result = statement!(const 0; Type::int(10); ConstantValue::int(6));
328
329 assert_eq!(result, expected);
330 }
331}