veryl_analyzer/ir/
module.rs1use crate::BigUint;
2use crate::HashMap;
3use crate::attribute::{AllowItem, Attribute};
4use crate::attribute_table;
5use crate::conv::Context;
6use crate::ir::assign_table::AssignTable;
7use crate::ir::{
8 Declaration, FfTable, Function, Type, VarId, VarIndex, VarKind, VarPath, Variable,
9};
10use crate::symbol::ClockDomain;
11use crate::value::ValueBigUint;
12use indent::indent_all_by;
13use std::fmt;
14use veryl_parser::resource_table::StrId;
15use veryl_parser::token_range::TokenRange;
16
17#[derive(Clone)]
18pub struct Module {
19 pub name: StrId,
20 pub token: TokenRange,
21 pub ports: HashMap<VarPath, VarId>,
22 pub port_types: HashMap<VarPath, (Type, ClockDomain)>,
23 pub variables: HashMap<VarId, Variable>,
24 pub functions: HashMap<VarId, Function>,
25 pub declarations: Vec<Declaration>,
26 pub suppress_unassigned: bool,
27}
28
29impl Module {
30 pub fn eval_assign(&self, context: &mut Context) {
31 if self.suppress_unassigned {
32 return;
33 }
34
35 context.variables = self.variables.clone();
36 context.functions = self.functions.clone();
37
38 let mut assign_table = AssignTable::new(context);
39
40 for x in &self.declarations {
41 let mut new_table = AssignTable::new(context);
42 x.eval_assign(context, &mut new_table);
43 assign_table.merge_by_or(context, &mut new_table, true);
44 }
45
46 for x in self.functions.values() {
47 let mut new_table = AssignTable::new(context);
48 x.eval_assign(context, &mut new_table);
49 assign_table.merge_by_or(context, &mut new_table, false);
50 }
51
52 let mut variables = self.variables.clone();
53
54 for (key, entry) in &assign_table.table {
55 if let Some(variable) = variables.get_mut(key)
56 && let Some(array) = entry.array.total()
57 {
58 for i in 0..array {
59 if let Some(x) = entry.mask.get(i) {
60 variable.set_assigned(i, x.clone());
61 }
62 }
63 }
64 }
65
66 for variable in variables.values() {
67 let check_skip = variable.r#type.is_systemverilog()
69 || variable.r#type.total_array().unwrap_or(0) > context.config.evaluate_array_limit
70 || matches!(variable.kind, VarKind::Inout)
71 || variable.r#type.array.total().is_none();
72
73 if variable.is_assignable() && !check_skip {
74 let zero: BigUint = 0u32.into();
75 let full_mask = variable
76 .total_width()
77 .map(ValueBigUint::gen_mask)
78 .unwrap_or_else(|| zero.clone());
79 let accumulated_reads = assign_table.accumulated_reads.get(&variable.id);
80
81 for index in &variable.unassigned() {
82 let assigned_mask = variable
83 .assigned
84 .get(*index)
85 .cloned()
86 .unwrap_or_else(|| zero.clone());
87 let unassigned_bits = &full_mask ^ &(&full_mask & &assigned_mask);
89 let read_mask = accumulated_reads
90 .and_then(|r| r.get(*index))
91 .cloned()
92 .unwrap_or_else(|| zero.clone());
93 let any_assigned = assigned_mask != zero;
96 let any_read_unassigned = (&read_mask & &unassigned_bits) != zero;
97 if any_assigned && !any_read_unassigned {
98 continue;
99 }
100
101 if !attribute_table::contains(
102 &variable.token.beg,
103 Attribute::Allow(AllowItem::UnassignVariable),
104 ) {
105 let index = VarIndex::from_index(*index, &variable.r#type.array);
106 context.insert_error(crate::AnalyzerError::unassign_variable(
107 &format!("{}{index}", variable.path),
108 &variable.token,
109 ));
110 }
111 }
112 }
113 }
114 }
115
116 pub fn gather_ff(&self, context: &mut Context, table: &mut FfTable) {
117 for (i, x) in self.declarations.iter().enumerate() {
118 x.gather_ff(context, table, i);
119 }
120 }
121}
122
123impl fmt::Display for Module {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 let mut ret = format!("module {} {{\n", self.name);
126
127 let mut variables: Vec<_> = self.variables.iter().collect();
128 variables.sort_by(|a, b| a.0.cmp(b.0));
129
130 let mut functions: Vec<_> = self.functions.iter().collect();
131 functions.sort_by(|a, b| a.0.cmp(b.0));
132
133 for (_, x) in variables {
134 let text = format!("{}\n", x);
135 ret.push_str(&indent_all_by(2, text));
136 }
137
138 for (_, x) in functions {
139 let text = format!("{}\n", x);
140 ret.push_str(&indent_all_by(2, text));
141 }
142
143 ret.push('\n');
144
145 for x in &self.declarations {
146 let text = format!("{}\n", x);
147 ret.push_str(&indent_all_by(2, text));
148 }
149
150 ret.push('}');
151 ret.fmt(f)
152 }
153}