1use itertools::Itertools;
2use nesty::{code, Code};
3use spade_codespan_reporting::term::termcolor;
4
5use num::{BigInt, BigUint, One, Signed, ToPrimitive, Zero};
6use spade_common::id_tracker::ExprIdTracker;
7use spade_common::location_info::Loc;
8use spade_common::name::NameID;
9use spade_common::num_ext::InfallibleToBigUint;
10use spade_diagnostics::emitter::CodespanEmitter;
11use spade_diagnostics::{CodeBundle, CompilationError, DiagHandler};
12
13use crate::aliasing::flatten_aliases;
14use crate::assertion_codegen::AssertedExpression;
15use crate::eval::eval_statements;
16use crate::renaming::{make_names_predictable, VerilogNameMap};
17use crate::type_list::TypeList;
18use crate::types::Type;
19use crate::unit_name::{InstanceMap, InstanceNameTracker};
20use crate::verilog::{self, assign, localparam_size_spec, logic, size_spec};
21use crate::wal::insert_wal_signals;
22use crate::{
23 enum_util, Binding, ConstantValue, Entity, MirInput, Operator, ParamName, Statement, ValueName,
24};
25
26pub mod util;
27
28pub use util::{escape_path, mangle_entity, mangle_input, mangle_output, TupleIndex};
29
30struct Context<'a> {
31 types: &'a TypeList,
32 source_code: &'a Option<CodeBundle>,
33 instance_names: &'a mut InstanceNameTracker,
34 instance_map: &'a mut InstanceMap,
35 unit_nameid: &'a NameID,
37}
38
39fn source_attribute(loc: &Option<Loc<()>>, code: &Option<CodeBundle>) -> Option<String> {
41 match (loc, code) {
42 (Some(l), Some(c)) => Some(format!(r#"(* src = "{}" *)"#, c.source_loc(l))),
43 _ => None,
44 }
45}
46
47fn add_to_name_map(name_map: &mut VerilogNameMap, name: &ValueName, ty: &Type) {
48 if ty.size() != BigUint::zero() {
49 name_map.insert(&name.var_name(), name.verilog_name_source_fwd());
50 }
51 if ty.backward_size() != BigUint::zero() {
52 name_map.insert(&name.backward_var_name(), name.verilog_name_source_back());
53 }
54}
55
56fn statement_declaration(
57 statement: &Statement,
58 code: &Option<CodeBundle>,
59 name_map: &mut VerilogNameMap,
60) -> Code {
61 match statement {
62 Statement::Binding(binding) => {
63 add_to_name_map(name_map, &binding.name, &binding.ty);
64 let name = binding.name.var_name();
65
66 let forward_declaration = if binding.ty.size() != BigUint::zero() {
67 let inner = vec![match &binding.ty {
68 crate::types::Type::Memory { inner, length } => {
69 let inner_w = inner.size();
70 if inner_w > 1u32.to_biguint() {
71 format!("logic[{inner_w}-1:0] {name}[{length}-1:0];")
72 } else {
73 format!("logic[{length}-1:0] {name};")
74 }
75 }
76 _ => logic(&name, &binding.ty.size()),
77 }];
78 code![
79 [0] source_attribute(&binding.loc, code);
80 [0] inner
81 ]
82 } else {
83 code![]
84 };
85
86 let backward_declaration = if binding.ty.backward_size() != BigUint::zero() {
87 code![
88 [0] source_attribute(&binding.loc, code);
89 [0] logic(
90 &binding.name.backward_var_name(),
91 &binding.ty.backward_size(),
92 );
93 ]
94 } else {
95 code![]
96 };
97
98 let ops = &binding
99 .operands
100 .iter()
101 .map(ValueName::var_name)
102 .collect::<Vec<_>>();
103
104 let assignment = match &binding.operator {
107 Operator::Alias => match binding.ty {
108 crate::types::Type::Memory { .. } => {
109 vec![format!("`define {} {}", name, ops[0])]
110 }
111 _ => vec![],
112 },
113 _ => vec![],
114 };
115
116 code! {
117 [0] &forward_declaration;
118 [0] &backward_declaration;
119 [0] &assignment;
120 }
121 }
122 Statement::Register(reg) => {
123 if reg.ty.backward_size() != BigUint::zero() {
124 panic!("Attempting to put value with a backward_size != 0 in a register")
125 }
126 if reg.ty.size() != BigUint::zero() {
127 add_to_name_map(name_map, ®.name, ®.ty);
128 let name = reg.name.var_name();
129 let declaration = verilog::reg(&name, ®.ty.size());
130 code! {
131 [0] source_attribute(®.loc, code);
132 [0] &declaration;
133 }
134 } else {
135 code! {}
136 }
137 }
138 Statement::Constant(_, _, _) => {
139 code! {}
141 }
142 Statement::Assert(_) => {
143 code! {}
144 }
145 Statement::Set { .. } => {
146 code! {}
147 }
148 Statement::WalTrace { .. } => {
149 panic!("Encountered a WalTrace mir node during codegen");
150 }
151 }
152}
153
154fn compute_tuple_index(idx: u64, sizes: &[BigUint]) -> TupleIndex {
155 let mut start_bit = BigUint::zero();
157 for i in 0..idx {
158 start_bit += &sizes[i as usize];
159 }
160
161 let target_width = &sizes[idx as usize];
162
163 let end_bit = &start_bit + target_width;
164
165 let total_width: BigUint = sizes.iter().sum();
166
167 if target_width == &0u32.to_biguint() {
169 TupleIndex::ZeroWidth
170 } else if sizes.iter().sum::<BigUint>() == 1u32.to_biguint() {
171 TupleIndex::None
172 } else if target_width == &1u32.to_biguint() {
173 TupleIndex::Single(total_width - start_bit - 1u32.to_biguint())
174 } else {
175 TupleIndex::Range {
176 left: &total_width - start_bit - 1u32.to_biguint(),
177 right: &total_width - end_bit,
178 }
179 }
180}
181
182fn forward_expression_code(binding: &Binding, types: &TypeList, ops: &[ValueName]) -> String {
183 let self_type = &binding.ty;
184 let op_names = ops.iter().map(|op| op.var_name()).collect::<Vec<_>>();
185
186 let name = binding.name.var_name();
187
188 macro_rules! binop {
189 ($verilog:expr) => {{
190 assert!(
191 binding.operands.len() == 2,
192 "expected 2 operands to binary operator"
193 );
194 format!("{} {} {}", op_names[0], $verilog, op_names[1])
195 }};
196 }
197
198 macro_rules! signed_binop {
199 ($verilog:expr) => {{
200 assert!(
201 binding.operands.len() == 2,
202 "expected 2 operands to binary operator"
203 );
204 format!(
205 "$signed({}) {} $signed({})",
206 op_names[0], $verilog, op_names[1]
207 )
208 }};
209 }
210
211 macro_rules! unop {
212 ($verilog:expr) => {{
213 assert!(
214 binding.operands.len() == 1,
215 "expected 1 operands to binary operator"
216 );
217 format!("{}{}", $verilog, op_names[0])
218 }};
219 }
220
221 match &binding.operator {
222 Operator::Add => signed_binop!("+"),
223 Operator::UnsignedAdd => binop!("+"),
224 Operator::Sub => signed_binop!("-"),
225 Operator::UnsignedSub => binop!("-"),
226 Operator::Mul => signed_binop!("*"),
227 Operator::UnsignedMul => binop!("*"),
228 Operator::Div => signed_binop!("/"),
229 Operator::UnsignedDiv => binop!("/"),
230 Operator::Mod => signed_binop!("%"),
231 Operator::UnsignedMod => binop!("%"),
232 Operator::Eq => binop!("=="),
233 Operator::NotEq => binop!("!="),
234 Operator::Gt => signed_binop!(">"),
235 Operator::UnsignedGt => binop!(">"),
236 Operator::Lt => signed_binop!("<"),
237 Operator::UnsignedLt => binop!("<"),
238 Operator::Ge => signed_binop!(">="),
239 Operator::UnsignedGe => binop!(">="),
240 Operator::Le => signed_binop!("<="),
241 Operator::UnsignedLe => binop!("<="),
242 Operator::LeftShift => binop!("<<"),
243 Operator::RightShift => binop!(">>"),
244 Operator::ArithmeticRightShift => signed_binop!(">>>"),
245 Operator::LogicalAnd => binop!("&&"),
246 Operator::LogicalOr => binop!("||"),
247 Operator::LogicalXor => binop!("^"),
248 Operator::LogicalNot => {
249 assert!(
250 op_names.len() == 1,
251 "Expected exactly 1 operand to not operator"
252 );
253 format!("!{}", op_names[0])
254 }
255 Operator::BitwiseNot => {
256 assert!(
257 op_names.len() == 1,
258 "Expected exactly 1 operand to bitwise not operator"
259 );
260 format!("~{}", op_names[0])
261 }
262 Operator::BitwiseAnd => binop!("&"),
263 Operator::BitwiseOr => binop!("|"),
264 Operator::BitwiseXor => binop!("^"),
265 Operator::USub => unop!("-"),
266 Operator::Not => unop!("!"),
267 Operator::ReduceAnd => unop!("&"),
268 Operator::ReduceOr => unop!("|"),
269 Operator::ReduceXor => unop!("^"),
270 Operator::DivPow2 => {
271 let dividend = &op_names[0];
279 let divisor = &op_names[1];
280 code! {
281 [0] "always_comb begin";
282 [1] format!("if ({divisor} == 0) begin");
283 [2] format!("{name} = {dividend};");
284 [1] "end";
285 [1] format!("else begin");
286 [2] format!("{name} = $signed($signed({dividend}) + $signed(1 << ({divisor} - 1))) >>> $signed({divisor});");
287 [1] "end";
288 [0] "end";
289 }.to_string()
290 }
291 Operator::Truncate => {
292 format!(
293 "{}[{}:0]",
294 op_names[0],
295 binding.ty.size() - 1u32.to_biguint()
296 )
297 }
298 Operator::Concat => {
299 format!(
300 "{{{}}}",
301 op_names.iter().map(|op| op.to_string()).join(", ")
302 )
303 }
304 Operator::SignExtend {
305 extra_bits,
306 operand_size,
307 } => match extra_bits.to_u32() {
308 Some(0) => op_names[0].to_string(),
309 Some(1) => format!(
310 "{{{}[{}], {}}}",
311 op_names[0],
312 operand_size - 1u32.to_biguint(),
313 op_names[0]
314 ),
315 _ => format!(
316 "#[#[ {extra_bits} #[ {op}[{last_index}] #]#], {op}#]",
317 op = op_names[0],
318 last_index = operand_size - 1u32.to_biguint(),
319 )
320 .replace("#[", "{")
324 .replace("#]", "}"),
325 },
326 Operator::ZeroExtend { extra_bits } => match extra_bits.to_u32() {
327 Some(0) => op_names[0].to_string(),
328 _ => format!("{{{}'b0, {}}}", extra_bits, op_names[0]),
329 },
330 Operator::Match => {
331 assert!(
332 op_names.len() % 2 == 0,
333 "Match statements must have an even number of operands"
334 );
335
336 let num_branches = op_names.len() / 2;
337
338 let mut conditions = vec![];
339 let mut cases = vec![];
340 for i in 0..num_branches {
341 let cond = &op_names[i * 2];
342 let result = &op_names[i * 2 + 1];
343
344 conditions.push(cond.clone());
345
346 let zeros = (0..i).map(|_| '0').collect::<String>();
347 let unknowns = (0..(num_branches - i - 1)).map(|_| '?').collect::<String>();
348 cases.push(format!(
349 "{}'b{}1{}: {} = {};",
350 num_branches, zeros, unknowns, name, result
351 ))
352 }
353
354 let fallback = format!("{}'dx", self_type.size());
355
356 code! (
357 [0] "always_comb begin";
358 [1] format!("priority casez ({{{}}})", conditions.join(", "));
359 [2] cases;
360 [2] format!("{num_branches}'b?: {name} = {fallback};");
361 [1] "endcase";
362 [0] "end";
363 )
364 .to_string()
365 }
366 Operator::Select => {
367 assert!(
368 binding.operands.len() == 3,
369 "expected 3 operands to Select operator"
370 );
371 format!("{} ? {} : {}", op_names[0], op_names[1], op_names[2])
372 }
373 Operator::IndexTuple(idx, ref types) => {
374 let sizes = types.iter().map(|t| t.size()).collect::<Vec<_>>();
375 let idx = compute_tuple_index(*idx, &sizes);
376 format!("{}{}", op_names[0], idx.verilog_code())
377 }
378 Operator::ConstructArray { .. } => {
379 format!(
382 "{{{}}}",
383 op_names
384 .iter()
385 .cloned()
386 .rev()
387 .collect::<Vec<_>>()
388 .join(", ")
389 )
390 }
391 Operator::IndexArray { array_size } => {
392 let member_size = self_type.size();
393 if array_size != &BigUint::one() {
394 if member_size == 1u32.to_biguint() {
395 format!("{}[{}]", op_names[0], op_names[1])
396 } else {
397 let end_index = format!("{} * {}", op_names[1], member_size);
398 let offset = member_size;
399
400 format!("{}[{}+:{}]", op_names[0], end_index, offset)
402 }
403 } else {
404 format!("{}", op_names[0])
405 }
406 }
407 Operator::RangeIndexArray {
408 start,
409 end_exclusive: end,
410 in_array_size,
411 } => {
412 let member_size = match self_type {
413 Type::Array { inner, length: _ } => inner.size(),
414 _ => panic!("Range index with non-array output"),
415 };
416 let num_elems = end - start;
417 if in_array_size == &BigUint::one() {
418 op_names[0].clone()
419 } else if member_size == BigUint::one() && num_elems == BigUint::one() {
420 format!("{}[{}]", op_names[0], start)
421 } else {
422 let end_index = (end * &member_size) - BigUint::one();
423 let offset = member_size * num_elems;
424
425 format!("{}[{}-:{}]", op_names[0], end_index, offset)
427 }
428 }
429 Operator::IndexMemory => {
430 format!("{}[{}]", op_names[0], op_names[1])
431 }
432 Operator::RangeIndexBits {
433 start,
434 end_exclusive,
435 } => {
436 if end_exclusive - start == 1u32.to_biguint() {
437 format!("{}[{start}]", op_names[0])
438 } else {
439 format!("{}[{end_exclusive}:{start}]", op_names[0])
440 }
441 }
442 Operator::DeclClockedMemory {
443 write_ports,
444 addr_w,
445 inner_w,
446 elems: _,
447 initial,
448 } => {
449 let full_port_width = 1u32.to_biguint() + addr_w + inner_w;
450
451 let initial_block = if let Some(vals) = initial {
452 let assignments = vals
453 .iter()
454 .enumerate()
455 .map(|(i, v)| {
456 let val = eval_statements(v).as_string();
457
458 format!("{}[{i}] = 'b{val};", name)
459 })
460 .collect::<Vec<_>>();
461 code! {
462 [0] "initial begin";
463 [1] assignments;
464 [0] "end";
465 }
466 } else {
467 code! {}
468 };
469
470 let update_blocks = (0..write_ports.to_usize().expect("Too many write ports"))
471 .map(|port| {
472 let we_index =
473 &full_port_width * (port + 1u32.to_biguint()) - 1u32.to_biguint();
474
475 let addr_start = &full_port_width * port + inner_w;
476 let addr = if *addr_w == 1u32.to_biguint() {
477 format!("{}[{}]", op_names[1], addr_start)
478 } else {
479 format!(
480 "{}[{}:{}]",
481 op_names[1],
482 &addr_start + addr_w - 1u32.to_biguint(),
483 addr_start
484 )
485 };
486
487 let write_value_start = port * &full_port_width;
488 let (write_index, write_value) = if *inner_w == 1u32.to_biguint() {
489 (
490 format!("{}[{addr}]", name),
491 format!("{}[{}]", op_names[1], &write_value_start),
492 )
493 } else {
494 (
495 format!("{}[{addr}]", name),
496 format!(
497 "{}[{end}:{write_value_start}]",
498 op_names[1],
499 end = &write_value_start + inner_w - 1u32.to_biguint()
500 ),
501 )
502 };
503 let we_signal = format!("{}[{we_index}]", op_names[1]);
504
505 code! {
506 [0] format!("if ({we_signal}) begin");
507 [1] format!("{write_index} <= {write_value};");
508 [0] "end"
509 }
510 .to_string()
511 })
512 .join("\n");
513
514 code! {
515 [0] initial_block;
516 [0] format!("always @(posedge {clk}) begin", clk = op_names[0]);
517 [1] update_blocks;
518 [0] "end";
519 }
520 .to_string()
521 }
522 Operator::ConstructEnum {
523 variant,
524 variant_count,
525 } => {
526 let tag_size = enum_util::tag_size(*variant_count);
527
528 let (variant_member_size, included_members) = match &binding.ty {
531 crate::types::Type::Enum(options) => {
532 let members = &options[*variant];
533 let size = members.iter().map(|t| t.size()).sum::<BigUint>();
534
535 let included_members = members
536 .iter()
537 .zip(op_names)
538 .filter_map(|(ty, name)| {
539 if ty.size() != BigUint::ZERO {
540 Some(name)
541 } else {
542 None
543 }
544 })
545 .collect::<Vec<_>>();
546 (size, included_members)
547 }
548 _ => panic!("Attempted enum construction of non-enum"),
549 };
550
551 let padding_size = binding.ty.size() - tag_size - variant_member_size;
552
553 let padding_text = if padding_size != BigUint::zero() {
554 format!(", {}'bX", padding_size)
555 } else {
556 String::new()
557 };
558
559 let ops_text = if included_members.is_empty() {
560 String::new()
561 } else {
562 format!(
563 "{}{}",
564 if tag_size != 0 { ", " } else { "" },
565 included_members.join(", ")
566 )
567 };
568
569 let tag = if tag_size != 0 {
570 format!("{tag_size}'d{variant}")
571 } else {
572 "".to_string()
573 };
574
575 format!("{{{tag}{ops_text}{padding_text}}}")
576 }
577 Operator::IsEnumVariant { variant, enum_type } => {
578 if enum_type.size() == BigUint::ZERO {
580 "1".to_string()
581 } else {
582 let tag_size = enum_util::tag_size(enum_type.assume_enum().len());
583 let total_size = enum_type.size();
584
585 let tag_end = &total_size - 1u32.to_biguint();
586 let tag_start = &total_size - tag_size as u64;
587
588 if tag_size == 0 {
589 "1".to_string()
590 } else if total_size == 1u32.to_biguint() {
591 format!("{} == 1'd{}", op_names[0], variant)
592 } else if tag_end == tag_start {
593 format!("{}[{}] == {}'d{}", op_names[0], tag_end, tag_size, variant)
594 } else {
595 format!(
596 "{}[{}:{}] == {}'d{}",
597 op_names[0], tag_end, tag_start, tag_size, variant
598 )
599 }
600 }
601 }
602 Operator::EnumMember {
603 variant,
604 member_index,
605 enum_type,
606 } => {
607 let variant_list = enum_type.assume_enum();
608 let tag_size = enum_util::tag_size(variant_list.len());
609 let full_size = enum_type.size();
610
611 let member_start = (tag_size as u64)
612 + variant_list[*variant][0..*member_index]
613 .iter()
614 .map(|t| t.size())
615 .sum::<BigUint>();
616
617 let member_end = &member_start + variant_list[*variant][*member_index].size();
618
619 let upper_idx = &full_size - &member_start - 1u32.to_biguint();
620 let lower_idx = full_size - &member_end;
621 if upper_idx == lower_idx && tag_size == 0 {
622 op_names[0].clone()
623 } else {
624 format!("{}[{}:{}]", op_names[0], upper_idx, lower_idx)
625 }
626 }
627 Operator::ReadPort => ops[0].backward_var_name(),
628 Operator::FlipPort => {
629 String::new()
631 }
632 Operator::ReadMutWires => {
633 String::new()
635 }
636 Operator::ConstructTuple => {
637 let mut members = ops
638 .iter()
639 .filter(|op| types[op].size() != BigUint::zero())
640 .map(|op| op.var_name());
641 format!("{{{}}}", members.join(", "))
644 }
645 Operator::Instance { .. } => {
646 String::new()
648 }
649 Operator::Alias => {
650 String::new()
652 }
653 Operator::Nop => String::new(),
654 }
655}
656
657fn backward_expression_code(binding: &Binding, types: &TypeList, ops: &[ValueName]) -> String {
658 let self_type = &binding.ty;
659 let op_names = ops
660 .iter()
661 .map(ValueName::backward_var_name)
662 .collect::<Vec<_>>();
663 let fwd_op_names = ops.iter().map(ValueName::var_name).collect::<Vec<_>>();
664 match &binding.operator {
665 Operator::Add
666 | Operator::UnsignedAdd
667 | Operator::Sub
668 | Operator::UnsignedSub
669 | Operator::Mul
670 | Operator::UnsignedMul
671 | Operator::Div
672 | Operator::UnsignedDiv
673 | Operator::Mod
674 | Operator::UnsignedMod
675 | Operator::Eq
676 | Operator::NotEq
677 | Operator::Gt
678 | Operator::UnsignedGt
679 | Operator::Lt
680 | Operator::UnsignedLt
681 | Operator::Ge
682 | Operator::UnsignedGe
683 | Operator::Le
684 | Operator::UnsignedLe
685 | Operator::LeftShift
686 | Operator::RightShift
687 | Operator::ArithmeticRightShift
688 | Operator::LogicalAnd
689 | Operator::LogicalOr
690 | Operator::LogicalXor
691 | Operator::LogicalNot
692 | Operator::BitwiseAnd
693 | Operator::BitwiseOr
694 | Operator::BitwiseXor
695 | Operator::USub
696 | Operator::Not
697 | Operator::BitwiseNot
698 | Operator::DivPow2
699 | Operator::ReduceAnd { .. }
700 | Operator::ReduceOr { .. }
701 | Operator::ReduceXor { .. }
702 | Operator::SignExtend { .. }
703 | Operator::ZeroExtend { .. }
704 | Operator::Concat
705 | Operator::DeclClockedMemory { .. }
706 | Operator::ConstructEnum { .. }
707 | Operator::IsEnumVariant { .. }
708 | Operator::EnumMember { .. }
709 | Operator::RangeIndexBits { .. }
710 | Operator::IndexMemory
711 | Operator::Select
712 | Operator::Match
713 | Operator::ReadPort
714 | Operator::Truncate => panic!(
715 "{} cannot be used on types with backward size",
716 binding.operator
717 ),
718 Operator::ConstructArray => {
719 format!(
722 "{{{}}}",
723 op_names
724 .iter()
725 .cloned()
726 .rev()
727 .collect::<Vec<_>>()
728 .join(", ")
729 )
730 }
731 Operator::IndexArray { array_size } => {
732 let member_size = self_type.backward_size();
733 if array_size != &BigUint::one() {
734 if member_size == 1u32.to_biguint() {
735 format!("{}[{}]", op_names[0], fwd_op_names[1])
736 } else {
737 let end_index = format!("{} * {}", fwd_op_names[1], member_size);
738 let offset = member_size;
739
740 format!("{}[{}+:{}]", op_names[0], end_index, offset)
742 }
743 } else {
744 op_names[0].clone()
745 }
746 }
747 Operator::RangeIndexArray {
748 start,
749 end_exclusive: end,
750 in_array_size,
751 } => {
752 let member_size = self_type.backward_size();
753 let elems = end - start;
754 if in_array_size == &BigUint::one() {
755 op_names[0].clone()
756 } else if member_size == BigUint::one() && elems == BigUint::one() {
757 format!("{}[{}]", op_names[0], start)
758 } else {
759 let end_index = format!("{} * {}", start, member_size);
760 let offset = member_size * elems;
761
762 format!("{}[{}+:{}]", op_names[0], end_index, offset)
764 }
765 }
766 Operator::ConstructTuple => {
767 let mut members = ops
768 .iter()
769 .filter(|op| types[op].backward_size() != BigUint::zero())
770 .map(|op| op.backward_var_name());
771 format!("{{{}}}", members.join(", "))
772 }
773 Operator::IndexTuple(index, inner_types) => {
774 let index = compute_tuple_index(
778 *index,
779 &inner_types
780 .iter()
781 .map(|t| t.backward_size())
782 .collect::<Vec<_>>(),
783 );
784 format!("{}{}", op_names[0], index.verilog_code())
785 }
786 Operator::FlipPort => {
787 String::new()
789 }
790 Operator::ReadMutWires => {
791 String::new()
793 }
794 Operator::Instance { .. } => String::new(),
795 Operator::Alias => {
796 String::new()
798 }
799 Operator::Nop => String::new(),
800 }
801}
802
803fn statement_code(statement: &Statement, ctx: &mut Context) -> Code {
804 match statement {
805 Statement::Binding(binding) => {
806 let name = binding.name.var_name();
807 let back_name = binding.name.backward_var_name();
808
809 let ops = &binding
810 .operands
811 .iter()
812 .map(ValueName::var_name)
813 .collect::<Vec<_>>();
814
815 let back_ops = &binding
816 .operands
817 .iter()
818 .map(ValueName::backward_var_name)
819 .collect::<Vec<_>>();
820
821 let forward_expression = if binding.ty.size() != BigUint::zero() {
822 Some(forward_expression_code(
823 binding,
824 ctx.types,
825 &binding.operands,
826 ))
827 } else {
828 None
829 };
830 let backward_expression = if binding.ty.backward_size() != BigUint::zero() {
831 Some(backward_expression_code(
832 binding,
833 ctx.types,
834 &binding.operands,
835 ))
836 } else {
837 None
838 };
839
840 let assignment = match &binding.operator {
842 Operator::Instance{name: module_name, params, argument_names, loc} => {
843 let param_string = if params.is_empty() {
844 "".into()
845 } else {
846 let param_strings = params.iter().map(|(name, value)| format!(".{}({})", name, value)).collect::<Vec<_>>();
847 format!("#({})", param_strings.join(", "))
848 };
849 let mut args = binding
851 .operands
852 .iter()
853 .zip(argument_names)
854 .flat_map(|(port, ParamName{name, no_mangle})| {
855 let ty = &ctx.types[port];
856
857 let mut result = vec![];
860 if ty.size() != BigUint::zero() {
861 result.push(format!(
862 ".{}({})",
863 mangle_input(no_mangle, name),
864 port.var_name()
865 ))
866 }
867 if ty.backward_size() != BigUint::zero() {
868 result.push(format!(
869 ".{}({})",
870 mangle_output(no_mangle, name),
871 port.backward_var_name()
872 ))
873 }
874 result
875 }).collect::<Vec<_>>();
876
877 if binding.ty.size() != BigUint::zero() {
878 args.push(format!(".output__({name})"));
879 }
880 if binding.ty.backward_size() != BigUint::zero() {
881 args.push(format!(".input__({back_name})"));
882 }
883
884 let instance_name = module_name.instance_name(
885 ctx.unit_nameid.clone(),
886 ctx.instance_map,
887 ctx.instance_names
888 );
889
890 code!{
891 [0] source_attribute(loc, ctx.source_code);
892 [0] format!(
893 "{}{} {}({});",
894 &module_name.as_verilog(),
895 if param_string.is_empty() { "".into() } else { format!("{}", param_string)},
896 instance_name,
897 args.join(", ")
898 )
899 }.to_string()
900 }
901 Operator::Alias => match binding.ty {
902 crate::types::Type::Memory { .. } => {
903 "".to_string()
905 }
906 _ => code! {
907 [0] forward_expression.map(|_| format!("assign {} = {};", name, ops[0]));
908 [0] backward_expression.map(|_| format!("assign {} = {};", back_ops[0], back_name));
909 }.to_string()
910 },
911 Operator::Match => forward_expression.unwrap(),
912 Operator::DivPow2 => forward_expression.unwrap(),
913 Operator::Nop => String::new(),
914 Operator::FlipPort => {
915 let has_fwd = binding.ty.size() != BigUint::zero();
916 let has_back = binding.ty.backward_size() != BigUint::zero();
917 code! {
920 [0] has_fwd.then(|| format!("assign {} = {};", name, back_ops[0]));
921 [0] has_back.then(|| format!("assign {} = {};", ops[0], back_name));
922 }
923 .to_string()
924 }
925 Operator::ReadMutWires => {
926 code! {
929 [0] format!("assign {} = {};", name, back_ops[0]);
930 }
931 .to_string()
932 }
933 Operator::DeclClockedMemory { .. } => forward_expression.unwrap(),
934 _ => code! {
935 [0] forward_expression.map(|f| format!("assign {} = {};", name, f));
936 [0] backward_expression.map(|b| format!("assign {} = {};", b, back_name));
937 }
938 .to_string(),
939 };
940
941 code! {
942 [0] &assignment
943 }
944 }
945 Statement::Register(reg) => {
946 let name = reg.name.var_name();
947 let main_body = if let Some((rst_trig, rst_val)) = ®.reset {
948 code! {
949 [0] &format!("always @(posedge {}) begin", reg.clock.var_name());
950 [1] &format!("if ({}) begin", rst_trig.var_name());
951 [2] &format!("{} <= {};", name, rst_val.var_name());
952 [1] &"end";
953 [1] &"else begin";
954 [2] &format!("{} <= {};", name, reg.value.var_name());
955 [1] &"end";
956 [0] &"end"
957 }
958 } else {
959 code! {
960 [0] &format!("always @(posedge {}) begin", reg.clock.var_name());
961 [1] &format!("{} <= {};", name, reg.value.var_name());
962 [0] &"end"
963 }
964 };
965
966 let initial_block = if let Some(initial) = reg.initial.as_ref() {
967 code! {
968 [0] "initial begin";
969 [1] format!("{} = 'b{};", name, eval_statements(initial).as_string());
970 [0] "end";
971 }
972 } else {
973 code![]
974 };
975
976 code! {
977 [0] initial_block;
978 [0] main_body
979 }
980 }
981 Statement::Constant(id, t, value) => {
982 let name = ValueName::Expr(*id).var_name();
983
984 let expression = match value {
985 ConstantValue::Int(val) => {
986 let size = match t {
987 crate::types::Type::Int(size) | crate::types::Type::UInt(size) => size,
988 _ => panic!("Const integer that is not const"),
989 };
990
991 let val_abs = val.abs();
992 let sign = if val < &BigInt::zero() { "-" } else { "" };
993
994 let size_spec = if *size >= 32u32.to_biguint() {
996 format!("{size}'d")
997 } else {
998 String::new()
999 };
1000 format!("{sign}{size_spec}{val_abs}")
1001 }
1002 ConstantValue::Bool(val) => format!("{}", if *val { 1 } else { 0 }),
1003 ConstantValue::HighImp => "'bz".to_string(),
1004 };
1005
1006 if t.size() != BigUint::ZERO {
1007 let size = localparam_size_spec(&t.size());
1008
1009 let assignment = format!("localparam{size} {name} = {expression};");
1010
1011 code! {
1012 [0] &assignment
1013 }
1014 } else {
1015 code! {}
1016 }
1017 }
1018 Statement::Assert(val) => {
1019 let mut msg_buf = termcolor::Buffer::ansi();
1023 let mut diag_handler = DiagHandler::new(Box::new(CodespanEmitter));
1024
1025 AssertedExpression(val.clone()).report(
1026 &mut msg_buf,
1027 ctx.source_code.as_ref().unwrap(),
1028 &mut diag_handler,
1029 );
1030
1031 let msg = String::from_utf8(msg_buf.as_slice().into())
1032 .map_err(|e| {
1033 println!("Internal error {e}: Failed to generate assert message, invalid utf-8 returned by codespan");
1034 })
1035 .unwrap_or_else(|_| String::new())
1036 .lines()
1037 .map(|line| {
1038 format!(r#"$display("{line}");"#)
1039 })
1040 .join("\n");
1041
1042 let val_var = val.var_name();
1043 code! {
1044 [0] format!("`ifndef SYNTHESIS");
1045 [0] format!("always @({val_var}) begin");
1046 [1] "#0";
1053 [1] format!("assert ({val_var})");
1054 [1] "else begin";
1055 [2] msg;
1056 [2] r#"$error("Assertion failed");"#;
1057 [2] r#"$fatal(1);"#;
1058 [1] "end";
1059 [0] "end";
1060 [0] format!("`endif")
1061 }
1062 }
1063 Statement::Set { target, value } => {
1064 let assignment = format!(
1065 "assign {} = {};",
1066 target.backward_var_name(),
1067 value.var_name()
1068 );
1069
1070 code! {
1071 [0] assignment
1072 }
1073 }
1074 Statement::WalTrace { .. } => {
1075 panic!("Encountered a WalTrace mir node during codegen");
1076 }
1077 }
1078}
1079
1080#[cfg(test)]
1081fn statement_code_and_declaration(
1082 statement: &Statement,
1083 types: &TypeList,
1084 source_code: &CodeBundle,
1085) -> Code {
1086 use spade_common::name::Path;
1087
1088 let mut ctx = Context {
1089 types,
1090 source_code: &Some(source_code.clone()),
1091 instance_names: &mut InstanceNameTracker::new(),
1092 instance_map: &mut InstanceMap::new(),
1093 unit_nameid: &NameID(0, Path::from_strs(&["dummy"])),
1094 };
1095 code! {
1096 [0] statement_declaration(statement, &Some(source_code.clone()), &mut VerilogNameMap::new());
1097 [0] statement_code(statement, &mut ctx);
1098 }
1099}
1100
1101#[derive(Clone)]
1103pub struct Codegenable(pub Entity);
1104
1105pub fn prepare_codegen(mut entity: Entity, expr_idtracker: &mut ExprIdTracker) -> Codegenable {
1106 flatten_aliases(&mut entity);
1107 make_names_predictable(&mut entity);
1108 insert_wal_signals(&mut entity, expr_idtracker, &mut None);
1109
1110 Codegenable(entity)
1111}
1112
1113pub fn entity_code(
1121 entity: &Codegenable,
1122 instance_map: &mut InstanceMap,
1123 source_code: &Option<CodeBundle>,
1124) -> (Code, VerilogNameMap) {
1125 let mut name_map = VerilogNameMap::new();
1126
1127 let Codegenable(entity) = entity;
1128
1129 let types = &TypeList::from_entity(entity);
1130
1131 let entity_name = entity.name.as_verilog();
1132
1133 let inputs = &entity.inputs;
1134
1135 let inputs = inputs.iter().map(
1136 |MirInput {
1137 name,
1138 val_name,
1139 ty,
1140 no_mangle,
1141 }| {
1142 if ty.size() != BigUint::zero() {
1143 name_map.insert(name, val_name.verilog_name_source_fwd());
1144 }
1145 if ty.backward_size() != BigUint::zero() {
1146 name_map.insert(name, val_name.verilog_name_source_back());
1147 }
1148
1149 let size = ty.size();
1150 let (input_head, input_code) = if size != BigUint::zero() {
1151 let name = mangle_input(no_mangle, name);
1152
1153 name_map.insert(&name, val_name.verilog_name_source_fwd());
1154
1155 let input_or_inout = match ty {
1156 Type::InOut(_) => "inout",
1157 _ => "input",
1158 };
1159
1160 let alias_assignment = if no_mangle.is_none() {
1165 code! {
1166 [0] &logic(&val_name.var_name(), &size);
1167 [0] &assign(&val_name.var_name(), &name)
1168 }
1169 } else {
1170 code! {}
1171 };
1172 (
1173 format!("{input_or_inout}{} {}", size_spec(&size), name),
1174 alias_assignment,
1175 )
1176 } else {
1177 (String::new(), code! {})
1178 };
1179
1180 let backward_size = ty.backward_size();
1181 let (output_head, output_code) = if backward_size != BigUint::zero() {
1182 let name = mangle_output(no_mangle, name);
1183 name_map.insert(&name, val_name.verilog_name_source_back());
1184 (
1185 format!("output{} {}", size_spec(&backward_size), name),
1186 code! {
1187 [0] &logic(&val_name.backward_var_name(), &backward_size);
1188 [0] &assign(&name, &val_name.backward_var_name())
1189 },
1190 )
1191 } else {
1192 (String::new(), code! {})
1193 };
1194
1195 let spacing = if !input_head.is_empty() && !output_head.is_empty() {
1196 ", "
1197 } else {
1198 ""
1199 };
1200 (
1201 format!("{input_head}{spacing}{output_head}"),
1202 code! {
1203 [0] input_code;
1204 [0] output_code;
1205 },
1206 )
1207 },
1208 );
1209
1210 let (inputs, input_assignments): (Vec<_>, Vec<_>) = inputs.unzip();
1211
1212 let back_port_size = entity.output_type.backward_size();
1213 let (back_port_definition, back_port_assignment) = if back_port_size != BigUint::zero() {
1214 let def = code! {
1215 [0] format!(
1216 "input{} input__",
1217 size_spec(&entity.output_type.backward_size())
1218 );
1219 };
1220 let assignment = code! {
1221 [0] assign(&entity.output.backward_var_name(), "input__")
1222 };
1223 (Some(def), Some(assignment))
1224 } else {
1225 (None, None)
1226 };
1227
1228 let output_size = entity.output_type.size();
1229 let (output_definition, output_assignment) = if output_size != BigUint::zero() {
1230 let def = code! {
1231 [0] format!("output{} output__", size_spec(&output_size))
1232 };
1233 let assignment = code! {[0] assign("output__", &entity.output.var_name())};
1234
1235 name_map.insert("output__", entity.output.verilog_name_source_fwd());
1236
1237 (Some(def), Some(assignment))
1238 } else {
1239 (None, None)
1240 };
1241
1242 let mut ctx = Context {
1243 types,
1244 source_code,
1245 instance_names: &mut InstanceNameTracker::new(),
1246 instance_map,
1247 unit_nameid: &entity.name.source,
1248 };
1249
1250 let mut body = Code::new();
1251
1252 for stmt in &entity.statements {
1253 body.join(&statement_declaration(stmt, source_code, &mut name_map))
1254 }
1255 for stmt in &entity.statements {
1256 body.join(&statement_code(stmt, &mut ctx))
1257 }
1258
1259 let port_definitions = inputs
1261 .into_iter()
1262 .map(|s| code! { [0] s})
1263 .chain(output_definition)
1264 .chain(back_port_definition)
1265 .map(|code| code.to_string())
1266 .filter(|s| !s.is_empty())
1267 .join(",\n");
1268
1269 let code = code! {
1270 [0] &format!("module {} (", entity_name);
1271 [2] &port_definitions;
1272 [1] &");";
1273 [1] "`ifdef COCOTB_SIM";
1274 [1] "string __top_module;";
1275 [1] "string __vcd_file;";
1276 [1] "initial begin";
1277 [2] format!(r#"if ($value$plusargs("TOP_MODULE=%s", __top_module) && __top_module == "{top_name}" && $value$plusargs("VCD_FILENAME=%s", __vcd_file)) begin"#, top_name = entity.name.without_escapes());
1278 [3] format!("$dumpfile (__vcd_file);");
1279 [3] format!("$dumpvars (0, {entity_name});");
1280 [2] "end";
1281 [1] "end";
1282 [1] "`endif";
1283 [1] &input_assignments;
1284 [1] &body;
1285 [1] &output_assignment;
1286 [1] &back_port_assignment;
1287 [0] &"endmodule"
1288 };
1289 (code, name_map)
1290}
1291
1292#[macro_export]
1293macro_rules! assert_same_code {
1294 ($got:expr, $expected:expr) => {
1295 if $got != $expected {
1296 println!("{}:\n{}", "got".red(), $got);
1297 println!("{}", "==============================================".red());
1298 println!("{}:\n{}", "expected".green(), $expected);
1299 println!(
1300 "{}",
1301 "==============================================".green()
1302 );
1303 println!("{}", prettydiff::diff_chars($got, $expected));
1304 println!(
1305 "{}",
1306 "==============================================".yellow()
1307 );
1308 panic!("Code mismatch")
1309 }
1310 };
1311}
1312
1313#[cfg(test)]
1314mod tests {
1315 use super::*;
1316 use colored::Colorize;
1317 use spade_common::id_tracker::ExprID;
1318 use spade_common::location_info::WithLocation;
1319 use spade_common::name::Path;
1320
1321 use crate as spade_mir;
1322 use crate::{entity, statement, types::Type};
1323
1324 use indoc::indoc;
1325
1326 #[test]
1327 fn size_1_wires_have_no_size_spec() {
1328 let binding = statement!(e(0); Type::Bool; Add; e(1), e(2));
1329
1330 let expected = indoc!(
1331 r#"
1332 logic _e_0;
1333 assign _e_0 = $signed(_e_1) + $signed(_e_2);"#
1334 );
1335
1336 assert_same_code!(
1337 &statement_code_and_declaration(
1338 &binding,
1339 &TypeList::empty(),
1340 &CodeBundle::new("".to_string())
1341 )
1342 .to_string(),
1343 expected
1344 );
1345 }
1346
1347 #[test]
1348 fn binding_code_works() {
1349 let binding = statement!(e(0); Type::int(5); Add; e(1), e(2));
1350
1351 let expected = indoc!(
1352 r#"
1353 logic[4:0] _e_0;
1354 assign _e_0 = $signed(_e_1) + $signed(_e_2);"#
1355 );
1356
1357 assert_same_code!(
1358 &statement_code_and_declaration(
1359 &binding,
1360 &TypeList::empty(),
1361 &CodeBundle::new("".to_string())
1362 )
1363 .to_string(),
1364 expected
1365 );
1366 }
1367
1368 #[test]
1369 fn registers_without_reset_work() {
1370 let reg = statement!(reg n(0, "r"); Type::int(7); clock (e(0)); e(1));
1371
1372 let expected = indoc!(
1373 r#"
1374 reg[6:0] \r ;
1375 always @(posedge _e_0) begin
1376 \r <= _e_1;
1377 end"#
1378 );
1379
1380 assert_same_code!(
1381 &statement_code_and_declaration(
1382 ®,
1383 &TypeList::empty(),
1384 &CodeBundle::new("".to_string())
1385 )
1386 .to_string(),
1387 expected
1388 );
1389 }
1390
1391 #[test]
1392 fn registers_with_reset_work() {
1393 let reg = statement!(reg n(0, "r"); Type::int(7); clock (e(0)); reset (e(2), e(3)); e(1));
1394
1395 let expected = indoc!(
1396 r#"
1397 reg[6:0] \r ;
1398 always @(posedge _e_0) begin
1399 if (_e_2) begin
1400 \r <= _e_3;
1401 end
1402 else begin
1403 \r <= _e_1;
1404 end
1405 end"#
1406 );
1407
1408 assert_same_code!(
1409 &statement_code_and_declaration(
1410 ®,
1411 &TypeList::empty(),
1412 &CodeBundle::new("".to_string())
1413 )
1414 .to_string(),
1415 expected
1416 );
1417 }
1418
1419 #[test]
1420 fn registers_with_initial_values_work() {
1421 let initial_value = vec![
1422 statement!(const 4; Type::int(7); ConstantValue::int(0b10_1100)),
1423 statement!(e(5); Type::int(7); Alias; e(4)),
1424 ];
1425 let reg =
1426 statement!(reg n(0, "r"); Type::int(7); clock (e(0)); initial (initial_value); e(1));
1427
1428 let expected = indoc!(
1429 r#"
1430 reg[6:0] \r ;
1431 initial begin
1432 \r = 'b0101100;
1433 end
1434 always @(posedge _e_0) begin
1435 \r <= _e_1;
1436 end"#
1437 );
1438
1439 assert_same_code!(
1440 &statement_code_and_declaration(
1441 ®,
1442 &TypeList::empty(),
1443 &CodeBundle::new("".to_string())
1444 )
1445 .to_string(),
1446 expected
1447 );
1448 }
1449
1450 #[test]
1451 fn entity_codegen_works() {
1452 let input = entity!(&["pong"]; ("op", n(0, "op"), Type::int(6)) -> Type::int(6); {
1453 (e(0); Type::int(6); Add; n(0, "op"), e(1))
1454 } => e(0));
1455
1456 let expected = indoc!(
1457 r#"
1458 module \pong (
1459 input[5:0] op_i,
1460 output[5:0] output__
1461 );
1462 `ifdef COCOTB_SIM
1463 string __top_module;
1464 string __vcd_file;
1465 initial begin
1466 if ($value$plusargs("TOP_MODULE=%s", __top_module) && __top_module == "pong" && $value$plusargs("VCD_FILENAME=%s", __vcd_file)) begin
1467 $dumpfile (__vcd_file);
1468 $dumpvars (0, \pong );
1469 end
1470 end
1471 `endif
1472 logic[5:0] \op ;
1473 assign \op = op_i;
1474 logic[5:0] _e_0;
1475 assign _e_0 = $signed(\op ) + $signed(_e_1);
1476 assign output__ = _e_0;
1477 endmodule"#
1478 );
1479
1480 assert_same_code!(
1481 &entity_code(
1482 &prepare_codegen(input.clone(), &mut ExprIdTracker::new()),
1483 &mut InstanceMap::new(),
1484 &None
1485 )
1486 .0
1487 .to_string(),
1488 expected
1489 );
1490 }
1491
1492 #[test]
1493 fn no_mangle_input_does_not_clash() {
1494 let input = spade_mir::Entity {
1495 name: spade_mir::unit_name::IntoUnitName::_test_into_unit_name("test"),
1496 inputs: vec![spade_mir::MirInput {
1497 name: "a".to_string(),
1498 val_name: ValueName::_test_named(0, "a".to_string()),
1499 ty: Type::Bool,
1500 no_mangle: Some(().nowhere()),
1501 }],
1502 output: ValueName::Expr(ExprID(0)),
1503 output_type: Type::Bool,
1504 statements: vec![],
1505 };
1506
1507 let expected = indoc!(
1508 r#"
1509 module test (
1510 input a,
1511 output output__
1512 );
1513 `ifdef COCOTB_SIM
1514 string __top_module;
1515 string __vcd_file;
1516 initial begin
1517 if ($value$plusargs("TOP_MODULE=%s", __top_module) && __top_module == "test" && $value$plusargs("VCD_FILENAME=%s", __vcd_file)) begin
1518 $dumpfile (__vcd_file);
1519 $dumpvars (0, test);
1520 end
1521 end
1522 `endif
1523 assign output__ = _e_0;
1524 endmodule"#
1525 );
1526
1527 assert_same_code!(
1528 &entity_code(
1529 &prepare_codegen(input.clone(), &mut ExprIdTracker::new()),
1530 &mut InstanceMap::new(),
1531 &None
1532 )
1533 .0
1534 .to_string(),
1535 expected
1536 );
1537 }
1538
1539 #[test]
1540 fn no_mangle_output_does_not_clash() {
1541 let input = spade_mir::Entity {
1542 name: spade_mir::unit_name::IntoUnitName::_test_into_unit_name("test"),
1543 inputs: vec![spade_mir::MirInput {
1544 name: "a".to_string(),
1545 val_name: ValueName::_test_named(0, "a".to_string()),
1546 ty: Type::Backward(Box::new(Type::Bool)),
1547 no_mangle: Some(().nowhere()),
1548 }],
1549 output: ValueName::Expr(ExprID(0)),
1550 output_type: Type::Bool,
1551 statements: vec![],
1552 };
1553
1554 let expected = indoc!(
1555 r#"
1556 module test (
1557 output a,
1558 output output__
1559 );
1560 `ifdef COCOTB_SIM
1561 string __top_module;
1562 string __vcd_file;
1563 initial begin
1564 if ($value$plusargs("TOP_MODULE=%s", __top_module) && __top_module == "test" && $value$plusargs("VCD_FILENAME=%s", __vcd_file)) begin
1565 $dumpfile (__vcd_file);
1566 $dumpvars (0, test);
1567 end
1568 end
1569 `endif
1570 logic \a_mut ;
1571 assign a = \a_mut ;
1572 assign output__ = _e_0;
1573 endmodule"#
1574 );
1575
1576 assert_same_code!(
1577 &entity_code(
1578 &prepare_codegen(input.clone(), &mut ExprIdTracker::new()),
1579 &mut InstanceMap::new(),
1580 &None
1581 )
1582 .0
1583 .to_string(),
1584 expected
1585 );
1586 }
1587
1588 #[test]
1589 fn pure_backward_input_produces_output_port() {
1590 let ty = Type::Backward(Box::new(Type::int(3)));
1591 let input = entity!(&["test"]; ("a", n(0, "a"), ty) -> Type::int(6); {
1592 (const 0; Type::int(6); crate::ConstantValue::int(3))
1593 } => e(0));
1594
1595 let expected = indoc!(
1596 r#"module \test (
1597 output[2:0] a_o,
1598 output[5:0] output__
1599 );
1600 `ifdef COCOTB_SIM
1601 string __top_module;
1602 string __vcd_file;
1603 initial begin
1604 if ($value$plusargs("TOP_MODULE=%s", __top_module) && __top_module == "test" && $value$plusargs("VCD_FILENAME=%s", __vcd_file)) begin
1605 $dumpfile (__vcd_file);
1606 $dumpvars (0, \test );
1607 end
1608 end
1609 `endif
1610 logic[2:0] \a_mut ;
1611 assign a_o = \a_mut ;
1612 localparam[5:0] _e_0 = 3;
1613 assign output__ = _e_0;
1614 endmodule"#
1615 );
1616
1617 assert_same_code!(
1618 &entity_code(
1619 &prepare_codegen(input.clone(), &mut ExprIdTracker::new()),
1620 &mut InstanceMap::new(),
1621 &None
1622 )
1623 .0
1624 .to_string(),
1625 expected
1626 );
1627 }
1628
1629 #[test]
1630 fn mixed_backward_input_works() {
1631 let ty = Type::Tuple(vec![Type::int(4), Type::Backward(Box::new(Type::int(3)))]);
1632 let input = entity!(&["test"]; ("a", n(0, "a"), ty) -> Type::int(6); {
1633 (const 0; Type::int(6); crate::ConstantValue::int(3))
1634 } => e(0));
1635
1636 let expected = indoc!(
1637 r#"module \test (
1638 input[3:0] a_i, output[2:0] a_o,
1639 output[5:0] output__
1640 );
1641 `ifdef COCOTB_SIM
1642 string __top_module;
1643 string __vcd_file;
1644 initial begin
1645 if ($value$plusargs("TOP_MODULE=%s", __top_module) && __top_module == "test" && $value$plusargs("VCD_FILENAME=%s", __vcd_file)) begin
1646 $dumpfile (__vcd_file);
1647 $dumpvars (0, \test );
1648 end
1649 end
1650 `endif
1651 logic[3:0] \a ;
1652 assign \a = a_i;
1653 logic[2:0] \a_mut ;
1654 assign a_o = \a_mut ;
1655 localparam[5:0] _e_0 = 3;
1656 assign output__ = _e_0;
1657 endmodule"#
1658 );
1659
1660 assert_same_code!(
1661 &entity_code(
1662 &prepare_codegen(input.clone(), &mut ExprIdTracker::new()),
1663 &mut InstanceMap::new(),
1664 &None
1665 )
1666 .0
1667 .to_string(),
1668 expected
1669 );
1670 }
1671
1672 #[test]
1673 fn mixed_backward_output_works() {
1674 let ty = Type::Tuple(vec![Type::int(4), Type::Backward(Box::new(Type::int(3)))]);
1675 let input = entity!("test"; () -> ty; {
1676 } => e(0));
1677
1678 let expected = indoc!(
1679 r#"module test (
1680 output[3:0] output__,
1681 input[2:0] input__
1682 );
1683 `ifdef COCOTB_SIM
1684 string __top_module;
1685 string __vcd_file;
1686 initial begin
1687 if ($value$plusargs("TOP_MODULE=%s", __top_module) && __top_module == "test" && $value$plusargs("VCD_FILENAME=%s", __vcd_file)) begin
1688 $dumpfile (__vcd_file);
1689 $dumpvars (0, test);
1690 end
1691 end
1692 `endif
1693 assign output__ = _e_0;
1694 assign _e_0_mut = input__;
1695 endmodule"#
1696 );
1697
1698 assert_same_code!(
1699 &entity_code(
1700 &prepare_codegen(input.clone(), &mut ExprIdTracker::new()),
1701 &mut InstanceMap::new(),
1702 &None
1703 )
1704 .0
1705 .to_string(),
1706 expected
1707 );
1708 }
1709
1710 #[test]
1711 fn constant_codegen_works() {
1712 let input = statement!(const 0; Type::int(10); crate::ConstantValue::int(6));
1713
1714 let expected = indoc!(
1715 r#"
1716 localparam[9:0] _e_0 = 6;"#
1717 );
1718
1719 assert_same_code!(
1720 &statement_code_and_declaration(
1721 &input,
1722 &TypeList::empty(),
1723 &CodeBundle::new("".to_string())
1724 )
1725 .to_string(),
1726 expected
1727 )
1728 }
1729
1730 #[test]
1731 fn pipeline_with_stage_references_codegens_correctly() {
1732 let inst_name = spade_mir::UnitName::_test_from_strs(&["A"]);
1733 let input = entity!(&["pl"]; (
1734 "clk", n(3, "clk"), Type::Bool,
1735 ) -> Type::int(16); {
1736 (reg n(10, "x__s1"); Type::int(16); clock(n(3, "clk")); n(0, "x_"));
1737 (e(0); Type::int(16); simple_instance((inst_name, vec![])););
1739 (n(0, "x_"); Type::int(16); Alias; e(0));
1740 (n(1, "x"); Type::int(16); Alias; n(0, "x_"));
1742 } => n(1, "x")
1743 );
1744
1745 let expected = indoc!(
1747 r#"
1748 module \pl (
1749 input clk_i,
1750 output[15:0] output__
1751 );
1752 `ifdef COCOTB_SIM
1753 string __top_module;
1754 string __vcd_file;
1755 initial begin
1756 if ($value$plusargs("TOP_MODULE=%s", __top_module) && __top_module == "pl" && $value$plusargs("VCD_FILENAME=%s", __vcd_file)) begin
1757 $dumpfile (__vcd_file);
1758 $dumpvars (0, \pl );
1759 end
1760 end
1761 `endif
1762 logic \clk ;
1763 assign \clk = clk_i;
1764 reg[15:0] \x__s1 ;
1765 logic[15:0] \x_ ;
1766 logic[15:0] \x ;
1767 always @(posedge \clk ) begin
1768 \x__s1 <= \x_ ;
1769 end
1770 \A A_0(.output__(\x_ ));
1771 assign \x = \x_ ;
1772 assign output__ = \x ;
1773 endmodule"#
1774 );
1775
1776 assert_same_code!(
1777 &entity_code(
1778 &prepare_codegen(input.clone(), &mut ExprIdTracker::new()),
1779 &mut InstanceMap::new(),
1780 &None
1781 )
1782 .0
1783 .to_string(),
1784 expected
1785 );
1786 }
1787
1788 #[test]
1789 fn duplicate_names_adds_nx() {
1790 let input = entity!(&["pl"]; (
1791 ) -> Type::int(16); {
1792 (n(1, "x"); Type::int(16); Not; e(0));
1793 (n(2, "x"); Type::int(16); Not; e(1));
1794 } => n(1, "x")
1795 );
1796
1797 let expected = indoc!(
1798 r#"
1799 module \pl (
1800 output[15:0] output__
1801 );
1802 `ifdef COCOTB_SIM
1803 string __top_module;
1804 string __vcd_file;
1805 initial begin
1806 if ($value$plusargs("TOP_MODULE=%s", __top_module) && __top_module == "pl" && $value$plusargs("VCD_FILENAME=%s", __vcd_file)) begin
1807 $dumpfile (__vcd_file);
1808 $dumpvars (0, \pl );
1809 end
1810 end
1811 `endif
1812 logic[15:0] \x ;
1813 logic[15:0] x_n1;
1814 assign \x = !_e_0;
1815 assign x_n1 = !_e_1;
1816 assign output__ = \x ;
1817 endmodule"#
1818 );
1819
1820 assert_same_code! {
1821 &entity_code(&prepare_codegen(input.clone(), &mut ExprIdTracker::new()), &mut InstanceMap::new(), &None).0.to_string(),
1822 expected
1823 }
1824 }
1825
1826 #[test]
1827 fn instance_map_is_populated() {
1828 let inst1_name = NameID(10, Path::from_strs(&["test1"]));
1829 let inst1_unit_name = spade_mir::UnitName {
1830 kind: spade_mir::unit_name::UnitNameKind::Unescaped("test1".into()),
1831 source: inst1_name.clone(),
1832 };
1833 let inst2_name = NameID(11, Path::from_strs(&["test1"]));
1834 let inst2_unit_name = spade_mir::UnitName {
1835 kind: spade_mir::unit_name::UnitNameKind::Unescaped("test1".into()),
1836 source: inst2_name.clone(),
1837 };
1838
1839 let top_name = NameID(1, Path::from_strs(&["top"]));
1840 let top_unit_name = spade_mir::UnitName {
1841 kind: spade_mir::unit_name::UnitNameKind::Unescaped("test1".into()),
1842 source: top_name.clone(),
1843 };
1844 let input = entity!(&top_unit_name; (
1845 "clk", n(3, "clk"), Type::Bool,
1846 ) -> Type::int(16); {
1847 (reg n(10, "x__s1"); Type::int(16); clock(n(3, "clk")); n(0, "x_"));
1848 (e(0); Type::int(16); Instance({
1850 name: inst1_unit_name,
1851 params: vec![],
1852 argument_names: vec![
1853 ParamName{name: "a".to_string(), no_mangle: None},
1854 ParamName{name: "b".to_string(), no_mangle: None},
1855 ],
1856 loc: None
1857 }););
1858 (e(0); Type::int(16); Instance({
1859 name: inst2_unit_name,
1860 params: vec![],
1861 argument_names: vec![
1862 ParamName{name: "a".to_string(), no_mangle: None},
1863 ParamName{name: "b".to_string(), no_mangle: None},
1864 ],
1865 loc: None
1866 }););
1867 (n(0, "x_"); Type::int(16); Alias; e(0));
1868 (n(1, "x"); Type::int(16); Alias; n(0, "x_"));
1870 } => n(1, "x")
1871 );
1872
1873 let mut instance_map = InstanceMap::new();
1874 entity_code(
1875 &prepare_codegen(input, &mut ExprIdTracker::new()),
1876 &mut instance_map,
1877 &None,
1878 );
1879
1880 let top = instance_map
1881 .inner
1882 .get(&(top_name.clone()))
1883 .expect("Failed to get top");
1884
1885 assert_eq!(
1886 top.get(&"test1_0".to_string())
1887 .expect("failed to get test1_0"),
1888 &inst1_name
1889 );
1890 assert_eq!(
1891 top.get(&"test1_1".to_string())
1892 .expect("failed to get test1_0"),
1893 &inst2_name
1894 );
1895 }
1896}
1897
1898#[cfg(test)]
1899mod backward_expression_tests {
1900 use super::*;
1901 use colored::Colorize;
1902 use spade_common::id_tracker::ExprID;
1903
1904 use crate as spade_mir;
1905 use crate::{statement, types::Type};
1906
1907 use indoc::indoc;
1908
1909 #[test]
1910 fn backward_alias_works() {
1911 let ty = Type::Backward(Box::new(Type::int(8)));
1912 let stmt = statement!(e(0); ty; Alias; e(1));
1913
1914 let expected = indoc! {
1915 r#"
1916 logic[7:0] _e_0_mut;
1917 assign _e_1_mut = _e_0_mut;"#
1918 };
1919
1920 assert_same_code!(
1921 &statement_code_and_declaration(
1922 &stmt,
1923 &TypeList::empty(),
1924 &CodeBundle::new("".to_string())
1925 )
1926 .to_string(),
1927 expected
1928 );
1929 }
1930
1931 #[test]
1932 fn backward_index_tuple_works() {
1933 let tuple_members = vec![Type::backward(Type::int(8)), Type::backward(Type::int(4))];
1934 let ty = Type::backward(Type::int(4));
1935 let stmt = statement!(e(0); ty; IndexTuple((1, tuple_members)); e(1));
1936
1937 let expected = indoc! {
1938 r#"
1939 logic[3:0] _e_0_mut;
1940 assign _e_1_mut[3:0] = _e_0_mut;"#
1941 };
1942
1943 assert_same_code!(
1944 &statement_code_and_declaration(
1945 &stmt,
1946 &TypeList::empty(),
1947 &CodeBundle::new("".to_string())
1948 )
1949 .to_string(),
1950 expected
1951 );
1952 }
1953
1954 #[test]
1955 fn flip_port_works() {
1956 let out_type = Type::Tuple(vec![Type::backward(Type::int(2)), Type::int(4)]);
1957 let stmt = statement!(e(0); out_type; FlipPort; e(1));
1958
1959 let expected = indoc! {
1960 r#"
1961 logic[3:0] _e_0;
1962 logic[1:0] _e_0_mut;
1963 assign _e_0 = _e_1_mut;
1964 assign _e_1 = _e_0_mut;"#
1965 };
1966
1967 assert_same_code!(
1968 &statement_code_and_declaration(
1969 &stmt,
1970 &TypeList::empty(),
1971 &CodeBundle::new("".to_string())
1972 )
1973 .to_string(),
1974 expected
1975 );
1976 }
1977
1978 #[test]
1979 fn construct_tuple_works() {
1980 let tuple_members = vec![Type::backward(Type::int(8)), Type::backward(Type::int(4))];
1981 let ty = Type::Tuple(tuple_members);
1982 let stmt = statement!(e(0); ty; ConstructTuple; e(1), e(2));
1983
1984 let type_list = TypeList::empty()
1985 .with(ValueName::Expr(ExprID(1)), Type::backward(Type::int(8)))
1986 .with(ValueName::Expr(ExprID(2)), Type::backward(Type::int(4)));
1987
1988 let expected = indoc! {
1989 r#"
1990 logic[11:0] _e_0_mut;
1991 assign {_e_1_mut, _e_2_mut} = _e_0_mut;"#
1992 };
1993
1994 assert_same_code!(
1995 &statement_code_and_declaration(&stmt, &type_list, &CodeBundle::new("".to_string()))
1996 .to_string(),
1997 expected
1998 );
1999 }
2000
2001 #[test]
2002 fn construct_tuple_works_on_mixed_direction_types() {
2003 let tuple_members = vec![
2004 Type::backward(Type::int(8)),
2005 Type::Tuple(vec![Type::backward(Type::int(4)), Type::int(4)]),
2006 Type::int(3),
2007 ];
2008 let ty = Type::Tuple(tuple_members);
2009 let stmt = statement!(e(0); ty; ConstructTuple; e(1), e(2), e(3));
2010
2011 let expected = indoc! {
2012 r#"
2013 logic[6:0] _e_0;
2014 logic[11:0] _e_0_mut;
2015 assign _e_0 = {_e_2, _e_3};
2016 assign {_e_1_mut, _e_2_mut} = _e_0_mut;"#
2017 };
2018
2019 let type_list = TypeList::empty()
2020 .with(ValueName::Expr(ExprID(1)), Type::backward(Type::int(8)))
2021 .with(
2022 ValueName::Expr(ExprID(2)),
2023 Type::Tuple(vec![Type::backward(Type::int(4)), Type::int(4)]),
2024 )
2025 .with(ValueName::Expr(ExprID(3)), Type::int(3));
2026
2027 assert_same_code!(
2028 &statement_code_and_declaration(&stmt, &type_list, &CodeBundle::new("".to_string()))
2029 .to_string(),
2030 expected
2031 );
2032 }
2033
2034 #[test]
2035 fn construct_array_works() {
2036 let ty = Type::Array {
2037 inner: Box::new(Type::backward(Type::int(5))),
2038 length: 3u32.to_biguint(),
2039 };
2040 let stmt = statement!(e(0); ty; ConstructArray; e(1), e(2), e(3));
2041
2042 let expected = indoc! {
2043 r#"
2044 logic[14:0] _e_0_mut;
2045 assign {_e_3_mut, _e_2_mut, _e_1_mut} = _e_0_mut;"#
2046 };
2047
2048 assert_same_code!(
2049 &statement_code_and_declaration(
2050 &stmt,
2051 &TypeList::empty(),
2052 &CodeBundle::new("".to_string())
2053 )
2054 .to_string(),
2055 expected
2056 );
2057 }
2058}
2059
2060#[cfg(test)]
2061mod expression_tests {
2062 use super::*;
2063 use colored::Colorize;
2064 use spade_codespan::Span;
2065 use spade_common::id_tracker::ExprID;
2066 use spade_common::location_info::WithLocation;
2067 use spade_common::num_ext::InfallibleToBigInt;
2068
2069 use crate::{self as spade_mir, value_name, UnitName};
2070 use crate::{statement, types::Type};
2071
2072 use indoc::{formatdoc, indoc};
2073
2074 macro_rules! binop_test {
2075 ($name:ident, $ty:expr, $verilog_ty:expr, $op:ident, $verilog_op:expr) => {
2076 #[test]
2077 fn $name() {
2078 let stmt = statement!(e(0); $ty; $op; e(1), e(2));
2079
2080 let expected = formatdoc!(
2081 r#"
2082 logic{} _e_0;
2083 assign _e_0 = _e_1 {} _e_2;"#, $verilog_ty, $verilog_op
2084 );
2085
2086 assert_same_code!(&statement_code_and_declaration(&stmt, &TypeList::empty(), &CodeBundle::new("".to_string())).to_string(), &expected)
2087 }
2088 }
2089 }
2090
2091 macro_rules! signed_binop_test {
2092 ($name:ident, $ty:expr, $verilog_ty:expr, $op:ident, $verilog_op:expr) => {
2093 #[test]
2094 fn $name() {
2095 let stmt = statement!(e(0); $ty; $op; e(1), e(2));
2096
2097 let expected = formatdoc!(
2098 r#"
2099 logic{} _e_0;
2100 assign _e_0 = $signed(_e_1) {} $signed(_e_2);"#, $verilog_ty, $verilog_op
2101 );
2102
2103 assert_same_code!(&statement_code_and_declaration(&stmt, &TypeList::empty(), &CodeBundle::new("".to_string())).to_string(), &expected)
2104 }
2105 }
2106 }
2107
2108 macro_rules! unop_test {
2109 ($name:ident, $ty:expr, $verilog_ty:expr, $op:ident, $verilog_op:expr) => {
2110 #[test]
2111 fn $name() {
2112 let stmt = statement!(e(0); $ty; $op; e(1));
2113
2114 let expected = formatdoc!(
2115 r#"
2116 logic{} _e_0;
2117 assign _e_0 = {}_e_1;"#, $verilog_ty, $verilog_op
2118 );
2119
2120 assert_same_code!(&statement_code_and_declaration(&stmt, &TypeList::empty(), &CodeBundle::new("".to_string())).to_string(), &expected)
2121 }
2122 }
2123 }
2124
2125 signed_binop_test!(binop_add_works, Type::int(2), "[1:0]", Add, "+");
2126 signed_binop_test!(binop_sub_works, Type::int(2), "[1:0]", Sub, "-");
2127 signed_binop_test!(binop_mul_works, Type::int(2), "[1:0]", Mul, "*");
2128 binop_test!(
2129 binop_left_shift_works,
2130 Type::int(2),
2131 "[1:0]",
2132 LeftShift,
2133 "<<"
2134 );
2135 binop_test!(
2136 binop_right_shift_works,
2137 Type::int(2),
2138 "[1:0]",
2139 RightShift,
2140 ">>"
2141 );
2142 signed_binop_test!(
2143 binop_arithmetic_right_shift_works,
2144 Type::int(2),
2145 "[1:0]",
2146 ArithmeticRightShift,
2147 ">>>"
2148 );
2149 binop_test!(binop_eq_works, Type::Bool, "", Eq, "==");
2150 signed_binop_test!(binop_gt_works, Type::Bool, "", Gt, ">");
2151 signed_binop_test!(binop_lt_works, Type::Bool, "", Lt, "<");
2152 signed_binop_test!(binop_ge_works, Type::Bool, "", Ge, ">=");
2153 signed_binop_test!(binop_le_works, Type::Bool, "", Le, "<=");
2154 binop_test!(binop_logical_and_works, Type::Bool, "", LogicalAnd, "&&");
2155 binop_test!(binop_logical_or_works, Type::Bool, "", LogicalOr, "||");
2156 binop_test!(bitwise_xor_works, Type::int(32), "[31:0]", BitwiseXor, "^");
2157 binop_test!(logical_xor_works, Type::Bool, "", LogicalXor, "^");
2159 unop_test!(not_works, Type::Bool, "", Not, "!");
2160 unop_test!(usub_works, Type::int(2), "[1:0]", USub, "-");
2161
2162 #[test]
2163 fn select_operator_works() {
2164 let stmt = statement!(e(0); Type::int(2); Select; e(1), e(2), e(3));
2165
2166 let expected = indoc!(
2167 r#"
2168 logic[1:0] _e_0;
2169 assign _e_0 = _e_1 ? _e_2 : _e_3;"#
2170 );
2171
2172 assert_same_code!(
2173 &statement_code_and_declaration(
2174 &stmt,
2175 &TypeList::empty(),
2176 &CodeBundle::new("".to_string())
2177 )
2178 .to_string(),
2179 expected
2180 );
2181 }
2182
2183 #[test]
2184 fn not_operator_works() {
2185 let stmt = statement!(e(0); Type::Bool; LogicalNot; e(1));
2186
2187 let expected = indoc!(
2188 r#"
2189 logic _e_0;
2190 assign _e_0 = !_e_1;"#
2191 );
2192
2193 assert_same_code!(
2194 &statement_code_and_declaration(
2195 &stmt,
2196 &TypeList::empty(),
2197 &CodeBundle::new("".to_string())
2198 )
2199 .to_string(),
2200 expected
2201 );
2202 }
2203
2204 #[test]
2205 fn match_operator_works() {
2206 let stmt = statement!(e(0); Type::int(2); Match; e(1), e(2), e(3), e(4));
2207
2208 let expected = indoc!(
2209 r#"
2210 logic[1:0] _e_0;
2211 always_comb begin
2212 priority casez ({_e_1, _e_3})
2213 2'b1?: _e_0 = _e_2;
2214 2'b01: _e_0 = _e_4;
2215 2'b?: _e_0 = 2'dx;
2216 endcase
2217 end"#
2218 );
2219
2220 assert_same_code!(
2221 &statement_code_and_declaration(
2222 &stmt,
2223 &TypeList::empty(),
2224 &CodeBundle::new("".to_string())
2225 )
2226 .to_string(),
2227 expected
2228 );
2229 }
2230
2231 #[test]
2232 fn boolean_constants_are_1_and_0() {
2233 let stmt = statement!(const 0; Type::Bool; ConstantValue::Bool(true));
2234
2235 let expected = indoc!(
2236 r#"
2237 localparam[0:0] _e_0 = 1;"#
2238 );
2239
2240 assert_same_code!(
2241 &statement_code_and_declaration(
2242 &stmt,
2243 &TypeList::empty(),
2244 &CodeBundle::new("".to_string())
2245 )
2246 .to_string(),
2247 expected
2248 );
2249 }
2250
2251 #[test]
2252 fn tuple_assembly_operator_works() {
2253 let ty = Type::Tuple(vec![Type::int(6), Type::int(3)]);
2254 let stmt = statement!(e(0); ty; ConstructTuple; e(1), e(2));
2255
2256 let expected = indoc!(
2257 r#"
2258 logic[8:0] _e_0;
2259 assign _e_0 = {_e_1, _e_2};"#
2260 );
2261
2262 assert_same_code!(
2263 &statement_code_and_declaration(
2264 &stmt,
2265 &TypeList::empty()
2266 .with(ValueName::Expr(ExprID(1)), Type::int(6))
2267 .with(ValueName::Expr(ExprID(2)), Type::int(3)),
2268 &CodeBundle::new("".to_string())
2269 )
2270 .to_string(),
2271 expected
2272 );
2273 }
2274
2275 #[test]
2276 fn enum_construction_operator_works() {
2277 let ty = Type::Enum(vec![vec![], vec![], vec![Type::int(10), Type::int(5)]]);
2278 let stmt = statement!(e(0); ty; ConstructEnum({variant: 2, variant_count: 3}); e(1), e(2));
2279
2280 let expected = indoc!(
2281 r#"
2282 logic[16:0] _e_0;
2283 assign _e_0 = {2'd2, _e_1, _e_2};"#
2284 );
2285
2286 assert_same_code!(
2287 &statement_code_and_declaration(
2288 &stmt,
2289 &TypeList::empty(),
2290 &CodeBundle::new("".to_string())
2291 )
2292 .to_string(),
2293 expected
2294 );
2295 }
2296
2297 #[test]
2298 fn is_enum_variant_operator_works() {
2299 let ty = Type::Enum(vec![vec![], vec![], vec![Type::int(10), Type::int(5)]]);
2300 let stmt = statement!(e(0); Type::Bool; IsEnumVariant({variant: 2, enum_type: ty}); e(1));
2301
2302 let expected = indoc!(
2303 r#"
2304 logic _e_0;
2305 assign _e_0 = _e_1[16:15] == 2'd2;"#
2306 );
2307
2308 assert_same_code!(
2309 &statement_code_and_declaration(
2310 &stmt,
2311 &TypeList::empty(),
2312 &CodeBundle::new("".to_string())
2313 )
2314 .to_string(),
2315 expected
2316 );
2317 }
2318
2319 #[test]
2320 fn is_enum_variant_operator_works_for_1_wide_tags() {
2321 let ty = Type::Enum(vec![vec![], vec![Type::int(10), Type::int(5)]]);
2322 let stmt = statement!(e(0); Type::Bool; IsEnumVariant({variant: 1, enum_type: ty}); e(1));
2323
2324 let expected = indoc!(
2325 r#"
2326 logic _e_0;
2327 assign _e_0 = _e_1[15] == 1'd1;"#
2328 );
2329
2330 assert_same_code!(
2331 &statement_code_and_declaration(
2332 &stmt,
2333 &TypeList::empty(),
2334 &CodeBundle::new("".to_string())
2335 )
2336 .to_string(),
2337 expected
2338 );
2339 }
2340
2341 #[test]
2342 fn enum_member_access_operator_works() {
2343 let ty = Type::Enum(vec![vec![], vec![], vec![Type::int(10), Type::int(5)]]);
2344 let stmt = statement!(e(0); Type::int(5); EnumMember({variant: 2, member_index: 1, enum_type: ty}); e(1));
2345
2346 let expected = indoc!(
2347 r#"
2348 logic[4:0] _e_0;
2349 assign _e_0 = _e_1[4:0];"#
2350 );
2351
2352 assert_same_code!(
2353 &statement_code_and_declaration(
2354 &stmt,
2355 &TypeList::empty(),
2356 &CodeBundle::new("".to_string())
2357 )
2358 .to_string(),
2359 expected
2360 );
2361 }
2362
2363 #[test]
2364 fn enum_construction_inserts_padding_undef_where_needed() {
2365 let ty = Type::Enum(vec![
2366 vec![],
2367 vec![Type::int(5)],
2368 vec![Type::int(10), Type::int(5)],
2369 ]);
2370 let stmt = statement!(e(0); ty; ConstructEnum({variant: 1, variant_count: 3}); e(1));
2371
2372 let expected = indoc!(
2373 r#"
2374 logic[16:0] _e_0;
2375 assign _e_0 = {2'd1, _e_1, 10'bX};"#
2376 );
2377
2378 assert_same_code!(
2379 &statement_code_and_declaration(
2380 &stmt,
2381 &TypeList::empty(),
2382 &CodeBundle::new("".to_string())
2383 )
2384 .to_string(),
2385 expected
2386 );
2387 }
2388
2389 #[test]
2390 fn tuple_indexing_works_for_first_value() {
2391 let ty = vec![Type::int(6), Type::int(3)];
2392 let stmt = statement!(e(0); Type::int(6); IndexTuple((0, ty)); e(1));
2393
2394 let expected = indoc!(
2395 r#"
2396 logic[5:0] _e_0;
2397 assign _e_0 = _e_1[8:3];"#
2398 );
2399
2400 assert_same_code!(
2401 &statement_code_and_declaration(
2402 &stmt,
2403 &TypeList::empty(),
2404 &CodeBundle::new("".to_string())
2405 )
2406 .to_string(),
2407 expected
2408 );
2409 }
2410 #[test]
2411 fn tuple_indexing_works() {
2412 let ty = vec![Type::int(6), Type::int(3)];
2413 let stmt = statement!(e(0); Type::int(6); IndexTuple((1, ty)); e(1));
2414
2415 let expected = indoc!(
2416 r#"
2417 logic[5:0] _e_0;
2418 assign _e_0 = _e_1[2:0];"#
2419 );
2420
2421 assert_same_code!(
2422 &statement_code_and_declaration(
2423 &stmt,
2424 &TypeList::empty(),
2425 &CodeBundle::new("".to_string())
2426 )
2427 .to_string(),
2428 expected
2429 );
2430 }
2431
2432 #[test]
2433 fn tuple_indexing_works_for_bools() {
2434 let ty = vec![Type::Bool, Type::int(3)];
2435 let stmt = statement!(e(0); Type::Bool; IndexTuple((0, ty)); e(1));
2436
2437 let expected = indoc!(
2438 r#"
2439 logic _e_0;
2440 assign _e_0 = _e_1[3];"#
2441 );
2442
2443 assert_same_code!(
2444 &statement_code_and_declaration(
2445 &stmt,
2446 &TypeList::empty(),
2447 &CodeBundle::new("".to_string())
2448 )
2449 .to_string(),
2450 expected
2451 );
2452 }
2453
2454 #[test]
2455 fn large_negative_literals_codegen_correctly() {
2456 let statement = statement!(const 0; Type::int(64); ConstantValue::int(-1));
2457
2458 let expected = indoc!(
2459 r#"
2460 localparam[63:0] _e_0 = -64'd1;"#
2461 );
2462
2463 assert_same_code!(
2464 &statement_code_and_declaration(
2465 &statement,
2466 &TypeList::empty(),
2467 &CodeBundle::new("".to_string())
2468 )
2469 .to_string(),
2470 expected
2471 );
2472 }
2473
2474 #[test]
2475 fn array_literals_work() {
2476 let ty = Type::Array {
2477 inner: Box::new(Type::int(3)),
2478 length: 3u32.to_biguint(),
2479 };
2480 let statement = statement!(e(0); ty; ConstructArray; e(1), e(2), e(3));
2481
2482 let expected = indoc!(
2483 r#"
2484 logic[8:0] _e_0;
2485 assign _e_0 = {_e_3, _e_2, _e_1};"#
2486 );
2487
2488 assert_same_code!(
2489 &statement_code_and_declaration(
2490 &statement,
2491 &TypeList::empty(),
2492 &CodeBundle::new("".to_string())
2493 )
2494 .to_string(),
2495 expected
2496 );
2497 }
2498
2499 #[test]
2500 fn array_indexing_works() {
2501 let statement =
2502 statement!(e(0); Type::int(3); IndexArray({array_size: 3u32.to_biguint()}); e(1), e(2));
2503
2504 let expected = indoc!(
2505 r#"
2506 logic[2:0] _e_0;
2507 assign _e_0 = _e_1[_e_2 * 3+:3];"#
2508 );
2509
2510 assert_same_code!(
2511 &statement_code_and_declaration(
2512 &statement,
2513 &TypeList::empty(),
2514 &CodeBundle::new("".to_string())
2515 )
2516 .to_string(),
2517 expected
2518 );
2519 }
2520
2521 #[test]
2522 fn array_indexing_works_for_1_bit_values() {
2523 let statement =
2524 statement!(e(0); Type::Bool; IndexArray({array_size: 4u32.to_biguint()}); e(1), e(2));
2525
2526 let expected = indoc!(
2527 r#"
2528 logic _e_0;
2529 assign _e_0 = _e_1[_e_2];"#
2530 );
2531
2532 assert_same_code!(
2533 &statement_code_and_declaration(
2534 &statement,
2535 &TypeList::empty(),
2536 &CodeBundle::new("".to_string())
2537 )
2538 .to_string(),
2539 expected
2540 );
2541 }
2542
2543 #[test]
2544 fn array_indexing_works_for_1_element_bool_arrays() {
2545 let statement =
2546 statement!(e(0); Type::Bool; IndexArray({array_size: 1u32.to_biguint()}); e(1), e(2));
2547
2548 let expected = indoc!(
2549 r#"
2550 logic _e_0;
2551 assign _e_0 = _e_1;"#
2552 );
2553
2554 assert_same_code!(
2555 &statement_code_and_declaration(
2556 &statement,
2557 &TypeList::empty(),
2558 &CodeBundle::new("".to_string())
2559 )
2560 .to_string(),
2561 expected
2562 );
2563 }
2564
2565 #[test]
2566 fn array_indexing_works_for_1_element_int_arrays() {
2567 let statement = statement!(e(0); Type::Int(10u32.to_biguint()); IndexArray({array_size: 1u32.to_biguint()}); e(1), e(2));
2568
2569 let expected = indoc!(
2570 r#"
2571 logic[9:0] _e_0;
2572 assign _e_0 = _e_1;"#
2573 );
2574
2575 assert_same_code!(
2576 &statement_code_and_declaration(
2577 &statement,
2578 &TypeList::empty(),
2579 &CodeBundle::new("".to_string())
2580 )
2581 .to_string(),
2582 expected
2583 );
2584 }
2585
2586 #[test]
2587 fn range_array_indexing_works() {
2588 let ty = Type::Array {
2589 inner: Box::new(Type::int(10)),
2590 length: 2u32.to_biguint(),
2591 };
2592 let statement = statement!(e(0); ty; RangeIndexArray({
2593 start: 1u32.to_biguint(),
2594 end_exclusive: 2u32.to_biguint(),
2595 in_array_size: 4u32.to_biguint()
2596 }); e(1), e(2));
2597
2598 let expected = indoc!(
2599 r#"
2600 logic[19:0] _e_0;
2601 assign _e_0 = _e_1[19-:10];"#
2602 );
2603
2604 assert_same_code!(
2605 &statement_code_and_declaration(
2606 &statement,
2607 &TypeList::empty(),
2608 &CodeBundle::new("".to_string())
2609 )
2610 .to_string(),
2611 expected
2612 );
2613 }
2614
2615 #[test]
2616 fn range_array_indexing_on_bool_array_works() {
2617 let ty = Type::Array {
2618 inner: Box::new(Type::Bool),
2619 length: 2u32.to_biguint(),
2620 };
2621 let statement = statement!(e(0); ty; RangeIndexArray({
2622 start: 1u32.to_biguint(),
2623 end_exclusive: 2u32.to_biguint(),
2624 in_array_size: 4u32.to_biguint()
2625 }); e(1), e(2));
2626
2627 let expected = indoc!(
2628 r#"
2629 logic[1:0] _e_0;
2630 assign _e_0 = _e_1[1];"#
2631 );
2632
2633 assert_same_code!(
2634 &statement_code_and_declaration(
2635 &statement,
2636 &TypeList::empty(),
2637 &CodeBundle::new("".to_string())
2638 )
2639 .to_string(),
2640 expected
2641 );
2642 }
2643
2644 #[test]
2645 fn range_array_indexing_on_single_element_array_works() {
2646 let ty = Type::Array {
2647 inner: Box::new(Type::int(10)),
2648 length: 1u32.to_biguint(),
2649 };
2650 let statement = statement!(e(0); ty; RangeIndexArray({
2651 start: 1u32.to_biguint(),
2652 end_exclusive: 2u32.to_biguint(),
2653 in_array_size: 1u32.to_biguint()
2654 }); e(1), e(2));
2655
2656 let expected = indoc!(
2657 r#"
2658 logic[9:0] _e_0;
2659 assign _e_0 = _e_1;"#
2660 );
2661
2662 assert_same_code!(
2663 &statement_code_and_declaration(
2664 &statement,
2665 &TypeList::empty(),
2666 &CodeBundle::new("".to_string())
2667 )
2668 .to_string(),
2669 expected
2670 );
2671 }
2672
2673 #[test]
2674 fn entity_instantiation_works() {
2675 let inst_name = UnitName::_test_from_strs(&["e_test"]);
2676 let stmt = statement!(
2677 e(0); Type::Bool; Instance({
2678 name: inst_name,
2679 params: vec![],
2680 argument_names: vec![
2681 ParamName{name: "a".to_string(), no_mangle: None},
2682 ParamName{name: "b".to_string(), no_mangle: None},
2683 ],
2684 loc: None
2685 });
2686 e(1),
2687 e(2)
2688 );
2689
2690 let expected = indoc!(
2691 r#"
2692 logic _e_0;
2693 \e_test e_test_0(.a_i(_e_1), .b_i(_e_2), .output__(_e_0));"#
2694 );
2695
2696 assert_same_code!(
2697 &statement_code_and_declaration(
2698 &stmt,
2699 &TypeList::empty()
2700 .with(ValueName::Expr(ExprID(1)), Type::Bool)
2701 .with(ValueName::Expr(ExprID(2)), Type::Bool),
2702 &CodeBundle::new("".to_string())
2703 )
2704 .to_string(),
2705 expected
2706 );
2707 }
2708
2709 #[test]
2710 fn entity_instantiation_with_back_and_forward_ports_works() {
2711 let inst_name = UnitName::_test_from_strs(&["e_test"]);
2712 let ty = Type::Tuple(vec![Type::backward(Type::Bool), Type::Bool]);
2713 let stmt = statement!(e(0); ty; Instance({
2714 name: inst_name,
2715 params: vec![],
2716 argument_names: vec![
2717 ParamName{name: "a".to_string(), no_mangle: None},
2718 ParamName{name: "b".to_string(), no_mangle: None},
2719 ],
2720 loc: None
2721 }); e(1), e(2));
2722
2723 let expected = indoc!(
2724 r#"
2725 logic _e_0;
2726 logic _e_0_mut;
2727 \e_test e_test_0(.a_i(_e_1), .b_i(_e_2), .output__(_e_0), .input__(_e_0_mut));"#
2728 );
2729
2730 assert_same_code!(
2731 &statement_code_and_declaration(
2732 &stmt,
2733 &TypeList::empty()
2734 .with(ValueName::Expr(ExprID(1)), Type::Bool)
2735 .with(ValueName::Expr(ExprID(2)), Type::Bool),
2736 &CodeBundle::new("".to_string())
2737 )
2738 .to_string(),
2739 expected
2740 );
2741 }
2742
2743 #[test]
2744 fn entity_instantiation_with_back_ports_works() {
2745 let ty = Type::backward(Type::Bool);
2746 let stmt = statement!(e(0); ty; Instance({
2747 name:UnitName::_test_from_strs(&["e_test"]),
2748 params: vec![],
2749 argument_names: vec![
2750 ParamName{name: "a".to_string(), no_mangle: None},
2751 ParamName{name: "b".to_string(), no_mangle: None},
2752 ],
2753 loc: None
2754 }); e(1), e(2));
2755
2756 let expected = indoc!(
2757 r#"
2758 logic _e_0_mut;
2759 \e_test e_test_0(.a_i(_e_1), .b_i(_e_2), .input__(_e_0_mut));"#
2760 );
2761
2762 assert_same_code!(
2763 &statement_code_and_declaration(
2764 &stmt,
2765 &TypeList::empty()
2766 .with(ValueName::Expr(ExprID(1)), Type::Bool)
2767 .with(ValueName::Expr(ExprID(2)), Type::Bool),
2768 &CodeBundle::new("".to_string())
2769 )
2770 .to_string(),
2771 expected
2772 );
2773 }
2774
2775 #[test]
2776 fn entity_instantiation_with_back_inputs_works() {
2777 let ty = Type::Bool;
2778 let stmt = statement!(e(0); ty; Instance({
2779 name:UnitName::_test_from_strs(&["test"]),
2780 params: vec![],
2781 argument_names: vec![
2782 ParamName{name: "a".to_string(), no_mangle: None},
2783 ParamName{name: "b".to_string(), no_mangle: None},
2784 ],
2785 loc: None
2786 }); e(1), e(2));
2787
2788 let expected = indoc!(
2789 r#"
2790 logic _e_0;
2791 \test test_0(.a_i(_e_1), .a_o(_e_1_mut), .b_o(_e_2_mut), .output__(_e_0));"#
2792 );
2793
2794 let type_list = TypeList::empty()
2795 .with(
2796 ValueName::Expr(ExprID(1)),
2797 Type::Tuple(vec![Type::Bool, Type::backward(Type::Bool)]),
2798 )
2799 .with(ValueName::Expr(ExprID(2)), Type::backward(Type::Bool));
2800
2801 assert_same_code!(
2802 &statement_code_and_declaration(&stmt, &type_list, &CodeBundle::new("".to_string()))
2803 .to_string(),
2804 expected
2805 );
2806 }
2807
2808 #[test]
2809 fn decl_clocked_array_works() {
2810 let t = Type::Array {
2811 inner: Box::new(Type::int(6)),
2812 length: 4u32.to_biguint(),
2813 };
2814 let stmt = statement!(e(0); t; DeclClockedMemory({
2815 write_ports: 2u32.to_biguint(),
2816 addr_w: 4u32.to_biguint(),
2817 inner_w: 6u32.to_biguint(),
2818 elems: 16u32.to_biguint(),
2819 initial: None
2820 }); e(1), e(2));
2821
2822 let expected = indoc!(
2825 r#"
2826 logic[23:0] _e_0;
2827 always @(posedge _e_1) begin
2828 if (_e_2[10]) begin
2829 _e_0[_e_2[9:6]] <= _e_2[5:0];
2830 end
2831 if (_e_2[21]) begin
2832 _e_0[_e_2[20:17]] <= _e_2[16:11];
2833 end
2834 end"#
2835 );
2836
2837 assert_same_code!(
2838 &statement_code_and_declaration(
2839 &stmt,
2840 &TypeList::empty(),
2841 &CodeBundle::new("".to_string())
2842 )
2843 .to_string(),
2844 expected
2845 );
2846 }
2847
2848 #[test]
2849 fn decl_clocked_array_with_1_bit_address_works() {
2850 let t = Type::Array {
2851 inner: Box::new(Type::int(6)),
2852 length: 4u32.to_biguint(),
2853 };
2854 let stmt = statement!(e(0); t; DeclClockedMemory({
2855 write_ports: 1u32.to_biguint(),
2856 addr_w: 1u32.to_biguint(),
2857 inner_w: 6u32.to_biguint(),
2858 elems: 16u32.to_biguint(),
2859 initial: None
2860 }); e(1), e(2));
2861
2862 let expected = indoc!(
2863 r#"
2864 logic[23:0] _e_0;
2865 always @(posedge _e_1) begin
2866 if (_e_2[7]) begin
2867 _e_0[_e_2[6]] <= _e_2[5:0];
2868 end
2869 end"#
2870 );
2871
2872 assert_same_code!(
2873 &statement_code_and_declaration(
2874 &stmt,
2875 &TypeList::empty(),
2876 &CodeBundle::new("".to_string())
2877 )
2878 .to_string(),
2879 expected
2880 );
2881 }
2882
2883 #[test]
2884 fn decl_clocked_array_with_1_bit_data_works() {
2885 let t = Type::Array {
2886 inner: Box::new(Type::Bool),
2887 length: 4u32.to_biguint(),
2888 };
2889 let stmt = statement!(e(0); t; DeclClockedMemory({
2890 write_ports: 1u32.to_biguint(),
2891 addr_w: 4u32.to_biguint(),
2892 inner_w: 1u32.to_biguint(),
2893 elems: 16u32.to_biguint(),
2894 initial: None
2895 }); e(1), e(2));
2896
2897 let expected = indoc!(
2900 r#"
2901 logic[3:0] _e_0;
2902 always @(posedge _e_1) begin
2903 if (_e_2[5]) begin
2904 _e_0[_e_2[4:1]] <= _e_2[0];
2905 end
2906 end"#
2907 );
2908
2909 assert_same_code!(
2910 &statement_code_and_declaration(
2911 &stmt,
2912 &TypeList::empty(),
2913 &CodeBundle::new("".to_string())
2914 )
2915 .to_string(),
2916 expected
2917 );
2918 }
2919
2920 #[test]
2921 fn decl_clocked_memory_with_initial_works() {
2922 let t = Type::Array {
2923 inner: Box::new(Type::Int(6u32.to_biguint())),
2924 length: 4u32.to_biguint(),
2925 };
2926 let stmt = statement!(e(0); t; DeclClockedMemory({
2927 write_ports: 2u32.to_biguint(),
2928 addr_w: 4u32.to_biguint(),
2929 inner_w: 6u32.to_biguint(),
2930 elems: 16u32.to_biguint(),
2931 initial: Some(vec![
2932 vec![statement!(const 10; Type::Int(6u32.to_biguint()); ConstantValue::Int(10.to_bigint()))],
2933 vec![statement!(const 10; Type::Int(6u32.to_biguint()); ConstantValue::Int(5.to_bigint()))],
2934 ])
2935 }); e(1), e(2));
2936
2937 let expected = indoc!(
2940 r#"
2941 logic[23:0] _e_0;
2942 initial begin
2943 _e_0[0] = 'b001010;
2944 _e_0[1] = 'b000101;
2945 end
2946 always @(posedge _e_1) begin
2947 if (_e_2[10]) begin
2948 _e_0[_e_2[9:6]] <= _e_2[5:0];
2949 end
2950 if (_e_2[21]) begin
2951 _e_0[_e_2[20:17]] <= _e_2[16:11];
2952 end
2953 end"#
2954 );
2955
2956 assert_same_code!(
2957 &statement_code_and_declaration(
2958 &stmt,
2959 &TypeList::empty(),
2960 &CodeBundle::new("".to_string())
2961 )
2962 .to_string(),
2963 expected
2964 );
2965 }
2966
2967 #[test]
2968 fn truncate_works() {
2969 let stmt = statement!(e(0); Type::int(5); Truncate; e(1));
2970
2971 let expected = indoc! {
2972 r#"
2973 logic[4:0] _e_0;
2974 assign _e_0 = _e_1[4:0];"#
2975 };
2976
2977 assert_same_code!(
2978 &statement_code_and_declaration(
2979 &stmt,
2980 &TypeList::empty(),
2981 &CodeBundle::new("".to_string())
2982 )
2983 .to_string(),
2984 expected
2985 );
2986 }
2987
2988 #[test]
2989 fn sext_works_for_many_bits() {
2990 let stmt = statement!(e(0); Type::int(5); SignExtend({extra_bits: 2u32.to_biguint(), operand_size: 3u32.to_biguint()}); e(1));
2991
2992 let expected = indoc! {
2993 r#"
2994 logic[4:0] _e_0;
2995 assign _e_0 = {{ 2 { _e_1[2] }}, _e_1};"#
2996 };
2997
2998 assert_same_code!(
2999 &statement_code_and_declaration(
3000 &stmt,
3001 &TypeList::empty(),
3002 &CodeBundle::new("".to_string())
3003 )
3004 .to_string(),
3005 expected
3006 );
3007 }
3008 #[test]
3009 fn sext_works_for_one_bits() {
3010 let stmt = statement!(e(0); Type::int(4); SignExtend({extra_bits: 1u32.to_biguint(), operand_size: 3u32.to_biguint()}); e(1));
3011
3012 let expected = indoc! {
3013 r#"
3014 logic[3:0] _e_0;
3015 assign _e_0 = {_e_1[2], _e_1};"#
3016 };
3017
3018 assert_same_code!(
3019 &statement_code_and_declaration(
3020 &stmt,
3021 &TypeList::empty(),
3022 &CodeBundle::new("".to_string())
3023 )
3024 .to_string(),
3025 expected
3026 );
3027 }
3028 #[test]
3029 fn sext_works_for_zero_bits() {
3030 let stmt = statement!(e(0); Type::int(3); SignExtend({extra_bits: 0u32.to_biguint(), operand_size: 3u32.to_biguint()}); e(1));
3031
3032 let expected = indoc! {
3033 r#"
3034 logic[2:0] _e_0;
3035 assign _e_0 = _e_1;"#
3036 };
3037
3038 assert_same_code!(
3039 &statement_code_and_declaration(
3040 &stmt,
3041 &TypeList::empty(),
3042 &CodeBundle::new("".to_string())
3043 )
3044 .to_string(),
3045 expected
3046 );
3047 }
3048
3049 #[test]
3050 fn zext_works_for_many_bits() {
3051 let stmt =
3052 statement!(e(0); Type::int(5); ZeroExtend({extra_bits: 2u32.to_biguint()}); e(1));
3053
3054 let expected = indoc! {
3055 r#"
3056 logic[4:0] _e_0;
3057 assign _e_0 = {2'b0, _e_1};"#
3058 };
3059
3060 assert_same_code!(
3061 &statement_code_and_declaration(
3062 &stmt,
3063 &TypeList::empty(),
3064 &CodeBundle::new("".to_string())
3065 )
3066 .to_string(),
3067 expected
3068 );
3069 }
3070 #[test]
3071 fn zext_works_for_one_bits() {
3072 let stmt =
3073 statement!(e(0); Type::int(4); ZeroExtend({extra_bits: 1u32.to_biguint()}); e(1));
3074
3075 let expected = indoc! {
3076 r#"
3077 logic[3:0] _e_0;
3078 assign _e_0 = {1'b0, _e_1};"#
3079 };
3080
3081 assert_same_code!(
3082 &statement_code_and_declaration(
3083 &stmt,
3084 &TypeList::empty(),
3085 &CodeBundle::new("".to_string())
3086 )
3087 .to_string(),
3088 expected
3089 );
3090 }
3091
3092 #[test]
3093 fn zext_works_for_zero_bits() {
3094 let stmt =
3095 statement!(e(0); Type::int(3); ZeroExtend({extra_bits: 0u32.to_biguint()}); e(1));
3096
3097 let expected = indoc! {
3098 r#"
3099 logic[2:0] _e_0;
3100 assign _e_0 = _e_1;"#
3101 };
3102
3103 assert_same_code!(
3104 &statement_code_and_declaration(
3105 &stmt,
3106 &TypeList::empty(),
3107 &CodeBundle::new("".to_string())
3108 )
3109 .to_string(),
3110 expected
3111 );
3112 }
3113
3114 #[test]
3115 fn div_pow2_works() {
3116 let stmt = statement!(e(0); Type::int(3); DivPow2; e(1), e(2));
3117
3118 let expected = indoc! {
3119 r#"
3120 logic[2:0] _e_0;
3121 always_comb begin
3122 if (_e_2 == 0) begin
3123 _e_0 = _e_1;
3124 end
3125 else begin
3126 _e_0 = $signed($signed(_e_1) + $signed(1 << (_e_2 - 1))) >>> $signed(_e_2);
3127 end
3128 end"#
3129 };
3130
3131 assert_same_code!(
3132 &statement_code_and_declaration(
3133 &stmt,
3134 &TypeList::empty(),
3135 &CodeBundle::new("".to_string())
3136 )
3137 .to_string(),
3138 expected
3139 )
3140 }
3141
3142 #[test]
3143 fn concat_works() {
3144 let stmt = statement!(e(0); Type::int(8); Concat; e(1), e(2));
3145
3146 let expected = indoc! {
3147 r#"
3148 logic[7:0] _e_0;
3149 assign _e_0 = {_e_1, _e_2};"#
3150 };
3151
3152 assert_same_code!(
3153 &statement_code_and_declaration(
3154 &stmt,
3155 &TypeList::empty(),
3156 &CodeBundle::new("".to_string())
3157 )
3158 .to_string(),
3159 expected
3160 );
3161 }
3162
3163 #[test]
3164 fn assertion_codegen_works() {
3165 let stmt = Statement::Assert(value_name!(e(0)).at(0, &Span::new(1, 2)));
3166
3167 let expected = indoc! {
3172 "
3173 `ifndef SYNTHESIS
3174 always @(_e_0) begin
3175 #0
3176 assert (_e_0)
3177 else begin
3178 $display(\"\x1b[0m\x1b[1m\x1b[38;5;9merror\x1b[0m\x1b[1m: Assertion failed\x1b[0m\");
3179 $display(\" \x1b[0m\x1b[34m┌─\x1b[0m <str>:1:2\");
3180 $display(\" \x1b[0m\x1b[34m│\x1b[0m\");
3181 $display(\"\x1b[0m\x1b[34m1\x1b[0m \x1b[0m\x1b[34m│\x1b[0m a\x1b[0m\x1b[38;5;9mb\x1b[0mcd\");
3182 $display(\" \x1b[0m\x1b[34m│\x1b[0m \x1b[0m\x1b[38;5;9m^\x1b[0m \x1b[0m\x1b[38;5;9mThis expression is false\x1b[0m\");
3183 $display(\"\");
3184 $error(\"Assertion failed\");
3185 $fatal(1);
3186 end
3187 end
3188 `endif"
3189 };
3190
3191 let source_code = CodeBundle::new("abcd".to_string());
3192
3193 assert_same_code!(
3194 &statement_code_and_declaration(&stmt, &TypeList::empty(), &source_code).to_string(),
3195 expected
3196 );
3197 }
3198
3199 #[test]
3200 fn set_codegen_works() {
3201 let stmt = Statement::Set {
3202 target: value_name!(e(0)).nowhere(),
3203 value: value_name!(e(1)).nowhere(),
3204 };
3205
3206 let expected = indoc! {
3207 r#"
3208 assign _e_0_mut = _e_1;"#
3209 };
3210
3211 assert_same_code!(
3212 &statement_code_and_declaration(
3213 &stmt,
3214 &TypeList::empty(),
3215 &CodeBundle::new("".to_string())
3216 )
3217 .to_string(),
3218 expected
3219 );
3220 }
3221
3222 #[test]
3223 fn read_mut_wire_codegen_works() {
3224 let stmt = statement!(e(0); Type::int(8); ReadPort; e(1));
3225
3226 let expected = indoc! {
3227 r#"
3228 logic[7:0] _e_0;
3229 assign _e_0 = _e_1_mut;"#
3230 };
3231
3232 assert_same_code!(
3233 &statement_code_and_declaration(
3234 &stmt,
3235 &TypeList::empty(),
3236 &CodeBundle::new("".to_string())
3237 )
3238 .to_string(),
3239 expected
3240 );
3241 }
3242
3243 #[test]
3244 fn const_codegen_large_bit_width_works() {
3245 let stmt = statement!(const 0; Type::int(32); crate::ConstantValue::int(3));
3246
3247 let expected = indoc! {
3248 r#"
3249 localparam[31:0] _e_0 = 32'd3;"#
3250 };
3251
3252 assert_same_code!(
3253 &statement_code_and_declaration(
3254 &stmt,
3255 &TypeList::empty(),
3256 &CodeBundle::new("".to_string())
3257 )
3258 .to_string(),
3259 expected
3260 );
3261 }
3262
3263 #[test]
3264 #[should_panic]
3265 fn compute_index_regression() {
3266 let result = compute_tuple_index(
3267 2,
3268 &[
3269 24u32.to_biguint(),
3270 17u32.to_biguint(),
3271 0u32.to_biguint(),
3272 2u32.to_biguint(),
3273 1u32.to_biguint(),
3274 1u32.to_biguint(),
3275 ],
3276 );
3277
3278 result.verilog_code();
3279 }
3280
3281 #[test]
3282 fn inout_codegens_as_inout() {
3283 let input = spade_mir::Entity {
3284 name: spade_mir::unit_name::IntoUnitName::_test_into_unit_name("test"),
3285 inputs: vec![spade_mir::MirInput {
3286 name: "a".to_string(),
3287 val_name: ValueName::_test_named(0, "a".to_string()),
3288 ty: Type::InOut(Box::new(Type::Bool)),
3289 no_mangle: Some(().nowhere()),
3290 }],
3291 output: ValueName::Expr(ExprID(0)),
3292 output_type: Type::unit(),
3293 statements: vec![],
3294 };
3295
3296 let expected = indoc!(
3297 r#"
3298 module test (
3299 inout a
3300 );
3301 `ifdef COCOTB_SIM
3302 string __top_module;
3303 string __vcd_file;
3304 initial begin
3305 if ($value$plusargs("TOP_MODULE=%s", __top_module) && __top_module == "test" && $value$plusargs("VCD_FILENAME=%s", __vcd_file)) begin
3306 $dumpfile (__vcd_file);
3307 $dumpvars (0, test);
3308 end
3309 end
3310 `endif
3311 endmodule"#
3312 );
3313
3314 assert_same_code!(
3315 &entity_code(
3316 &prepare_codegen(input.clone(), &mut ExprIdTracker::new()),
3317 &mut InstanceMap::new(),
3318 &None
3319 )
3320 .0
3321 .to_string(),
3322 expected
3323 );
3324 }
3325}