sim: fix sim.write to struct #9
|
@ -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(
|
||||
TargetPathElement::from(TargetPathBundleField { name }).intern_sized(),
|
||||
),
|
||||
value.field_by_name(name),
|
||||
let sub_target = target.join(
|
||||
TargetPathElement::from(TargetPathBundleField { name }).intern_sized(),
|
||||
);
|
||||
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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue