WIP adding enums to simulator
This commit is contained in:
parent
d3f52292a1
commit
4422157db8
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
bundle::{BundleField, BundleType},
|
bundle::{BundleField, BundleType},
|
||||||
|
enum_::{EnumType, EnumVariant},
|
||||||
expr::{
|
expr::{
|
||||||
ops,
|
ops,
|
||||||
target::{
|
target::{
|
||||||
|
@ -36,7 +37,7 @@ use crate::{
|
||||||
ty::StaticType,
|
ty::StaticType,
|
||||||
util::{BitSliceWriteWithBase, DebugAsDisplay},
|
util::{BitSliceWriteWithBase, DebugAsDisplay},
|
||||||
};
|
};
|
||||||
use bitvec::{bits, order::Lsb0, slice::BitSlice, vec::BitVec};
|
use bitvec::{bits, order::Lsb0, slice::BitSlice, vec::BitVec, view::BitView};
|
||||||
use hashbrown::{HashMap, HashSet};
|
use hashbrown::{HashMap, HashSet};
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use num_traits::{Signed, ToPrimitive, Zero};
|
use num_traits::{Signed, ToPrimitive, Zero};
|
||||||
|
@ -1229,6 +1230,7 @@ pub struct Compiler {
|
||||||
assignments: Assignments,
|
assignments: Assignments,
|
||||||
clock_triggers: Vec<ClockTrigger>,
|
clock_triggers: Vec<ClockTrigger>,
|
||||||
compiled_value_to_clock_trigger_map: HashMap<CompiledValue<Clock>, ClockTrigger>,
|
compiled_value_to_clock_trigger_map: HashMap<CompiledValue<Clock>, ClockTrigger>,
|
||||||
|
enum_discriminants: HashMap<CompiledValue<Enum>, StatePartIndex<StatePartKindSmallSlots>>,
|
||||||
registers: Vec<Register>,
|
registers: Vec<Register>,
|
||||||
traces: Vec<SimTrace<()>>,
|
traces: Vec<SimTrace<()>>,
|
||||||
}
|
}
|
||||||
|
@ -1252,6 +1254,7 @@ impl Compiler {
|
||||||
assignments: Assignments::default(),
|
assignments: Assignments::default(),
|
||||||
clock_triggers: Vec::new(),
|
clock_triggers: Vec::new(),
|
||||||
compiled_value_to_clock_trigger_map: HashMap::new(),
|
compiled_value_to_clock_trigger_map: HashMap::new(),
|
||||||
|
enum_discriminants: HashMap::new(),
|
||||||
registers: Vec::new(),
|
registers: Vec::new(),
|
||||||
traces: Vec::new(),
|
traces: Vec::new(),
|
||||||
}
|
}
|
||||||
|
@ -1308,7 +1311,7 @@ impl Compiler {
|
||||||
flow,
|
flow,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
CanonicalType::Bool(ty) => TraceBool {
|
CanonicalType::Bool(_) => TraceBool {
|
||||||
id: self.make_trace_scalar_helper(
|
id: self.make_trace_scalar_helper(
|
||||||
target,
|
target,
|
||||||
|index| SimTraceKind::SmallBool { index },
|
|index| SimTraceKind::SmallBool { index },
|
||||||
|
@ -1318,10 +1321,27 @@ impl Compiler {
|
||||||
flow,
|
flow,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
CanonicalType::Array(ty) => unreachable!(),
|
CanonicalType::Array(_) => unreachable!(),
|
||||||
CanonicalType::Enum(ty) => todo!(),
|
CanonicalType::Enum(ty) => {
|
||||||
CanonicalType::Bundle(ty) => unreachable!(),
|
assert_eq!(ty.discriminant_bit_width(), ty.type_properties().bit_width);
|
||||||
CanonicalType::AsyncReset(ty) => TraceAsyncReset {
|
let compiled_value = self.compile_value(target);
|
||||||
|
let discriminant = self.compile_enum_discriminant(
|
||||||
|
compiled_value.map_ty(Enum::from_canonical),
|
||||||
|
target.target.base().source_location(),
|
||||||
|
);
|
||||||
|
TraceFieldlessEnum {
|
||||||
|
id: self.new_sim_trace(SimTraceKind::EnumDiscriminant {
|
||||||
|
index: discriminant,
|
||||||
|
ty,
|
||||||
|
}),
|
||||||
|
name,
|
||||||
|
ty,
|
||||||
|
flow,
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
CanonicalType::Bundle(_) => unreachable!(),
|
||||||
|
CanonicalType::AsyncReset(_) => TraceAsyncReset {
|
||||||
id: self.make_trace_scalar_helper(
|
id: self.make_trace_scalar_helper(
|
||||||
target,
|
target,
|
||||||
|index| SimTraceKind::SmallAsyncReset { index },
|
|index| SimTraceKind::SmallAsyncReset { index },
|
||||||
|
@ -1331,7 +1351,7 @@ impl Compiler {
|
||||||
flow,
|
flow,
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
CanonicalType::SyncReset(ty) => TraceSyncReset {
|
CanonicalType::SyncReset(_) => TraceSyncReset {
|
||||||
id: self.make_trace_scalar_helper(
|
id: self.make_trace_scalar_helper(
|
||||||
target,
|
target,
|
||||||
|index| SimTraceKind::SmallSyncReset { index },
|
|index| SimTraceKind::SmallSyncReset { index },
|
||||||
|
@ -1342,7 +1362,7 @@ impl Compiler {
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
CanonicalType::Reset(_) => unreachable!(),
|
CanonicalType::Reset(_) => unreachable!(),
|
||||||
CanonicalType::Clock(ty) => TraceClock {
|
CanonicalType::Clock(_) => TraceClock {
|
||||||
id: self.make_trace_scalar_helper(
|
id: self.make_trace_scalar_helper(
|
||||||
target,
|
target,
|
||||||
|index| SimTraceKind::SmallClock { index },
|
|index| SimTraceKind::SmallClock { index },
|
||||||
|
@ -1381,7 +1401,13 @@ impl Compiler {
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
CanonicalType::Enum(ty) => todo!(),
|
CanonicalType::Enum(ty) => {
|
||||||
|
if ty.variants().iter().all(|v| v.ty.is_none()) {
|
||||||
|
self.make_trace_scalar(target, name)
|
||||||
|
} else {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
CanonicalType::Bundle(ty) => {
|
CanonicalType::Bundle(ty) => {
|
||||||
let fields = Interned::from_iter(ty.fields().iter().map(|field| {
|
let fields = Interned::from_iter(ty.fields().iter().map(|field| {
|
||||||
self.make_trace_decl_child(
|
self.make_trace_decl_child(
|
||||||
|
@ -2752,6 +2778,71 @@ impl Compiler {
|
||||||
self.compiled_value_to_clock_trigger_map.insert(clk, retval);
|
self.compiled_value_to_clock_trigger_map.insert(clk, retval);
|
||||||
retval
|
retval
|
||||||
}
|
}
|
||||||
|
fn compile_enum_discriminant(
|
||||||
|
&mut self,
|
||||||
|
enum_value: CompiledValue<Enum>,
|
||||||
|
source_location: SourceLocation,
|
||||||
|
) -> StatePartIndex<StatePartKindSmallSlots> {
|
||||||
|
if let Some(&retval) = self.enum_discriminants.get(&enum_value) {
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
let retval_ty = Enum::new(
|
||||||
|
enum_value
|
||||||
|
.layout
|
||||||
|
.ty
|
||||||
|
.variants()
|
||||||
|
.iter()
|
||||||
|
.map(|variant| EnumVariant {
|
||||||
|
name: variant.name,
|
||||||
|
ty: None,
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
let retval = if retval_ty == enum_value.layout.ty
|
||||||
|
&& enum_value.range.len() == TypeLen::A_SMALL_SLOT
|
||||||
|
{
|
||||||
|
enum_value.range.small_slots.start
|
||||||
|
} else {
|
||||||
|
let retval = self
|
||||||
|
.insns
|
||||||
|
.state_layout
|
||||||
|
.ty
|
||||||
|
.small_slots
|
||||||
|
.allocate(&StatePartLayout::scalar(SlotDebugData {
|
||||||
|
name: Interned::default(),
|
||||||
|
ty: retval_ty.canonical(),
|
||||||
|
}))
|
||||||
|
.start;
|
||||||
|
let discriminant_bit_width = enum_value.layout.ty.discriminant_bit_width();
|
||||||
|
let discriminant_mask = !(!0u64 << discriminant_bit_width);
|
||||||
|
let insn = match enum_value.range.len() {
|
||||||
|
TypeLen::A_BIG_SLOT => Insn::AndBigWithSmallImmediate {
|
||||||
|
dest: retval,
|
||||||
|
lhs: enum_value.range.big_slots.start,
|
||||||
|
rhs: discriminant_mask,
|
||||||
|
},
|
||||||
|
TypeLen::A_SMALL_SLOT => {
|
||||||
|
if discriminant_bit_width == enum_value.layout.ty.type_properties().bit_width {
|
||||||
|
Insn::CopySmall {
|
||||||
|
dest: retval,
|
||||||
|
src: enum_value.range.small_slots.start,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Insn::AndSmallImmediate {
|
||||||
|
dest: retval,
|
||||||
|
lhs: enum_value.range.small_slots.start,
|
||||||
|
rhs: discriminant_mask,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
self.add_assignment(Interned::default(), [insn], source_location);
|
||||||
|
retval
|
||||||
|
};
|
||||||
|
self.enum_discriminants.insert(enum_value, retval);
|
||||||
|
retval
|
||||||
|
}
|
||||||
fn compile_stmt_reg<R: ResetType>(
|
fn compile_stmt_reg<R: ResetType>(
|
||||||
&mut self,
|
&mut self,
|
||||||
stmt_reg: StmtReg<R>,
|
stmt_reg: StmtReg<R>,
|
||||||
|
@ -3681,6 +3772,12 @@ pub trait TraceWriter: fmt::Debug + 'static {
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.set_signal_bool(id, value)
|
self.set_signal_bool(id, value)
|
||||||
}
|
}
|
||||||
|
fn set_signal_enum_discriminant(
|
||||||
|
&mut self,
|
||||||
|
id: TraceScalarId,
|
||||||
|
variant_index: usize,
|
||||||
|
ty: Enum,
|
||||||
|
) -> Result<(), Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DynTraceWriterDecls(Box<dyn TraceWriterDeclsDynTrait>);
|
pub struct DynTraceWriterDecls(Box<dyn TraceWriterDeclsDynTrait>);
|
||||||
|
@ -3717,6 +3814,12 @@ trait TraceWriterDynTrait: fmt::Debug + 'static {
|
||||||
fn set_signal_sync_reset_dyn(&mut self, id: TraceScalarId, value: bool) -> std::io::Result<()>;
|
fn set_signal_sync_reset_dyn(&mut self, id: TraceScalarId, value: bool) -> std::io::Result<()>;
|
||||||
fn set_signal_async_reset_dyn(&mut self, id: TraceScalarId, value: bool)
|
fn set_signal_async_reset_dyn(&mut self, id: TraceScalarId, value: bool)
|
||||||
-> std::io::Result<()>;
|
-> std::io::Result<()>;
|
||||||
|
fn set_signal_enum_discriminant_dyn(
|
||||||
|
&mut self,
|
||||||
|
id: TraceScalarId,
|
||||||
|
variant_index: usize,
|
||||||
|
ty: Enum,
|
||||||
|
) -> std::io::Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: TraceWriter> TraceWriterDynTrait for T {
|
impl<T: TraceWriter> TraceWriterDynTrait for T {
|
||||||
|
@ -3754,6 +3857,17 @@ impl<T: TraceWriter> TraceWriterDynTrait for T {
|
||||||
) -> std::io::Result<()> {
|
) -> std::io::Result<()> {
|
||||||
Ok(TraceWriter::set_signal_async_reset(self, id, value).map_err(err_into_io)?)
|
Ok(TraceWriter::set_signal_async_reset(self, id, value).map_err(err_into_io)?)
|
||||||
}
|
}
|
||||||
|
fn set_signal_enum_discriminant_dyn(
|
||||||
|
&mut self,
|
||||||
|
id: TraceScalarId,
|
||||||
|
variant_index: usize,
|
||||||
|
ty: Enum,
|
||||||
|
) -> std::io::Result<()> {
|
||||||
|
Ok(
|
||||||
|
TraceWriter::set_signal_enum_discriminant(self, id, variant_index, ty)
|
||||||
|
.map_err(err_into_io)?,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DynTraceWriter(Box<dyn TraceWriterDynTrait>);
|
pub struct DynTraceWriter(Box<dyn TraceWriterDynTrait>);
|
||||||
|
@ -3800,6 +3914,15 @@ impl TraceWriter for DynTraceWriter {
|
||||||
) -> Result<(), Self::Error> {
|
) -> Result<(), Self::Error> {
|
||||||
self.0.set_signal_async_reset_dyn(id, value)
|
self.0.set_signal_async_reset_dyn(id, value)
|
||||||
}
|
}
|
||||||
|
fn set_signal_enum_discriminant(
|
||||||
|
&mut self,
|
||||||
|
id: TraceScalarId,
|
||||||
|
variant_index: usize,
|
||||||
|
ty: Enum,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
self.0
|
||||||
|
.set_signal_enum_discriminant_dyn(id, variant_index, ty)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -3894,6 +4017,10 @@ enum SimTraceKind {
|
||||||
SmallClock {
|
SmallClock {
|
||||||
index: StatePartIndex<StatePartKindSmallSlots>,
|
index: StatePartIndex<StatePartKindSmallSlots>,
|
||||||
},
|
},
|
||||||
|
EnumDiscriminant {
|
||||||
|
index: StatePartIndex<StatePartKindSmallSlots>,
|
||||||
|
ty: Enum,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimTraceKind {
|
impl SimTraceKind {
|
||||||
|
@ -3913,6 +4040,9 @@ impl SimTraceKind {
|
||||||
| SimTraceKind::SmallAsyncReset { index: _ }
|
| SimTraceKind::SmallAsyncReset { index: _ }
|
||||||
| SimTraceKind::SmallSyncReset { index: _ }
|
| SimTraceKind::SmallSyncReset { index: _ }
|
||||||
| SimTraceKind::SmallClock { index: _ } => BitVec::repeat(false, 1),
|
| SimTraceKind::SmallClock { index: _ } => BitVec::repeat(false, 1),
|
||||||
|
SimTraceKind::EnumDiscriminant { index: _, ty } => {
|
||||||
|
BitVec::repeat(false, ty.discriminant_bit_width())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4042,6 +4172,16 @@ impl SimulationImpl {
|
||||||
SimTraceKind::BigClock { .. } | SimTraceKind::SmallClock { .. } => {
|
SimTraceKind::BigClock { .. } | SimTraceKind::SmallClock { .. } => {
|
||||||
trace_writer.set_signal_clock(id, state[0])?;
|
trace_writer.set_signal_clock(id, state[0])?;
|
||||||
}
|
}
|
||||||
|
SimTraceKind::EnumDiscriminant { ty, .. } => {
|
||||||
|
let mut variant_index = [0; mem::size_of::<usize>()];
|
||||||
|
variant_index.view_bits_mut::<Lsb0>()[0..state.len()]
|
||||||
|
.clone_from_bitslice(state);
|
||||||
|
trace_writer.set_signal_enum_discriminant(
|
||||||
|
id,
|
||||||
|
usize::from_le_bytes(variant_index),
|
||||||
|
ty,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(trace_writer)
|
Ok(trace_writer)
|
||||||
|
@ -4091,7 +4231,8 @@ impl SimulationImpl {
|
||||||
state.set(0, !self.state.big_slots[index].is_zero());
|
state.set(0, !self.state.big_slots[index].is_zero());
|
||||||
}
|
}
|
||||||
SimTraceKind::SmallUInt { index, ty: _ }
|
SimTraceKind::SmallUInt { index, ty: _ }
|
||||||
| SimTraceKind::SmallSInt { index, ty: _ } => {
|
| SimTraceKind::SmallSInt { index, ty: _ }
|
||||||
|
| SimTraceKind::EnumDiscriminant { index, ty: _ } => {
|
||||||
let bytes = self.state.small_slots[index].to_le_bytes();
|
let bytes = self.state.small_slots[index].to_le_bytes();
|
||||||
let bitslice = BitSlice::<u8, Lsb0>::from_slice(&bytes);
|
let bitslice = BitSlice::<u8, Lsb0>::from_slice(&bytes);
|
||||||
let bitslice = &bitslice[..state.len()];
|
let bitslice = &bitslice[..state.len()];
|
||||||
|
|
|
@ -2260,6 +2260,35 @@ impl_insns! {
|
||||||
state.small_slots[dest] = value;
|
state.small_slots[dest] = value;
|
||||||
next!();
|
next!();
|
||||||
}
|
}
|
||||||
|
AndSmallImmediate {
|
||||||
|
#[kind = Output]
|
||||||
|
dest: StatePartIndex<StatePartKindSmallSlots>,
|
||||||
|
#[kind = Input]
|
||||||
|
lhs: StatePartIndex<StatePartKindSmallSlots>,
|
||||||
|
#[kind = Immediate]
|
||||||
|
rhs: SmallUInt,
|
||||||
|
} => {
|
||||||
|
let value = state.small_slots[lhs] & rhs;
|
||||||
|
state.small_slots[dest] = value;
|
||||||
|
next!();
|
||||||
|
}
|
||||||
|
AndBigWithSmallImmediate {
|
||||||
|
#[kind = Output]
|
||||||
|
dest: StatePartIndex<StatePartKindSmallSlots>,
|
||||||
|
#[kind = Input]
|
||||||
|
lhs: StatePartIndex<StatePartKindBigSlots>,
|
||||||
|
#[kind = Immediate]
|
||||||
|
rhs: SmallUInt,
|
||||||
|
} => {
|
||||||
|
let lhs = &state.big_slots[lhs];
|
||||||
|
let mut lhs_lsb64 = lhs.iter_u64_digits().next().unwrap_or(0);
|
||||||
|
if lhs.is_negative() {
|
||||||
|
lhs_lsb64 = lhs_lsb64.wrapping_neg();
|
||||||
|
}
|
||||||
|
let value = lhs_lsb64 & rhs;
|
||||||
|
state.small_slots[dest] = value;
|
||||||
|
next!();
|
||||||
|
}
|
||||||
Or {
|
Or {
|
||||||
#[kind = Output]
|
#[kind = Output]
|
||||||
dest: StatePartIndex<StatePartKindBigSlots>,
|
dest: StatePartIndex<StatePartKindBigSlots>,
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// See Notices.txt for copyright information
|
// See Notices.txt for copyright information
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
enum_::{Enum, EnumType},
|
||||||
expr::Flow,
|
expr::Flow,
|
||||||
int::UInt,
|
int::UInt,
|
||||||
sim::{
|
sim::{
|
||||||
|
@ -13,7 +14,11 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use bitvec::slice::BitSlice;
|
use bitvec::slice::BitSlice;
|
||||||
use std::{fmt, io, mem};
|
use std::{
|
||||||
|
fmt::{self, Display},
|
||||||
|
io::{self, Write},
|
||||||
|
mem,
|
||||||
|
};
|
||||||
|
|
||||||
pub struct VcdWriterDecls<W: io::Write + 'static> {
|
pub struct VcdWriterDecls<W: io::Write + 'static> {
|
||||||
writer: W,
|
writer: W,
|
||||||
|
@ -190,6 +195,46 @@ fn write_scalar_id<W: io::Write>(writer: &mut W, id: TraceScalarId) -> io::Resul
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_escaped<W: io::Write>(writer: &mut W, value: impl Display) -> io::Result<()> {
|
||||||
|
// escaping rules from function GTKWave uses to decode VCD strings:
|
||||||
|
// https://github.com/gtkwave/gtkwave/blob/491f24d7e8619cfc1fcc65704ee5c967d1083c18/lib/libfst/fstapi.c#L7090
|
||||||
|
struct Wrapper<W>(W);
|
||||||
|
impl<W: io::Write> io::Write for Wrapper<W> {
|
||||||
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
|
if buf.is_empty() {
|
||||||
|
return self.0.write(buf);
|
||||||
|
}
|
||||||
|
let mut retval = 0;
|
||||||
|
for &byte in buf {
|
||||||
|
match byte {
|
||||||
|
b'\\' | b'\'' | b'"' | b'?' => self.0.write_all(&[b'\\', byte])?,
|
||||||
|
b'\n' => self.0.write_all(br"\n")?,
|
||||||
|
b'\r' => self.0.write_all(br"\r")?,
|
||||||
|
b'\t' => self.0.write_all(br"\t")?,
|
||||||
|
0x7 => self.0.write_all(br"\a")?,
|
||||||
|
0x8 => self.0.write_all(br"\b")?,
|
||||||
|
0xC => self.0.write_all(br"\f")?,
|
||||||
|
0xB => self.0.write_all(br"\v")?,
|
||||||
|
_ => {
|
||||||
|
if byte.is_ascii_graphic() {
|
||||||
|
self.0.write_all(&[byte])?;
|
||||||
|
} else {
|
||||||
|
write!(self.0, r"\x{byte:02x}")?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
retval += 1;
|
||||||
|
}
|
||||||
|
Ok(retval)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn flush(&mut self) -> io::Result<()> {
|
||||||
|
self.0.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write!(Wrapper(writer), "{value}")
|
||||||
|
}
|
||||||
|
|
||||||
fn write_vcd_var<W: io::Write>(
|
fn write_vcd_var<W: io::Write>(
|
||||||
writer: &mut W,
|
writer: &mut W,
|
||||||
var_type: &str,
|
var_type: &str,
|
||||||
|
@ -251,13 +296,25 @@ impl WriteTrace for TraceBool {
|
||||||
|
|
||||||
impl WriteTrace for TraceFieldlessEnum {
|
impl WriteTrace for TraceFieldlessEnum {
|
||||||
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, arg: A) -> io::Result<()> {
|
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, arg: A) -> io::Result<()> {
|
||||||
todo!()
|
let Self { id, name, ty, flow } = self;
|
||||||
|
TraceEnumDiscriminant { id, name, ty, flow }.write_trace(writer, arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WriteTrace for TraceEnumDiscriminant {
|
impl WriteTrace for TraceEnumDiscriminant {
|
||||||
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, arg: A) -> io::Result<()> {
|
fn write_trace<W: io::Write, A: Arg>(self, writer: &mut W, arg: A) -> io::Result<()> {
|
||||||
todo!()
|
let ArgInType {
|
||||||
|
source_var_type: _,
|
||||||
|
sink_var_type: _,
|
||||||
|
duplex_var_type: _,
|
||||||
|
} = arg.in_type();
|
||||||
|
let Self {
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
ty: _,
|
||||||
|
flow: _,
|
||||||
|
} = self;
|
||||||
|
write_vcd_var(writer, "string", 1, id, &name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,6 +526,17 @@ impl<W: io::Write + 'static> VcdWriter<W> {
|
||||||
pub fn timescale(&self) -> SimDuration {
|
pub fn timescale(&self) -> SimDuration {
|
||||||
self.timescale
|
self.timescale
|
||||||
}
|
}
|
||||||
|
fn write_string_value_change(
|
||||||
|
&mut self,
|
||||||
|
value: impl Display,
|
||||||
|
id: TraceScalarId,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
self.writer.write_all(b"s")?;
|
||||||
|
write_escaped(&mut self.writer, value)?;
|
||||||
|
self.writer.write_all(b" ")?;
|
||||||
|
write_scalar_id(&mut self.writer, id)?;
|
||||||
|
self.writer.write_all(b"\n")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: io::Write> TraceWriter for VcdWriter<W> {
|
impl<W: io::Write> TraceWriter for VcdWriter<W> {
|
||||||
|
@ -525,6 +593,24 @@ impl<W: io::Write> TraceWriter for VcdWriter<W> {
|
||||||
fn close(mut self) -> Result<(), Self::Error> {
|
fn close(mut self) -> Result<(), Self::Error> {
|
||||||
self.writer.flush()
|
self.writer.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_signal_enum_discriminant(
|
||||||
|
&mut self,
|
||||||
|
id: TraceScalarId,
|
||||||
|
variant_index: usize,
|
||||||
|
ty: Enum,
|
||||||
|
) -> Result<(), Self::Error> {
|
||||||
|
self.write_string_value_change(
|
||||||
|
format_args!(
|
||||||
|
"{} ({variant_index})",
|
||||||
|
ty.variants()
|
||||||
|
.get(variant_index)
|
||||||
|
.map(|v| &*v.name)
|
||||||
|
.unwrap_or("<invalid>"),
|
||||||
|
),
|
||||||
|
id,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: io::Write> fmt::Debug for VcdWriter<W> {
|
impl<W: io::Write> fmt::Debug for VcdWriter<W> {
|
||||||
|
|
Loading…
Reference in a new issue