sim: fix sim.write to struct #9

Merged
programmerjake merged 1 commit from programmerjake/fayalite:fix-sim-write-struct into master 2024-12-19 05:04:18 +00:00
2 changed files with 73 additions and 23 deletions

View file

@ -6429,7 +6429,7 @@ impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType);
struct SimulationImpl {
state: interpreter::State,
io: Expr<Bundle>,
uninitialized_inputs: HashSet<Target>,
uninitialized_inputs: HashMap<Target, Vec<Target>>,
io_targets: HashMap<Target, CompiledValue<CanonicalType>>,
made_initial_step: bool,
needs_settle: bool,
@ -6483,37 +6483,52 @@ impl SimulationImpl {
.field("clocks_triggered", clocks_triggered)
.finish_non_exhaustive()
}
fn parse_io(&mut self, target: Target, value: CompiledValue<CanonicalType>) {
/// returns `true` if `target` or any sub-targets are uninitialized inputs
fn parse_io(&mut self, target: Target, value: CompiledValue<CanonicalType>) -> bool {
self.io_targets.insert(target, value);
match value.layout.body {
CompiledTypeLayoutBody::Scalar => match target.flow() {
Flow::Source => {}
Flow::Source => false,
Flow::Sink => {
self.uninitialized_inputs.insert(target);
self.uninitialized_inputs.insert(target, vec![]);
true
}
Flow::Duplex => unreachable!(),
},
CompiledTypeLayoutBody::Array { .. } => {
let value = value.map_ty(Array::from_canonical);
let mut sub_targets = Vec::new();
for index in 0..value.layout.ty.len() {
self.parse_io(
target.join(
TargetPathElement::from(TargetPathArrayElement { index })
.intern_sized(),
),
value.element(index),
let sub_target = target.join(
TargetPathElement::from(TargetPathArrayElement { index }).intern_sized(),
);
if self.parse_io(sub_target, value.element(index)) {
sub_targets.push(sub_target);
}
}
if sub_targets.is_empty() {
false
} else {
self.uninitialized_inputs.insert(target, sub_targets);
true
}
}
CompiledTypeLayoutBody::Bundle { .. } => {
let value = value.map_ty(Bundle::from_canonical);
let mut sub_targets = Vec::new();
for BundleField { name, .. } in value.layout.ty.fields() {
self.parse_io(
target.join(
let sub_target = target.join(
TargetPathElement::from(TargetPathBundleField { name }).intern_sized(),
),
value.field_by_name(name),
);
if self.parse_io(sub_target, value.field_by_name(name)) {
sub_targets.push(sub_target);
}
}
if sub_targets.is_empty() {
false
} else {
self.uninitialized_inputs.insert(target, sub_targets);
true
}
}
}
@ -6522,7 +6537,7 @@ impl SimulationImpl {
let mut retval = Self {
state: State::new(compiled.insns),
io: compiled.io.to_expr(),
uninitialized_inputs: HashSet::new(),
uninitialized_inputs: HashMap::new(),
io_targets: HashMap::new(),
made_initial_step: false,
needs_settle: true,
@ -6791,6 +6806,35 @@ impl SimulationImpl {
};
panic!("simulator read/write expression must not have dynamic array indexes");
}
fn mark_target_as_initialized(&mut self, mut target: Target) {
fn remove_target_and_children(
uninitialized_inputs: &mut HashMap<Target, Vec<Target>>,
target: Target,
) {
let Some(children) = uninitialized_inputs.remove(&target) else {
return;
};
for child in children {
remove_target_and_children(uninitialized_inputs, child);
}
}
remove_target_and_children(&mut self.uninitialized_inputs, target);
while let Some(target_child) = target.child() {
let parent = target_child.parent();
for child in self
.uninitialized_inputs
.get(&*parent)
.map(|v| &**v)
.unwrap_or(&[])
{
if self.uninitialized_inputs.contains_key(child) {
return;
}
}
target = *parent;
self.uninitialized_inputs.remove(&target);
}
}
#[track_caller]
fn read_helper(&mut self, io: Expr<CanonicalType>) -> CompiledValue<CanonicalType> {
let Some(target) = io.target() else {
@ -6810,7 +6854,7 @@ impl SimulationImpl {
self.settle();
}
Flow::Sink => {
if self.uninitialized_inputs.contains(&*target) {
if self.uninitialized_inputs.contains_key(&*target) {
panic!("can't read from an uninitialized input");
}
}
@ -6833,7 +6877,7 @@ impl SimulationImpl {
Flow::Duplex => unreachable!(),
}
if !self.made_initial_step {
self.uninitialized_inputs.remove(&*target);
self.mark_target_as_initialized(*target);
}
self.needs_settle = true;
compiled_value
@ -7136,11 +7180,11 @@ pub struct Simulation<T: BundleType> {
io: Expr<T>,
}
struct SortedSetDebug<'a, T>(&'a HashSet<T>);
struct SortedSetDebug<'a, T, V>(&'a HashMap<T, V>);
impl<T: fmt::Debug> fmt::Debug for SortedSetDebug<'_, T> {
impl<T: fmt::Debug, V> fmt::Debug for SortedSetDebug<'_, T, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut entries = Vec::from_iter(self.0.iter().map(|v| {
let mut entries = Vec::from_iter(self.0.iter().map(|(v, _)| {
if f.alternate() {
format!("{v:#?}")
} else {

View file

@ -255,8 +255,14 @@ fn test_shift_register() {
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(
sim.io().cd,
#[hdl]
ClockDomain {
clk: false.to_clock(),
rst: true.to_sync_reset(),
},
);
sim.write_bool(sim.io().d, false);
sim.advance_time(SimDuration::from_micros(1));
sim.write_clock(sim.io().cd.clk, true);