forked from libre-chip/fayalite
		
	sim: fix sim.write to struct
This commit is contained in:
		
							parent
							
								
									21c73051ec
								
							
						
					
					
						commit
						36bad52978
					
				
					 2 changed files with 73 additions and 23 deletions
				
			
		| 
						 | 
				
			
			@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue