sim: fix sim.write to struct #9
|
@ -6429,7 +6429,7 @@ impl_to_sim_value_for_int_value!(SIntValue, SInt, SIntType);
|
||||||
struct SimulationImpl {
|
struct SimulationImpl {
|
||||||
state: interpreter::State,
|
state: interpreter::State,
|
||||||
io: Expr<Bundle>,
|
io: Expr<Bundle>,
|
||||||
uninitialized_inputs: HashSet<Target>,
|
uninitialized_inputs: HashMap<Target, Vec<Target>>,
|
||||||
io_targets: HashMap<Target, CompiledValue<CanonicalType>>,
|
io_targets: HashMap<Target, CompiledValue<CanonicalType>>,
|
||||||
made_initial_step: bool,
|
made_initial_step: bool,
|
||||||
needs_settle: bool,
|
needs_settle: bool,
|
||||||
|
@ -6483,37 +6483,52 @@ impl SimulationImpl {
|
||||||
.field("clocks_triggered", clocks_triggered)
|
.field("clocks_triggered", clocks_triggered)
|
||||||
.finish_non_exhaustive()
|
.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);
|
self.io_targets.insert(target, value);
|
||||||
match value.layout.body {
|
match value.layout.body {
|
||||||
CompiledTypeLayoutBody::Scalar => match target.flow() {
|
CompiledTypeLayoutBody::Scalar => match target.flow() {
|
||||||
Flow::Source => {}
|
Flow::Source => false,
|
||||||
Flow::Sink => {
|
Flow::Sink => {
|
||||||
self.uninitialized_inputs.insert(target);
|
self.uninitialized_inputs.insert(target, vec![]);
|
||||||
|
true
|
||||||
}
|
}
|
||||||
Flow::Duplex => unreachable!(),
|
Flow::Duplex => unreachable!(),
|
||||||
},
|
},
|
||||||
CompiledTypeLayoutBody::Array { .. } => {
|
CompiledTypeLayoutBody::Array { .. } => {
|
||||||
let value = value.map_ty(Array::from_canonical);
|
let value = value.map_ty(Array::from_canonical);
|
||||||
|
let mut sub_targets = Vec::new();
|
||||||
for index in 0..value.layout.ty.len() {
|
for index in 0..value.layout.ty.len() {
|
||||||
self.parse_io(
|
let sub_target = target.join(
|
||||||
target.join(
|
TargetPathElement::from(TargetPathArrayElement { index }).intern_sized(),
|
||||||
TargetPathElement::from(TargetPathArrayElement { index })
|
|
||||||
.intern_sized(),
|
|
||||||
),
|
|
||||||
value.element(index),
|
|
||||||
);
|
);
|
||||||
|
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 { .. } => {
|
CompiledTypeLayoutBody::Bundle { .. } => {
|
||||||
let value = value.map_ty(Bundle::from_canonical);
|
let value = value.map_ty(Bundle::from_canonical);
|
||||||
|
let mut sub_targets = Vec::new();
|
||||||
for BundleField { name, .. } in value.layout.ty.fields() {
|
for BundleField { name, .. } in value.layout.ty.fields() {
|
||||||
self.parse_io(
|
let sub_target = target.join(
|
||||||
target.join(
|
TargetPathElement::from(TargetPathBundleField { name }).intern_sized(),
|
||||||
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 {
|
let mut retval = Self {
|
||||||
state: State::new(compiled.insns),
|
state: State::new(compiled.insns),
|
||||||
io: compiled.io.to_expr(),
|
io: compiled.io.to_expr(),
|
||||||
uninitialized_inputs: HashSet::new(),
|
uninitialized_inputs: HashMap::new(),
|
||||||
io_targets: HashMap::new(),
|
io_targets: HashMap::new(),
|
||||||
made_initial_step: false,
|
made_initial_step: false,
|
||||||
needs_settle: true,
|
needs_settle: true,
|
||||||
|
@ -6791,6 +6806,35 @@ impl SimulationImpl {
|
||||||
};
|
};
|
||||||
panic!("simulator read/write expression must not have dynamic array indexes");
|
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]
|
#[track_caller]
|
||||||
fn read_helper(&mut self, io: Expr<CanonicalType>) -> CompiledValue<CanonicalType> {
|
fn read_helper(&mut self, io: Expr<CanonicalType>) -> CompiledValue<CanonicalType> {
|
||||||
let Some(target) = io.target() else {
|
let Some(target) = io.target() else {
|
||||||
|
@ -6810,7 +6854,7 @@ impl SimulationImpl {
|
||||||
self.settle();
|
self.settle();
|
||||||
}
|
}
|
||||||
Flow::Sink => {
|
Flow::Sink => {
|
||||||
if self.uninitialized_inputs.contains(&*target) {
|
if self.uninitialized_inputs.contains_key(&*target) {
|
||||||
panic!("can't read from an uninitialized input");
|
panic!("can't read from an uninitialized input");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6833,7 +6877,7 @@ impl SimulationImpl {
|
||||||
Flow::Duplex => unreachable!(),
|
Flow::Duplex => unreachable!(),
|
||||||
}
|
}
|
||||||
if !self.made_initial_step {
|
if !self.made_initial_step {
|
||||||
self.uninitialized_inputs.remove(&*target);
|
self.mark_target_as_initialized(*target);
|
||||||
}
|
}
|
||||||
self.needs_settle = true;
|
self.needs_settle = true;
|
||||||
compiled_value
|
compiled_value
|
||||||
|
@ -7136,11 +7180,11 @@ pub struct Simulation<T: BundleType> {
|
||||||
io: Expr<T>,
|
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 {
|
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() {
|
if f.alternate() {
|
||||||
format!("{v:#?}")
|
format!("{v:#?}")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -255,8 +255,14 @@ fn test_shift_register() {
|
||||||
let mut sim = Simulation::new(shift_register());
|
let mut sim = Simulation::new(shift_register());
|
||||||
let mut writer = RcWriter::default();
|
let mut writer = RcWriter::default();
|
||||||
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
|
sim.add_trace_writer(VcdWriterDecls::new(writer.clone()));
|
||||||
sim.write_clock(sim.io().cd.clk, false);
|
sim.write(
|
||||||
sim.write_reset(sim.io().cd.rst, true);
|
sim.io().cd,
|
||||||
|
#[hdl]
|
||||||
|
ClockDomain {
|
||||||
|
clk: false.to_clock(),
|
||||||
|
rst: true.to_sync_reset(),
|
||||||
|
},
|
||||||
|
);
|
||||||
sim.write_bool(sim.io().d, false);
|
sim.write_bool(sim.io().d, false);
|
||||||
sim.advance_time(SimDuration::from_micros(1));
|
sim.advance_time(SimDuration::from_micros(1));
|
||||||
sim.write_clock(sim.io().cd.clk, true);
|
sim.write_clock(sim.io().cd.clk, true);
|
||||||
|
|
Loading…
Reference in a new issue