gsim/
tracing.rs

1use crate::id_lists::IdInternal;
2use crate::SimulatorData;
3use std::num::{NonZeroU16, NonZeroU8};
4
5#[derive(Debug, Clone, Copy)]
6enum TimescaleUnit {
7    Seconds,
8    Milliseconds,
9    Microseconds,
10    Nanoseconds,
11    Picoseconds,
12}
13
14impl std::fmt::Display for TimescaleUnit {
15    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16        let s = match self {
17            TimescaleUnit::Seconds => "s",
18            TimescaleUnit::Milliseconds => "ms",
19            TimescaleUnit::Microseconds => "us",
20            TimescaleUnit::Nanoseconds => "ns",
21            TimescaleUnit::Picoseconds => "ps",
22        };
23
24        f.write_str(s)
25    }
26}
27
28/// The timescale in a VCD file
29#[derive(Debug, Clone, Copy)]
30pub struct Timescale {
31    unit: TimescaleUnit,
32    value: NonZeroU16,
33}
34
35impl std::default::Default for Timescale {
36    fn default() -> Self {
37        Self {
38            unit: TimescaleUnit::Nanoseconds,
39            value: NonZeroU16::MIN,
40        }
41    }
42}
43
44impl std::fmt::Display for Timescale {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        write!(f, "{}{}", self.value, self.unit)
47    }
48}
49
50#[allow(missing_docs)]
51impl Timescale {
52    pub const fn seconds(seconds: NonZeroU16) -> Self {
53        Self {
54            unit: TimescaleUnit::Seconds,
55            value: seconds,
56        }
57    }
58
59    pub const fn milliseconds(milliseconds: NonZeroU16) -> Self {
60        Self {
61            unit: TimescaleUnit::Milliseconds,
62            value: milliseconds,
63        }
64    }
65
66    pub const fn microseconds(microseconds: NonZeroU16) -> Self {
67        Self {
68            unit: TimescaleUnit::Microseconds,
69            value: microseconds,
70        }
71    }
72
73    pub const fn nanoseconds(nanoseconds: NonZeroU16) -> Self {
74        Self {
75            unit: TimescaleUnit::Nanoseconds,
76            value: nanoseconds,
77        }
78    }
79
80    pub const fn picoseconds(picoseconds: NonZeroU16) -> Self {
81        Self {
82            unit: TimescaleUnit::Picoseconds,
83            value: picoseconds,
84        }
85    }
86}
87
88pub(crate) fn write_vcd_header<VCD: std::io::Write>(
89    data: &SimulatorData,
90    vcd: &mut VCD,
91    timescale: Timescale,
92) -> std::io::Result<()> {
93    use cow_utils::CowUtils;
94
95    const VERSION: &str = env!("CARGO_PKG_VERSION");
96    let now = chrono::Local::now().format("%A, %B %e %Y, %X");
97    writeln!(vcd, "$version Gsim {VERSION} $end")?;
98    writeln!(vcd, "$date {now} $end")?;
99    writeln!(vcd, "$timescale {timescale} $end")?;
100    writeln!(vcd, "$scope module SIM $end")?;
101    for (&wire_id, wire_name) in &data.wire_names {
102        let wire_name = wire_name.cow_replace(char::is_whitespace, "_");
103        let wire_width = data.get_wire_width(wire_id).unwrap();
104        let ident = wire_id.to_u32();
105        writeln!(vcd, "    $var wire {wire_width} W{ident} {wire_name} $end")?;
106    }
107    writeln!(vcd, "$upscope $end")?;
108    writeln!(vcd, "$enddefinitions $end")?;
109
110    Ok(())
111}
112
113pub(crate) fn trace_vcd<VCD: std::io::Write>(
114    data: &SimulatorData,
115    vcd: &mut VCD,
116    time: u64,
117) -> std::io::Result<()> {
118    writeln!(vcd, "#{time}")?;
119    for &wire_id in data.wire_names.keys() {
120        let wire_width = data.get_wire_width(wire_id).unwrap();
121        let wire_state = data.get_wire_state(wire_id).unwrap();
122        let ident = wire_id.to_u32();
123        if wire_width > NonZeroU8::MIN {
124            writeln!(vcd, "b{} W{ident}", wire_state.display_string(wire_width))?;
125        } else {
126            writeln!(vcd, "{}W{ident}", wire_state.get_bit_state(0))?;
127        }
128    }
129
130    Ok(())
131}