add a simulator #3

Merged
programmerjake merged 58 commits from adding-simulator into master 2024-12-16 04:06:48 +00:00
2 changed files with 92 additions and 20 deletions
Showing only changes of commit 11ddbc43c7 - Show all commits

View file

@ -3620,6 +3620,7 @@ struct SimulationImpl {
uninitialized_inputs: HashSet<Target>, uninitialized_inputs: HashSet<Target>,
io_targets: HashMap<Target, CompiledValue<CanonicalType>>, io_targets: HashMap<Target, CompiledValue<CanonicalType>>,
made_initial_step: bool, made_initial_step: bool,
needs_settle: bool,
trace_decls: TraceModule, trace_decls: TraceModule,
traces: Box<[SimTrace<BitVec>]>, traces: Box<[SimTrace<BitVec>]>,
trace_writers: Vec<TraceWriterState<DynTraceWriterDecls>>, trace_writers: Vec<TraceWriterState<DynTraceWriterDecls>>,
@ -3669,6 +3670,7 @@ impl SimulationImpl {
uninitialized_inputs: HashSet::new(), uninitialized_inputs: HashSet::new(),
io_targets: HashMap::new(), io_targets: HashMap::new(),
made_initial_step: false, made_initial_step: false,
needs_settle: true,
trace_decls: compiled.base_module.trace_decls, trace_decls: compiled.base_module.trace_decls,
traces: Box::from_iter(compiled.traces.iter().map( traces: Box::from_iter(compiled.traces.iter().map(
|&SimTrace { |&SimTrace {
@ -3804,9 +3806,7 @@ impl SimulationImpl {
} }
#[track_caller] #[track_caller]
fn advance_time(&mut self, duration: SimDuration) { fn advance_time(&mut self, duration: SimDuration) {
if !self.made_initial_step { self.settle_step();
self.settle_step();
}
self.instant += duration; self.instant += duration;
self.for_each_trace_writer_storing_error(|this, mut trace_writer_state| { self.for_each_trace_writer_storing_error(|this, mut trace_writer_state| {
match &mut trace_writer_state { match &mut trace_writer_state {
@ -3825,6 +3825,9 @@ impl SimulationImpl {
self.uninitialized_inputs.is_empty(), self.uninitialized_inputs.is_empty(),
"didn't initialize all inputs", "didn't initialize all inputs",
); );
if !self.needs_settle {
return;
}
self.state.setup_call(0); self.state.setup_call(0);
self.state.run(); self.state.run();
if self.made_initial_step { if self.made_initial_step {
@ -3833,6 +3836,7 @@ impl SimulationImpl {
self.read_traces::<true>(); self.read_traces::<true>();
} }
self.made_initial_step = true; self.made_initial_step = true;
self.needs_settle = false;
self.for_each_trace_writer_storing_error(|this, trace_writer_state| { self.for_each_trace_writer_storing_error(|this, trace_writer_state| {
Ok(match trace_writer_state { Ok(match trace_writer_state {
TraceWriterState::Decls(trace_writer_decls) => TraceWriterState::Running( TraceWriterState::Decls(trace_writer_decls) => TraceWriterState::Running(
@ -3861,12 +3865,14 @@ impl SimulationImpl {
panic!("simulator read/write expression must not have dynamic array indexes"); panic!("simulator read/write expression must not have dynamic array indexes");
} }
#[track_caller] #[track_caller]
fn read_bool_or_int<I: BoolOrIntType>(&self, io: Expr<I>) -> I::Value { fn read_bool_or_int<I: BoolOrIntType>(&mut self, io: Expr<I>) -> I::Value {
let Some(target) = io.target() else { let Some(target) = io.target() else {
panic!("can't read from expression that's not a field/element of `Simulation::io()`"); panic!("can't read from expression that's not a field/element of `Simulation::io()`");
}; };
let compiled_value = self.get_io(*target); let compiled_value = self.get_io(*target);
if !self.made_initial_step { if self.made_initial_step {
self.settle_step();
} else {
match target.flow() { match target.flow() {
Flow::Source => { Flow::Source => {
panic!("can't read from an output before the simulation has made any steps"); panic!("can't read from an output before the simulation has made any steps");
@ -3906,6 +3912,7 @@ impl SimulationImpl {
if !self.made_initial_step { if !self.made_initial_step {
self.uninitialized_inputs.remove(&*target); self.uninitialized_inputs.remove(&*target);
} }
self.needs_settle = true;
match compiled_value.range.len() { match compiled_value.range.len() {
TypeLen::A_SMALL_SLOT => { TypeLen::A_SMALL_SLOT => {
self.state.small_slots[compiled_value.range.small_slots.start] = self.state.small_slots[compiled_value.range.small_slots.start] =
@ -3981,9 +3988,15 @@ impl SimulationImpl {
retval retval
} }
fn close(mut self) -> std::io::Result<()> { fn close(mut self) -> std::io::Result<()> {
if self.made_initial_step {
self.settle_step();
}
self.close_all_trace_writers() self.close_all_trace_writers()
} }
fn flush_traces(&mut self) -> std::io::Result<()> { fn flush_traces(&mut self) -> std::io::Result<()> {
if self.made_initial_step {
self.settle_step();
}
self.for_each_trace_writer_getting_error( self.for_each_trace_writer_getting_error(
|this, trace_writer: TraceWriterState<DynTraceWriterDecls>| match trace_writer { |this, trace_writer: TraceWriterState<DynTraceWriterDecls>| match trace_writer {
TraceWriterState::Decls(v) => { TraceWriterState::Decls(v) => {
@ -4068,6 +4081,7 @@ impl<T: BundleType> fmt::Debug for Simulation<T> {
uninitialized_inputs, uninitialized_inputs,
io_targets, io_targets,
made_initial_step, made_initial_step,
needs_settle,
trace_decls, trace_decls,
traces, traces,
trace_writers, trace_writers,
@ -4084,6 +4098,7 @@ impl<T: BundleType> fmt::Debug for Simulation<T> {
) )
.field("io_targets", &SortedMapDebug(io_targets)) .field("io_targets", &SortedMapDebug(io_targets))
.field("made_initial_step", made_initial_step) .field("made_initial_step", made_initial_step)
.field("needs_settle", needs_settle)
.field("trace_decls", trace_decls) .field("trace_decls", trace_decls)
.field("traces", traces) .field("traces", traces)
.field("trace_writers", trace_writers) .field("trace_writers", trace_writers)
@ -4140,7 +4155,7 @@ impl<T: BundleType> Simulation<T> {
self.sim_impl.advance_time(duration); self.sim_impl.advance_time(duration);
} }
#[track_caller] #[track_caller]
pub fn read_bool_or_int<I: BoolOrIntType>(&self, io: Expr<I>) -> I::Value { pub fn read_bool_or_int<I: BoolOrIntType>(&mut self, io: Expr<I>) -> I::Value {
self.sim_impl.read_bool_or_int(io) self.sim_impl.read_bool_or_int(io)
} }
#[track_caller] #[track_caller]

View file

@ -120,6 +120,7 @@ fn test_connect_const() {
}, },
}, },
made_initial_step: true, made_initial_step: true,
needs_settle: false,
trace_decls: TraceModule { trace_decls: TraceModule {
name: "connect_const", name: "connect_const",
children: [ children: [
@ -182,7 +183,6 @@ pub fn mod1() {
connect(o, child); connect(o, child);
} }
#[cfg(todo)]
#[hdl] #[hdl]
#[test] #[test]
fn test_mod1() { fn test_mod1() {
@ -195,10 +195,58 @@ fn test_mod1() {
sim.advance_time(SimDuration::from_micros(1)); sim.advance_time(SimDuration::from_micros(1));
sim.write_bool_or_int(sim.io().o.i, 0xA_hdl_u4); sim.write_bool_or_int(sim.io().o.i, 0xA_hdl_u4);
sim.advance_time(SimDuration::from_micros(1)); sim.advance_time(SimDuration::from_micros(1));
sim.flush_traces().unwrap();
let vcd = String::from_utf8(writer.take()).unwrap(); let vcd = String::from_utf8(writer.take()).unwrap();
println!("####### VCD:\n{vcd}\n#######"); println!("####### VCD:\n{vcd}\n#######");
todo!("generated vcd is incorrect"); if vcd
if vcd != r#""# { != r#"$timescale 1 ps $end
$scope module mod1 $end
$scope struct o $end
$var wire 4 ! i $end
$var wire 2 " o $end
$var wire 2 # i2 $end
$var wire 4 $ o2 $end
$upscope $end
$scope struct child $end
$var wire 4 ) i $end
$var wire 2 * o $end
$var wire 2 + i2 $end
$var wire 4 , o2 $end
$upscope $end
$scope module mod1_child $end
$var wire 4 % i $end
$var wire 2 & o $end
$var wire 2 ' i2 $end
$var wire 4 ( o2 $end
$upscope $end
$upscope $end
$enddefinitions $end
$dumpvars
b11 !
b11 "
b10 #
b1110 $
b11 %
b11 &
b10 '
b1110 (
b11 )
b11 *
b10 +
b1110 ,
$end
#1000000
b1010 !
b10 "
b1111 $
b1010 %
b10 &
b1111 (
b1010 )
b10 *
b1111 ,
#2000000
"# {
panic!(); panic!();
} }
let sim_debug = format!("{sim:#?}"); let sim_debug = format!("{sim:#?}");
@ -718,6 +766,7 @@ fn test_mod1() {
}, },
}, },
made_initial_step: true, made_initial_step: true,
needs_settle: false,
trace_decls: TraceModule { trace_decls: TraceModule {
name: "mod1", name: "mod1",
children: [ children: [
@ -887,7 +936,7 @@ fn test_mod1() {
ty: UInt<4>, ty: UInt<4>,
}, },
state: 0xa, state: 0xa,
last_state: 0xa, last_state: 0x3,
}, },
SimTrace { SimTrace {
id: TraceScalarId(1), id: TraceScalarId(1),
@ -896,7 +945,7 @@ fn test_mod1() {
ty: SInt<2>, ty: SInt<2>,
}, },
state: 0x2, state: 0x2,
last_state: 0x2, last_state: 0x3,
}, },
SimTrace { SimTrace {
id: TraceScalarId(2), id: TraceScalarId(2),
@ -914,7 +963,7 @@ fn test_mod1() {
ty: UInt<4>, ty: UInt<4>,
}, },
state: 0xf, state: 0xf,
last_state: 0xf, last_state: 0xe,
}, },
SimTrace { SimTrace {
id: TraceScalarId(4), id: TraceScalarId(4),
@ -923,7 +972,7 @@ fn test_mod1() {
ty: UInt<4>, ty: UInt<4>,
}, },
state: 0xa, state: 0xa,
last_state: 0xa, last_state: 0x3,
}, },
SimTrace { SimTrace {
id: TraceScalarId(5), id: TraceScalarId(5),
@ -932,7 +981,7 @@ fn test_mod1() {
ty: SInt<2>, ty: SInt<2>,
}, },
state: 0x2, state: 0x2,
last_state: 0x2, last_state: 0x3,
}, },
SimTrace { SimTrace {
id: TraceScalarId(6), id: TraceScalarId(6),
@ -950,7 +999,7 @@ fn test_mod1() {
ty: UInt<4>, ty: UInt<4>,
}, },
state: 0xf, state: 0xf,
last_state: 0xf, last_state: 0xe,
}, },
SimTrace { SimTrace {
id: TraceScalarId(8), id: TraceScalarId(8),
@ -959,7 +1008,7 @@ fn test_mod1() {
ty: UInt<4>, ty: UInt<4>,
}, },
state: 0xa, state: 0xa,
last_state: 0xa, last_state: 0x3,
}, },
SimTrace { SimTrace {
id: TraceScalarId(9), id: TraceScalarId(9),
@ -968,7 +1017,7 @@ fn test_mod1() {
ty: SInt<2>, ty: SInt<2>,
}, },
state: 0x2, state: 0x2,
last_state: 0x2, last_state: 0x3,
}, },
SimTrace { SimTrace {
id: TraceScalarId(10), id: TraceScalarId(10),
@ -986,11 +1035,19 @@ fn test_mod1() {
ty: UInt<4>, ty: UInt<4>,
}, },
state: 0xf, state: 0xf,
last_state: 0xf, last_state: 0xe,
}, },
], ],
trace_writers: [], trace_writers: [
instant: 0 s, Running(
VcdWriter {
finished_init: true,
timescale: 1 ps,
..
},
),
],
instant: 2 μs,
}"# { }"# {
panic!(); panic!();
} }