1use itertools::Itertools;
2use rustc_hash::FxHashMap as HashMap;
9use spade_common::id_tracker::ExprID;
10
11use crate::{diff::VarMap, Entity};
12use crate::{Binding, MirInput, Register, Statement, ValueName};
13
14pub fn translate_expr(
15 name: ExprID,
16 lhs_trans: &impl Fn(ExprID) -> Option<ExprID>,
17 rhs_trans: &impl Fn(ExprID) -> Option<ExprID>,
18) -> String {
19 let lhs = lhs_trans(name)
20 .map(|n| format!("{}", n.0))
21 .unwrap_or_else(|| "?".to_string());
22 let rhs = rhs_trans(name)
23 .map(|n| format!("{}", n.0))
24 .unwrap_or_else(|| "?".to_string());
25
26 format!("e({}|{})", lhs, rhs)
27}
28
29pub fn translate_name(
30 (id, name): (u64, &str),
31 lhs_trans: &impl Fn(u64) -> Option<u64>,
32 rhs_trans: &impl Fn(u64) -> Option<u64>,
33) -> String {
34 let lhs = lhs_trans(id)
35 .map(|i| format!("{}", i))
36 .unwrap_or_else(|| "?".to_string());
37 let rhs = rhs_trans(id)
38 .map(|i| format!("{}", i))
39 .unwrap_or_else(|| "?".to_string());
40
41 format!("n({}|{}, {})", lhs, rhs, name)
42}
43
44pub struct NameTranslator<F, G>
45where
46 F: Fn(ExprID) -> Option<ExprID>,
47 G: Fn(u64) -> Option<u64>,
48{
49 expr: F,
50 name: G,
51}
52
53pub fn identity_name_translator(
54) -> NameTranslator<impl Fn(ExprID) -> Option<ExprID>, impl Fn(u64) -> Option<u64>> {
55 NameTranslator {
56 expr: Some,
57 name: Some,
58 }
59}
60
61pub fn map_name_translator(
62 expr: HashMap<ExprID, ExprID>,
63 name: HashMap<u64, u64>,
64) -> NameTranslator<impl Fn(ExprID) -> Option<ExprID>, impl Fn(u64) -> Option<u64>> {
65 NameTranslator {
66 expr: move |x| expr.get(&x).cloned(),
67 name: move |x| name.get(&x).cloned(),
68 }
69}
70
71pub fn translate_val_name<LF, LG, RF, RG>(
72 name: &ValueName,
73 lhs_trans: &NameTranslator<LF, LG>,
74 rhs_trans: &NameTranslator<RF, RG>,
75) -> String
76where
77 LF: Fn(ExprID) -> Option<ExprID>,
78 LG: Fn(u64) -> Option<u64>,
79 RF: Fn(ExprID) -> Option<ExprID>,
80 RG: Fn(u64) -> Option<u64>,
81{
82 match name {
83 ValueName::Named(id, n, _) => translate_name((*id, n), &lhs_trans.name, &rhs_trans.name),
84 ValueName::Expr(id) => translate_expr(*id, &lhs_trans.expr, &rhs_trans.expr),
85 }
86}
87
88pub fn translate_statement<LF, LG, RF, RG>(
89 statement: &Statement,
90 lhs_trans: &NameTranslator<LF, LG>,
91 rhs_trans: &NameTranslator<RF, RG>,
92) -> String
93where
94 LF: Fn(ExprID) -> Option<ExprID>,
95 LG: Fn(u64) -> Option<u64>,
96 RF: Fn(ExprID) -> Option<ExprID>,
97 RG: Fn(u64) -> Option<u64>,
98{
99 match statement {
100 Statement::Binding(Binding {
101 name,
102 operator,
103 operands,
104 ty,
105 loc: _,
106 }) => {
107 let name = translate_val_name(name, lhs_trans, rhs_trans);
108 let operands = operands
109 .iter()
110 .map(|op| translate_val_name(op, lhs_trans, rhs_trans))
111 .collect::<Vec<_>>()
112 .join(",");
113
114 format!("{}: {} <- {}({})", name, ty, operator, operands)
115 }
116 Statement::Register(Register {
117 name,
118 ty,
119 clock,
120 reset,
121 initial,
122 value,
123 loc: _,
124 traced,
125 }) => {
126 let name = translate_val_name(name, lhs_trans, rhs_trans);
127 let clock = translate_val_name(clock, lhs_trans, rhs_trans);
128 let reset = reset
129 .as_ref()
130 .map(|(trig, val)| {
131 let trig = translate_val_name(trig, lhs_trans, rhs_trans);
132 let val = translate_val_name(val, lhs_trans, rhs_trans);
133 format!(" reset ({}, {})", trig, val)
134 })
135 .unwrap_or_else(|| "".to_string());
136 let initial = initial
137 .as_ref()
138 .map(|i| {
139 format!(
140 " initial ({})",
141 i.iter().map(|v| format!("{v}").to_string()).join("; ")
142 )
143 })
144 .unwrap_or_else(|| "".to_string());
145 let value = translate_val_name(value, lhs_trans, rhs_trans);
146 let traced = if let Some(traced) = traced {
147 format!(
148 "traced({})",
149 translate_val_name(traced, lhs_trans, rhs_trans)
150 )
151 } else {
152 "".to_string()
153 };
154
155 format!("{traced}reg {name}: {ty} clock {clock}{reset}{initial} {value}",)
156 }
157 Statement::Constant(name, ty, value) => {
158 let name = translate_expr(*name, &lhs_trans.expr, &rhs_trans.expr);
159
160 format!("const {}: {} = {}", name, ty, value)
161 }
162 Statement::Assert(value) => {
163 let value = translate_val_name(value, lhs_trans, rhs_trans);
164 format!("assert {value}")
165 }
166 Statement::Set { target, value } => {
167 let value = translate_val_name(value, lhs_trans, rhs_trans);
168 let target = translate_val_name(target, lhs_trans, rhs_trans);
169 format!("set {target} = {value}")
170 }
171 Statement::WalTrace {
172 name,
173 val,
174 suffix,
175 ty,
176 } => {
177 let name = translate_val_name(name, lhs_trans, rhs_trans);
178 let val = translate_val_name(val, lhs_trans, rhs_trans);
179 format!("wal_trace ({name}, {val}, '{suffix}', {ty})")
180 }
181 Statement::Error => {
182 format!("Error")
183 }
184 }
185}
186
187pub fn translate_entity<LF, LG, RF, RG>(
188 entity: &Entity,
189 lhs_trans: &NameTranslator<LF, LG>,
190 rhs_trans: &NameTranslator<RF, RG>,
191) -> String
192where
193 LF: Fn(ExprID) -> Option<ExprID>,
194 LG: Fn(u64) -> Option<u64>,
195 RF: Fn(ExprID) -> Option<ExprID>,
196 RG: Fn(u64) -> Option<u64>,
197{
198 let Entity {
199 name,
200 inputs,
201 output,
202 output_type,
203 statements,
204 verilog_attr_groups,
205 } = entity;
206
207 let verilog_attr_groups = verilog_attr_groups
208 .iter()
209 .map(|attrs| {
210 let contents = attrs
211 .iter()
212 .map(|(key, value)| match value {
213 Some(v) => format!("{key} = {v:?}"),
214 None => key.clone(),
215 })
216 .join(",");
217
218 format!("#[verilog_attrs({contents})]\n")
219 })
220 .join("");
221
222 let inputs = inputs
223 .iter()
224 .map(
225 |MirInput {
226 name,
227 val_name,
228 ty,
229 no_mangle,
230 }| {
231 let val_name = translate_val_name(val_name, lhs_trans, rhs_trans);
232
233 format!(
234 "({}{name}, {val_name}: {ty})",
235 no_mangle.map(|_| "#[no_mangle]").unwrap_or("")
236 )
237 },
238 )
239 .collect::<Vec<_>>()
240 .join(",");
241
242 let output = translate_val_name(output, lhs_trans, rhs_trans);
243
244 let statements = statements
245 .iter()
246 .map(|s| translate_statement(s, lhs_trans, rhs_trans))
247 .map(|s| format!(" {}", s))
248 .collect::<Vec<_>>()
249 .join("\n");
250
251 indoc::formatdoc!(
252 r#"{}entity {}({}) -> {} {{
253 {}
254 }} => {}"#,
255 verilog_attr_groups,
256 name,
257 inputs,
258 output_type,
259 statements,
260 output
261 )
262}
263
264pub fn translated_strings(lhs: &Entity, rhs: &Entity, map: &VarMap) -> (String, String) {
266 let lhs_string = translate_entity(
267 lhs,
268 &identity_name_translator(),
269 &map_name_translator(map.expr_map.clone(), map.name_map.clone()),
270 );
271
272 let rhs_string = translate_entity(
273 rhs,
274 &map_name_translator(map.expr_map_rev.clone(), map.name_map_rev.clone()),
275 &identity_name_translator(),
276 );
277
278 (lhs_string, rhs_string)
279}