kaze/
validation.rs

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}