1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use crate::docs::vcd2svg::display_metrics::DisplayMetrics;
use crate::docs::vcd2svg::timed_value::TimedValue;
use crate::docs::vcd2svg::utils::{value_to_bigint, value_to_bool};
use num_bigint::BigInt;
use std::clone::Clone;
use std::collections::HashMap;
use std::fs::File;
use std::iter::Iterator;
use std::string::ToString;
use svg::Document;
use vcd::IdCode;
type StringTrace = Vec<TimedValue<String>>;
type VectorTrace = Vec<TimedValue<BigInt>>;
type BinaryTrace = Vec<TimedValue<bool>>;
pub struct TraceCollection {
pub signal_names: Vec<(IdCode, String)>,
pub string_valued: HashMap<IdCode, StringTrace>,
pub vector_valued: HashMap<IdCode, VectorTrace>,
pub scalar_valued: HashMap<IdCode, BinaryTrace>,
}
impl TraceCollection {
pub fn parse(signals: &[&str], mut file: File) -> anyhow::Result<Self> {
let mut parser = vcd::Parser::new(&mut file);
let header = parser.parse_header()?;
let mut string_valued = HashMap::new();
let mut vector_valued = HashMap::new();
let mut scalar_valued = HashMap::new();
let mut signal_names = Vec::new();
for signal in signals {
let path = signal.split(".").collect::<Vec<_>>();
let sig = header
.find_var(&path)
.ok_or_else(|| anyhow::Error::msg(format!("cannot resolve signal {}", signal)))?;
if sig.size == 0 {
string_valued.insert(sig.code, StringTrace::new());
} else if sig.size == 1 {
scalar_valued.insert(sig.code, BinaryTrace::new());
} else {
vector_valued.insert(sig.code, VectorTrace::new());
}
signal_names.push((sig.code, signal.to_string()));
}
let mut timestamp = 0_u64;
for command_result in parser {
let command = command_result?;
match command {
vcd::Command::Timestamp(x) => {
timestamp = x;
}
vcd::Command::ChangeScalar(i, v) => {
if let Some(s) = scalar_valued.get_mut(&i) {
s.push(TimedValue {
time: timestamp,
value: value_to_bool(&v)?,
})
}
}
vcd::Command::ChangeVector(i, v) => {
if let Some(s) = vector_valued.get_mut(&i) {
s.push(TimedValue {
time: timestamp,
value: value_to_bigint(&v)?,
})
}
}
vcd::Command::ChangeString(i, v) => {
if let Some(s) = string_valued.get_mut(&i) {
s.push(TimedValue {
time: timestamp,
value: v.clone(),
})
}
}
_ => {}
}
}
Ok(Self {
signal_names,
string_valued,
vector_valued,
scalar_valued,
})
}
pub fn as_svg(&self, metrics: &DisplayMetrics) -> anyhow::Result<Document> {
let document = Document::new()
.set(
"viewBox",
(0, 0, metrics.canvas_width, metrics.canvas_height),
)
.add(metrics.background_rect());
let mut document = document
.add(metrics.signal_rect())
.add(metrics.timescale_header_rect())
.add(metrics.timescale_midline());
document = metrics.timescale(document);
for (index, details) in self.signal_names.iter().enumerate() {
document = document
.add(metrics.signal_label(index, &details.1))
.add(metrics.signal_line(index));
document = metrics.horiz_grid_line(index, document);
if let Some(s) = self.scalar_valued.get(&details.0) {
document = document.add(metrics.bit_signal_plot(index, s));
} else if let Some(s) = self.vector_valued.get(&details.0) {
document = metrics.vector_signal_plot(index, s, document);
} else if let Some(s) = self.string_valued.get(&details.0) {
document = metrics.vector_signal_plot(index, s, document);
} else {
anyhow::bail!("Unable to find signal {} in the trace...", details.1)
}
}
Ok(document)
}
}