diff --git a/crates/fayalite/src/sim/vcd.rs b/crates/fayalite/src/sim/vcd.rs index b8248e3..fde30be 100644 --- a/crates/fayalite/src/sim/vcd.rs +++ b/crates/fayalite/src/sim/vcd.rs @@ -5,6 +5,7 @@ use crate::{ enum_::{Enum, EnumType}, expr::Flow, int::UInt, + intern::{Intern, Interned}, sim::{ time::{SimDuration, SimInstant}, TraceArray, TraceAsyncReset, TraceBool, TraceBundle, TraceClock, TraceDecl, @@ -15,12 +16,73 @@ use crate::{ }, }; use bitvec::{order::Lsb0, slice::BitSlice}; +use hashbrown::{hash_map::Entry, HashMap}; use std::{ - fmt, - io::{self, Write}, - mem, + fmt::{self, Write as _}, + io, mem, }; +#[derive(Default)] +struct Scope { + last_inserted: HashMap, usize>, +} + +#[derive(Copy, Clone)] +struct VerilogIdentifier { + unescaped_name: Interned, +} + +impl VerilogIdentifier { + fn needs_escape(self) -> bool { + // we only allow ascii, so we can just check bytes + let Some((&first, rest)) = self.unescaped_name.as_bytes().split_first() else { + unreachable!("Scope::new_identifier guarantees a non-empty name"); + }; + if !first.is_ascii_alphabetic() && first != b'_' { + true + } else { + rest.iter() + .any(|&ch| !ch.is_ascii_alphanumeric() && ch != b'_' && ch != b'$') + } + } +} + +impl fmt::Display for VerilogIdentifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if self.needs_escape() { + f.write_str("\\")?; + } + write!(f, "{}", Escaped(self.unescaped_name)) + } +} + +impl Scope { + fn new_identifier(&mut self, unescaped_name: Interned) -> VerilogIdentifier { + let next_disambiguator = match self.last_inserted.entry(unescaped_name) { + Entry::Vacant(entry) => { + entry.insert(1); + return VerilogIdentifier { unescaped_name }; + } + Entry::Occupied(entry) => entry.get() + 1, + }; + let mut disambiguated_name = String::from(&*unescaped_name); + for disambiguator in next_disambiguator.. { + disambiguated_name.truncate(unescaped_name.len()); + write!(disambiguated_name, "_{disambiguator}").expect("can't fail"); + if let Entry::Vacant(entry) = self.last_inserted.entry((*disambiguated_name).intern()) { + let retval = VerilogIdentifier { + unescaped_name: *entry.key(), + }; + entry.insert(1); + // speed up future searches + self.last_inserted.insert(unescaped_name, disambiguator); + return retval; + } + } + panic!("too many names"); + } +} + pub struct VcdWriterDecls { writer: W, timescale: SimDuration, @@ -97,14 +159,20 @@ impl fmt::Debug for VcdWriterDecls { } } +/// pass in scope to ensure it's not available in child scope fn write_vcd_scope( writer: &mut W, scope_type: &str, - scope_name: &str, - f: impl FnOnce(&mut W) -> io::Result, + scope_name: Interned, + scope: &mut Scope, + f: impl FnOnce(&mut W, &mut Scope) -> io::Result, ) -> io::Result { - writeln!(writer, "$scope {scope_type} {scope_name} $end")?; - let retval = f(writer)?; + writeln!( + writer, + "$scope {scope_type} {} $end", + scope.new_identifier(scope_name), + )?; + let retval = f(writer, &mut Scope::default())?; writeln!(writer, "$upscope $end")?; Ok(retval) } @@ -143,24 +211,28 @@ trait_arg! { struct ArgModule<'a> { properties: &'a mut VcdWriterProperties, + scope: &'a mut Scope, } impl<'a> ArgModule<'a> { fn reborrow(&mut self) -> ArgModule<'_> { ArgModule { properties: self.properties, + scope: self.scope, } } } struct ArgModuleBody<'a> { properties: &'a mut VcdWriterProperties, + scope: &'a mut Scope, } impl<'a> ArgModuleBody<'a> { fn reborrow(&mut self) -> ArgModuleBody<'_> { ArgModuleBody { properties: self.properties, + scope: self.scope, } } } @@ -170,6 +242,7 @@ struct ArgInType<'a> { sink_var_type: &'static str, duplex_var_type: &'static str, properties: &'a mut VcdWriterProperties, + scope: &'a mut Scope, } impl<'a> ArgInType<'a> { @@ -179,6 +252,7 @@ impl<'a> ArgInType<'a> { sink_var_type: self.sink_var_type, duplex_var_type: self.duplex_var_type, properties: self.properties, + scope: self.scope, } } } @@ -226,55 +300,42 @@ fn write_vcd_id(writer: &mut W, mut id: usize) -> io::Result<()> { Ok(()) } -fn write_escaped(writer: &mut W, value: impl fmt::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); - impl io::Write for Wrapper { - fn write(&mut self, buf: &[u8]) -> io::Result { - 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}")?; +struct Escaped(T); + +impl fmt::Display for Escaped { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::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); + impl fmt::Write for Wrapper { + fn write_str(&mut self, s: &str) -> fmt::Result { + for byte in s.bytes() { + match byte { + b'\\' | b'\'' | b'"' | b'?' => { + self.0.write_str("\\")?; + self.0.write_char(byte as char)?; + } + b'\n' => self.0.write_str(r"\n")?, + b'\r' => self.0.write_str(r"\r")?, + b'\t' => self.0.write_str(r"\t")?, + 0x7 => self.0.write_str(r"\a")?, + 0x8 => self.0.write_str(r"\b")?, + 0xC => self.0.write_str(r"\f")?, + 0xB => self.0.write_str(r"\v")?, + _ => { + if byte.is_ascii_graphic() { + self.0.write_char(byte as char)?; + } else { + write!(self.0, r"\x{byte:02x}")?; + } } } } - retval += 1; + Ok(()) } - Ok(retval) - } - - fn flush(&mut self) -> io::Result<()> { - self.0.flush() } + write!(Wrapper(f), "{}", self.0) } - write!(Wrapper(writer), "{value}") -} - -fn is_unescaped_verilog_identifier(ident: &str) -> bool { - // we only allow ascii, so we can just check bytes - let Some((&first, rest)) = ident.as_bytes().split_first() else { - return false; // empty string is not an identifier - }; - (first.is_ascii_alphabetic() || first == b'_') - && rest - .iter() - .all(|&ch| ch.is_ascii_alphanumeric() || ch == b'_' || ch == b'$') } fn write_vcd_var( @@ -284,7 +345,7 @@ fn write_vcd_var( var_type: &str, size: usize, location: TraceLocation, - name: &str, + name: VerilogIdentifier, ) -> io::Result<()> { let id = match location { TraceLocation::Scalar(id) => id.as_usize(), @@ -319,12 +380,7 @@ fn write_vcd_var( }; write!(writer, "$var {var_type} {size} ")?; write_vcd_id(writer, id)?; - writer.write_all(b" ")?; - if !is_unescaped_verilog_identifier(name) { - writer.write_all(b"\\")?; - } - write_escaped(writer, name)?; - writer.write_all(b" $end\n") + writeln!(writer, " {name} $end") } impl WriteTrace for TraceUInt { @@ -334,6 +390,7 @@ impl WriteTrace for TraceUInt { sink_var_type, duplex_var_type, properties, + scope, } = arg.in_type(); let Self { location, @@ -356,7 +413,7 @@ impl WriteTrace for TraceUInt { var_type, ty.width(), location, - &name, + scope.new_identifier(name), ) } } @@ -421,6 +478,7 @@ impl WriteTrace for TraceEnumDiscriminant { sink_var_type: _, duplex_var_type: _, properties, + scope, } = arg.in_type(); let Self { location, @@ -435,7 +493,7 @@ impl WriteTrace for TraceEnumDiscriminant { "string", 1, location, - &name, + scope.new_identifier(name), ) } } @@ -507,11 +565,11 @@ impl WriteTrace for TraceScope { impl WriteTrace for TraceModule { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModule { properties } = arg.module(); + let ArgModule { properties, scope } = arg.module(); let Self { name, children } = self; - write_vcd_scope(writer, "module", &name, |writer| { + write_vcd_scope(writer, "module", name, scope, |writer, scope| { for child in children { - child.write_trace(writer, ArgModuleBody { properties })?; + child.write_trace(writer, ArgModuleBody { properties, scope })?; } Ok(()) }) @@ -520,7 +578,7 @@ impl WriteTrace for TraceModule { impl WriteTrace for TraceInstance { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties } = arg.module_body(); + let ArgModuleBody { properties, scope } = arg.module_body(); let Self { name: _, instance_io, @@ -534,15 +592,16 @@ impl WriteTrace for TraceInstance { sink_var_type: "wire", duplex_var_type: "wire", properties, + scope, }, )?; - module.write_trace(writer, ArgModule { properties }) + module.write_trace(writer, ArgModule { properties, scope }) } } impl WriteTrace for TraceMem { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties } = arg.module_body(); + let ArgModuleBody { properties, scope } = arg.module_body(); let Self { id, name, @@ -551,27 +610,41 @@ impl WriteTrace for TraceMem { ports, array_type, } = self; - write_vcd_scope(writer, "struct", &*name, |writer| { - write_vcd_scope(writer, "struct", "contents", |writer| { - for element_index in 0..array_type.len() { - write_vcd_scope(writer, "struct", &format!("[{element_index}]"), |writer| { - properties.memory_properties[id.as_usize()].element_index = element_index; - properties.memory_properties[id.as_usize()].element_part_index = 0; - element_type.write_trace( + write_vcd_scope(writer, "struct", name, scope, |writer, scope| { + write_vcd_scope( + writer, + "struct", + "contents".intern(), + scope, + |writer, scope| { + for element_index in 0..array_type.len() { + write_vcd_scope( writer, - ArgInType { - source_var_type: "reg", - sink_var_type: "reg", - duplex_var_type: "reg", - properties, + "struct", + Intern::intern_owned(format!("[{element_index}]")), + scope, + |writer, scope| { + properties.memory_properties[id.as_usize()].element_index = + element_index; + properties.memory_properties[id.as_usize()].element_part_index = 0; + element_type.write_trace( + writer, + ArgInType { + source_var_type: "reg", + sink_var_type: "reg", + duplex_var_type: "reg", + properties, + scope, + }, + ) }, - ) - })?; - } - Ok(()) - })?; + )?; + } + Ok(()) + }, + )?; for port in ports { - port.write_trace(writer, ArgModuleBody { properties })?; + port.write_trace(writer, ArgModuleBody { properties, scope })?; } Ok(()) }) @@ -580,7 +653,7 @@ impl WriteTrace for TraceMem { impl WriteTrace for TraceMemPort { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties } = arg.module_body(); + let ArgModuleBody { properties, scope } = arg.module_body(); let Self { name: _, bundle, @@ -593,6 +666,7 @@ impl WriteTrace for TraceMemPort { sink_var_type: "wire", duplex_var_type: "wire", properties, + scope, }, ) } @@ -600,7 +674,7 @@ impl WriteTrace for TraceMemPort { impl WriteTrace for TraceWire { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties } = arg.module_body(); + let ArgModuleBody { properties, scope } = arg.module_body(); let Self { name: _, child, @@ -613,6 +687,7 @@ impl WriteTrace for TraceWire { sink_var_type: "wire", duplex_var_type: "wire", properties, + scope, }, ) } @@ -620,7 +695,7 @@ impl WriteTrace for TraceWire { impl WriteTrace for TraceReg { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties } = arg.module_body(); + let ArgModuleBody { properties, scope } = arg.module_body(); let Self { name: _, child, @@ -633,6 +708,7 @@ impl WriteTrace for TraceReg { sink_var_type: "reg", duplex_var_type: "reg", properties, + scope, }, ) } @@ -640,7 +716,7 @@ impl WriteTrace for TraceReg { impl WriteTrace for TraceModuleIO { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let ArgModuleBody { properties } = arg.module_body(); + let ArgModuleBody { properties, scope } = arg.module_body(); let Self { name: _, child, @@ -654,6 +730,7 @@ impl WriteTrace for TraceModuleIO { sink_var_type: "wire", duplex_var_type: "wire", properties, + scope, }, ) } @@ -661,16 +738,31 @@ impl WriteTrace for TraceModuleIO { impl WriteTrace for TraceBundle { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let mut arg = arg.in_type(); + let ArgInType { + source_var_type, + sink_var_type, + duplex_var_type, + properties, + scope, + } = arg.in_type(); let Self { name, fields, ty: _, flow: _, } = self; - write_vcd_scope(writer, "struct", &name, |writer| { + write_vcd_scope(writer, "struct", name, scope, |writer, scope| { for field in fields { - field.write_trace(writer, arg.reborrow())?; + field.write_trace( + writer, + ArgInType { + source_var_type, + sink_var_type, + duplex_var_type, + properties, + scope, + }, + )?; } Ok(()) }) @@ -679,16 +771,31 @@ impl WriteTrace for TraceBundle { impl WriteTrace for TraceArray { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let mut arg = arg.in_type(); + let ArgInType { + source_var_type, + sink_var_type, + duplex_var_type, + properties, + scope, + } = arg.in_type(); let Self { name, elements, ty: _, flow: _, } = self; - write_vcd_scope(writer, "struct", &name, |writer| { + write_vcd_scope(writer, "struct", name, scope, |writer, scope| { for element in elements { - element.write_trace(writer, arg.reborrow())?; + element.write_trace( + writer, + ArgInType { + source_var_type, + sink_var_type, + duplex_var_type, + properties, + scope, + }, + )?; } Ok(()) }) @@ -697,7 +804,13 @@ impl WriteTrace for TraceArray { impl WriteTrace for TraceEnumWithFields { fn write_trace(self, writer: &mut W, mut arg: A) -> io::Result<()> { - let mut arg = arg.in_type(); + let ArgInType { + source_var_type, + sink_var_type, + duplex_var_type, + properties, + scope, + } = arg.in_type(); let Self { name, discriminant, @@ -705,10 +818,28 @@ impl WriteTrace for TraceEnumWithFields { ty: _, flow: _, } = self; - write_vcd_scope(writer, "struct", &name, |writer| { - discriminant.write_trace(writer, arg.reborrow())?; + write_vcd_scope(writer, "struct", name, scope, |writer, scope| { + discriminant.write_trace( + writer, + ArgInType { + source_var_type, + sink_var_type, + duplex_var_type, + properties, + scope, + }, + )?; for field in non_empty_fields { - field.write_trace(writer, arg.reborrow())?; + field.write_trace( + writer, + ArgInType { + source_var_type, + sink_var_type, + duplex_var_type, + properties, + scope, + }, + )?; } Ok(()) }) @@ -744,6 +875,7 @@ impl TraceWriterDecls for VcdWriterDecls { &mut writer, ArgModule { properties: &mut properties, + scope: &mut Scope::default(), }, )?; writeln!(writer, "$enddefinitions $end")?; @@ -798,9 +930,7 @@ fn write_string_value_change( value: impl fmt::Display, id: usize, ) -> io::Result<()> { - writer.write_all(b"s")?; - write_escaped(writer, value)?; - writer.write_all(b" ")?; + write!(writer, "s{} ", Escaped(value))?; write_vcd_id(writer, id)?; writer.write_all(b"\n") } @@ -946,3 +1076,49 @@ impl fmt::Debug for VcdWriter { .finish_non_exhaustive() } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_scope() { + let mut scope = Scope::default(); + assert_eq!(&*scope.new_identifier("foo".intern()).unescaped_name, "foo"); + assert_eq!( + &*scope.new_identifier("foo_0".intern()).unescaped_name, + "foo_0" + ); + assert_eq!( + &*scope.new_identifier("foo_1".intern()).unescaped_name, + "foo_1" + ); + assert_eq!( + &*scope.new_identifier("foo_3".intern()).unescaped_name, + "foo_3" + ); + assert_eq!( + &*scope.new_identifier("foo".intern()).unescaped_name, + "foo_2" + ); + assert_eq!( + &*scope.new_identifier("foo".intern()).unescaped_name, + "foo_4" + ); + assert_eq!( + &*scope.new_identifier("foo_0".intern()).unescaped_name, + "foo_0_2" + ); + assert_eq!( + &*scope.new_identifier("foo_1".intern()).unescaped_name, + "foo_1_2" + ); + for i in 5..1000u64 { + // verify it actually picks the next available identifier with no skips or duplicates + assert_eq!( + *scope.new_identifier("foo".intern()).unescaped_name, + format!("foo_{i}"), + ); + } + } +} diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index a249235..13e84eb 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -1246,3 +1246,33 @@ fn test_memories3() { panic!(); } } + +#[hdl_module(outline_generated)] +pub fn duplicate_names() { + #[hdl] + let w = wire(); + connect(w, 5u8); + #[hdl] + let w = wire(); + connect(w, 6u8); +} + +#[test] +fn test_duplicate_names() { + let _n = SourceLocation::normalize_files_for_tests(); + let mut sim = Simulation::new(duplicate_names()); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + sim.advance_time(SimDuration::from_micros(1)); + sim.flush_traces().unwrap(); + let vcd = String::from_utf8(writer.take()).unwrap(); + println!("####### VCD:\n{vcd}\n#######"); + if vcd != include_str!("sim/expected/duplicate_names.vcd") { + panic!(); + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug != include_str!("sim/expected/duplicate_names.txt") { + panic!(); + } +} diff --git a/crates/fayalite/tests/sim/expected/duplicate_names.txt b/crates/fayalite/tests/sim/expected/duplicate_names.txt new file mode 100644 index 0000000..8a59861 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/duplicate_names.txt @@ -0,0 +1,153 @@ +Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartLayout { + len: 4, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w", + ty: UInt<8>, + }, + SlotDebugData { + name: "", + ty: UInt<8>, + }, + SlotDebugData { + name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w", + ty: UInt<8>, + }, + SlotDebugData { + name: "", + ty: UInt<8>, + }, + ], + .. + }, + }, + memories: StatePartLayout { + len: 0, + debug_data: [], + layout_data: [], + .. + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:1:1 + 0: Const { + dest: StatePartIndex(3), // (0x6) SlotDebugData { name: "", ty: UInt<8> }, + value: 0x6, + }, + // at: module-XXXXXXXXXX.rs:5:1 + 1: Copy { + dest: StatePartIndex(2), // (0x6) SlotDebugData { name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w", ty: UInt<8> }, + src: StatePartIndex(3), // (0x6) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 2: Const { + dest: StatePartIndex(1), // (0x5) SlotDebugData { name: "", ty: UInt<8> }, + value: 0x5, + }, + // at: module-XXXXXXXXXX.rs:3:1 + 3: Copy { + dest: StatePartIndex(0), // (0x5) SlotDebugData { name: "InstantiatedModule(duplicate_names: duplicate_names).duplicate_names::w", ty: UInt<8> }, + src: StatePartIndex(1), // (0x5) SlotDebugData { name: "", ty: UInt<8> }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + 4: Return, + ], + .. + }, + pc: 4, + memory_write_log: [], + memories: StatePart { + value: [], + }, + small_slots: StatePart { + value: [], + }, + big_slots: StatePart { + value: [ + 5, + 5, + 6, + 6, + ], + }, + }, + io: Instance { + name: ::duplicate_names, + instantiated: Module { + name: duplicate_names, + .. + }, + }, + uninitialized_inputs: {}, + io_targets: {}, + made_initial_step: true, + needs_settle: false, + trace_decls: TraceModule { + name: "duplicate_names", + children: [ + TraceWire { + name: "w", + child: TraceUInt { + location: TraceScalarId(0), + name: "w", + ty: UInt<8>, + flow: Duplex, + }, + ty: UInt<8>, + }, + TraceWire { + name: "w", + child: TraceUInt { + location: TraceScalarId(1), + name: "w", + ty: UInt<8>, + flow: Duplex, + }, + ty: UInt<8>, + }, + ], + }, + traces: [ + SimTrace { + id: TraceScalarId(0), + kind: BigUInt { + index: StatePartIndex(0), + ty: UInt<8>, + }, + state: 0x05, + last_state: 0x05, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigUInt { + index: StatePartIndex(2), + ty: UInt<8>, + }, + state: 0x06, + last_state: 0x06, + }, + ], + trace_memories: {}, + trace_writers: [ + Running( + VcdWriter { + finished_init: true, + timescale: 1 ps, + .. + }, + ), + ], + instant: 1 μs, + clocks_triggered: [], + .. +} \ No newline at end of file diff --git a/crates/fayalite/tests/sim/expected/duplicate_names.vcd b/crates/fayalite/tests/sim/expected/duplicate_names.vcd new file mode 100644 index 0000000..1e9f6c6 --- /dev/null +++ b/crates/fayalite/tests/sim/expected/duplicate_names.vcd @@ -0,0 +1,11 @@ +$timescale 1 ps $end +$scope module duplicate_names $end +$var wire 8 ! w $end +$var wire 8 " w_2 $end +$upscope $end +$enddefinitions $end +$dumpvars +b101 ! +b110 " +$end +#1000000 diff --git a/crates/fayalite/tests/sim/expected/memories.vcd b/crates/fayalite/tests/sim/expected/memories.vcd index 72af410..bedc354 100644 --- a/crates/fayalite/tests/sim/expected/memories.vcd +++ b/crates/fayalite/tests/sim/expected/memories.vcd @@ -24,97 +24,97 @@ $upscope $end $upscope $end $scope struct mem $end $scope struct contents $end -$scope struct [0] $end +$scope struct \[0] $end $scope struct mem $end $var reg 8 9 \0 $end $var reg 8 I \1 $end $upscope $end $upscope $end -$scope struct [1] $end +$scope struct \[1] $end $scope struct mem $end $var reg 8 : \0 $end $var reg 8 J \1 $end $upscope $end $upscope $end -$scope struct [2] $end +$scope struct \[2] $end $scope struct mem $end $var reg 8 ; \0 $end $var reg 8 K \1 $end $upscope $end $upscope $end -$scope struct [3] $end +$scope struct \[3] $end $scope struct mem $end $var reg 8 < \0 $end $var reg 8 L \1 $end $upscope $end $upscope $end -$scope struct [4] $end +$scope struct \[4] $end $scope struct mem $end $var reg 8 = \0 $end $var reg 8 M \1 $end $upscope $end $upscope $end -$scope struct [5] $end +$scope struct \[5] $end $scope struct mem $end $var reg 8 > \0 $end $var reg 8 N \1 $end $upscope $end $upscope $end -$scope struct [6] $end +$scope struct \[6] $end $scope struct mem $end $var reg 8 ? \0 $end $var reg 8 O \1 $end $upscope $end $upscope $end -$scope struct [7] $end +$scope struct \[7] $end $scope struct mem $end $var reg 8 @ \0 $end $var reg 8 P \1 $end $upscope $end $upscope $end -$scope struct [8] $end +$scope struct \[8] $end $scope struct mem $end $var reg 8 A \0 $end $var reg 8 Q \1 $end $upscope $end $upscope $end -$scope struct [9] $end +$scope struct \[9] $end $scope struct mem $end $var reg 8 B \0 $end $var reg 8 R \1 $end $upscope $end $upscope $end -$scope struct [10] $end +$scope struct \[10] $end $scope struct mem $end $var reg 8 C \0 $end $var reg 8 S \1 $end $upscope $end $upscope $end -$scope struct [11] $end +$scope struct \[11] $end $scope struct mem $end $var reg 8 D \0 $end $var reg 8 T \1 $end $upscope $end $upscope $end -$scope struct [12] $end +$scope struct \[12] $end $scope struct mem $end $var reg 8 E \0 $end $var reg 8 U \1 $end $upscope $end $upscope $end -$scope struct [13] $end +$scope struct \[13] $end $scope struct mem $end $var reg 8 F \0 $end $var reg 8 V \1 $end $upscope $end $upscope $end -$scope struct [14] $end +$scope struct \[14] $end $scope struct mem $end $var reg 8 G \0 $end $var reg 8 W \1 $end $upscope $end $upscope $end -$scope struct [15] $end +$scope struct \[15] $end $scope struct mem $end $var reg 8 H \0 $end $var reg 8 X \1 $end diff --git a/crates/fayalite/tests/sim/expected/memories2.vcd b/crates/fayalite/tests/sim/expected/memories2.vcd index bd48f24..4039754 100644 --- a/crates/fayalite/tests/sim/expected/memories2.vcd +++ b/crates/fayalite/tests/sim/expected/memories2.vcd @@ -11,31 +11,31 @@ $var wire 1 ' wmask $end $upscope $end $scope struct mem $end $scope struct contents $end -$scope struct [0] $end +$scope struct \[0] $end $scope struct mem $end $var string 1 1 \$tag $end $var reg 1 6 HdlSome $end $upscope $end $upscope $end -$scope struct [1] $end +$scope struct \[1] $end $scope struct mem $end $var string 1 2 \$tag $end $var reg 1 7 HdlSome $end $upscope $end $upscope $end -$scope struct [2] $end +$scope struct \[2] $end $scope struct mem $end $var string 1 3 \$tag $end $var reg 1 8 HdlSome $end $upscope $end $upscope $end -$scope struct [3] $end +$scope struct \[3] $end $scope struct mem $end $var string 1 4 \$tag $end $var reg 1 9 HdlSome $end $upscope $end $upscope $end -$scope struct [4] $end +$scope struct \[4] $end $scope struct mem $end $var string 1 5 \$tag $end $var reg 1 : HdlSome $end diff --git a/crates/fayalite/tests/sim/expected/memories3.vcd b/crates/fayalite/tests/sim/expected/memories3.vcd index 328fcaa..5768560 100644 --- a/crates/fayalite/tests/sim/expected/memories3.vcd +++ b/crates/fayalite/tests/sim/expected/memories3.vcd @@ -42,7 +42,7 @@ $upscope $end $upscope $end $scope struct mem $end $scope struct contents $end -$scope struct [0] $end +$scope struct \[0] $end $scope struct mem $end $var reg 8 ] \[0] $end $var reg 8 e \[1] $end @@ -54,7 +54,7 @@ $var reg 8 /" \[6] $end $var reg 8 7" \[7] $end $upscope $end $upscope $end -$scope struct [1] $end +$scope struct \[1] $end $scope struct mem $end $var reg 8 ^ \[0] $end $var reg 8 f \[1] $end @@ -66,7 +66,7 @@ $var reg 8 0" \[6] $end $var reg 8 8" \[7] $end $upscope $end $upscope $end -$scope struct [2] $end +$scope struct \[2] $end $scope struct mem $end $var reg 8 _ \[0] $end $var reg 8 g \[1] $end @@ -78,7 +78,7 @@ $var reg 8 1" \[6] $end $var reg 8 9" \[7] $end $upscope $end $upscope $end -$scope struct [3] $end +$scope struct \[3] $end $scope struct mem $end $var reg 8 ` \[0] $end $var reg 8 h \[1] $end @@ -90,7 +90,7 @@ $var reg 8 2" \[6] $end $var reg 8 :" \[7] $end $upscope $end $upscope $end -$scope struct [4] $end +$scope struct \[4] $end $scope struct mem $end $var reg 8 a \[0] $end $var reg 8 i \[1] $end @@ -102,7 +102,7 @@ $var reg 8 3" \[6] $end $var reg 8 ;" \[7] $end $upscope $end $upscope $end -$scope struct [5] $end +$scope struct \[5] $end $scope struct mem $end $var reg 8 b \[0] $end $var reg 8 j \[1] $end @@ -114,7 +114,7 @@ $var reg 8 4" \[6] $end $var reg 8 <" \[7] $end $upscope $end $upscope $end -$scope struct [6] $end +$scope struct \[6] $end $scope struct mem $end $var reg 8 c \[0] $end $var reg 8 k \[1] $end @@ -126,7 +126,7 @@ $var reg 8 5" \[6] $end $var reg 8 =" \[7] $end $upscope $end $upscope $end -$scope struct [7] $end +$scope struct \[7] $end $scope struct mem $end $var reg 8 d \[0] $end $var reg 8 l \[1] $end