1use crate::ast::{
2 Verilog, VerilogConditional, VerilogExpression, VerilogLink, VerilogLinkDetails, VerilogMatch,
3};
4use crate::atom::{Atom, AtomKind};
5use crate::block::Block;
6use crate::named_path::NamedPath;
7use crate::probe::Probe;
8use crate::type_descriptor::TypeKind;
9use crate::verilog_visitor::VerilogVisitor;
10use petgraph::algo::{connected_components, is_cyclic_directed};
11use petgraph::dot::Dot;
12use petgraph::prelude::*;
13use petgraph::unionfind::UnionFind;
14use petgraph::visit::NodeIndexable;
15use std::collections::HashMap;
16
17#[derive(Clone, Debug, Copy, PartialEq)]
18enum SignalNodeKind {
19 Normal,
20 Bidirectional,
21 Source,
22 Sink,
23}
24
25#[derive(Clone, Debug, Copy, PartialEq)]
26enum SignalEdgeKind {
27 Assign,
28 Input,
29 Clock,
30 Reset,
31 Output,
32 Extern,
33 Constant,
34}
35
36#[derive(Clone, Debug, PartialEq)]
37struct SignalNode {
38 pub name: String,
39 pub kind: SignalNodeKind,
40}
41
42#[derive(Clone, Debug, Default)]
43struct SignalGraph {
44 pub graph: Graph<SignalNode, SignalEdgeKind, Directed>,
45}
46
47impl SignalGraph {
48 fn dot(&self) -> String {
49 format!("{:?}", Dot::new(&self.graph))
50 }
51 fn add_signal_node(&mut self, node: &SignalNode) -> NodeIndex {
52 let index = self.graph.node_indices().find(|i| self.graph[*i].eq(node));
53 match index {
54 Some(n) => n,
55 None => self.graph.add_node(node.clone()),
56 }
57 }
58 fn add_signal_edge(&mut self, from: &SignalNode, to: NodeIndex, kind: SignalEdgeKind) {
59 let from_index = self.add_signal_node(from);
60 if !self.graph.contains_edge(from_index, to) {
61 self.graph.add_edge(from_index, to, kind);
62 }
63 }
64}
65
66#[derive(Clone, Debug, Copy)]
67enum ExpressionMode {
68 Write,
69 Read,
70}
71
72type ReadScope = Vec<SignalNode>;
73
74struct TimingChecker {
75 path: NamedPath,
76 namespace: NamedPath,
77 mode: ExpressionMode,
78 write_name: String,
79 read_names: Vec<ReadScope>,
80 pub graph: SignalGraph,
81}
82
83impl Default for TimingChecker {
84 fn default() -> Self {
85 Self {
86 path: Default::default(),
87 namespace: Default::default(),
88 mode: ExpressionMode::Write,
89 write_name: "".to_string(),
90 read_names: vec![],
91 graph: Default::default(),
92 }
93 }
94}
95
96impl TimingChecker {
97 fn set_write_mode(&mut self) {
98 self.mode = ExpressionMode::Write;
99 }
100 fn set_read_mode(&mut self) {
101 self.mode = ExpressionMode::Read;
102 }
103 fn push_read_scope(&mut self) {
104 self.read_names.push(vec![]);
105 }
106 fn pop_read_scope(&mut self) {
107 self.read_names.pop();
108 }
109 fn clear_scope(&mut self) {
110 self.read_names.clear();
111 self.read_names.push(Default::default());
112 }
113 fn add_read(&mut self, name: &str, kind: SignalNodeKind) {
114 if self.read_names.is_empty() {
115 self.read_names.push(ReadScope::default());
116 }
117 self.read_names.last_mut().unwrap().push(SignalNode {
118 name: name.into(),
119 kind: kind,
120 })
121 }
122 fn add_code(&mut self, module: &str, code: Verilog) {
123 if let Verilog::Combinatorial(code) = &code {
124 self.visit_block(code);
125 }
126 }
127 fn add_write(&mut self, write_name: &str, kind: SignalNodeKind, edge: SignalEdgeKind) {
128 assert!(!write_name.is_empty());
129 let write_node = SignalNode {
130 name: write_name.into(),
131 kind,
132 };
133 let write_id = self.graph.add_signal_node(&write_node);
134 for scope in &self.read_names {
135 for read in scope {
136 println!("Adding edge from {:?} -> {:?}", read, write_node);
137 self.graph.add_signal_edge(read, write_id, edge);
138 }
139 }
140 }
141 fn link_fixup(&self, x: &VerilogLinkDetails) -> (String, String) {
142 let v1 = format!(
143 "{}${}${}",
144 self.path.to_string(),
145 x.other_name.replace('[', "$").replace(']', ""),
146 x.my_name
147 );
148 let v2 = format!(
149 "{}${}${}",
150 self.path.to_string(),
151 x.owner_name.replace('[', "$").replace(']', ""),
152 x.my_name
153 );
154 (v1, v2)
155 }
156}
157
158impl VerilogVisitor for TimingChecker {
159 fn visit_conditional(&mut self, c: &VerilogConditional) {
160 self.push_read_scope();
161 self.visit_expression(&c.test);
162 self.visit_block(&c.then);
163 self.visit_block_or_conditional(&c.otherwise);
164 self.pop_read_scope();
165 }
166 fn visit_match(&mut self, m: &VerilogMatch) {
167 self.visit_expression(&m.test);
168 self.push_read_scope();
169 for case in &m.cases {
170 self.visit_case(case);
171 }
172 self.pop_read_scope();
173 }
174 fn visit_assignment(&mut self, l: &VerilogExpression, r: &VerilogExpression) {
175 self.push_read_scope();
176 self.write_name = Default::default();
177 self.mode = ExpressionMode::Write;
178 self.visit_expression(l);
179 self.mode = ExpressionMode::Read;
180 self.visit_expression(r);
181 let write_name = self.write_name.clone();
182 self.add_write(&write_name, SignalNodeKind::Normal, SignalEdgeKind::Assign);
183 self.pop_read_scope();
184 }
185 fn visit_slice_assignment(
186 &mut self,
187 base: &VerilogExpression,
188 width: &usize,
189 offset: &VerilogExpression,
190 replacement: &VerilogExpression,
191 ) {
192 self.push_read_scope();
193 self.write_name = Default::default();
194 self.mode = ExpressionMode::Write;
195 self.visit_expression(base);
196 self.mode = ExpressionMode::Read;
197 self.visit_expression(offset);
198 self.visit_expression(replacement);
199 let write_name = self.write_name.clone();
200 self.add_write(&write_name, SignalNodeKind::Normal, SignalEdgeKind::Assign);
201 self.pop_read_scope();
202 }
203 fn visit_signal(&mut self, c: &str) {
204 let c = format!("{}${}", self.path.to_string(), c).replace("$next", "");
205 match self.mode {
206 ExpressionMode::Write => self.write_name = c,
207 ExpressionMode::Read => self.add_read(&c, SignalNodeKind::Normal),
208 }
209 }
210 fn visit_link(&mut self, c: &[VerilogLink]) {
211 for link in c {
212 match link {
213 VerilogLink::Forward(x) => {
214 self.push_read_scope();
215 let (w, r) = self.link_fixup(x);
216 self.add_read(&r, SignalNodeKind::Normal);
217 self.add_write(&w, SignalNodeKind::Normal, SignalEdgeKind::Assign);
218 self.pop_read_scope();
219 }
220 VerilogLink::Backward(x) => {
221 self.push_read_scope();
222 let (r, w) = self.link_fixup(x);
223 self.add_read(&r, SignalNodeKind::Normal);
224 self.add_write(&w, SignalNodeKind::Normal, SignalEdgeKind::Assign);
225 self.pop_read_scope();
226 }
227 VerilogLink::Bidirectional(x) => {
228 let (w, r) = self.link_fixup(x);
229 self.push_read_scope();
230 self.add_read(&r, SignalNodeKind::Bidirectional);
231 self.add_write(&w, SignalNodeKind::Bidirectional, SignalEdgeKind::Assign);
232 self.pop_read_scope();
233 }
234 }
235 }
236 }
237}
238
239impl Probe for TimingChecker {
240 fn visit_start_scope(&mut self, name: &str, node: &dyn Block) {
241 println!("Start scope {}", name);
242 self.path.push(name);
243 self.namespace.reset();
244 self.add_code(&self.path.to_string(), node.hdl());
245 for info in &node.timing() {
246 self.push_read_scope();
252 self.add_read(
253 &format!("{}${}", self.path.to_string(), info.name),
254 SignalNodeKind::Source,
255 );
256 for output in &info.outputs {
257 self.add_write(
258 &format!("{}${}", self.path.to_string(), output),
259 SignalNodeKind::Normal,
260 SignalEdgeKind::Output,
261 );
262 }
263 self.pop_read_scope();
264 let write_name = format!("{}${}", self.path.to_string(), info.name);
265 for input in &info.inputs {
266 self.push_read_scope();
267 self.add_read(
268 &format!("{}${}", self.path.to_string(), input),
269 SignalNodeKind::Normal,
270 );
271 self.add_write(&write_name, SignalNodeKind::Sink, SignalEdgeKind::Input);
272 self.pop_read_scope();
273 }
274 self.push_read_scope();
275 self.add_read(
276 &format!("{}${}", self.path.to_string(), info.clock),
277 SignalNodeKind::Normal,
278 );
279 self.add_write(&write_name, SignalNodeKind::Sink, SignalEdgeKind::Clock);
280 self.pop_read_scope();
281 }
282 self.clear_scope();
283 }
284 fn visit_start_namespace(&mut self, name: &str, _node: &dyn Block) {
285 println!("Start Namespace {}", name);
286 self.namespace.push(name);
287 }
288 fn visit_atom(&mut self, name: &str, signal: &dyn Atom) {
289 let module_path = self.path.to_string();
290 let namespace = self.namespace.flat("$");
291 let name = if namespace.is_empty() {
292 name.to_owned()
293 } else {
294 format!("{}${}", namespace, name)
295 };
296 let is_top_scope = self.path.to_string().eq("top");
298 let global_signal_name = format!("{}${}", self.path.to_string(), name);
299 match signal.kind() {
300 AtomKind::InputParameter | AtomKind::InOutParameter => {
301 if is_top_scope {
302 let my_id = self.graph.add_signal_node(&SignalNode {
303 name: global_signal_name.clone(),
304 kind: SignalNodeKind::Normal,
305 });
306 self.graph.add_signal_edge(
307 &SignalNode {
308 name: format!("extern${}", name),
309 kind: SignalNodeKind::Source,
310 },
311 my_id,
312 SignalEdgeKind::Extern,
313 );
314 }
315 }
316 AtomKind::Constant => {
317 let my_id = self.graph.add_signal_node(&SignalNode {
318 name: global_signal_name.clone(),
319 kind: SignalNodeKind::Normal,
320 });
321 self.graph.add_signal_edge(
322 &SignalNode {
323 name: format!("const${}", name),
324 kind: SignalNodeKind::Source,
325 },
326 my_id,
327 SignalEdgeKind::Constant,
328 );
329 }
330 _ => {}
331 }
332 let descriptor = &signal.descriptor();
333 if let TypeKind::Enum(x) = &descriptor.kind {
334 for label in x {
335 let label = label.replace("::", "$");
336 let my_id = self.graph.add_signal_node(&SignalNode {
337 name: format!("{}${}", module_path, label),
338 kind: SignalNodeKind::Normal,
339 });
340 self.graph.add_signal_edge(
341 &SignalNode {
342 name: format!("const${}", label),
343 kind: SignalNodeKind::Source,
344 },
345 my_id,
346 SignalEdgeKind::Constant,
347 );
348 let my_id = self.graph.add_signal_node(&SignalNode {
349 name: format!("{}${}", self.path.parent(), label),
350 kind: SignalNodeKind::Normal,
351 });
352 self.graph.add_signal_edge(
353 &SignalNode {
354 name: format!("const${}", label),
355 kind: SignalNodeKind::Source,
356 },
357 my_id,
358 SignalEdgeKind::Constant,
359 );
360 }
361 }
362 }
363 fn visit_end_namespace(&mut self, _name: &str, _node: &dyn Block) {
364 self.namespace.pop();
365 }
366 fn visit_end_scope(&mut self, _name: &str, _node: &dyn Block) {
367 self.path.pop();
368 }
369}
370
371pub fn check_timing<U: Block>(uut: &U) {
372 let mut scan = TimingChecker::default();
373 uut.accept("top", &mut scan);
374 let dot = scan.graph.dot();
376 println!("Graph is cyclic: {}", is_cyclic_directed(&scan.graph.graph));
377 println!(
378 "Number of connected components: {}",
379 connected_components(&scan.graph.graph)
380 );
381 let g = &scan.graph.graph;
382 let mut vertex_sets = UnionFind::new(g.node_count());
383 for edge in g.edge_references() {
384 let (a, b) = (edge.source(), edge.target());
385 vertex_sets.union(g.to_index(a), g.to_index(b));
386 }
387 let mut labels = vertex_sets.into_labeling();
388 let mut unique_labels = labels.clone();
389 unique_labels.sort_unstable();
390 unique_labels.dedup();
391 for subgraph in unique_labels {
393 let mut remap: HashMap<_, _> = Default::default();
394 let mut s: Graph<SignalNode, SignalEdgeKind> = Graph::default();
395 for (ndx, label) in labels.iter().enumerate() {
396 if *label == subgraph {
397 let old_index = g.from_index(ndx);
398 let old_weight = g[g.from_index(ndx)].clone();
399 let new_index = s.add_node(old_weight);
400 remap.insert(old_index, new_index);
401 }
402 }
403 for edge in g.edge_references() {
404 let (a, b) = (edge.source(), edge.target());
405 assert!(!(remap.contains_key(&a) ^ remap.contains_key(&b)));
406 if remap.contains_key(&a) {
407 let a_new = remap.get(&a).unwrap();
408 let b_new = remap.get(&b).unwrap();
409 s.add_edge(*a_new, *b_new, *edge.weight());
410 }
411 }
412 }
419 }