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, ReferencedEntry};
7use crate::ir::{
8 Declaration, FfTable, Function, Signature, 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
17pub type AssignTokens = HashMap<VarId, Vec<TokenRange>>;
21
22#[derive(Clone)]
23pub struct Module {
24 pub name: StrId,
25 pub signature: Signature,
28 pub token: TokenRange,
29 pub ports: HashMap<VarPath, VarId>,
30 pub port_types: HashMap<VarPath, (Type, ClockDomain)>,
31 pub variables: HashMap<VarId, Variable>,
32 pub functions: HashMap<VarId, Function>,
33 pub interface_members: HashMap<VarId, Variable>,
37 pub declarations: Vec<Declaration>,
38 pub suppress_unassigned: bool,
39 pub per_decl_refs: HashMap<usize, HashMap<VarId, ReferencedEntry>>,
43 pub assign_tokens: AssignTokens,
47 pub ff_table: FfTable,
54}
55
56impl Module {
57 pub fn eval_assign(&mut self, context: &mut Context) {
58 self.rebuild_ff_table(context);
63
64 if self.suppress_unassigned {
65 return;
66 }
67
68 context.variables = self.variables.clone();
69 context.functions = self.functions.clone();
70
71 let mut assign_table = AssignTable::new(context);
72
73 for (i, x) in self.declarations.iter().enumerate() {
74 let mut new_table = AssignTable::new(context);
75 x.eval_assign(context, &mut new_table);
76 if matches!(x, Declaration::Initial(_)) {
77 new_table.exempt_initial_writes(context);
78 }
79 let snapshot = std::mem::take(&mut new_table.refernced);
83 self.per_decl_refs.insert(i, snapshot);
84 assign_table.merge_by_or_from(context, &mut new_table, true, true);
85 }
86
87 for x in self.functions.values() {
88 let mut new_table = AssignTable::new(context);
89 x.eval_assign(context, &mut new_table);
90 assign_table.merge_by_or(context, &mut new_table, false);
91 }
92
93 let mut variables = self.variables.clone();
94
95 for (key, entry) in &assign_table.table {
96 if let Some(variable) = variables.get_mut(key)
97 && let Some(array) = entry.array.total()
98 {
99 for i in 0..array {
100 if let Some(x) = entry.mask.get(i) {
101 variable.set_assigned(i, x.clone());
102 }
103 }
104 }
105 self.assign_tokens.insert(*key, entry.tokens.clone());
107 }
108
109 for variable in variables.values() {
110 let check_skip = variable.r#type.is_systemverilog()
112 || variable.r#type.total_array().unwrap_or(0) > context.config.evaluate_array_limit
113 || matches!(variable.kind, VarKind::Inout)
114 || variable.r#type.array.total().is_none();
115
116 if variable.is_assignable() && !check_skip {
117 let zero: BigUint = 0u32.into();
118 let full_mask = variable
119 .total_width()
120 .map(ValueBigUint::gen_mask)
121 .unwrap_or_else(|| zero.clone());
122 let accumulated_reads = assign_table.accumulated_reads.get(&variable.id);
123
124 for index in &variable.unassigned() {
125 let assigned_mask = variable
126 .assigned
127 .get(*index)
128 .cloned()
129 .unwrap_or_else(|| zero.clone());
130 let unassigned_bits = &full_mask ^ &(&full_mask & &assigned_mask);
132 let read_mask = accumulated_reads
133 .and_then(|r| r.get(*index))
134 .cloned()
135 .unwrap_or_else(|| zero.clone());
136 let any_assigned = assigned_mask != zero;
140 let any_read_unassigned = (&read_mask & &unassigned_bits) != zero;
141 if any_assigned
142 && !any_read_unassigned
143 && !matches!(variable.kind, VarKind::Output)
144 && unassigned_bits != zero
145 {
146 continue;
147 }
148 if unassigned_bits == zero {
149 continue;
150 }
151
152 if !attribute_table::contains(
153 &variable.token.beg,
154 Attribute::Allow(AllowItem::UnassignVariable),
155 ) {
156 let index = VarIndex::from_index(*index, &variable.r#type.array);
157 context.insert_error(crate::AnalyzerError::unassign_variable(
158 &format!("{}{index}", variable.path),
159 &variable.token,
160 ));
161 }
162 }
163 }
164 }
165 }
166
167 pub fn gather_ff(&self, context: &mut Context, table: &mut FfTable) {
168 for (i, x) in self.declarations.iter().enumerate() {
169 x.gather_ff(context, table, i);
170 }
171 }
172
173 pub fn rebuild_ff_table(&mut self, context: &mut Context) {
177 let saved_vars = std::mem::take(&mut context.variables);
178 let saved_funcs = std::mem::take(&mut context.functions);
179 context.variables = self.variables.clone();
180 context.functions = self.functions.clone();
181
182 let mut table = FfTable::default();
183 self.gather_ff(context, &mut table);
184 table.update_is_ff(&self.declarations, context);
185 self.ff_table = table;
186
187 context.variables = saved_vars;
188 context.functions = saved_funcs;
189 }
190}
191
192impl fmt::Display for Module {
193 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
194 let mut ret = format!("module {} {{\n", self.name);
195
196 let mut variables: Vec<_> = self.variables.iter().collect();
197 variables.sort_by(|a, b| a.0.cmp(b.0));
198
199 let mut functions: Vec<_> = self.functions.iter().collect();
200 functions.sort_by(|a, b| a.0.cmp(b.0));
201
202 for (_, x) in variables {
203 let text = format!("{}\n", x);
204 ret.push_str(&indent_all_by(2, text));
205 }
206
207 for (_, x) in functions {
208 let text = format!("{}\n", x);
209 ret.push_str(&indent_all_by(2, text));
210 }
211
212 ret.push('\n');
213
214 for x in &self.declarations {
215 let text = format!("{}\n", x);
216 ret.push_str(&indent_all_by(2, text));
217 }
218
219 ret.push('}');
220 ret.fmt(f)
221 }
222}