From fd45465d357e0e94ddfdd0e28fbda2c673f6d9bc Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Sun, 1 Dec 2024 20:14:13 -0800 Subject: [PATCH] sim: add support for registers --- crates/fayalite/src/sim.rs | 487 ++++- crates/fayalite/src/sim/interpreter.rs | 33 + crates/fayalite/tests/sim.rs | 2481 +++++++++++++++++++++++- 3 files changed, 2944 insertions(+), 57 deletions(-) diff --git a/crates/fayalite/src/sim.rs b/crates/fayalite/src/sim.rs index 857ced9..6a18355 100644 --- a/crates/fayalite/src/sim.rs +++ b/crates/fayalite/src/sim.rs @@ -21,6 +21,7 @@ use crate::{ StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, TargetInInstantiatedModule, }, prelude::*, + reset::{ResetType, ResetTypeDispatch}, sim::{ interpreter::{ Insn, InsnField, InsnFieldKind, InsnFieldType, Insns, InsnsBuilding, InsnsBuildingDone, @@ -208,6 +209,14 @@ impl CompiledValue { fn write(self) -> (CompiledTypeLayout, TypeIndexRange) { self.write.unwrap_or((self.layout, self.range)) } + fn write_value(self) -> Self { + let (layout, range) = self.write(); + Self { + layout, + range, + write: None, + } + } fn map( self, mut f: impl FnMut( @@ -1180,6 +1189,29 @@ impl Assignment { } } +#[derive(Debug)] +struct RegisterReset { + is_async: bool, + init: CompiledValue, + rst: StatePartIndex, +} + +#[derive(Debug, Clone, Copy)] +struct ClockTrigger { + last_clk_was_low: StatePartIndex, + clk: StatePartIndex, + clk_triggered: StatePartIndex, + source_location: SourceLocation, +} + +#[derive(Debug)] +struct Register { + value: CompiledValue, + clk_triggered: StatePartIndex, + reset: Option, + source_location: SourceLocation, +} + #[derive(Debug)] pub struct Compiler { insns: Insns, @@ -1192,7 +1224,12 @@ pub struct Compiler { decl_conditions: HashMap>, compiled_values_to_dyn_array_indexes: HashMap, StatePartIndex>, + compiled_value_bool_dest_is_small_map: + HashMap, StatePartIndex>, assignments: Assignments, + clock_triggers: Vec, + compiled_value_to_clock_trigger_map: HashMap, ClockTrigger>, + registers: Vec, traces: Vec>, } @@ -1211,7 +1248,11 @@ impl Compiler { compiled_exprs_to_values: HashMap::new(), decl_conditions: HashMap::new(), compiled_values_to_dyn_array_indexes: HashMap::new(), + compiled_value_bool_dest_is_small_map: HashMap::new(), assignments: Assignments::default(), + clock_triggers: Vec::new(), + compiled_value_to_clock_trigger_map: HashMap::new(), + registers: Vec::new(), traces: Vec::new(), } } @@ -1664,6 +1705,48 @@ impl Compiler { .insert(compiled_value, retval); retval } + fn compiled_value_bool_dest_is_small( + &mut self, + compiled_value: CompiledValue, + source_location: SourceLocation, + ) -> StatePartIndex { + if let Some(&retval) = self + .compiled_value_bool_dest_is_small_map + .get(&compiled_value) + { + return retval; + } + let retval = match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => compiled_value.range.small_slots.start, + TypeLen::A_BIG_SLOT => { + let debug_data = SlotDebugData { + name: Interned::default(), + ty: Bool.canonical(), + }; + let dest = self + .insns + .allocate_variable(&TypeLayout { + small_slots: StatePartLayout::scalar(debug_data), + big_slots: StatePartLayout::empty(), + }) + .small_slots + .start; + self.add_assignment( + Interned::default(), + vec![Insn::IsNonZeroDestIsSmall { + dest, + src: compiled_value.range.big_slots.start, + }], + source_location, + ); + dest + } + _ => unreachable!(), + }; + self.compiled_value_bool_dest_is_small_map + .insert(compiled_value, retval); + retval + } fn compile_expr( &mut self, instantiated_module: InstantiatedModule, @@ -2626,6 +2709,125 @@ impl Compiler { source_location, ); } + fn compile_clock( + &mut self, + clk: CompiledValue, + source_location: SourceLocation, + ) -> ClockTrigger { + if let Some(&retval) = self.compiled_value_to_clock_trigger_map.get(&clk) { + return retval; + } + let mut alloc_small_slot = |part_name: &str| { + self.insns + .state_layout + .ty + .small_slots + .allocate(&StatePartLayout::scalar(SlotDebugData { + name: Interned::default(), + ty: Bool.canonical(), + })) + .start + }; + let last_clk_was_low = alloc_small_slot("last_clk_was_low"); + let clk_triggered = alloc_small_slot("clk_triggered"); + let retval = ClockTrigger { + last_clk_was_low, + clk: self.compiled_value_bool_dest_is_small( + clk.map_ty(CanonicalType::Clock), + source_location, + ), + clk_triggered, + source_location, + }; + self.add_assignment( + Interned::default(), + [Insn::AndSmall { + dest: clk_triggered, + lhs: retval.clk, + rhs: last_clk_was_low, + }], + source_location, + ); + self.clock_triggers.push(retval); + self.compiled_value_to_clock_trigger_map.insert(clk, retval); + retval + } + fn compile_stmt_reg( + &mut self, + stmt_reg: StmtReg, + instantiated_module: InstantiatedModule, + value: CompiledValue, + ) { + let StmtReg { annotations, reg } = stmt_reg; + let clk = self.compile_expr(instantiated_module, Expr::canonical(reg.clock_domain().clk)); + let clk = self + .compiled_expr_to_value(clk, reg.source_location()) + .map_ty(Clock::from_canonical); + let clk = self.compile_clock(clk, reg.source_location()); + struct Dispatch; + impl ResetTypeDispatch for Dispatch { + type Input = (); + + type Output = bool; + + fn reset(self, _input: Self::Input) -> Self::Output { + unreachable!() + } + + fn sync_reset(self, _input: Self::Input) -> Self::Output { + false + } + + fn async_reset(self, _input: Self::Input) -> Self::Output { + true + } + } + let reset = if let Some(init) = reg.init() { + let init = self.compile_expr(instantiated_module, init); + let init = self.compiled_expr_to_value(init, reg.source_location()); + let rst = + self.compile_expr(instantiated_module, Expr::canonical(reg.clock_domain().rst)); + let rst = self.compiled_expr_to_value(rst, reg.source_location()); + let rst = self.compiled_value_bool_dest_is_small(rst, reg.source_location()); + let is_async = R::dispatch((), Dispatch); + if is_async { + let cond = Expr::canonical(reg.clock_domain().rst.cast_to(Bool)); + let cond = self.compile_expr(instantiated_module, cond); + let cond = self.compiled_expr_to_value(cond, reg.source_location()); + let cond = cond.map_ty(Bool::from_canonical); + // write to the register's current value since asynchronous reset is combinational + let lhs = CompiledValue { + layout: value.layout, + range: value.range, + write: None, + } + .into(); + self.compile_simple_connect( + [Cond { + body: CondBody::IfTrue { cond }, + source_location: reg.source_location(), + }][..] + .intern(), + lhs, + init, + reg.source_location(), + ); + } + Some(RegisterReset { + is_async, + init, + rst, + }) + } else { + None + }; + self.registers.push(Register { + value, + clk_triggered: clk.clk_triggered, + reset, + source_location: reg.source_location(), + }); + } fn compile_declaration( &mut self, declaration: StmtDeclaration, @@ -2644,17 +2846,17 @@ impl Compiler { target: target_base.into(), }; self.decl_conditions.insert(target, conditions); - self.compile_value(target); + let compiled_value = self.compile_value(target); match declaration { StmtDeclaration::Wire(StmtWire { annotations, wire }) => {} - StmtDeclaration::Reg(StmtReg { annotations, reg }) => { - todo!(); + StmtDeclaration::Reg(_) => { + unreachable!("Reset types were already replaced by SyncReset or AsyncReset"); } - StmtDeclaration::RegSync(StmtReg { annotations, reg }) => { - todo!(); + StmtDeclaration::RegSync(stmt_reg) => { + self.compile_stmt_reg(stmt_reg, *parent_module, compiled_value) } - StmtDeclaration::RegAsync(StmtReg { annotations, reg }) => { - todo!(); + StmtDeclaration::RegAsync(stmt_reg) => { + self.compile_stmt_reg(stmt_reg, *parent_module, compiled_value) } StmtDeclaration::Instance(StmtInstance { annotations, @@ -2938,10 +3140,109 @@ impl Compiler { } } } + fn process_clocks(&mut self) -> Interned<[StatePartIndex]> { + mem::take(&mut self.clock_triggers) + .into_iter() + .map( + |ClockTrigger { + last_clk_was_low, + clk, + clk_triggered, + source_location, + }| { + self.insns.push( + Insn::NotSmall { + dest: last_clk_was_low, + src: clk, + }, + source_location, + ); + clk_triggered + }, + ) + .collect() + } + fn process_registers(&mut self) { + for Register { + value, + clk_triggered, + reset, + source_location, + } in mem::take(&mut self.registers) + { + let write_to_current_value = |value_to_write: CompiledValue| { + let TypeIndexRange { + small_slots, + big_slots, + } = value.range; + small_slots + .iter() + .zip(value_to_write.range.small_slots.iter()) + .map(|(base, src)| Insn::CopySmall { dest: base, src }) + .chain( + big_slots + .iter() + .zip(value_to_write.range.big_slots.iter()) + .map(|(base, src)| Insn::Copy { dest: base, src }), + ) + }; + match reset { + Some(RegisterReset { + is_async, + init, + rst, + }) => { + let reg_end = self.insns.new_label(); + let reg_reset = self.insns.new_label(); + let branch_if_reset = Insn::BranchIfSmallNonZero { + target: reg_reset, + value: rst, + }; + let branch_if_not_triggered = Insn::BranchIfSmallZero { + target: reg_end, + value: clk_triggered, + }; + if is_async { + self.insns.push(branch_if_reset, source_location); + self.insns.push(branch_if_not_triggered, source_location); + } else { + self.insns.push(branch_if_not_triggered, source_location); + self.insns.push(branch_if_reset, source_location); + } + for insn in write_to_current_value(value.write_value()) { + self.insns.push(insn, source_location); + } + self.insns + .push(Insn::Branch { target: reg_end }, source_location); + self.insns.define_label_at_next_insn(reg_reset); + for insn in write_to_current_value(init) { + self.insns.push(insn, source_location); + } + self.insns.define_label_at_next_insn(reg_end); + } + None => { + let reg_end = self.insns.new_label(); + self.insns.push( + Insn::BranchIfSmallZero { + target: reg_end, + value: clk_triggered, + }, + source_location, + ); + for insn in write_to_current_value(value.write_value()) { + self.insns.push(insn, source_location); + } + self.insns.define_label_at_next_insn(reg_end); + } + } + } + } pub fn compile(mut self) -> Compiled { let base_module = *self.compile_module(InstantiatedModule::Base(self.base_module).intern_sized()); self.process_assignments(); + self.process_registers(); + let clocks_triggered = self.process_clocks(); self.insns .push(Insn::Return, self.base_module.source_location()); Compiled { @@ -2956,6 +3257,7 @@ impl Compiler { self.original_base_module.source_location(), ), traces: Intern::intern_owned(self.traces), + clocks_triggered, } } } @@ -2972,6 +3274,7 @@ pub struct Compiled { base_module: CompiledModule, io: Instance, traces: Interned<[SimTrace<()>]>, + clocks_triggered: Interned<[StatePartIndex]>, } impl Compiled { @@ -2984,12 +3287,14 @@ impl Compiled { base_module, io, traces, + clocks_triggered, } = self; Compiled { insns, base_module, io: Instance::from_canonical(io.canonical()), traces, + clocks_triggered, } } pub fn from_canonical(canonical: Compiled) -> Self { @@ -2998,12 +3303,14 @@ impl Compiled { base_module, io, traces, + clocks_triggered, } = canonical; Self { insns, base_module, io: Instance::from_canonical(io.canonical()), traces, + clocks_triggered, } } } @@ -3621,6 +3928,7 @@ struct SimulationImpl { traces: Box<[SimTrace]>, trace_writers: Vec>, instant: SimInstant, + clocks_triggered: Interned<[StatePartIndex]>, } impl SimulationImpl { @@ -3683,6 +3991,7 @@ impl SimulationImpl { )), trace_writers: vec![], instant: SimInstant::START, + clocks_triggered: compiled.clocks_triggered, }; let io_target = Target::from(compiled.io); for (BundleField { name, .. }, value) in compiled @@ -3802,7 +4111,7 @@ impl SimulationImpl { } #[track_caller] fn advance_time(&mut self, duration: SimDuration) { - self.settle_step(); + self.settle(); self.instant += duration; self.for_each_trace_writer_storing_error(|this, mut trace_writer_state| { match &mut trace_writer_state { @@ -3816,37 +4125,43 @@ impl SimulationImpl { }); } #[track_caller] - fn settle_step(&mut self) { + fn settle(&mut self) { assert!( self.uninitialized_inputs.is_empty(), "didn't initialize all inputs", ); - if !self.needs_settle { - return; + for _ in 0..100000 { + if !self.needs_settle { + return; + } + self.state.setup_call(0); + self.state.run(); + if self.made_initial_step { + self.read_traces::(); + } else { + self.read_traces::(); + } + self.made_initial_step = true; + self.needs_settle = self + .clocks_triggered + .iter() + .any(|i| self.state.small_slots[*i] != 0); + self.for_each_trace_writer_storing_error(|this, trace_writer_state| { + Ok(match trace_writer_state { + TraceWriterState::Decls(trace_writer_decls) => TraceWriterState::Running( + this.init_trace_writer(trace_writer_decls.write_decls(this.trace_decls)?)?, + ), + TraceWriterState::Init(trace_writer) => { + TraceWriterState::Running(this.init_trace_writer(trace_writer)?) + } + TraceWriterState::Running(trace_writer) => { + TraceWriterState::Running(this.update_trace_writer(trace_writer)?) + } + TraceWriterState::Errored(e) => TraceWriterState::Errored(e), + }) + }); } - self.state.setup_call(0); - self.state.run(); - if self.made_initial_step { - self.read_traces::(); - } else { - self.read_traces::(); - } - self.made_initial_step = true; - self.needs_settle = false; - self.for_each_trace_writer_storing_error(|this, trace_writer_state| { - Ok(match trace_writer_state { - TraceWriterState::Decls(trace_writer_decls) => TraceWriterState::Running( - this.init_trace_writer(trace_writer_decls.write_decls(this.trace_decls)?)?, - ), - TraceWriterState::Init(trace_writer) => { - TraceWriterState::Running(this.init_trace_writer(trace_writer)?) - } - TraceWriterState::Running(trace_writer) => { - TraceWriterState::Running(this.update_trace_writer(trace_writer)?) - } - TraceWriterState::Errored(e) => TraceWriterState::Errored(e), - }) - }); + panic!("settle(): took too many steps"); } #[track_caller] fn get_io(&self, target: Target) -> CompiledValue { @@ -3861,13 +4176,13 @@ impl SimulationImpl { panic!("simulator read/write expression must not have dynamic array indexes"); } #[track_caller] - fn read_bool_or_int(&mut self, io: Expr) -> I::Value { + fn read_helper(&mut self, io: Expr) -> CompiledValue { let Some(target) = io.target() else { panic!("can't read from expression that's not a field/element of `Simulation::io()`"); }; let compiled_value = self.get_io(*target); if self.made_initial_step { - self.settle_step(); + self.settle(); } else { match target.flow() { Flow::Source => { @@ -3881,6 +4196,56 @@ impl SimulationImpl { Flow::Duplex => unreachable!(), } } + compiled_value + } + #[track_caller] + fn write_helper(&mut self, io: Expr) -> CompiledValue { + let Some(target) = io.target() else { + panic!("can't write to an expression that's not a field/element of `Simulation::io()`"); + }; + let compiled_value = self.get_io(*target); + match target.flow() { + Flow::Source => { + panic!("can't write to an output"); + } + Flow::Sink => {} + Flow::Duplex => unreachable!(), + } + if !self.made_initial_step { + self.uninitialized_inputs.remove(&*target); + } + self.needs_settle = true; + compiled_value + } + #[track_caller] + fn read_bit(&mut self, io: Expr) -> bool { + let compiled_value = self.read_helper(Expr::canonical(io)); + match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => { + self.state.small_slots[compiled_value.range.small_slots.start] != 0 + } + TypeLen::A_BIG_SLOT => !self.state.big_slots[compiled_value.range.big_slots.start] + .clone() + .is_zero(), + _ => unreachable!(), + } + } + #[track_caller] + fn write_bit(&mut self, io: Expr, value: bool) { + let compiled_value = self.write_helper(io); + match compiled_value.range.len() { + TypeLen::A_SMALL_SLOT => { + self.state.small_slots[compiled_value.range.small_slots.start] = value as _; + } + TypeLen::A_BIG_SLOT => { + self.state.big_slots[compiled_value.range.big_slots.start] = value.into() + } + _ => unreachable!(), + } + } + #[track_caller] + fn read_bool_or_int(&mut self, io: Expr) -> I::Value { + let compiled_value = self.read_helper(Expr::canonical(io)); match compiled_value.range.len() { TypeLen::A_SMALL_SLOT => Expr::ty(io).value_from_int_wrapping( self.state.small_slots[compiled_value.range.small_slots.start], @@ -3893,22 +4258,8 @@ impl SimulationImpl { } #[track_caller] fn write_bool_or_int(&mut self, io: Expr, value: I::Value) { - let Some(target) = io.target() else { - panic!("can't write to an expression that's not a field/element of `Simulation::io()`"); - }; - let compiled_value = self.get_io(*target); - match target.flow() { - Flow::Source => { - panic!("can't write to an output"); - } - Flow::Sink => {} - Flow::Duplex => unreachable!(), - } + let compiled_value = self.write_helper(Expr::canonical(io)); let value: BigInt = value.into(); - if !self.made_initial_step { - self.uninitialized_inputs.remove(&*target); - } - self.needs_settle = true; match compiled_value.range.len() { TypeLen::A_SMALL_SLOT => { self.state.small_slots[compiled_value.range.small_slots.start] = @@ -3985,13 +4336,13 @@ impl SimulationImpl { } fn close(mut self) -> std::io::Result<()> { if self.made_initial_step { - self.settle_step(); + self.settle(); } self.close_all_trace_writers() } fn flush_traces(&mut self) -> std::io::Result<()> { if self.made_initial_step { - self.settle_step(); + self.settle(); } self.for_each_trace_writer_getting_error( |this, trace_writer: TraceWriterState| match trace_writer { @@ -4082,6 +4433,7 @@ impl fmt::Debug for Simulation { traces, trace_writers, instant, + clocks_triggered, }, io, } = self; @@ -4099,6 +4451,7 @@ impl fmt::Debug for Simulation { .field("traces", traces) .field("trace_writers", trace_writers) .field("instant", instant) + .field("clocks_triggered", clocks_triggered) .finish() } } @@ -4143,8 +4496,8 @@ impl Simulation { } } #[track_caller] - pub fn settle_step(&mut self) { - self.sim_impl.settle_step(); + pub fn settle(&mut self) { + self.sim_impl.settle(); } #[track_caller] pub fn advance_time(&mut self, duration: SimDuration) { @@ -4168,4 +4521,28 @@ impl Simulation { self.sim_impl .write_bool_or_int(io, I::bits_to_value(Cow::Borrowed(&value))); } + #[track_caller] + pub fn write_clock(&mut self, io: Expr, value: bool) { + self.sim_impl.write_bit(Expr::canonical(io), value); + } + #[track_caller] + pub fn read_clock(&mut self, io: Expr) -> bool { + self.sim_impl.read_bit(Expr::canonical(io)) + } + #[track_caller] + pub fn write_bool(&mut self, io: Expr, value: bool) { + self.sim_impl.write_bit(Expr::canonical(io), value); + } + #[track_caller] + pub fn read_bool(&mut self, io: Expr) -> bool { + self.sim_impl.read_bit(Expr::canonical(io)) + } + #[track_caller] + pub fn write_reset(&mut self, io: Expr, value: bool) { + self.sim_impl.write_bit(Expr::canonical(io), value); + } + #[track_caller] + pub fn read_reset(&mut self, io: Expr) -> bool { + self.sim_impl.read_bit(Expr::canonical(io)) + } } diff --git a/crates/fayalite/src/sim/interpreter.rs b/crates/fayalite/src/sim/interpreter.rs index 5ef2fbc..643b604 100644 --- a/crates/fayalite/src/sim/interpreter.rs +++ b/crates/fayalite/src/sim/interpreter.rs @@ -2201,6 +2201,17 @@ impl_insns! { state.small_slots[dest] = value; next!(); } + IsNonZeroDestIsSmall { + #[kind = Output] + dest: StatePartIndex, + #[kind = Input] + src: StatePartIndex, + } => { + let src = &state.big_slots[src]; + let value = !src.is_zero(); + state.small_slots[dest] = value as SmallUInt; + next!(); + } CastToSInt { #[kind = Output] dest: StatePartIndex, @@ -2237,6 +2248,18 @@ impl_insns! { state.big_slots[dest] = value; next!(); } + AndSmall { + #[kind = Output] + dest: StatePartIndex, + #[kind = Input] + lhs: StatePartIndex, + #[kind = Input] + rhs: StatePartIndex, + } => { + let value = state.small_slots[lhs] & state.small_slots[rhs]; + state.small_slots[dest] = value; + next!(); + } Or { #[kind = Output] dest: StatePartIndex, @@ -2283,6 +2306,16 @@ impl_insns! { state.big_slots[dest] = value; next!(); } + NotSmall { + #[kind = Output] + dest: StatePartIndex, + #[kind = Input] + src: StatePartIndex, + } => { + let value = !state.small_slots[src]; + state.small_slots[dest] = value; + next!(); + } Neg { #[kind = Output] dest: StatePartIndex, diff --git a/crates/fayalite/tests/sim.rs b/crates/fayalite/tests/sim.rs index b329603..f34bb89 100644 --- a/crates/fayalite/tests/sim.rs +++ b/crates/fayalite/tests/sim.rs @@ -3,6 +3,7 @@ use fayalite::{ int::UIntValue, prelude::*, + reset::ResetType, sim::{time::SimDuration, vcd::VcdWriterDecls, Simulation}, util::RcWriter, }; @@ -18,7 +19,7 @@ pub fn connect_const() { fn test_connect_const() { let _n = SourceLocation::normalize_files_for_tests(); let mut sim = Simulation::new(connect_const()); - sim.settle_step(); + sim.settle(); let sim_debug = format!("{sim:#?}"); println!("#######\n{sim_debug}\n#######"); if sim_debug @@ -150,6 +151,7 @@ fn test_connect_const() { ], trace_writers: [], instant: 0 s, + clocks_triggered: [], }"# { panic!(); } @@ -172,7 +174,7 @@ fn test_connect_const_reset() { let mut sim = Simulation::new(connect_const_reset()); let mut writer = RcWriter::default(); sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); - sim.settle_step(); + sim.settle(); sim.advance_time(SimDuration::from_micros(1)); sim.flush_traces().unwrap(); let vcd = String::from_utf8(writer.take()).unwrap(); @@ -410,6 +412,7 @@ $end ), ], instant: 1 μs, + clocks_triggered: [], }"# { panic!(); } @@ -1308,6 +1311,7 @@ b1111 , ), ], instant: 2 μs, + clocks_triggered: [], }"# { panic!(); } @@ -1316,3 +1320,2476 @@ b1111 , let expected = 0xF_hdl_u4; assert_eq!(sim.read_bool_or_int(sim.io().o.o2).to_expr(), expected); } + +#[hdl_module(outline_generated)] +pub fn counter() { + #[hdl] + let cd: ClockDomain = m.input(); + #[hdl] + let count_reg: UInt<4> = reg_builder().clock_domain(cd).reset(3_hdl_u4); + connect_any(count_reg, count_reg + 1_hdl_u1); + #[hdl] + let count: UInt<4> = m.output(); + connect(count, count_reg); +} + +#[hdl] +#[test] +fn test_counter_sync() { + let _n = SourceLocation::normalize_files_for_tests(); + let mut sim = Simulation::new(counter::()); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + sim.write_clock(sim.io().cd.clk, false); + sim.write_reset(sim.io().cd.rst, true); + sim.advance_time(SimDuration::from_micros(1)); + sim.write_clock(sim.io().cd.clk, true); + sim.settle(); + let reset_value = 3_hdl_u4; + assert_eq!( + reset_value, + sim.read_bool_or_int(sim.io().count).to_expr(), + "vcd:\n{}", + String::from_utf8(writer.take()).unwrap(), + ); + sim.write_reset(sim.io().cd.rst, false); + sim.advance_time(SimDuration::from_micros(1)); + for i in 0..32u32 { + assert_eq!( + UInt::<4>::new_static().from_int_wrapping(i + 3), + sim.read_bool_or_int(sim.io().count), + "vcd:\n{}", + String::from_utf8(writer.take()).unwrap(), + ); + sim.write_clock(sim.io().cd.clk, false); + sim.advance_time(SimDuration::from_micros(1)); + sim.write_clock(sim.io().cd.clk, true); + 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 + != r#"$timescale 1 ps $end +$scope module counter $end +$scope struct cd $end +$var wire 1 ! clk $end +$var wire 1 " rst $end +$upscope $end +$var wire 4 # count $end +$var reg 4 $ count_reg $end +$upscope $end +$enddefinitions $end +$dumpvars +0! +1" +b0 # +b0 $ +$end +#1000000 +1! +b11 $ +b11 # +0" +#2000000 +0! +#3000000 +1! +b100 $ +b100 # +#4000000 +0! +#5000000 +1! +b101 $ +b101 # +#6000000 +0! +#7000000 +1! +b110 $ +b110 # +#8000000 +0! +#9000000 +1! +b111 $ +b111 # +#10000000 +0! +#11000000 +1! +b1000 $ +b1000 # +#12000000 +0! +#13000000 +1! +b1001 $ +b1001 # +#14000000 +0! +#15000000 +1! +b1010 $ +b1010 # +#16000000 +0! +#17000000 +1! +b1011 $ +b1011 # +#18000000 +0! +#19000000 +1! +b1100 $ +b1100 # +#20000000 +0! +#21000000 +1! +b1101 $ +b1101 # +#22000000 +0! +#23000000 +1! +b1110 $ +b1110 # +#24000000 +0! +#25000000 +1! +b1111 $ +b1111 # +#26000000 +0! +#27000000 +1! +b0 $ +b0 # +#28000000 +0! +#29000000 +1! +b1 $ +b1 # +#30000000 +0! +#31000000 +1! +b10 $ +b10 # +#32000000 +0! +#33000000 +1! +b11 $ +b11 # +#34000000 +0! +#35000000 +1! +b100 $ +b100 # +#36000000 +0! +#37000000 +1! +b101 $ +b101 # +#38000000 +0! +#39000000 +1! +b110 $ +b110 # +#40000000 +0! +#41000000 +1! +b111 $ +b111 # +#42000000 +0! +#43000000 +1! +b1000 $ +b1000 # +#44000000 +0! +#45000000 +1! +b1001 $ +b1001 # +#46000000 +0! +#47000000 +1! +b1010 $ +b1010 # +#48000000 +0! +#49000000 +1! +b1011 $ +b1011 # +#50000000 +0! +#51000000 +1! +b1100 $ +b1100 # +#52000000 +0! +#53000000 +1! +b1101 $ +b1101 # +#54000000 +0! +#55000000 +1! +b1110 $ +b1110 # +#56000000 +0! +#57000000 +1! +b1111 $ +b1111 # +#58000000 +0! +#59000000 +1! +b0 $ +b0 # +#60000000 +0! +#61000000 +1! +b1 $ +b1 # +#62000000 +0! +#63000000 +1! +b10 $ +b10 # +#64000000 +0! +#65000000 +1! +b11 $ +b11 # +#66000000 +"# { + panic!(); + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug + != r#"Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 4, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + big_slots: StatePartAllocationLayout { + len: 9, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::cd.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::cd.rst", + ty: SyncReset, + }, + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::count", + ty: UInt<4>, + }, + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::count_reg", + ty: UInt<4>, + }, + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::count_reg$next", + ty: UInt<4>, + }, + SlotDebugData { + name: "", + ty: UInt<4>, + }, + SlotDebugData { + name: "", + ty: UInt<1>, + }, + SlotDebugData { + name: "", + ty: UInt<5>, + }, + SlotDebugData { + name: "", + ty: UInt<4>, + }, + ], + .. + }, + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:6:1 + Copy { + dest: StatePartIndex(2), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count", ty: UInt<4> }, + src: StatePartIndex(3), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + Const { + dest: StatePartIndex(6), // SlotDebugData { name: "", ty: UInt<1> }, + value: 1, + }, + Add { + dest: StatePartIndex(7), // SlotDebugData { name: "", ty: UInt<5> }, + lhs: StatePartIndex(3), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> }, + rhs: StatePartIndex(6), // SlotDebugData { name: "", ty: UInt<1> }, + }, + CastToUInt { + dest: StatePartIndex(8), // SlotDebugData { name: "", ty: UInt<4> }, + src: StatePartIndex(7), // SlotDebugData { name: "", ty: UInt<5> }, + dest_width: 4, + }, + // at: module-XXXXXXXXXX.rs:4:1 + Copy { + dest: StatePartIndex(4), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg$next", ty: UInt<4> }, + src: StatePartIndex(8), // SlotDebugData { name: "", ty: UInt<4> }, + }, + // at: module-XXXXXXXXXX.rs:3:1 + IsNonZeroDestIsSmall { + dest: StatePartIndex(3), // SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(1), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.rst", ty: SyncReset }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + Const { + dest: StatePartIndex(5), // SlotDebugData { name: "", ty: UInt<4> }, + value: 3, + }, + // at: module-XXXXXXXXXX.rs:3:1 + IsNonZeroDestIsSmall { + dest: StatePartIndex(2), // SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(0), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.clk", ty: Clock }, + }, + AndSmall { + dest: StatePartIndex(1), // SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(2), // SlotDebugData { name: "", ty: Bool }, + rhs: StatePartIndex(0), // SlotDebugData { name: "", ty: Bool }, + }, + BranchIfSmallZero { + target: 14, + value: StatePartIndex(1), // SlotDebugData { name: "", ty: Bool }, + }, + BranchIfSmallNonZero { + target: 13, + value: StatePartIndex(3), // SlotDebugData { name: "", ty: Bool }, + }, + Copy { + dest: StatePartIndex(3), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> }, + src: StatePartIndex(4), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg$next", ty: UInt<4> }, + }, + Branch { + target: 14, + }, + Copy { + dest: StatePartIndex(3), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> }, + src: StatePartIndex(5), // SlotDebugData { name: "", ty: UInt<4> }, + }, + NotSmall { + dest: StatePartIndex(0), // SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(2), // SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + Return, + ], + .. + }, + pc: 15, + small_slots: StatePart { + value: [ + 18446744073709551614, + 0, + 1, + 0, + ], + }, + big_slots: StatePart { + value: [ + 1, + 0, + 3, + 3, + 4, + 3, + 1, + 4, + 4, + ], + }, + }, + io: Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }, + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + rst: SyncReset, + }, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::cd.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::cd.rst", + ty: SyncReset, + }, + ], + .. + }, + }, + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: SyncReset, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 2 }, + }, + write: None, + }, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd.clk: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, + }, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd.rst: CompiledValue { + layout: CompiledTypeLayout { + ty: SyncReset, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 1, len: 1 }, + }, + write: None, + }, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.count: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<4>, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::count", + ty: UInt<4>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 2, len: 1 }, + }, + write: None, + }, + }, + made_initial_step: true, + needs_settle: false, + trace_decls: TraceModule { + name: "counter", + children: [ + TraceModuleIO { + name: "cd", + child: TraceBundle { + name: "cd", + fields: [ + TraceClock { + id: TraceScalarId(0), + name: "clk", + flow: Source, + }, + TraceSyncReset { + id: TraceScalarId(1), + name: "rst", + flow: Source, + }, + ], + ty: Bundle { + /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + rst: SyncReset, + }, + flow: Source, + }, + ty: Bundle { + /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + rst: SyncReset, + }, + flow: Source, + }, + TraceModuleIO { + name: "count", + child: TraceUInt { + id: TraceScalarId(2), + name: "count", + ty: UInt<4>, + flow: Sink, + }, + ty: UInt<4>, + flow: Sink, + }, + TraceReg { + name: "count_reg", + child: TraceUInt { + id: TraceScalarId(3), + name: "count_reg", + ty: UInt<4>, + flow: Duplex, + }, + ty: UInt<4>, + }, + ], + }, + traces: [ + SimTrace { + id: TraceScalarId(0), + kind: BigClock { + index: StatePartIndex(0), + }, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigSyncReset { + index: StatePartIndex(1), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(2), + kind: BigUInt { + index: StatePartIndex(2), + ty: UInt<4>, + }, + state: 0x3, + last_state: 0x2, + }, + SimTrace { + id: TraceScalarId(3), + kind: BigUInt { + index: StatePartIndex(3), + ty: UInt<4>, + }, + state: 0x3, + last_state: 0x3, + }, + ], + trace_writers: [ + Running( + VcdWriter { + finished_init: true, + timescale: 1 ps, + .. + }, + ), + ], + instant: 66 μs, + clocks_triggered: [ + StatePartIndex(1), + ], +}"# { + panic!(); + } +} + +#[hdl] +#[test] +fn test_counter_async() { + let _n = SourceLocation::normalize_files_for_tests(); + let mut sim = Simulation::new(counter::()); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + sim.write_clock(sim.io().cd.clk, false); + sim.write_reset(sim.io().cd.rst, false); + sim.advance_time(SimDuration::from_nanos(500)); + sim.write_reset(sim.io().cd.rst, true); + let reset_value = 3_hdl_u4; + assert_eq!( + reset_value, + sim.read_bool_or_int(sim.io().count).to_expr(), + "vcd:\n{}", + String::from_utf8(writer.take()).unwrap(), + ); + sim.advance_time(SimDuration::from_nanos(500)); + sim.write_clock(sim.io().cd.clk, true); + sim.advance_time(SimDuration::from_nanos(500)); + sim.write_reset(sim.io().cd.rst, false); + sim.advance_time(SimDuration::from_nanos(500)); + for i in 0..32u32 { + assert_eq!( + UInt::<4>::new_static().from_int_wrapping(i + 3), + sim.read_bool_or_int(sim.io().count), + "vcd:\n{}", + String::from_utf8(writer.take()).unwrap(), + ); + sim.write_clock(sim.io().cd.clk, false); + sim.advance_time(SimDuration::from_micros(1)); + sim.write_clock(sim.io().cd.clk, true); + 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 + != r#"$timescale 1 ps $end +$scope module counter $end +$scope struct cd $end +$var wire 1 ! clk $end +$var wire 1 " rst $end +$upscope $end +$var wire 4 # count $end +$var reg 4 $ count_reg $end +$upscope $end +$enddefinitions $end +$dumpvars +0! +0" +b0 # +b0 $ +$end +#500000 +1" +b11 # +b11 $ +#1000000 +1! +#1500000 +0" +#2000000 +0! +#3000000 +1! +b100 $ +b100 # +#4000000 +0! +#5000000 +1! +b101 $ +b101 # +#6000000 +0! +#7000000 +1! +b110 $ +b110 # +#8000000 +0! +#9000000 +1! +b111 $ +b111 # +#10000000 +0! +#11000000 +1! +b1000 $ +b1000 # +#12000000 +0! +#13000000 +1! +b1001 $ +b1001 # +#14000000 +0! +#15000000 +1! +b1010 $ +b1010 # +#16000000 +0! +#17000000 +1! +b1011 $ +b1011 # +#18000000 +0! +#19000000 +1! +b1100 $ +b1100 # +#20000000 +0! +#21000000 +1! +b1101 $ +b1101 # +#22000000 +0! +#23000000 +1! +b1110 $ +b1110 # +#24000000 +0! +#25000000 +1! +b1111 $ +b1111 # +#26000000 +0! +#27000000 +1! +b0 $ +b0 # +#28000000 +0! +#29000000 +1! +b1 $ +b1 # +#30000000 +0! +#31000000 +1! +b10 $ +b10 # +#32000000 +0! +#33000000 +1! +b11 $ +b11 # +#34000000 +0! +#35000000 +1! +b100 $ +b100 # +#36000000 +0! +#37000000 +1! +b101 $ +b101 # +#38000000 +0! +#39000000 +1! +b110 $ +b110 # +#40000000 +0! +#41000000 +1! +b111 $ +b111 # +#42000000 +0! +#43000000 +1! +b1000 $ +b1000 # +#44000000 +0! +#45000000 +1! +b1001 $ +b1001 # +#46000000 +0! +#47000000 +1! +b1010 $ +b1010 # +#48000000 +0! +#49000000 +1! +b1011 $ +b1011 # +#50000000 +0! +#51000000 +1! +b1100 $ +b1100 # +#52000000 +0! +#53000000 +1! +b1101 $ +b1101 # +#54000000 +0! +#55000000 +1! +b1110 $ +b1110 # +#56000000 +0! +#57000000 +1! +b1111 $ +b1111 # +#58000000 +0! +#59000000 +1! +b0 $ +b0 # +#60000000 +0! +#61000000 +1! +b1 $ +b1 # +#62000000 +0! +#63000000 +1! +b10 $ +b10 # +#64000000 +0! +#65000000 +1! +b11 $ +b11 # +#66000000 +"# { + panic!(); + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug + != r#"Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 4, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + big_slots: StatePartAllocationLayout { + len: 10, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::cd.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::cd.rst", + ty: AsyncReset, + }, + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::count", + ty: UInt<4>, + }, + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::count_reg", + ty: UInt<4>, + }, + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::count_reg$next", + ty: UInt<4>, + }, + SlotDebugData { + name: "", + ty: UInt<4>, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: UInt<1>, + }, + SlotDebugData { + name: "", + ty: UInt<5>, + }, + SlotDebugData { + name: "", + ty: UInt<4>, + }, + ], + .. + }, + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:1:1 + Const { + dest: StatePartIndex(7), // SlotDebugData { name: "", ty: UInt<1> }, + value: 1, + }, + Copy { + dest: StatePartIndex(6), // SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(1), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.rst", ty: AsyncReset }, + }, + // at: module-XXXXXXXXXX.rs:3:1 + IsNonZeroDestIsSmall { + dest: StatePartIndex(3), // SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(1), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.rst", ty: AsyncReset }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + Const { + dest: StatePartIndex(5), // SlotDebugData { name: "", ty: UInt<4> }, + value: 3, + }, + // at: module-XXXXXXXXXX.rs:3:1 + BranchIfZero { + target: 6, + value: StatePartIndex(6), // SlotDebugData { name: "", ty: Bool }, + }, + Copy { + dest: StatePartIndex(3), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> }, + src: StatePartIndex(5), // SlotDebugData { name: "", ty: UInt<4> }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + Add { + dest: StatePartIndex(8), // SlotDebugData { name: "", ty: UInt<5> }, + lhs: StatePartIndex(3), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> }, + rhs: StatePartIndex(7), // SlotDebugData { name: "", ty: UInt<1> }, + }, + CastToUInt { + dest: StatePartIndex(9), // SlotDebugData { name: "", ty: UInt<4> }, + src: StatePartIndex(8), // SlotDebugData { name: "", ty: UInt<5> }, + dest_width: 4, + }, + // at: module-XXXXXXXXXX.rs:4:1 + Copy { + dest: StatePartIndex(4), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg$next", ty: UInt<4> }, + src: StatePartIndex(9), // SlotDebugData { name: "", ty: UInt<4> }, + }, + // at: module-XXXXXXXXXX.rs:6:1 + Copy { + dest: StatePartIndex(2), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count", ty: UInt<4> }, + src: StatePartIndex(3), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> }, + }, + // at: module-XXXXXXXXXX.rs:3:1 + IsNonZeroDestIsSmall { + dest: StatePartIndex(2), // SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(0), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::cd.clk", ty: Clock }, + }, + AndSmall { + dest: StatePartIndex(1), // SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(2), // SlotDebugData { name: "", ty: Bool }, + rhs: StatePartIndex(0), // SlotDebugData { name: "", ty: Bool }, + }, + BranchIfSmallNonZero { + target: 16, + value: StatePartIndex(3), // SlotDebugData { name: "", ty: Bool }, + }, + BranchIfSmallZero { + target: 17, + value: StatePartIndex(1), // SlotDebugData { name: "", ty: Bool }, + }, + Copy { + dest: StatePartIndex(3), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> }, + src: StatePartIndex(4), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg$next", ty: UInt<4> }, + }, + Branch { + target: 17, + }, + Copy { + dest: StatePartIndex(3), // SlotDebugData { name: "InstantiatedModule(counter: counter).counter::count_reg", ty: UInt<4> }, + src: StatePartIndex(5), // SlotDebugData { name: "", ty: UInt<4> }, + }, + NotSmall { + dest: StatePartIndex(0), // SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(2), // SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + Return, + ], + .. + }, + pc: 18, + small_slots: StatePart { + value: [ + 18446744073709551614, + 0, + 1, + 0, + ], + }, + big_slots: StatePart { + value: [ + 1, + 0, + 3, + 3, + 4, + 3, + 0, + 1, + 4, + 4, + ], + }, + }, + io: Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }, + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + rst: AsyncReset, + }, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::cd.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::cd.rst", + ty: AsyncReset, + }, + ], + .. + }, + }, + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: AsyncReset, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: AsyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 2 }, + }, + write: None, + }, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd.clk: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, + }, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.cd.rst: CompiledValue { + layout: CompiledTypeLayout { + ty: AsyncReset, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: AsyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 1, len: 1 }, + }, + write: None, + }, + Instance { + name: ::counter, + instantiated: Module { + name: counter, + .. + }, + }.count: CompiledValue { + layout: CompiledTypeLayout { + ty: UInt<4>, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(counter: counter).counter::count", + ty: UInt<4>, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 2, len: 1 }, + }, + write: None, + }, + }, + made_initial_step: true, + needs_settle: false, + trace_decls: TraceModule { + name: "counter", + children: [ + TraceModuleIO { + name: "cd", + child: TraceBundle { + name: "cd", + fields: [ + TraceClock { + id: TraceScalarId(0), + name: "clk", + flow: Source, + }, + TraceAsyncReset { + id: TraceScalarId(1), + name: "rst", + flow: Source, + }, + ], + ty: Bundle { + /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + rst: AsyncReset, + }, + flow: Source, + }, + ty: Bundle { + /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + rst: AsyncReset, + }, + flow: Source, + }, + TraceModuleIO { + name: "count", + child: TraceUInt { + id: TraceScalarId(2), + name: "count", + ty: UInt<4>, + flow: Sink, + }, + ty: UInt<4>, + flow: Sink, + }, + TraceReg { + name: "count_reg", + child: TraceUInt { + id: TraceScalarId(3), + name: "count_reg", + ty: UInt<4>, + flow: Duplex, + }, + ty: UInt<4>, + }, + ], + }, + traces: [ + SimTrace { + id: TraceScalarId(0), + kind: BigClock { + index: StatePartIndex(0), + }, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigAsyncReset { + index: StatePartIndex(1), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(2), + kind: BigUInt { + index: StatePartIndex(2), + ty: UInt<4>, + }, + state: 0x3, + last_state: 0x2, + }, + SimTrace { + id: TraceScalarId(3), + kind: BigUInt { + index: StatePartIndex(3), + ty: UInt<4>, + }, + state: 0x3, + last_state: 0x3, + }, + ], + trace_writers: [ + Running( + VcdWriter { + finished_init: true, + timescale: 1 ps, + .. + }, + ), + ], + instant: 66 μs, + clocks_triggered: [ + StatePartIndex(1), + ], +}"# { + panic!(); + } +} + +#[hdl_module(outline_generated)] +pub fn shift_register() { + #[hdl] + let cd: ClockDomain = m.input(); + #[hdl] + let d: Bool = m.input(); + #[hdl] + let q: Bool = m.output(); + #[hdl] + let reg0: Bool = reg_builder().clock_domain(cd).reset(false); + connect(reg0, d); + #[hdl] + let reg1: Bool = reg_builder().clock_domain(cd).reset(false); + connect(reg1, reg0); + #[hdl] + let reg2: Bool = reg_builder().clock_domain(cd).reset(false); + connect(reg2, reg1); + #[hdl] + let reg3: Bool = reg_builder().clock_domain(cd).reset(false); + connect(reg3, reg2); + connect(q, reg3); +} + +#[hdl] +#[test] +fn test_shift_register() { + let _n = SourceLocation::normalize_files_for_tests(); + let mut sim = Simulation::new(shift_register()); + let mut writer = RcWriter::default(); + sim.add_trace_writer(VcdWriterDecls::new(writer.clone())); + sim.write_clock(sim.io().cd.clk, false); + sim.write_reset(sim.io().cd.rst, true); + sim.write_bool(sim.io().d, false); + sim.advance_time(SimDuration::from_micros(1)); + sim.write_clock(sim.io().cd.clk, true); + sim.advance_time(SimDuration::from_nanos(100)); + sim.write_reset(sim.io().cd.rst, false); + sim.advance_time(SimDuration::from_nanos(900)); + let data = [ + false, true, true, false, false, true, false, true, true, true, true, + ]; + for cycle in 0..32usize { + if let Some(out_cycle) = cycle.checked_sub(4) { + if let Some(expected) = data.get(out_cycle) { + assert_eq!( + *expected, + sim.read_bool(sim.io().q), + "cycle: {cycle}\nvcd:\n{}", + String::from_utf8(writer.take()).unwrap(), + ); + } + } + sim.write_bool(sim.io().d, data.get(cycle).copied().unwrap_or(false)); + sim.write_clock(sim.io().cd.clk, false); + sim.advance_time(SimDuration::from_micros(1)); + sim.write_clock(sim.io().cd.clk, true); + 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 + != r#"$timescale 1 ps $end +$scope module shift_register $end +$scope struct cd $end +$var wire 1 ! clk $end +$var wire 1 " rst $end +$upscope $end +$var wire 1 # d $end +$var wire 1 $ q $end +$var reg 1 % reg0 $end +$var reg 1 & reg1 $end +$var reg 1 ' reg2 $end +$var reg 1 ( reg3 $end +$upscope $end +$enddefinitions $end +$dumpvars +0! +1" +0# +0$ +0% +0& +0' +0( +$end +#1000000 +1! +#1100000 +0" +#2000000 +0! +#3000000 +1! +#4000000 +0! +1# +#5000000 +1! +1% +#6000000 +0! +#7000000 +1! +1& +#8000000 +0! +0# +#9000000 +1! +0% +1' +#10000000 +0! +#11000000 +1! +0& +1( +1$ +#12000000 +0! +1# +#13000000 +1! +1% +0' +#14000000 +0! +0# +#15000000 +1! +0% +1& +0( +0$ +#16000000 +0! +1# +#17000000 +1! +1% +0& +1' +#18000000 +0! +#19000000 +1! +1& +0' +1( +1$ +#20000000 +0! +#21000000 +1! +1' +0( +0$ +#22000000 +0! +#23000000 +1! +1( +1$ +#24000000 +0! +0# +#25000000 +1! +0% +#26000000 +0! +#27000000 +1! +0& +#28000000 +0! +#29000000 +1! +0' +#30000000 +0! +#31000000 +1! +0( +0$ +#32000000 +0! +#33000000 +1! +#34000000 +0! +#35000000 +1! +#36000000 +0! +#37000000 +1! +#38000000 +0! +#39000000 +1! +#40000000 +0! +#41000000 +1! +#42000000 +0! +#43000000 +1! +#44000000 +0! +#45000000 +1! +#46000000 +0! +#47000000 +1! +#48000000 +0! +#49000000 +1! +#50000000 +0! +#51000000 +1! +#52000000 +0! +#53000000 +1! +#54000000 +0! +#55000000 +1! +#56000000 +0! +#57000000 +1! +#58000000 +0! +#59000000 +1! +#60000000 +0! +#61000000 +1! +#62000000 +0! +#63000000 +1! +#64000000 +0! +#65000000 +1! +#66000000 +"# { + panic!(); + } + let sim_debug = format!("{sim:#?}"); + println!("#######\n{sim_debug}\n#######"); + if sim_debug + != r#"Simulation { + state: State { + insns: Insns { + state_layout: StateLayout { + ty: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 4, + debug_data: [ + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + ], + .. + }, + big_slots: StatePartAllocationLayout { + len: 13, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.rst", + ty: SyncReset, + }, + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::d", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::q", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::reg0", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::reg0$next", + ty: Bool, + }, + SlotDebugData { + name: "", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::reg1", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::reg1$next", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::reg2", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::reg2$next", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::reg3", + ty: Bool, + }, + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::reg3$next", + ty: Bool, + }, + ], + .. + }, + }, + }, + insns: [ + // at: module-XXXXXXXXXX.rs:13:1 + Copy { + dest: StatePartIndex(3), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::q", ty: Bool }, + src: StatePartIndex(11), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg3", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:12:1 + Copy { + dest: StatePartIndex(12), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg3$next", ty: Bool }, + src: StatePartIndex(9), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg2", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:10:1 + Copy { + dest: StatePartIndex(10), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg2$next", ty: Bool }, + src: StatePartIndex(7), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg1", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:8:1 + Copy { + dest: StatePartIndex(8), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg1$next", ty: Bool }, + src: StatePartIndex(4), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg0", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:6:1 + Copy { + dest: StatePartIndex(5), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg0$next", ty: Bool }, + src: StatePartIndex(2), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::d", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:5:1 + IsNonZeroDestIsSmall { + dest: StatePartIndex(3), // SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(1), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.rst", ty: SyncReset }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + Const { + dest: StatePartIndex(6), // SlotDebugData { name: "", ty: Bool }, + value: 0, + }, + // at: module-XXXXXXXXXX.rs:5:1 + IsNonZeroDestIsSmall { + dest: StatePartIndex(2), // SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(0), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.clk", ty: Clock }, + }, + AndSmall { + dest: StatePartIndex(1), // SlotDebugData { name: "", ty: Bool }, + lhs: StatePartIndex(2), // SlotDebugData { name: "", ty: Bool }, + rhs: StatePartIndex(0), // SlotDebugData { name: "", ty: Bool }, + }, + BranchIfSmallZero { + target: 14, + value: StatePartIndex(1), // SlotDebugData { name: "", ty: Bool }, + }, + BranchIfSmallNonZero { + target: 13, + value: StatePartIndex(3), // SlotDebugData { name: "", ty: Bool }, + }, + Copy { + dest: StatePartIndex(4), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg0", ty: Bool }, + src: StatePartIndex(5), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg0$next", ty: Bool }, + }, + Branch { + target: 14, + }, + Copy { + dest: StatePartIndex(4), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg0", ty: Bool }, + src: StatePartIndex(6), // SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:7:1 + BranchIfSmallZero { + target: 19, + value: StatePartIndex(1), // SlotDebugData { name: "", ty: Bool }, + }, + BranchIfSmallNonZero { + target: 18, + value: StatePartIndex(3), // SlotDebugData { name: "", ty: Bool }, + }, + Copy { + dest: StatePartIndex(7), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg1", ty: Bool }, + src: StatePartIndex(8), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg1$next", ty: Bool }, + }, + Branch { + target: 19, + }, + Copy { + dest: StatePartIndex(7), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg1", ty: Bool }, + src: StatePartIndex(6), // SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:9:1 + BranchIfSmallZero { + target: 24, + value: StatePartIndex(1), // SlotDebugData { name: "", ty: Bool }, + }, + BranchIfSmallNonZero { + target: 23, + value: StatePartIndex(3), // SlotDebugData { name: "", ty: Bool }, + }, + Copy { + dest: StatePartIndex(9), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg2", ty: Bool }, + src: StatePartIndex(10), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg2$next", ty: Bool }, + }, + Branch { + target: 24, + }, + Copy { + dest: StatePartIndex(9), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg2", ty: Bool }, + src: StatePartIndex(6), // SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:11:1 + BranchIfSmallZero { + target: 29, + value: StatePartIndex(1), // SlotDebugData { name: "", ty: Bool }, + }, + BranchIfSmallNonZero { + target: 28, + value: StatePartIndex(3), // SlotDebugData { name: "", ty: Bool }, + }, + Copy { + dest: StatePartIndex(11), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg3", ty: Bool }, + src: StatePartIndex(12), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg3$next", ty: Bool }, + }, + Branch { + target: 29, + }, + Copy { + dest: StatePartIndex(11), // SlotDebugData { name: "InstantiatedModule(shift_register: shift_register).shift_register::reg3", ty: Bool }, + src: StatePartIndex(6), // SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:5:1 + NotSmall { + dest: StatePartIndex(0), // SlotDebugData { name: "", ty: Bool }, + src: StatePartIndex(2), // SlotDebugData { name: "", ty: Bool }, + }, + // at: module-XXXXXXXXXX.rs:1:1 + Return, + ], + .. + }, + pc: 30, + small_slots: StatePart { + value: [ + 18446744073709551614, + 0, + 1, + 0, + ], + }, + big_slots: StatePart { + value: [ + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + }, + }, + io: Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }, + uninitialized_inputs: {}, + io_targets: { + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.cd: CompiledValue { + layout: CompiledTypeLayout { + ty: Bundle { + /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + rst: SyncReset, + }, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 2, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.clk", + ty: Clock, + }, + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::cd.rst", + ty: SyncReset, + }, + ], + .. + }, + }, + body: Bundle { + fields: [ + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(0), + }, + ty: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + CompiledBundleField { + offset: TypeIndex { + small_slots: StatePartIndex(0), + big_slots: StatePartIndex(1), + }, + ty: CompiledTypeLayout { + ty: SyncReset, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + }, + ], + }, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 2 }, + }, + write: None, + }, + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.cd.clk: CompiledValue { + layout: CompiledTypeLayout { + ty: Clock, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: Clock, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 0, len: 1 }, + }, + write: None, + }, + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.cd.rst: CompiledValue { + layout: CompiledTypeLayout { + ty: SyncReset, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "", + ty: SyncReset, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 1, len: 1 }, + }, + write: None, + }, + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.d: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::d", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 2, len: 1 }, + }, + write: None, + }, + Instance { + name: ::shift_register, + instantiated: Module { + name: shift_register, + .. + }, + }.q: CompiledValue { + layout: CompiledTypeLayout { + ty: Bool, + layout: TypeLayout { + small_slots: StatePartAllocationLayout { + len: 0, + debug_data: [], + .. + }, + big_slots: StatePartAllocationLayout { + len: 1, + debug_data: [ + SlotDebugData { + name: "InstantiatedModule(shift_register: shift_register).shift_register::q", + ty: Bool, + }, + ], + .. + }, + }, + body: Scalar, + }, + range: TypeIndexRange { + small_slots: StatePartIndexRange { start: 0, len: 0 }, + big_slots: StatePartIndexRange { start: 3, len: 1 }, + }, + write: None, + }, + }, + made_initial_step: true, + needs_settle: false, + trace_decls: TraceModule { + name: "shift_register", + children: [ + TraceModuleIO { + name: "cd", + child: TraceBundle { + name: "cd", + fields: [ + TraceClock { + id: TraceScalarId(0), + name: "clk", + flow: Source, + }, + TraceSyncReset { + id: TraceScalarId(1), + name: "rst", + flow: Source, + }, + ], + ty: Bundle { + /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + rst: SyncReset, + }, + flow: Source, + }, + ty: Bundle { + /* offset = 0 */ + clk: Clock, + /* offset = 1 */ + rst: SyncReset, + }, + flow: Source, + }, + TraceModuleIO { + name: "d", + child: TraceBool { + id: TraceScalarId(2), + name: "d", + flow: Source, + }, + ty: Bool, + flow: Source, + }, + TraceModuleIO { + name: "q", + child: TraceBool { + id: TraceScalarId(3), + name: "q", + flow: Sink, + }, + ty: Bool, + flow: Sink, + }, + TraceReg { + name: "reg0", + child: TraceBool { + id: TraceScalarId(4), + name: "reg0", + flow: Duplex, + }, + ty: Bool, + }, + TraceReg { + name: "reg1", + child: TraceBool { + id: TraceScalarId(5), + name: "reg1", + flow: Duplex, + }, + ty: Bool, + }, + TraceReg { + name: "reg2", + child: TraceBool { + id: TraceScalarId(6), + name: "reg2", + flow: Duplex, + }, + ty: Bool, + }, + TraceReg { + name: "reg3", + child: TraceBool { + id: TraceScalarId(7), + name: "reg3", + flow: Duplex, + }, + ty: Bool, + }, + ], + }, + traces: [ + SimTrace { + id: TraceScalarId(0), + kind: BigClock { + index: StatePartIndex(0), + }, + state: 0x1, + last_state: 0x1, + }, + SimTrace { + id: TraceScalarId(1), + kind: BigSyncReset { + index: StatePartIndex(1), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(2), + kind: BigBool { + index: StatePartIndex(2), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(3), + kind: BigBool { + index: StatePartIndex(3), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(4), + kind: BigBool { + index: StatePartIndex(4), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(5), + kind: BigBool { + index: StatePartIndex(7), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(6), + kind: BigBool { + index: StatePartIndex(9), + }, + state: 0x0, + last_state: 0x0, + }, + SimTrace { + id: TraceScalarId(7), + kind: BigBool { + index: StatePartIndex(11), + }, + state: 0x0, + last_state: 0x0, + }, + ], + trace_writers: [ + Running( + VcdWriter { + finished_init: true, + timescale: 1 ps, + .. + }, + ), + ], + instant: 66 μs, + clocks_triggered: [ + StatePartIndex(1), + ], +}"# { + panic!(); + } +}