1use evalexpr::ContextWithMutableVariables;
2use num_bigint::BigUint;
3use regex::Regex;
4
5use crate::ast::{
6 VerilogBlock, VerilogBlockOrConditional, VerilogCase, VerilogConditional, VerilogExpression,
7 VerilogLink, VerilogLinkDetails, VerilogLiteral, VerilogLoop, VerilogMatch, VerilogOp,
8 VerilogOpUnary,
9};
10use crate::code_writer::CodeWriter;
11use crate::verilog_visitor::{walk_block, VerilogVisitor};
12
13struct LoopVariable {
14 variable: String,
15 value: usize,
16}
17
18#[derive(Default)]
19struct VerilogCodeGenerator {
20 io: CodeWriter,
21 loops: Vec<LoopVariable>,
22 links: Vec<VerilogLink>,
23}
24
25impl VerilogCodeGenerator {
26 fn array_index_simplification(&self, a: &str) -> String {
27 let re = Regex::new(r"\[([^\]]*)\]").unwrap();
28 let mut context = evalexpr::HashMapContext::new();
29 for lvar in &self.loops {
30 let _ = context.set_value(lvar.variable.clone(), (lvar.value as i64).into());
31 }
32 if let Some(x) = re.captures(a) {
33 if x.len() == 2 {
34 if let Some(txt) = x.get(1) {
35 let arg = evalexpr::eval_with_context(txt.as_str(), &context).unwrap();
36 return re.replace(a, format!("$${}", arg)).to_string();
37 }
38 }
39 }
40 a.to_string()
41 }
42
43 fn link_fixup(&self, x: &VerilogLinkDetails) -> VerilogLinkDetails {
44 VerilogLinkDetails {
45 my_name: self.ident_fixup(&x.my_name),
46 owner_name: self.ident_fixup(&x.owner_name),
47 other_name: self.ident_fixup(&x.other_name),
48 }
49 }
50
51 fn ident_fixup(&self, a: &str) -> String {
52 let mut x = a.to_owned();
53 for index in &self.loops {
54 if x == index.variable {
55 x = format!("{}", index.value);
56 }
57 }
58 if x.starts_with(".") {
59 x.remove(0);
60 }
61 x = x
62 .replace(".", "$")
63 .replace("::", "$")
64 .trim_end_matches("$next")
65 .to_owned();
66 if x.contains('[') {
67 x = self.array_index_simplification(&x);
68 }
69 x
70 }
71}
72
73impl ToString for VerilogCodeGenerator {
74 fn to_string(&self) -> String {
75 self.io.to_string()
76 }
77}
78
79pub fn verilog_link_extraction(code: &VerilogBlock) -> Vec<VerilogLink> {
80 let mut gen = VerilogCodeGenerator::default();
81 gen.visit_block(code);
82 gen.links
83}
84
85pub fn verilog_combinatorial(code: &VerilogBlock) -> String {
86 let mut gen = VerilogCodeGenerator::default();
87 gen.visit_block(code);
88 format!("always @(*) {}\n", gen.to_string())
89}
90
91impl VerilogVisitor for VerilogCodeGenerator {
92 fn visit_block(&mut self, b: &VerilogBlock) {
93 self.io.writeln("begin");
94 self.io.push();
95 walk_block(self, b);
96 self.io.pop();
97 self.io.add_line("end");
98 }
99
100 fn visit_loop(&mut self, a: &VerilogLoop) {
101 let start = a.from.as_usize();
102 let end = a.to.as_usize();
103 for i in start..end {
104 self.loops.push(LoopVariable {
105 variable: a.index.clone(),
106 value: i,
107 });
108 walk_block(self, &a.block);
109 self.loops.pop();
110 }
111 }
112
113 fn visit_slice_assignment(
114 &mut self,
115 base: &VerilogExpression,
116 width: &usize,
117 offset: &VerilogExpression,
118 replacement: &VerilogExpression,
119 ) {
120 self.visit_expression(base);
121 self.io.write("[(");
122 self.visit_expression(offset);
123 self.io.write(format!(")+:({})] = ", width));
124 self.visit_expression(replacement);
125 self.io.writeln(";");
126 }
127
128 fn visit_conditional(&mut self, c: &VerilogConditional) {
129 self.io.write("if (");
130 self.visit_expression(&c.test);
131 self.io.write(") ");
132 self.visit_block(&c.then);
133 self.visit_block_or_conditional(&c.otherwise);
134 }
135
136 fn visit_block_or_conditional(&mut self, o: &VerilogBlockOrConditional) {
137 match &o {
138 VerilogBlockOrConditional::Block(b) => {
139 self.io.write("else ");
140 self.visit_block(&b);
141 }
142 VerilogBlockOrConditional::Conditional(c) => {
143 self.io.write("else ");
144 self.visit_statement(c);
145 }
146 VerilogBlockOrConditional::None => {}
147 }
148 }
149
150 fn visit_match(&mut self, m: &VerilogMatch) {
151 self.io.write("case (");
152 self.visit_expression(&m.test);
153 self.io.writeln(")");
154 self.io.push();
155 m.cases.iter().for_each(|x| self.visit_case(x));
156 self.io.pop();
157 self.io.writeln("endcase")
158 }
159
160 fn visit_comment(&mut self, x: &str) {
161 self.io.add(format!("// {}", x));
162 }
163
164 fn visit_signal(&mut self, sig: &str) {
165 self.io.write(self.ident_fixup(sig));
166 }
167
168 fn visit_literal(&mut self, v: &VerilogLiteral) {
169 self.io.write(v.to_string());
170 }
171
172 fn visit_link(&mut self, l: &[VerilogLink]) {
173 for link in l {
174 self.links.push(match link {
175 VerilogLink::Forward(x) => VerilogLink::Forward(self.link_fixup(x)),
176 VerilogLink::Backward(x) => VerilogLink::Backward(self.link_fixup(x)),
177 VerilogLink::Bidirectional(x) => VerilogLink::Bidirectional(self.link_fixup(x)),
178 })
179 }
180 }
181
182 fn visit_case(&mut self, c: &VerilogCase) {
183 self.io.write(self.ident_fixup(&c.condition));
184 self.io.writeln(":");
185 self.io.push();
186 self.visit_block(&c.block);
187 self.io.pop();
188 }
189
190 fn visit_binop(&mut self, l: &VerilogExpression, o: &VerilogOp, r: &VerilogExpression) {
191 self.visit_expression(l);
192 self.io.write(" ");
193 self.io.write(match o {
194 VerilogOp::Add => "+",
195 VerilogOp::Sub => "-",
196 VerilogOp::Mul => "*",
197 VerilogOp::LogicalAnd => "&&",
198 VerilogOp::LogicalOr => "||",
199 VerilogOp::BitXor => "^",
200 VerilogOp::BitAnd => "&",
201 VerilogOp::BitOr => "|",
202 VerilogOp::Shl => "<<",
203 VerilogOp::Shr => ">>",
204 VerilogOp::Eq => "==",
205 VerilogOp::Lt => "<",
206 VerilogOp::Le => "<=",
207 VerilogOp::Ne => "!=",
208 VerilogOp::Ge => ">=",
209 VerilogOp::Gt => ">",
210 });
211 self.io.write(" ");
212 self.visit_expression(r);
213 }
214
215 fn visit_unop(&mut self, o: &VerilogOpUnary, r: &VerilogExpression) {
216 self.io.write(match o {
217 VerilogOpUnary::Not => "~",
218 VerilogOpUnary::Neg => "-",
219 VerilogOpUnary::All => "&",
220 VerilogOpUnary::Any => "|",
221 VerilogOpUnary::Xor => "^",
222 });
223 self.visit_expression(r);
224 }
225
226 fn visit_assignment(&mut self, l: &VerilogExpression, r: &VerilogExpression) {
227 self.visit_expression(l);
228 self.io.write(" = ");
229 self.visit_expression(r);
230 self.io.writeln(";");
231 }
232
233 fn visit_paren(&mut self, e: &VerilogExpression) {
234 self.io.write("(");
235 self.visit_expression(e);
236 self.io.write(")");
237 }
238
239 fn visit_cast(&mut self, e: &VerilogExpression, bits: &usize) {
240 self.io.write("((");
241 self.visit_expression(e);
242 let mask = (BigUint::from(1_u32) << bits) - 1_u32;
243 self.io.write(format!(") & {}'h{:x})", bits, mask))
244 }
245
246 fn visit_signed(&mut self, a: &VerilogExpression) {
247 self.io.write("$signed(");
248 self.visit_expression(a);
249 self.io.write(")");
250 }
251
252 fn visit_unsigned(&mut self, a: &VerilogExpression) {
253 self.io.write("$unsigned(");
254 self.visit_expression(a);
255 self.io.write(")");
256 }
257
258 fn visit_index(&mut self, a: &VerilogExpression, b: &VerilogExpression) {
259 self.visit_expression(a);
260 self.io.write("[");
261 self.visit_expression(b);
262 self.io.write("]");
263 }
264
265 fn visit_slice(&mut self, sig: &VerilogExpression, width: &usize, offset: &VerilogExpression) {
266 self.visit_expression(sig);
267 self.io.write("[(");
268 self.visit_expression(offset);
269 self.io.write(format!(")+:({})]", width));
270 }
271
272 fn visit_index_replace(
273 &mut self,
274 sig: &VerilogExpression,
275 ndx: &VerilogExpression,
276 val: &VerilogExpression,
277 ) {
278 self.io.write("(");
279 self.visit_expression(sig);
280 self.io.write(" & ~(1 << (");
281 self.visit_expression(ndx);
282 self.io.write(")) | ((");
283 self.visit_expression(val);
284 self.io.write(") << (");
285 self.visit_expression(ndx);
286 self.io.write(")))");
287 }
288}
289
290#[test]
291fn test_array_replacement() {
292 let re = Regex::new(r"\[([^\]]*)\]").unwrap();
293 let test = "a[((i+1))]";
294 let captures = re.captures(test);
295 let mut context = evalexpr::HashMapContext::new();
296 context.set_value("i".to_string(), 5.into()).unwrap();
297 if let Some(x) = re.captures(test) {
298 println!("Match {:?}", x);
299 if x.len() == 2 {
300 if let Some(txt) = x.get(1) {
301 let arg = evalexpr::eval_with_context(txt.as_str(), &context).unwrap();
302 println!("Replace {} -> {}", txt.as_str(), arg);
303 println!("Update {}", re.replace(test, format!("$${}", arg)))
304 }
305 }
306 }
307 assert!(captures.is_some());
308}
309
310pub fn filter_blackbox_directives(t: &str) -> String {
311 let mut in_black_box = false;
312 let mut ret = vec![];
313 for line in t.split("\n") {
314 in_black_box = in_black_box || line.starts_with("(* blackbox *)");
315 if !in_black_box {
316 ret.push(line);
317 }
318 if line.starts_with("endmodule") {
319 in_black_box = false;
320 }
321 }
322 ret.join("\n")
323}
324
325#[test]
326fn test_filter_bb_directives() {
327 let p = r#"
328blah
329more code
330goes here
331
332(* blackbox *)
333module my_famous_module(
334 super_secret_arg1,
335 super_secret_arg2,
336 super_secret_arg3);
337/* Comment */
338endmodule
339
340stuff
341"#;
342 let q = filter_blackbox_directives(p);
343 println!("{}", q);
344 assert!(!q.contains("blackbox"));
345 assert!(!q.contains("module"));
346 assert!(!q.contains("endmodule"));
347 assert!(q.contains("more code"));
348 assert!(q.contains("stuff"));
349}