1use std::ptr;
2
3use super::module_context::*;
4
5use crate::graph;
6
7use typed_arena::Arena;
8
9struct ModuleStackFrame<'graph, 'frame> {
10 parent: Option<(
11 &'graph graph::Instance<'graph>,
12 &'frame ModuleStackFrame<'graph, 'frame>,
13 )>,
14 module: &'graph graph::Module<'graph>,
15}
16
17pub fn validate_module_hierarchy<'graph>(m: &'graph graph::Module<'graph>) {
18 detect_recursive_definitions(
19 m,
20 &ModuleStackFrame {
21 parent: None,
22 module: m,
23 },
24 m,
25 );
26 detect_undriven_registers(
27 m,
28 &ModuleStackFrame {
29 parent: None,
30 module: m,
31 },
32 m,
33 );
34 detect_mem_errors(
35 m,
36 &ModuleStackFrame {
37 parent: None,
38 module: m,
39 },
40 m,
41 );
42 let context_arena = Arena::new();
43 let root_context = context_arena.alloc(ModuleContext::new());
44 detect_combinational_loops(m, root_context, &context_arena, m);
45}
46
47fn detect_recursive_definitions<'graph, 'frame>(
48 m: &graph::Module<'graph>,
49 module_stack_frame: &ModuleStackFrame<'graph, 'frame>,
50 root: &graph::Module<'graph>,
51) {
52 for instance in m.instances.borrow().iter() {
53 let instantiated_module = instance.instantiated_module;
54
55 if ptr::eq(instantiated_module, m) {
56 panic!("Cannot generate code for module \"{}\" because it has a recursive definition formed by an instance of itself called \"{}\".", m.name, instance.name);
57 }
58
59 let mut frame = module_stack_frame;
60 loop {
61 if ptr::eq(instantiated_module, frame.module) {
62 panic!("Cannot generate code for module \"{}\" because it has a recursive definition formed by an instance of itself called \"{}\" in module \"{}\".", root.name, instance.name, m.name);
63 }
64
65 if let Some((_, parent)) = frame.parent {
66 frame = parent;
67 } else {
68 break;
69 }
70 }
71
72 for input_name in instantiated_module.inputs.borrow().keys() {
73 if !instance.driven_inputs.borrow().contains_key(input_name) {
74 panic!("Cannot generate code for module \"{}\" because module \"{}\" contains an instance of module \"{}\" called \"{}\" whose input \"{}\" is not driven.", root.name, m.name, instantiated_module.name, instance.name, input_name);
75 }
76 }
77
78 detect_recursive_definitions(
79 instantiated_module,
80 &ModuleStackFrame {
81 parent: Some((instance, module_stack_frame)),
82 module: instantiated_module,
83 },
84 root,
85 );
86 }
87}
88
89fn detect_undriven_registers<'graph, 'frame>(
90 m: &graph::Module<'graph>,
91 module_stack_frame: &ModuleStackFrame<'graph, 'frame>,
92 root: &graph::Module<'graph>,
93) {
94 for register in m.registers.borrow().iter() {
95 match register.data {
96 graph::SignalData::Reg { ref data } => {
97 if data.next.borrow().is_none() {
98 panic!("Cannot generate code for module \"{}\" because module \"{}\" contains a register called \"{}\" which is not driven.", root.name, m.name, data.name);
99 }
100 }
101 _ => unreachable!(),
102 }
103 }
104
105 for instance in m.instances.borrow().iter() {
106 let instantiated_module = instance.instantiated_module;
107
108 detect_undriven_registers(
109 instantiated_module,
110 &ModuleStackFrame {
111 parent: Some((instance, module_stack_frame)),
112 module: instantiated_module,
113 },
114 root,
115 );
116 }
117}
118
119fn detect_mem_errors<'graph, 'frame>(
120 m: &graph::Module<'graph>,
121 module_stack_frame: &ModuleStackFrame<'graph, 'frame>,
122 root: &graph::Module<'graph>,
123) {
124 for mem in m.mems.borrow().iter() {
125 if mem.read_ports.borrow().is_empty() {
126 panic!("Cannot generate code for module \"{}\" because module \"{}\" contains a memory called \"{}\" which doesn't have any read ports.", root.name, m.name, mem.name);
127 }
128
129 if mem.initial_contents.borrow().is_none() && mem.write_port.borrow().is_none() {
130 panic!("Cannot generate code for module \"{}\" because module \"{}\" contains a memory called \"{}\" which doesn't have initial contents or a write port specified. At least one of the two is required.", root.name, m.name, mem.name);
131 }
132 }
133
134 for instance in m.instances.borrow().iter() {
135 let instantiated_module = instance.instantiated_module;
136
137 detect_mem_errors(
138 instantiated_module,
139 &ModuleStackFrame {
140 parent: Some((instance, module_stack_frame)),
141 module: instantiated_module,
142 },
143 root,
144 );
145 }
146}
147
148fn detect_combinational_loops<'graph, 'arena>(
149 m: &graph::Module<'graph>,
150 context: &'arena ModuleContext<'graph, 'arena>,
151 context_arena: &'arena Arena<ModuleContext<'graph, 'arena>>,
152 root: &graph::Module<'graph>,
153) {
154 for instance in m.instances.borrow().iter() {
155 let instantiated_module = instance.instantiated_module;
156
157 let context = context.get_child(instance, context_arena);
158
159 for (_, output) in instantiated_module.outputs.borrow().iter() {
160 trace_signal(output, context, context_arena, (context, output), root);
161 }
162
163 detect_combinational_loops(instantiated_module, context, context_arena, root);
164 }
165}
166
167fn trace_signal<'graph, 'arena>(
168 signal: &'graph graph::Signal<'graph>,
169 context: &'arena ModuleContext<'graph, 'arena>,
170 context_arena: &'arena Arena<ModuleContext<'graph, 'arena>>,
171 source_output: (
172 &'arena ModuleContext<'graph, 'arena>,
173 &'graph graph::Signal<'graph>,
174 ),
175 root: &graph::Module<'graph>,
176) {
177 struct Frame<'graph, 'arena> {
178 signal: &'graph graph::Signal<'graph>,
179 context: &'arena ModuleContext<'graph, 'arena>,
180 }
181
182 let mut frames = Vec::new();
183 frames.push(Frame { signal, context });
184
185 while let Some(frame) = frames.pop() {
186 let signal = frame.signal;
187 let context = frame.context;
188
189 match signal.data {
190 graph::SignalData::Lit { .. } => (),
191
192 graph::SignalData::Input { ref name, .. } => {
193 if let Some((instance, parent)) = context.instance_and_parent {
194 frames.push(Frame {
195 signal: instance.driven_inputs.borrow()[name],
196 context: parent,
197 });
198 }
199 }
200
201 graph::SignalData::Reg { .. } => (),
202
203 graph::SignalData::UnOp { ref source, .. } => {
204 frames.push(Frame {
205 signal: source,
206 context,
207 });
208 }
209 graph::SignalData::SimpleBinOp {
210 ref lhs, ref rhs, ..
211 } => {
212 frames.push(Frame {
213 signal: lhs,
214 context,
215 });
216 frames.push(Frame {
217 signal: rhs,
218 context,
219 });
220 }
221 graph::SignalData::AdditiveBinOp {
222 ref lhs, ref rhs, ..
223 } => {
224 frames.push(Frame {
225 signal: lhs,
226 context,
227 });
228 frames.push(Frame {
229 signal: rhs,
230 context,
231 });
232 }
233 graph::SignalData::ComparisonBinOp {
234 ref lhs, ref rhs, ..
235 } => {
236 frames.push(Frame {
237 signal: lhs,
238 context,
239 });
240 frames.push(Frame {
241 signal: rhs,
242 context,
243 });
244 }
245 graph::SignalData::ShiftBinOp {
246 ref lhs, ref rhs, ..
247 } => {
248 frames.push(Frame {
249 signal: lhs,
250 context,
251 });
252 frames.push(Frame {
253 signal: rhs,
254 context,
255 });
256 }
257
258 graph::SignalData::Mul {
259 ref lhs, ref rhs, ..
260 } => {
261 frames.push(Frame {
262 signal: lhs,
263 context,
264 });
265 frames.push(Frame {
266 signal: rhs,
267 context,
268 });
269 }
270 graph::SignalData::MulSigned {
271 ref lhs, ref rhs, ..
272 } => {
273 frames.push(Frame {
274 signal: lhs,
275 context,
276 });
277 frames.push(Frame {
278 signal: rhs,
279 context,
280 });
281 }
282
283 graph::SignalData::Bits { ref source, .. } => {
284 frames.push(Frame {
285 signal: source,
286 context,
287 });
288 }
289
290 graph::SignalData::Repeat { ref source, .. } => {
291 frames.push(Frame {
292 signal: source,
293 context,
294 });
295 }
296 graph::SignalData::Concat {
297 ref lhs, ref rhs, ..
298 } => {
299 frames.push(Frame {
300 signal: lhs,
301 context,
302 });
303 frames.push(Frame {
304 signal: rhs,
305 context,
306 });
307 }
308
309 graph::SignalData::Mux {
310 ref cond,
311 ref when_true,
312 ref when_false,
313 ..
314 } => {
315 frames.push(Frame {
316 signal: cond,
317 context,
318 });
319 frames.push(Frame {
320 signal: when_true,
321 context,
322 });
323 frames.push(Frame {
324 signal: when_false,
325 context,
326 });
327 }
328
329 graph::SignalData::InstanceOutput {
330 instance, ref name, ..
331 } => {
332 let instantiated_module = instance.instantiated_module;
333 let output = instantiated_module.outputs.borrow()[name];
334 let context = context.get_child(instance, context_arena);
335 if context == source_output.0 && output == source_output.1 {
336 panic!("Cannot generate code for module \"{}\" because module \"{}\" contains an output called \"{}\" which forms a combinational loop with itself.", root.name, instantiated_module.name, name);
337 }
338 frames.push(Frame {
339 signal: output,
340 context,
341 });
342 }
343
344 graph::SignalData::MemReadPortOutput { .. } => (),
345 }
346 }
347}