use std::io;
use crate::{
Command, Header, IdCode, ReferenceIndex, Scope, ScopeItem, ScopeType, SimulationCommand,
TimescaleUnit, Value, Var, VarType,
};
pub struct Writer<W: io::Write> {
writer: W,
next_id_code: IdCode,
scope_depth: usize,
}
impl<W: io::Write> Writer<W> {
pub fn new(writer: W) -> Writer<W> {
Writer {
writer,
next_id_code: IdCode::FIRST,
scope_depth: 0,
}
}
pub fn writer(&mut self) -> &mut W {
&mut self.writer
}
pub fn flush(&mut self) -> io::Result<()> {
self.writer.flush()
}
pub fn header(&mut self, h: &Header) -> io::Result<()> {
if let Some(ref s) = h.date {
self.date(s)?;
}
if let Some(ref s) = h.version {
self.version(s)?;
}
if let Some((v, u)) = h.timescale {
self.timescale(v, u)?;
}
for i in &h.items {
match *i {
ScopeItem::Var(ref v) => self.var(v)?,
ScopeItem::Scope(ref s) => self.scope(s)?,
ScopeItem::Comment(ref c) => self.comment(c)?,
}
}
self.enddefinitions()
}
pub fn comment(&mut self, v: &str) -> io::Result<()> {
writeln!(self.writer, "$comment\n {}\n$end", v)
}
pub fn date(&mut self, v: &str) -> io::Result<()> {
writeln!(self.writer, "$date\n {}\n$end", v)
}
pub fn version(&mut self, v: &str) -> io::Result<()> {
writeln!(self.writer, "$version\n {}\n$end", v)
}
pub fn timescale(&mut self, ts: u32, unit: TimescaleUnit) -> io::Result<()> {
writeln!(self.writer, "$timescale {} {} $end", ts, unit)
}
pub fn scope_def(&mut self, t: ScopeType, i: &str) -> io::Result<()> {
self.scope_depth += 1;
writeln!(self.writer, "$scope {} {} $end", t, i)
}
pub fn add_module(&mut self, identifier: &str) -> io::Result<()> {
self.scope_def(ScopeType::Module, identifier)
}
pub fn upscope(&mut self) -> io::Result<()> {
debug_assert!(
self.scope_depth > 0,
"Generating invalid VCD: upscope without a matching scope"
);
self.scope_depth -= 1;
writeln!(self.writer, "$upscope $end")
}
pub fn scope(&mut self, s: &Scope) -> io::Result<()> {
self.scope_def(s.scope_type, &s.identifier[..])?;
for i in &s.items {
match *i {
ScopeItem::Var(ref v) => self.var(v)?,
ScopeItem::Scope(ref s) => self.scope(s)?,
ScopeItem::Comment(ref c) => self.comment(c)?,
}
}
self.upscope()
}
pub fn var_def(
&mut self,
var_type: VarType,
width: u32,
id: IdCode,
reference: &str,
index: Option<ReferenceIndex>,
) -> io::Result<()> {
debug_assert!(
self.scope_depth > 0,
"Generating invalid VCD: variable must be in a scope"
);
if id >= self.next_id_code {
self.next_id_code = id.next();
}
match index {
Some(idx) => writeln!(
self.writer,
"$var {} {} {} {} {} $end",
var_type, width, id, reference, idx
),
None => writeln!(
self.writer,
"$var {} {} {} {} $end",
var_type, width, id, reference
),
}
}
pub fn add_var(
&mut self,
var_type: VarType,
width: u32,
reference: &str,
index: Option<ReferenceIndex>,
) -> io::Result<IdCode> {
let id = self.next_id_code;
self.var_def(var_type, width, id, reference, index)?;
Ok(id)
}
pub fn add_wire(&mut self, width: u32, reference: &str) -> io::Result<IdCode> {
self.add_var(VarType::Wire, width, reference, None)
}
pub fn var(&mut self, v: &Var) -> io::Result<()> {
self.var_def(v.var_type, v.size, v.code, &v.reference[..], v.index)
}
pub fn enddefinitions(&mut self) -> io::Result<()> {
debug_assert!(
self.scope_depth == 0,
"Generating invalid VCD: {} scopes must be closed with $upscope before $enddefinitions",
self.scope_depth
);
writeln!(self.writer, "$enddefinitions $end")
}
pub fn timestamp(&mut self, ts: u64) -> io::Result<()> {
writeln!(self.writer, "#{}", ts)
}
pub fn change_scalar<V: Into<Value>>(&mut self, id: IdCode, v: V) -> io::Result<()> {
writeln!(self.writer, "{}{}", v.into(), id)
}
pub fn change_vector(&mut self, id: IdCode, v: impl IntoIterator<Item=Value>) -> io::Result<()> {
write!(self.writer, "b")?;
for i in v {
write!(self.writer, "{}", i)?
}
writeln!(self.writer, " {}", id)
}
pub fn change_real(&mut self, id: IdCode, v: f64) -> io::Result<()> {
writeln!(self.writer, "r{} {}", v, id)
}
pub fn change_string(&mut self, id: IdCode, v: &str) -> io::Result<()> {
writeln!(self.writer, "s{} {}", v, id)
}
pub fn begin(&mut self, c: SimulationCommand) -> io::Result<()> {
writeln!(self.writer, "${}", c)
}
pub fn end(&mut self) -> io::Result<()> {
writeln!(self.writer, "$end")
}
pub fn command(&mut self, c: &Command) -> io::Result<()> {
use Command::*;
match *c {
Comment(ref c) => self.comment(&c[..]),
Date(ref c) => self.date(&c[..]),
Version(ref c) => self.version(&c[..]),
Timescale(v, u) => self.timescale(v, u),
ScopeDef(t, ref i) => self.scope_def(t, &i[..]),
Upscope => self.upscope(),
VarDef(t, s, i, ref r, idx) => self.var_def(t, s, i, &r[..], idx),
Enddefinitions => self.enddefinitions(),
Timestamp(t) => self.timestamp(t),
ChangeScalar(i, v) => self.change_scalar(i, v),
ChangeVector(i, ref v) => self.change_vector(i, v),
ChangeReal(i, v) => self.change_real(i, v),
ChangeString(i, ref v) => self.change_string(i, v),
Begin(c) => self.begin(c),
End(_) => self.end(),
}
}
}