diff --git a/interp/src/flatten/primitives/builder.rs b/interp/src/flatten/primitives/builder.rs index 976288a422..8d6d10174d 100644 --- a/interp/src/flatten/primitives/builder.rs +++ b/interp/src/flatten/primitives/builder.rs @@ -130,8 +130,8 @@ pub fn build_primitive( } } - CellPrototype::Unknown(_, _) => { - todo!() + CellPrototype::Unknown(s, _) => { + todo!("Primitives {s} not yet implemented") } } } diff --git a/interp/src/flatten/structures/environment/env.rs b/interp/src/flatten/structures/environment/env.rs index 97378842d4..1ecd6fae57 100644 --- a/interp/src/flatten/structures/environment/env.rs +++ b/interp/src/flatten/structures/environment/env.rs @@ -251,6 +251,12 @@ impl<'a> Environment<'a> { .expect("Called layout component with a non-component cell."); let comp_aux = &self.ctx.secondary[*comp_id]; + // Insert the component's continuous assignments into the program counter, if non-empty + let cont_assigns = self.ctx.primary[*comp_id].continuous_assignments; + if !cont_assigns.is_empty() { + self.pc.push_continuous_assigns(comp, cont_assigns); + } + // first layout the signature for sig_port in comp_aux.signature.iter() { let idx = self.ports.push(PortValue::new_undef()); @@ -574,6 +580,15 @@ impl<'a> Simulator<'a> { } } }) + .chain( + self.env.pc.continuous_assigns().iter().map(|x| { + ScheduledAssignments::new(x.comp, x.assigns, None) + }), + ) + .chain(self.env.pc.with_map().iter().map(|(ctrl_pt, comb_grp)| { + let assigns = self.ctx().primary[*comb_grp].assignments; + ScheduledAssignments::new(ctrl_pt.comp, assigns, None) + })) .collect() } @@ -587,7 +602,7 @@ impl<'a> Simulator<'a> { let mut leaf_nodes = vec![]; let mut new_nodes = vec![]; - let (vecs, par_map) = self.env.pc.mut_refs(); + let (mut vecs, mut par_map, mut with_map) = self.env.pc.take_fields(); vecs.retain_mut(|node| { // just considering a single node case for the moment @@ -626,7 +641,22 @@ impl<'a> Simulator<'a> { } ControlNode::If(i) => { if i.cond_group().is_some() { - todo!("if statement has a with clause") + if with_map.contains_key(node) { + with_map.remove(node); + return node.mutate_into_next(self.env.ctx); + } else { + let comb_group = i.cond_group().unwrap(); + let comb_assigns = ScheduledAssignments::new(node.comp, self.env.ctx.primary[comb_group].assignments, None); + + with_map.insert(node.clone(), comb_group); + + // TODO griffin: Sort out a way to make this error less terrible + // NOTE THIS MIGHT INTRODUCE A BUG SINCE THE PORTS + // HAVE NOT BEEN UNDEFINED YET + self.simulate_combinational(&[comb_assigns]).expect("something went wrong in evaluating with clause for if statement"); + + // now we fall through and proceed as normal + } } let target = GlobalPortRef::from_local( @@ -652,7 +682,12 @@ impl<'a> Simulator<'a> { } ControlNode::While(w) => { if w.cond_group().is_some() { - todo!("while statement has a with clause") + let comb_group = with_map.entry(node.clone()).or_insert(w.cond_group().unwrap()); + let comb_assigns = ScheduledAssignments::new(node.comp, self.env.ctx.primary[*comb_group].assignments, None); + + // NOTE THIS MIGHT INTRODUCE A BUG SINCE THE PORTS + // HAVE NOT BEEN UNDEFINED YET + self.simulate_combinational(&[comb_assigns]).expect("something went wrong in evaluating with clause for while statement"); } let target = GlobalPortRef::from_local( @@ -677,6 +712,9 @@ impl<'a> Simulator<'a> { *node = node.new_retain_comp(w.body()); true } else { + if w.cond_group().is_some() { + with_map.remove(node); + } // ascend the tree node.mutate_into_next(self.env.ctx) } @@ -708,6 +746,8 @@ impl<'a> Simulator<'a> { } }); + self.env.pc.restore_fields(vecs, par_map, with_map); + // insert all the new nodes from the par into the program counter self.env.pc.vec_mut().extend(new_nodes); @@ -734,7 +774,9 @@ impl<'a> Simulator<'a> { } } - self.simulate_combinational(&leaf_nodes)?; + let assigns_bundle = self.get_assignments(&leaf_nodes); + + self.simulate_combinational(&assigns_bundle)?; for cell in self.env.cells.values_mut() { match cell { @@ -819,9 +861,8 @@ impl<'a> Simulator<'a> { fn simulate_combinational( &mut self, - control_points: &[ControlPoint], + assigns_bundle: &[ScheduledAssignments], ) -> InterpreterResult<()> { - let assigns_bundle = self.get_assignments(control_points); let mut has_changed = true; // TODO griffin: rewrite this so that someone can actually read it diff --git a/interp/src/flatten/structures/environment/program_counter.rs b/interp/src/flatten/structures/environment/program_counter.rs index bd3daf0731..a4e0f0bd21 100644 --- a/interp/src/flatten/structures/environment/program_counter.rs +++ b/interp/src/flatten/structures/environment/program_counter.rs @@ -4,8 +4,11 @@ use ahash::{HashMap, HashMapExt}; use super::super::context::Context; use crate::flatten::{ - flat_ir::prelude::{ControlIdx, ControlMap, ControlNode, GlobalCellIdx}, - structures::index_trait::{impl_index_nonzero, IndexRef}, + flat_ir::prelude::{ + AssignmentIdx, CombGroupIdx, ControlIdx, ControlMap, ControlNode, + GlobalCellIdx, + }, + structures::index_trait::{impl_index_nonzero, IndexRange, IndexRef}, }; use itertools::{FoldWhile, Itertools}; @@ -55,6 +58,12 @@ impl ControlPoint { } } +#[derive(Debug, Clone)] +pub struct ContinuousAssignments { + pub comp: GlobalCellIdx, + pub assigns: IndexRange, +} + /// An index for searching up and down a tree. This is used to index into /// various control nodes. For If blocks the true branch is denoted by 0 and /// the false by 1. The same is true for while blocks. For seq and par blocks, @@ -147,7 +156,12 @@ impl SearchPath { return Some(*node); } - ControlNode::If(_) => { + ControlNode::If(i) => { + if i.cond_group().is_some() { + // since this has a with, we need to re-visit + // the node to clean-up the with group + return Some(*node); + } // there is nothing to do when ascending to an if as it // is already done once the body is done continue; @@ -323,12 +337,14 @@ pub type ChildCount = u16; pub(crate) struct ProgramCounter { vec: Vec, par_map: HashMap, + continuous_assigns: Vec, + with_map: HashMap, } // we need a few things from the program counter impl ProgramCounter { - pub fn new(ctx: &Context) -> Self { + pub(crate) fn new(ctx: &Context) -> Self { let root = ctx.entry_point; // this relies on the fact that we construct the root cell-ledger // as the first possible cell in the program. If that changes this will break. @@ -350,6 +366,8 @@ impl ProgramCounter { Self { vec, par_map: HashMap::new(), + continuous_assigns: Vec::new(), + with_map: HashMap::new(), } } @@ -377,15 +395,46 @@ impl ProgramCounter { &self.par_map } - /// returns mutable references to both vec and par_map. - /// This is useful for when you need to mutate both at the same time. - pub fn mut_refs( + pub fn take_fields( &mut self, ) -> ( - &mut Vec, - &mut HashMap, + Vec, + HashMap, + HashMap, + ) { + ( + std::mem::take(&mut self.vec), + std::mem::take(&mut self.par_map), + std::mem::take(&mut self.with_map), + ) + } + + pub fn restore_fields( + &mut self, + vec: Vec, + par_map: HashMap, + with_map: HashMap, ) { - (&mut self.vec, &mut self.par_map) + self.vec = vec; + self.par_map = par_map; + self.with_map = with_map; + } + + pub(crate) fn push_continuous_assigns( + &mut self, + comp: GlobalCellIdx, + assigns: IndexRange, + ) { + let assigns = ContinuousAssignments { comp, assigns }; + self.continuous_assigns.push(assigns) + } + + pub(crate) fn continuous_assigns(&self) -> &[ContinuousAssignments] { + &self.continuous_assigns + } + + pub(crate) fn with_map(&self) -> &HashMap { + &self.with_map } } diff --git a/interp/src/serialization/data_dump.rs b/interp/src/serialization/data_dump.rs index d05667c0bd..fdabfd2dca 100644 --- a/interp/src/serialization/data_dump.rs +++ b/interp/src/serialization/data_dump.rs @@ -149,6 +149,7 @@ impl DataDump { write!(writer, "{}", header_str).unwrap(); let written = writer.write(&self.data)?; + writer.flush()?; assert_eq!(written, self.data.len()); Ok(()) }