extern crate vcd;
use super::*;
use std::io;
pub enum TimeScaleUnit {
S,
Ms,
Us,
Ns,
Ps,
Fs,
}
impl From<TimeScaleUnit> for vcd::TimescaleUnit {
fn from(time_scale_unit: TimeScaleUnit) -> Self {
match time_scale_unit {
TimeScaleUnit::S => vcd::TimescaleUnit::S,
TimeScaleUnit::Ms => vcd::TimescaleUnit::MS,
TimeScaleUnit::Us => vcd::TimescaleUnit::US,
TimeScaleUnit::Ns => vcd::TimescaleUnit::NS,
TimeScaleUnit::Ps => vcd::TimescaleUnit::PS,
TimeScaleUnit::Fs => vcd::TimescaleUnit::FS,
}
}
}
pub struct VcdTrace<W: io::Write> {
module_hierarchy_depth: u32,
signals: Vec<VcdTraceSignal>,
w: vcd::Writer<W>,
}
impl<W: io::Write> VcdTrace<W> {
pub fn new(w: W, time_scale: u32, time_scale_unit: TimeScaleUnit) -> io::Result<VcdTrace<W>> {
let mut w = vcd::Writer::new(w);
w.timescale(time_scale, time_scale_unit.into())?;
Ok(VcdTrace {
module_hierarchy_depth: 0,
signals: Vec::new(),
w,
})
}
}
impl<W: io::Write> Trace for VcdTrace<W> {
type SignalId = usize;
fn push_module(&mut self, name: &'static str) -> io::Result<()> {
self.w.add_module(name)?;
self.module_hierarchy_depth += 1;
Ok(())
}
fn pop_module(&mut self) -> io::Result<()> {
self.w.upscope()?;
self.module_hierarchy_depth -= 1;
if self.module_hierarchy_depth == 0 {
self.w.enddefinitions()?;
}
Ok(())
}
fn add_signal(
&mut self,
name: &'static str,
bit_width: u32,
type_: TraceValueType,
) -> io::Result<Self::SignalId> {
let ret = self.signals.len();
self.signals.push(VcdTraceSignal {
bit_width,
type_,
id: self.w.add_wire(bit_width, name)?,
});
Ok(ret)
}
fn update_time_stamp(&mut self, time_stamp: u64) -> io::Result<()> {
self.w.timestamp(time_stamp)
}
fn update_signal(&mut self, signal_id: &Self::SignalId, value: TraceValue) -> io::Result<()> {
let signal = &self.signals[*signal_id];
if let TraceValueType::Bool = signal.type_ {
self.w.change_scalar(
signal.id,
match value {
TraceValue::Bool(value) => value,
TraceValue::U32(_) | TraceValue::U64(_) | TraceValue::U128(_) => unreachable!(),
},
)?;
} else {
let value = match value {
TraceValue::Bool(_) => unreachable!(),
TraceValue::U32(value) => value as _,
TraceValue::U64(value) => value as _,
TraceValue::U128(value) => value,
};
let mut scalar_values = [vcd::Value::V0; 128];
for i in 0..signal.bit_width as usize {
scalar_values[i] = ((value >> (signal.bit_width as usize - 1 - i)) & 1 != 0).into();
}
self.w
.change_vector(signal.id, &scalar_values[0..signal.bit_width as usize])?;
}
Ok(())
}
}
struct VcdTraceSignal {
bit_width: u32,
type_: TraceValueType,
id: vcd::IdCode,
}