WIP adding enums to simulator
This commit is contained in:
		
							parent
							
								
									d3f52292a1
								
							
						
					
					
						commit
						4422157db8
					
				
					 3 changed files with 269 additions and 13 deletions
				
			
		|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue