forked from libre-chip/fayalite
		
	WIP adding VCD output
This commit is contained in:
		
							parent
							
								
									0095570f19
								
							
						
					
					
						commit
						288a6b71b9
					
				
					 3 changed files with 731 additions and 6 deletions
				
			
		|  | @ -21,16 +21,21 @@ use crate::{ | |||
|         StmtWire, | ||||
|     }, | ||||
|     prelude::*, | ||||
|     sim::interpreter::{ | ||||
|         Insn, InsnField, InsnFieldKind, InsnFieldType, Insns, InsnsBuilding, InsnsBuildingDone, | ||||
|         SlotDebugData, SmallUInt, State, StatePartArrayIndex, StatePartArrayIndexed, | ||||
|         StatePartIndex, StatePartIndexRange, StatePartKind, StatePartKindBigSlots, | ||||
|         StatePartKindSmallSlots, StatePartLayout, StatePartLen, StatePartsValue, TypeArrayIndex, | ||||
|         TypeArrayIndexes, TypeIndex, TypeIndexRange, TypeLayout, TypeLen, TypeParts, | ||||
|     sim::{ | ||||
|         interpreter::{ | ||||
|             Insn, InsnField, InsnFieldKind, InsnFieldType, Insns, InsnsBuilding, InsnsBuildingDone, | ||||
|             SlotDebugData, SmallUInt, State, StatePartArrayIndex, StatePartArrayIndexed, | ||||
|             StatePartIndex, StatePartIndexRange, StatePartKind, StatePartKindBigSlots, | ||||
|             StatePartKindSmallSlots, StatePartLayout, StatePartLen, StatePartsValue, | ||||
|             TypeArrayIndex, TypeArrayIndexes, TypeIndex, TypeIndexRange, TypeLayout, TypeLen, | ||||
|             TypeParts, | ||||
|         }, | ||||
|         time::SimInstant, | ||||
|     }, | ||||
|     ty::StaticType, | ||||
|     util::DebugAsDisplay, | ||||
| }; | ||||
| use bitvec::{bits, order::Lsb0, slice::BitSlice}; | ||||
| use hashbrown::{HashMap, HashSet}; | ||||
| use num_bigint::BigInt; | ||||
| use num_traits::ToPrimitive; | ||||
|  | @ -40,6 +45,7 @@ use petgraph::visit::{ | |||
| use std::{borrow::Cow, collections::BTreeSet, fmt, marker::PhantomData, mem, ops::IndexMut}; | ||||
| 
 | ||||
| mod interpreter; | ||||
| pub mod time; | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] | ||||
| enum CondBody { | ||||
|  | @ -2756,6 +2762,11 @@ impl Compiler { | |||
|                 self.base_module, | ||||
|                 self.base_module.source_location(), | ||||
|             ), | ||||
|             trace_decls: TraceModule { | ||||
|                 name: self.base_module.name(), | ||||
|                 children: Interned::default(), // TODO: finish
 | ||||
|             }, | ||||
|             traces: Interned::default(), // TODO: finish
 | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -2770,6 +2781,8 @@ pub struct Compiled<T: BundleType> { | |||
|     insns: Interned<Insns<InsnsBuildingDone>>, | ||||
|     base_module: CompiledModule, | ||||
|     io: Instance<T>, | ||||
|     trace_decls: TraceModule, | ||||
|     traces: Interned<[SimTrace]>, | ||||
| } | ||||
| 
 | ||||
| impl<T: BundleType> Compiled<T> { | ||||
|  | @ -2781,11 +2794,15 @@ impl<T: BundleType> Compiled<T> { | |||
|             insns, | ||||
|             base_module, | ||||
|             io, | ||||
|             trace_decls, | ||||
|             traces, | ||||
|         } = self; | ||||
|         Compiled { | ||||
|             insns, | ||||
|             base_module, | ||||
|             io: Instance::from_canonical(io.canonical()), | ||||
|             trace_decls, | ||||
|             traces, | ||||
|         } | ||||
|     } | ||||
|     pub fn from_canonical(canonical: Compiled<Bundle>) -> Self { | ||||
|  | @ -2793,21 +2810,471 @@ impl<T: BundleType> Compiled<T> { | |||
|             insns, | ||||
|             base_module, | ||||
|             io, | ||||
|             trace_decls, | ||||
|             traces, | ||||
|         } = canonical; | ||||
|         Self { | ||||
|             insns, | ||||
|             base_module, | ||||
|             io: Instance::from_canonical(io.canonical()), | ||||
|             trace_decls, | ||||
|             traces, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | ||||
| pub struct TraceScalarId(usize); | ||||
| 
 | ||||
| impl TraceScalarId { | ||||
|     pub fn as_usize(self) -> usize { | ||||
|         self.0 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| macro_rules! impl_trace_decl { | ||||
|     ( | ||||
|         $( | ||||
|             #[kind = $category_kind:ident] | ||||
|             $(#[$category_meta:meta])* | ||||
|             $category_variant:ident($category_enum:ident { | ||||
|                 fn $category_property_fn:ident(self) -> $category_property_fn_ret_ty:ty; | ||||
|                 $( | ||||
|                     $(#[$meta:meta])* | ||||
|                     $variant:ident($struct:ident { | ||||
|                         fn $property_fn:ident($property_fn_self:ident) -> _ $property_fn_block:block | ||||
|                         $($(#[$field_meta:meta])* | ||||
|                         $field_name:ident: $field_ty:ty,)* | ||||
|                     }), | ||||
|                 )* | ||||
|             }), | ||||
|         )* | ||||
|     ) => { | ||||
|         $( | ||||
|             #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | ||||
|             #[non_exhaustive] | ||||
|             $(#[$category_meta])* | ||||
|             pub enum $category_kind { | ||||
|                 $($(#[$meta])* | ||||
|                 $variant,)* | ||||
|             } | ||||
| 
 | ||||
|             impl From<$category_kind> for TraceKind { | ||||
|                 fn from(v: $category_kind) -> Self { | ||||
|                     TraceKind::$category_variant(v) | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | ||||
|             #[non_exhaustive] | ||||
|             $(#[$category_meta])* | ||||
|             pub enum $category_enum { | ||||
|                 $($(#[$meta])* | ||||
|                 $variant($struct),)* | ||||
|             } | ||||
| 
 | ||||
|             impl $category_enum { | ||||
|                 pub fn kind(self) -> $category_kind { | ||||
|                     match self { | ||||
|                         $(Self::$variant(_) => $category_kind::$variant,)* | ||||
|                     } | ||||
|                 } | ||||
|                 pub fn name(self) -> Interned<str> { | ||||
|                     match self { | ||||
|                         $(Self::$variant(v) => v.name,)* | ||||
|                     } | ||||
|                 } | ||||
|                 pub fn $category_property_fn(self) -> $category_property_fn_ret_ty { | ||||
|                     match self { | ||||
|                         $(Self::$variant(v) => v.$property_fn(),)* | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             impl From<$category_enum> for TraceDecl { | ||||
|                 fn from(v: $category_enum) -> Self { | ||||
|                     TraceDecl::$category_variant(v) | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             $( | ||||
|                 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | ||||
|                 #[non_exhaustive] | ||||
|                 $(#[$meta])* | ||||
|                 pub struct $struct { | ||||
|                     $($(#[$field_meta])* | ||||
|                     pub $field_name: $field_ty,)* | ||||
|                 } | ||||
| 
 | ||||
|                 impl $struct { | ||||
|                     pub fn $property_fn($property_fn_self) -> $category_property_fn_ret_ty $property_fn_block | ||||
|                 } | ||||
| 
 | ||||
|                 impl From<$struct> for $category_enum { | ||||
|                     fn from(v: $struct) -> Self { | ||||
|                         $category_enum::$variant(v) | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 impl From<$struct> for TraceDecl { | ||||
|                     fn from(v: $struct) -> Self { | ||||
|                         TraceDecl::$category_variant($category_enum::$variant(v)) | ||||
|                     } | ||||
|                 } | ||||
|             )* | ||||
|         )* | ||||
| 
 | ||||
|         #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] | ||||
|         pub enum TraceKind { | ||||
|             $($(#[$category_meta])* | ||||
|             $category_variant($category_kind),)* | ||||
|         } | ||||
| 
 | ||||
|         #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | ||||
|         pub enum TraceDecl { | ||||
|             $($(#[$category_meta])* | ||||
|             $category_variant($category_enum),)* | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| impl_trace_decl! { | ||||
|     #[kind = TraceScopeKind] | ||||
|     Scope(TraceScope { | ||||
|         fn children(self) -> Interned<[TraceDecl]>; | ||||
|         Module(TraceModule { | ||||
|             fn children(self) -> _ { | ||||
|                 self.children | ||||
|             } | ||||
|             name: Interned<str>, | ||||
|             children: Interned<[TraceDecl]>, | ||||
|         }), | ||||
|         Instance(TraceInstance { | ||||
|             fn children(self) -> _ { | ||||
|                 self.children | ||||
|             } | ||||
|             name: Interned<str>, | ||||
|             children: Interned<[TraceDecl]>, | ||||
|             ty: Bundle, | ||||
|             flow: Flow, | ||||
|         }), | ||||
|         ModuleIO(TraceModuleIO { | ||||
|             fn children(self) -> _ { | ||||
|                 self.children | ||||
|             } | ||||
|             name: Interned<str>, | ||||
|             children: Interned<[TraceDecl]>, | ||||
|             ty: Bundle, | ||||
|             flow: Flow, | ||||
|         }), | ||||
|         Bundle(TraceBundle { | ||||
|             fn children(self) -> _ { | ||||
|                 self.children | ||||
|             } | ||||
|             name: Interned<str>, | ||||
|             children: Interned<[TraceDecl]>, | ||||
|             ty: Bundle, | ||||
|             flow: Flow, | ||||
|         }), | ||||
|         Array(TraceArray { | ||||
|             fn children(self) -> _ { | ||||
|                 self.children | ||||
|             } | ||||
|             name: Interned<str>, | ||||
|             children: Interned<[TraceDecl]>, | ||||
|             ty: Array, | ||||
|             flow: Flow, | ||||
|         }), | ||||
|         EnumWithFields(TraceEnumWithFields { | ||||
|             fn children(self) -> _ { | ||||
|                 self.children | ||||
|             } | ||||
|             name: Interned<str>, | ||||
|             children: Interned<[TraceDecl]>, | ||||
|             ty: Enum, | ||||
|             flow: Flow, | ||||
|         }), | ||||
|     }), | ||||
|     #[kind = TraceScalarKind] | ||||
|     Scalar(TraceScalar { | ||||
|         fn id(self) -> TraceScalarId; | ||||
|         UInt(TraceUInt { | ||||
|             fn id(self) -> _ { | ||||
|                 self.id | ||||
|             } | ||||
|             id: TraceScalarId, | ||||
|             name: Interned<str>, | ||||
|             ty: UInt, | ||||
|             flow: Flow, | ||||
|         }), | ||||
|         SInt(TraceSInt { | ||||
|             fn id(self) -> _ { | ||||
|                 self.id | ||||
|             } | ||||
|             id: TraceScalarId, | ||||
|             name: Interned<str>, | ||||
|             ty: SInt, | ||||
|             flow: Flow, | ||||
|         }), | ||||
|         Bool(TraceBool { | ||||
|             fn id(self) -> _ { | ||||
|                 self.id | ||||
|             } | ||||
|             id: TraceScalarId, | ||||
|             name: Interned<str>, | ||||
|             ty: Bool, | ||||
|             flow: Flow, | ||||
|         }), | ||||
|         FieldlessEnum(TraceFieldlessEnum { | ||||
|             fn id(self) -> _ { | ||||
|                 self.id | ||||
|             } | ||||
|             id: TraceScalarId, | ||||
|             name: Interned<str>, | ||||
|             ty: Enum, | ||||
|             flow: Flow, | ||||
|         }), | ||||
|         EnumDiscriminant(TraceEnumDiscriminant { | ||||
|             fn id(self) -> _ { | ||||
|                 self.id | ||||
|             } | ||||
|             id: TraceScalarId, | ||||
|             name: Interned<str>, | ||||
|             ty: Enum, | ||||
|             flow: Flow, | ||||
|         }), | ||||
|         Clock(TraceClock { | ||||
|             fn id(self) -> _ { | ||||
|                 self.id | ||||
|             } | ||||
|             id: TraceScalarId, | ||||
|             name: Interned<str>, | ||||
|             ty: Clock, | ||||
|             flow: Flow, | ||||
|         }), | ||||
|         SyncReset(TraceSyncReset { | ||||
|             fn id(self) -> _ { | ||||
|                 self.id | ||||
|             } | ||||
|             id: TraceScalarId, | ||||
|             name: Interned<str>, | ||||
|             ty: SyncReset, | ||||
|             flow: Flow, | ||||
|         }), | ||||
|         AsyncReset(TraceAsyncReset { | ||||
|             fn id(self) -> _ { | ||||
|                 self.id | ||||
|             } | ||||
|             id: TraceScalarId, | ||||
|             name: Interned<str>, | ||||
|             ty: AsyncReset, | ||||
|             flow: Flow, | ||||
|         }), | ||||
|     }), | ||||
| } | ||||
| 
 | ||||
| pub trait TraceWriterDecls: fmt::Debug + 'static + Sized { | ||||
|     type Error: std::error::Error + Send + Sync + 'static; | ||||
|     type TraceWriter: TraceWriter<Error = Self::Error>; | ||||
|     fn write_decls(self, module: TraceModule) -> Result<Self::TraceWriter, Self::Error>; | ||||
| } | ||||
| 
 | ||||
| trait TraceWriterDeclsDynTrait: fmt::Debug { | ||||
|     fn write_decls_dyn(self: Box<Self>, module: TraceModule) -> std::io::Result<DynTraceWriter>; | ||||
| } | ||||
| 
 | ||||
| fn err_into_io<E: std::error::Error + Send + Sync + 'static>(e: E) -> std::io::Error { | ||||
|     match <dyn std::error::Error + Send + Sync>::downcast::<std::io::Error>(Box::new(e)) { | ||||
|         Ok(retval) => *retval, | ||||
|         Err(e) => std::io::Error::other(e), | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T: TraceWriterDecls> TraceWriterDeclsDynTrait for T { | ||||
|     fn write_decls_dyn(self: Box<Self>, module: TraceModule) -> std::io::Result<DynTraceWriter> { | ||||
|         Ok(DynTraceWriter(Box::new( | ||||
|             TraceWriterDecls::write_decls(*self, module).map_err(err_into_io)?, | ||||
|         ))) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub trait TraceWriter: fmt::Debug + 'static { | ||||
|     type Error: std::error::Error + Send + Sync + 'static; | ||||
|     fn finish_init(&mut self) -> Result<(), Self::Error> { | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn change_time_to(&mut self, instant: SimInstant) -> Result<(), Self::Error> { | ||||
|         let _ = instant; | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn flush(&mut self) -> Result<(), Self::Error> { | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn close(self) -> Result<(), Self::Error> | ||||
|     where | ||||
|         Self: Sized, | ||||
|     { | ||||
|         Ok(()) | ||||
|     } | ||||
|     fn set_signal_uint(&mut self, id: TraceScalarId, value: &BitSlice) -> Result<(), Self::Error>; | ||||
|     fn set_signal_sint(&mut self, id: TraceScalarId, value: &BitSlice) -> Result<(), Self::Error>; | ||||
|     fn set_signal_bool(&mut self, id: TraceScalarId, value: bool) -> Result<(), Self::Error> { | ||||
|         if value { | ||||
|             self.set_signal_uint(id, bits![1]) | ||||
|         } else { | ||||
|             self.set_signal_uint(id, bits![0]) | ||||
|         } | ||||
|     } | ||||
|     fn set_signal_clock(&mut self, id: TraceScalarId, value: bool) -> Result<(), Self::Error> { | ||||
|         self.set_signal_bool(id, value) | ||||
|     } | ||||
|     fn set_signal_sync_reset(&mut self, id: TraceScalarId, value: bool) -> Result<(), Self::Error> { | ||||
|         self.set_signal_bool(id, value) | ||||
|     } | ||||
|     fn set_signal_async_reset( | ||||
|         &mut self, | ||||
|         id: TraceScalarId, | ||||
|         value: bool, | ||||
|     ) -> Result<(), Self::Error> { | ||||
|         self.set_signal_bool(id, value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct DynTraceWriterDecls(Box<dyn TraceWriterDeclsDynTrait>); | ||||
| 
 | ||||
| impl fmt::Debug for DynTraceWriterDecls { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         self.0.fmt(f) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TraceWriterDecls for DynTraceWriterDecls { | ||||
|     type Error = std::io::Error; | ||||
|     type TraceWriter = DynTraceWriter; | ||||
|     fn write_decls(self, module: TraceModule) -> Result<Self::TraceWriter, Self::Error> { | ||||
|         self.0.write_decls_dyn(module) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| trait TraceWriterDynTrait: fmt::Debug + 'static { | ||||
|     fn finish_init_dyn(&mut self) -> std::io::Result<()>; | ||||
|     fn change_time_to_dyn(&mut self, instant: SimInstant) -> std::io::Result<()>; | ||||
|     fn flush_dyn(&mut self) -> std::io::Result<()>; | ||||
|     fn close_dyn(self: Box<Self>) -> std::io::Result<()>; | ||||
|     fn set_signal_uint_dyn(&mut self, id: TraceScalarId, value: &BitSlice) -> std::io::Result<()>; | ||||
|     fn set_signal_sint_dyn(&mut self, id: TraceScalarId, value: &BitSlice) -> std::io::Result<()>; | ||||
|     fn set_signal_bool_dyn(&mut self, id: TraceScalarId, value: bool) -> std::io::Result<()>; | ||||
|     fn set_signal_clock_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) | ||||
|         -> std::io::Result<()>; | ||||
| } | ||||
| 
 | ||||
| impl<T: TraceWriter> TraceWriterDynTrait for T { | ||||
|     fn finish_init_dyn(&mut self) -> std::io::Result<()> { | ||||
|         Ok(TraceWriter::finish_init(self).map_err(err_into_io)?) | ||||
|     } | ||||
|     fn change_time_to_dyn(&mut self, instant: SimInstant) -> std::io::Result<()> { | ||||
|         Ok(TraceWriter::change_time_to(self, instant).map_err(err_into_io)?) | ||||
|     } | ||||
|     fn flush_dyn(&mut self) -> std::io::Result<()> { | ||||
|         Ok(TraceWriter::flush(self).map_err(err_into_io)?) | ||||
|     } | ||||
|     fn close_dyn(self: Box<Self>) -> std::io::Result<()> { | ||||
|         Ok(TraceWriter::close(*self).map_err(err_into_io)?) | ||||
|     } | ||||
|     fn set_signal_uint_dyn(&mut self, id: TraceScalarId, value: &BitSlice) -> std::io::Result<()> { | ||||
|         Ok(TraceWriter::set_signal_uint(self, id, value).map_err(err_into_io)?) | ||||
|     } | ||||
|     fn set_signal_sint_dyn(&mut self, id: TraceScalarId, value: &BitSlice) -> std::io::Result<()> { | ||||
|         Ok(TraceWriter::set_signal_sint(self, id, value).map_err(err_into_io)?) | ||||
|     } | ||||
|     fn set_signal_bool_dyn(&mut self, id: TraceScalarId, value: bool) -> std::io::Result<()> { | ||||
|         Ok(TraceWriter::set_signal_bool(self, id, value).map_err(err_into_io)?) | ||||
|     } | ||||
|     fn set_signal_clock_dyn(&mut self, id: TraceScalarId, value: bool) -> std::io::Result<()> { | ||||
|         Ok(TraceWriter::set_signal_clock(self, id, value).map_err(err_into_io)?) | ||||
|     } | ||||
|     fn set_signal_sync_reset_dyn(&mut self, id: TraceScalarId, value: bool) -> std::io::Result<()> { | ||||
|         Ok(TraceWriter::set_signal_sync_reset(self, id, value).map_err(err_into_io)?) | ||||
|     } | ||||
|     fn set_signal_async_reset_dyn( | ||||
|         &mut self, | ||||
|         id: TraceScalarId, | ||||
|         value: bool, | ||||
|     ) -> std::io::Result<()> { | ||||
|         Ok(TraceWriter::set_signal_async_reset(self, id, value).map_err(err_into_io)?) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct DynTraceWriter(Box<dyn TraceWriterDynTrait>); | ||||
| 
 | ||||
| impl fmt::Debug for DynTraceWriter { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         self.0.fmt(f) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TraceWriter for DynTraceWriter { | ||||
|     type Error = std::io::Error; | ||||
|     fn finish_init(&mut self) -> Result<(), Self::Error> { | ||||
|         self.0.finish_init_dyn() | ||||
|     } | ||||
|     fn flush(&mut self) -> Result<(), Self::Error> { | ||||
|         self.0.flush_dyn() | ||||
|     } | ||||
|     fn close(self) -> Result<(), Self::Error> { | ||||
|         self.0.close_dyn() | ||||
|     } | ||||
|     fn change_time_to(&mut self, instant: SimInstant) -> Result<(), Self::Error> { | ||||
|         self.0.change_time_to_dyn(instant) | ||||
|     } | ||||
|     fn set_signal_uint(&mut self, id: TraceScalarId, value: &BitSlice) -> Result<(), Self::Error> { | ||||
|         self.0.set_signal_uint_dyn(id, value) | ||||
|     } | ||||
|     fn set_signal_sint(&mut self, id: TraceScalarId, value: &BitSlice) -> Result<(), Self::Error> { | ||||
|         self.0.set_signal_sint_dyn(id, value) | ||||
|     } | ||||
|     fn set_signal_bool(&mut self, id: TraceScalarId, value: bool) -> Result<(), Self::Error> { | ||||
|         self.0.set_signal_bool_dyn(id, value) | ||||
|     } | ||||
|     fn set_signal_clock(&mut self, id: TraceScalarId, value: bool) -> Result<(), Self::Error> { | ||||
|         self.0.set_signal_clock_dyn(id, value) | ||||
|     } | ||||
|     fn set_signal_sync_reset(&mut self, id: TraceScalarId, value: bool) -> Result<(), Self::Error> { | ||||
|         self.0.set_signal_sync_reset_dyn(id, value) | ||||
|     } | ||||
|     fn set_signal_async_reset( | ||||
|         &mut self, | ||||
|         id: TraceScalarId, | ||||
|         value: bool, | ||||
|     ) -> Result<(), Self::Error> { | ||||
|         self.0.set_signal_async_reset_dyn(id, value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug)] | ||||
| enum TraceWriterState<T: TraceWriterDecls> { | ||||
|     Decls(T), | ||||
|     Init(T::TraceWriter), | ||||
|     Running(T::TraceWriter), | ||||
|     Errored(Option<T::Error>), | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, PartialEq, Eq, Hash, Debug)] | ||||
| struct SimTrace { | ||||
|     id: TraceScalarId, | ||||
| } | ||||
| 
 | ||||
| struct SimulationImpl { | ||||
|     state: interpreter::State, | ||||
|     io: Expr<Bundle>, | ||||
|     uninitialized_inputs: HashSet<Target>, | ||||
|     io_targets: HashMap<Target, CompiledValue<CanonicalType>>, | ||||
|     made_initial_step: bool, | ||||
|     trace_decls: TraceModule, | ||||
|     traces: Interned<[SimTrace]>, | ||||
|     trace_writers: Vec<TraceWriterState<DynTraceWriterDecls>>, | ||||
| } | ||||
| 
 | ||||
| impl SimulationImpl { | ||||
|  | @ -2853,6 +3320,9 @@ impl SimulationImpl { | |||
|             uninitialized_inputs: HashSet::new(), | ||||
|             io_targets: HashMap::new(), | ||||
|             made_initial_step: false, | ||||
|             trace_decls: compiled.trace_decls, | ||||
|             traces: compiled.traces, | ||||
|             trace_writers: vec![], | ||||
|         }; | ||||
|         let io_target = Target::from(compiled.io); | ||||
|         for (BundleField { name, .. }, value) in compiled | ||||
|  | @ -2991,6 +3461,72 @@ impl SimulationImpl { | |||
|             _ => unreachable!(), | ||||
|         } | ||||
|     } | ||||
|     fn close_all_trace_writers(&mut self) -> std::io::Result<()> { | ||||
|         let trace_writers = mem::take(&mut self.trace_writers); | ||||
|         let mut retval = Ok(()); | ||||
|         let close_trace_writer = | ||||
|             |trace_writer: TraceWriterState<DynTraceWriterDecls>| match trace_writer { | ||||
|                 TraceWriterState::Decls(v) => v.write_decls(self.trace_decls)?.close(), | ||||
|                 TraceWriterState::Init(v) => v.close(), | ||||
|                 TraceWriterState::Running(v) => v.close(), | ||||
|                 TraceWriterState::Errored(Some(e)) => Err(e), | ||||
|                 TraceWriterState::Errored(None) => Ok(()), | ||||
|             }; | ||||
|         for trace_writer in trace_writers { | ||||
|             retval = retval.and(close_trace_writer(trace_writer)); | ||||
|         } | ||||
|         retval | ||||
|     } | ||||
|     fn close(mut self) -> std::io::Result<()> { | ||||
|         self.close_all_trace_writers() | ||||
|     } | ||||
|     fn flush_traces(&mut self) -> std::io::Result<()> { | ||||
|         let flush_trace_writer = |trace_writer: TraceWriterState<DynTraceWriterDecls>| { | ||||
|             Ok(Some(match trace_writer { | ||||
|                 TraceWriterState::Decls(v) => { | ||||
|                     let mut v = v.write_decls(self.trace_decls)?; | ||||
|                     v.flush()?; | ||||
|                     TraceWriterState::Init(v) | ||||
|                 } | ||||
|                 TraceWriterState::Init(mut v) => { | ||||
|                     v.flush()?; | ||||
|                     TraceWriterState::Init(v) | ||||
|                 } | ||||
|                 TraceWriterState::Running(mut v) => { | ||||
|                     v.flush()?; | ||||
|                     TraceWriterState::Running(v) | ||||
|                 } | ||||
|                 TraceWriterState::Errored(Some(e)) => return Err(e), | ||||
|                 TraceWriterState::Errored(None) => return Ok(None), | ||||
|             })) | ||||
|         }; | ||||
|         let mut retval = Ok(()); | ||||
|         for trace_writer in &mut self.trace_writers { | ||||
|             *trace_writer = match flush_trace_writer(mem::replace( | ||||
|                 trace_writer, | ||||
|                 TraceWriterState::Errored(None), | ||||
|             )) { | ||||
|                 Ok(Some(v)) => v, | ||||
|                 Ok(None) => TraceWriterState::Errored(None), | ||||
|                 Err(e) => { | ||||
|                     if retval.is_ok() { | ||||
|                         retval = Err(e); | ||||
|                         TraceWriterState::Errored(None) | ||||
|                     } else { | ||||
|                         TraceWriterState::Errored(Some(e)) | ||||
|                     } | ||||
|                 } | ||||
|             }; | ||||
|         } | ||||
|         retval | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Drop for SimulationImpl { | ||||
|     fn drop(&mut self) { | ||||
|         self.close_all_trace_writers() | ||||
|             .expect("error closing trace writers"); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub struct Simulation<T: BundleType> { | ||||
|  | @ -3048,6 +3584,9 @@ impl<T: BundleType> fmt::Debug for Simulation<T> { | |||
|                     uninitialized_inputs, | ||||
|                     io_targets, | ||||
|                     made_initial_step, | ||||
|                     trace_decls, | ||||
|                     traces, | ||||
|                     trace_writers, | ||||
|                 }, | ||||
|             io, | ||||
|         } = self; | ||||
|  | @ -3060,6 +3599,9 @@ impl<T: BundleType> fmt::Debug for Simulation<T> { | |||
|             ) | ||||
|             .field("io_targets", &SortedMapDebug(io_targets)) | ||||
|             .field("made_initial_step", made_initial_step) | ||||
|             .field("trace_decls", trace_decls) | ||||
|             .field("traces", traces) | ||||
|             .field("trace_writers", trace_writers) | ||||
|             .finish() | ||||
|     } | ||||
| } | ||||
|  | @ -3068,6 +3610,12 @@ impl<T: BundleType> Simulation<T> { | |||
|     pub fn new(module: Interned<Module<T>>) -> Self { | ||||
|         Self::from_compiled(Compiled::new(module)) | ||||
|     } | ||||
|     pub fn flush_traces(&mut self) -> std::io::Result<()> { | ||||
|         self.sim_impl.flush_traces() | ||||
|     } | ||||
|     pub fn close(self) -> std::io::Result<()> { | ||||
|         self.sim_impl.close() | ||||
|     } | ||||
|     pub fn canonical(self) -> Simulation<Bundle> { | ||||
|         let Self { sim_impl, io } = self; | ||||
|         Simulation { | ||||
|  |  | |||
							
								
								
									
										165
									
								
								crates/fayalite/src/sim/time.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								crates/fayalite/src/sim/time.rs
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,165 @@ | |||
| // SPDX-License-Identifier: LGPL-3.0-or-later
 | ||||
| // See Notices.txt for copyright information
 | ||||
| use std::{fmt, time::Duration}; | ||||
| 
 | ||||
| #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] | ||||
| pub struct SimInstant { | ||||
|     time_since_start: SimDuration, | ||||
| } | ||||
| 
 | ||||
| impl fmt::Debug for SimInstant { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         self.time_since_start.fmt(f) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] | ||||
| pub struct SimDuration { | ||||
|     attos: u128, | ||||
| } | ||||
| 
 | ||||
| #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)] | ||||
| pub struct SimDurationParts { | ||||
|     pub attos: u16, | ||||
|     pub femtos: u16, | ||||
|     pub picos: u16, | ||||
|     pub nanos: u16, | ||||
|     pub micros: u16, | ||||
|     pub millis: u16, | ||||
|     pub secs: u128, | ||||
| } | ||||
| 
 | ||||
| macro_rules! impl_duration_units { | ||||
|     ( | ||||
|         $( | ||||
|             #[unit_const = $UNIT:ident, from_units = $from_units:ident, units = $units:ident, suffix = $suffix:literal] | ||||
|             const $log10_units_per_sec:ident: u32 = $log10_units_per_sec_value:expr; | ||||
|         )* | ||||
|     ) => { | ||||
|         impl SimDuration { | ||||
|             $( | ||||
|                 const $log10_units_per_sec: u32 = $log10_units_per_sec_value; | ||||
|                 pub const fn $from_units($units: u128) -> Self { | ||||
|                     Self::from_units_helper::<{ Self::$log10_units_per_sec }>($units) | ||||
|                 } | ||||
|             )* | ||||
|             pub const fn into_parts(mut self) -> SimDurationParts { | ||||
|                 $( | ||||
|                     let $units = self.attos / const { 10u128.pow(Self::LOG10_ATTOS_PER_SEC - Self::$log10_units_per_sec) }; | ||||
|                     self.attos %= const { 10u128.pow(Self::LOG10_ATTOS_PER_SEC - Self::$log10_units_per_sec) }; | ||||
|                 )* | ||||
|                 SimDurationParts { | ||||
|                     $($units: $units as _,)* | ||||
|                 } | ||||
|             } | ||||
|             pub const fn from_parts_checked(parts: SimDurationParts) -> Option<Self> { | ||||
|                 let attos = 0u128; | ||||
|                 $( | ||||
|                     let Some(product) = const { 10u128.pow(Self::LOG10_ATTOS_PER_SEC - Self::$log10_units_per_sec) }.checked_mul(parts.$units as u128) else { | ||||
|                         return None; | ||||
|                     }; | ||||
|                     let Some(attos) = attos.checked_add(product) else { | ||||
|                         return None; | ||||
|                     }; | ||||
|                 )* | ||||
|                 Some(Self { | ||||
|                     attos, | ||||
|                 }) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         impl fmt::Debug for SimDuration { | ||||
|             fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|                 let ilog10_attos = match self.attos.checked_ilog10() { | ||||
|                     Some(v) => v, | ||||
|                     None => Self::LOG10_ATTOS_PER_SEC, | ||||
|                 }; | ||||
|                 let (suffix, int, fraction, fraction_digits) = | ||||
|                     match Self::LOG10_ATTOS_PER_SEC.saturating_sub(ilog10_attos) { | ||||
|                     $( | ||||
|                         ..=Self::$log10_units_per_sec => { | ||||
|                             let divisor = const { 10u128.pow(Self::LOG10_ATTOS_PER_SEC - Self::$log10_units_per_sec) }; | ||||
|                             ( | ||||
|                                 $suffix, | ||||
|                                 self.attos / divisor, | ||||
|                                 self.attos % divisor, | ||||
|                                 (Self::LOG10_ATTOS_PER_SEC - Self::$log10_units_per_sec) as usize, | ||||
|                             ) | ||||
|                         }, | ||||
|                     )* | ||||
|                     _ => unreachable!(), | ||||
|                 }; | ||||
|                 write!(f, "{int}")?; | ||||
|                 if fraction != 0 { | ||||
|                     write!(f, ".{fraction:0fraction_digits$}")?; | ||||
|                 } | ||||
|                 write!(f, " {suffix}") | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #[cfg(test)] | ||||
|         #[test] | ||||
|         fn test_duration_debug() { | ||||
|             $( | ||||
|                 assert_eq!( | ||||
|                     format!("{:?}", SimDuration::$from_units(123)), | ||||
|                     concat!("123 ", $suffix) | ||||
|                 ); | ||||
|                 assert_eq!( | ||||
|                     format!("{:?}", SimDuration::$from_units(1)), | ||||
|                     concat!("1 ", $suffix), | ||||
|                 ); | ||||
|                 let mut v = SimDuration::$from_units(1); | ||||
|                 if v.attos < 1 << 53 { | ||||
|                     v.attos += 1; | ||||
|                     assert_eq!( | ||||
|                         format!("{v:?}"), | ||||
|                         format!("{} {}", v.attos as f64 / 10.0f64.powf((SimDuration::LOG10_ATTOS_PER_SEC - SimDuration::$log10_units_per_sec) as f64), $suffix), | ||||
|                         "1 {} + 1 as == {} as", $suffix, v.attos, | ||||
|                     ); | ||||
|                 } | ||||
|             )* | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| impl_duration_units! { | ||||
|     #[unit_const = SECOND, from_units = from_secs, units = secs, suffix = "s"] | ||||
|     const LOG10_SECS_PER_SEC: u32 = 0; | ||||
|     #[unit_const = MILLISECOND, from_units = from_millis, units = millis, suffix = "ms"] | ||||
|     const LOG10_MILLIS_PER_SEC: u32 = 3; | ||||
|     #[unit_const = MICROSECOND, from_units = from_micros, units = micros, suffix = "μs"] | ||||
|     const LOG10_MICROS_PER_SEC: u32 = 6; | ||||
|     #[unit_const = NANOSECOND, from_units = from_nanos, units = nanos, suffix = "ns"] | ||||
|     const LOG10_NANOS_PER_SEC: u32 = 9; | ||||
|     #[unit_const = PICOSECOND, from_units = from_picos, units = picos, suffix = "ps"] | ||||
|     const LOG10_PICOS_PER_SEC: u32 = 12; | ||||
|     #[unit_const = FEMTOSECOND, from_units = from_femtos, units = femtos, suffix = "fs"] | ||||
|     const LOG10_FEMTOS_PER_SEC: u32 = 15; | ||||
|     #[unit_const = ATTOSECOND, from_units = from_attos, units = attos, suffix = "as"] | ||||
|     const LOG10_ATTOS_PER_SEC: u32 = 18; | ||||
| } | ||||
| 
 | ||||
| impl SimDuration { | ||||
|     const fn from_units_helper<const UNITS_PER_SEC: u32>(units: u128) -> Self { | ||||
|         let Some(attos) = | ||||
|             units.checked_mul(const { 10u128.pow(Self::LOG10_ATTOS_PER_SEC - UNITS_PER_SEC) }) | ||||
|         else { | ||||
|             panic!("duration too big"); | ||||
|         }; | ||||
|         Self { attos } | ||||
|     } | ||||
|     pub const ZERO: SimDuration = SimDuration::from_secs(0); | ||||
|     pub const fn from_parts(parts: SimDurationParts) -> Self { | ||||
|         match Self::from_parts_checked(parts) { | ||||
|             Some(v) => v, | ||||
|             None => panic!("duration too big"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<Duration> for SimDuration { | ||||
|     fn from(duration: Duration) -> Self { | ||||
|         Self::from_nanos(duration.as_nanos()) | ||||
|     } | ||||
| } | ||||
|  | @ -115,6 +115,12 @@ fn test_connect_const() { | |||
|         }, | ||||
|     }, | ||||
|     made_initial_step: true, | ||||
|     trace_decls: TraceModule { | ||||
|         name: "connect_const", | ||||
|         children: [], | ||||
|     }, | ||||
|     traces: [], | ||||
|     trace_writers: [], | ||||
| }"# {
 | ||||
|         panic!(); | ||||
|     } | ||||
|  | @ -673,6 +679,12 @@ fn test_mod1() { | |||
|         }, | ||||
|     }, | ||||
|     made_initial_step: true, | ||||
|     trace_decls: TraceModule { | ||||
|         name: "mod1", | ||||
|         children: [], | ||||
|     }, | ||||
|     traces: [], | ||||
|     trace_writers: [], | ||||
| }"# {
 | ||||
|         panic!(); | ||||
|     } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue