1use spade_common::id_tracker::{ExprIdTracker, NameIdTracker};
2
3use crate::{types::Type, Binding, ConstantValue, Entity, Operator, Statement, ValueName};
4
5pub fn wal_alias(
6 source: &ValueName,
7 prefix: &str,
8 suffix: &str,
9 ty: &Type,
10 idtracker: &mut Option<&mut NameIdTracker>,
11) -> Statement {
12 let new_name = ValueName::Named(
16 idtracker.as_mut().map(|t| t.next()).unwrap_or_default(),
17 format!("{prefix}{suffix}"),
18 source.into(),
19 );
20
21 Statement::Binding(Binding {
22 name: new_name,
23 operator: Operator::Alias,
24 operands: vec![source.clone()],
25 ty: ty.clone(),
26 loc: None,
27 })
28}
29
30pub fn insert_wal_signals(
35 entity: &mut Entity,
36 expr_idtracker: &mut ExprIdTracker,
37 name_idtracker: &mut Option<&mut NameIdTracker>,
38) {
39 let new_statements = entity
40 .statements
41 .iter()
42 .flat_map(|s| {
43 match s {
44 Statement::Register(reg) => {
45 if let Some(traced_name) = ®.traced {
46 let prefix = traced_name.unescaped_var_name();
47 let mut result = vec![
48 s.clone(),
50 wal_alias(
51 traced_name,
52 &prefix,
53 "__wal_fsm_state",
54 ®.ty,
55 name_idtracker,
56 ),
57 wal_alias(
58 ®.clock,
59 &prefix,
60 "__wal_fsm_clk",
61 &Type::Bool,
62 name_idtracker,
63 ),
64 ];
65 let rst_signal = if let Some(rst) = ®.reset {
66 rst.0.clone()
67 } else {
68 let id = expr_idtracker.next();
69 result.push(Statement::Constant(
70 id,
71 Type::Bool,
72 ConstantValue::Bool(false),
73 ));
74 ValueName::Expr(id)
75 };
76 result.push(wal_alias(
77 &rst_signal,
78 &prefix,
79 "__wal_fsm_rst",
80 &Type::Bool,
81 name_idtracker,
82 ));
83 result
84 } else {
85 vec![s.clone()]
86 }
87 }
88 Statement::WalTrace {
89 name,
90 val,
91 suffix,
92 ty,
93 } => {
94 vec![wal_alias(
95 val,
96 &name.unescaped_var_name(),
97 suffix,
98 ty,
99 name_idtracker,
100 )]
101 }
102 other => vec![other.clone()],
103 }
104 })
105 .collect();
106 entity.statements = new_statements;
107}
108
109#[cfg(test)]
110mod test {
111 use spade_common::id_tracker::{ExprIdTracker, NameIdTracker};
112
113 use crate::{self as spade_mir, assert_same_mir, ConstantValue};
114 use crate::{entity, types::Type};
115
116 use super::insert_wal_signals;
117 use colored::Colorize;
118
119 #[test]
120 fn traced_register_has_wal_tracing_applied() {
121 let mut input = entity!(&["name"]; (
122 "clk", n(1, "clk"), Type::Bool,
123 "x", n(2, "x"), Type::Bool,
124 "rst", n(3, "rst"), Type::Bool,
125 ) -> Type::Bool; {
126 (const 0; Type::Bool; ConstantValue::Bool(true));
127 (traced(n(0, "state"))
128 reg n(0, "state"); Type::int(5); clock(n(1, "clk")); reset (n(3, "rst"), e(0)); n(2, "x"));
129 } => n(2, "x"));
130
131 let expected = entity!(&["name"]; (
132 "clk", n(0, "clk"), Type::Bool,
133 "x", n(2, "x"), Type::Bool,
134 "rst", n(3, "rst"), Type::Bool,
135 ) -> Type::Bool; {
136 (const 0; Type::Bool; ConstantValue::Bool(true));
137 (traced(n(1, "state"))
138 reg n(1, "state"); Type::int(5); clock(n(0, "clk")); reset (n(3, "rst"), e(0)); n(2, "x"));
139 (n(10, "state__wal_fsm_state"); Type::int(5); Alias; n(1, "state"));
140 (n(11, "state__wal_fsm_clk"); Type::Bool; Alias; n(0, "clk"));
141 (n(12, "state__wal_fsm_rst"); Type::Bool; Alias; n(3, "rst"));
142 } => n(2, "x"));
143
144 insert_wal_signals(
145 &mut input,
146 &mut ExprIdTracker::new(),
147 &mut Some(&mut NameIdTracker::new_at(100)),
148 );
149
150 assert_same_mir!(&input, &expected);
151 }
152
153 #[test]
154 fn traced_register_without_reset_has_wal_tracing_applied() {
155 let mut input = entity!(&["name"]; (
156 "clk", n(0, "clk"), Type::Bool,
157 "x", n(2, "x"), Type::Bool,
158 ) -> Type::Bool; {
159 (const 0; Type::Bool; ConstantValue::Bool(true));
160 (traced(n(1, "state"))
161 reg n(1, "state"); Type::int(5); clock(n(0, "clk")); n(2, "x"));
162 } => n(2, "x"));
163
164 let expected = entity!(&["name"]; (
165 "clk", n(0, "clk"), Type::Bool,
166 "x", n(2, "x"), Type::Bool,
167 ) -> Type::Bool; {
168 (const 0; Type::Bool; ConstantValue::Bool(true));
169 (traced(n(1, "state"))
170 reg n(1, "state"); Type::int(5); clock(n(0, "clk")); n(2, "x"));
171 (n(10, "state_n1__wal_fsm_state"); Type::int(5); Alias; n(1, "state"));
172 (n(11, "state_n1__wal_fsm_clk"); Type::Bool; Alias; n(0, "clk"));
173 (const 10; Type::Bool; ConstantValue::Bool(false));
174 (n(12, "state_n1__wal_fsm_rst"); Type::Bool; Alias; e(10));
175 } => n(2, "x"));
176
177 insert_wal_signals(
178 &mut input,
179 &mut ExprIdTracker::new_at(10),
180 &mut Some(&mut NameIdTracker::new_at(100)),
181 );
182
183 assert_same_mir!(&input, &expected);
184 }
185
186 #[test]
187 fn traced_suffix_has_tracing_applied() {
188 let inner = vec![
189 ("a".to_string(), Type::int(4)),
190 ("b".to_string(), Type::int(8)),
191 ];
192 let inner_types = inner.iter().map(|f| f.1.clone()).collect::<Vec<_>>();
193 let ty = Type::Struct(inner);
194
195 let mut input = entity!(&["name"]; (
196 "x", n(2, "x"), ty.clone(),
197 ) -> Type::Bool; {
198 (n(0, "y"); ty.clone(); Alias; n(2, "x"));
199 (e(0); Type::int(4); IndexTuple((0, inner_types.clone())); n(0, "y"));
200 (wal_trace(n(0, "y"), e(0), "__a__wal_suffix__", Type::int(4)));
201 (e(1); Type::int(8); IndexTuple((1, inner_types.clone())); n(0, "y"));
202 (wal_trace(n(0, "y"), e(1), "__b__wal_suffix__", Type::int(8)))
203 } => n(2, "x"));
204
205 let expected = entity!(&["name"]; (
206 "x", n(2, "x"), ty.clone(),
207 ) -> Type::Bool; {
208 (n(0, "y"); ty.clone(); Alias; n(2, "x"));
209 (e(0); Type::int(4); IndexTuple((0, inner_types.clone())); n(0, "y"));
210 (n(4, "y__a__wal_suffix__"); Type::int(4); Alias; e(0));
211 (e(1); Type::int(8); IndexTuple((1, inner_types.clone())); n(0, "y"));
212 (n(5, "y__b__wal_suffix__"); Type::int(8); Alias; e(1));
213 } => n(2, "x"));
214
215 insert_wal_signals(
216 &mut input,
217 &mut ExprIdTracker::new_at(10),
218 &mut Some(&mut NameIdTracker::new_at(100)),
219 );
220
221 assert_same_mir!(&input, &expected);
222 }
223}