Simulation::settle_step() works for simple modules

This commit is contained in:
Jacob Lifshay 2024-11-13 21:20:15 -08:00
parent a6e40839ac
commit f54e55a143
Signed by: programmerjake
SSH key fingerprint: SHA256:HnFTLGpSm4Q4Fj502oCFisjZSoakwEuTsJJMSke63RQ
3 changed files with 1221 additions and 166 deletions

View file

@ -40,13 +40,13 @@ mod interpreter;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
enum CondBody { enum CondBody {
IfTrue { IfTrue {
cond: CompiledExpr<Bool>, cond: CompiledValue<Bool>,
}, },
IfFalse { IfFalse {
cond: CompiledExpr<Bool>, cond: CompiledValue<Bool>,
}, },
MatchArm { MatchArm {
enum_expr: CompiledExpr<Enum>, enum_expr: CompiledValue<Enum>,
variant_index: usize, variant_index: usize,
}, },
} }
@ -267,8 +267,8 @@ impl<T: Type> CompiledValue<T> {
} }
impl CompiledValue<Enum> { impl CompiledValue<Enum> {
fn add_discriminant_to_set(self, offset: TypeIndex, inputs: &mut SlotSet) { fn add_discriminant_to_set(self, inputs: &mut SlotSet) {
inputs.extend([self.range.offset(offset)]); inputs.extend([self.range]);
} }
} }
@ -359,19 +359,6 @@ impl<T: Type> CompiledExpr<T> {
} }
} }
impl CompiledExpr<Enum> {
fn add_discriminant_and_indexes_to_set(self, inputs: &mut SlotSet) {
let Self {
static_part,
indexes,
} = self;
indexes.as_ref().for_each_offset(|offset| {
static_part.add_discriminant_to_set(offset, inputs);
});
inputs.extend(indexes.as_ref().iter());
}
}
impl CompiledExpr<Bundle> { impl CompiledExpr<Bundle> {
fn field_by_index(self, field_index: usize) -> CompiledExpr<CanonicalType> { fn field_by_index(self, field_index: usize) -> CompiledExpr<CanonicalType> {
CompiledExpr { CompiledExpr {
@ -446,48 +433,118 @@ enum AssignmentIO {
}, },
} }
#[derive(Debug, Default)] #[derive(Debug)]
struct Assignments { enum Assignments {
assignments: Vec<Assignment>, Accumulating {
slot_readers: Option<SlotToAssignmentIndexFullMap>, assignments: Vec<Assignment>,
slot_writers: Option<SlotToAssignmentIndexFullMap>, },
Finalized {
assignments: Box<[Assignment]>,
slot_readers: SlotToAssignmentIndexFullMap,
slot_writers: SlotToAssignmentIndexFullMap,
assignment_immediate_predecessors: Box<[Box<[usize]>]>,
assignment_immediate_successors: Box<[Box<[usize]>]>,
},
}
impl Default for Assignments {
fn default() -> Self {
Self::Accumulating {
assignments: Vec::new(),
}
}
} }
impl Assignments { impl Assignments {
fn finalize(&mut self, slots_len: TypeLen) { fn finalize(&mut self, slots_len: TypeLen) {
assert!( let Self::Accumulating { assignments } = self else {
self.slot_readers.is_none() && self.slot_writers.is_none(), unreachable!("already finalized");
"already finalized" };
); let assignments = mem::take(assignments).into_boxed_slice();
let mut slot_readers = SlotToAssignmentIndexFullMap::new(slots_len); let mut slot_readers = SlotToAssignmentIndexFullMap::new(slots_len);
let mut slot_writers = SlotToAssignmentIndexFullMap::new(slots_len); let mut slot_writers = SlotToAssignmentIndexFullMap::new(slots_len);
for (assignment_index, assignment) in self.assignments.iter().enumerate() { let mut assignment_immediate_predecessors = vec![BTreeSet::new(); assignments.len()];
let mut assignment_immediate_successors = vec![BTreeSet::new(); assignments.len()];
for (assignment_index, assignment) in assignments.iter().enumerate() {
slot_readers slot_readers
.keys_for_assignment(assignment_index) .keys_for_assignment(assignment_index)
.extend([&assignment.inputs]); .extend([&assignment.inputs]);
slot_writers let SlotSet(TypeParts {
.keys_for_assignment(assignment_index) small_slots,
.extend([&assignment.outputs]); big_slots,
}) = &assignment.outputs;
for &slot in small_slots {
if let Some(&pred) = slot_writers[slot].last() {
assignment_immediate_predecessors[assignment_index].insert(pred);
assignment_immediate_successors[pred].insert(assignment_index);
}
slot_writers[slot].push(assignment_index);
}
for &slot in big_slots {
if let Some(&pred) = slot_writers[slot].last() {
assignment_immediate_predecessors[assignment_index].insert(pred);
assignment_immediate_successors[pred].insert(assignment_index);
}
slot_writers[slot].push(assignment_index);
}
} }
self.slot_readers = Some(slot_readers); *self = Self::Finalized {
self.slot_writers = Some(slot_writers); assignments,
slot_readers,
slot_writers,
assignment_immediate_predecessors: assignment_immediate_predecessors
.into_iter()
.map(Box::from_iter)
.collect(),
assignment_immediate_successors: assignment_immediate_successors
.into_iter()
.map(Box::from_iter)
.collect(),
};
} }
fn push(&mut self, v: Assignment) { fn push(&mut self, v: Assignment) {
assert!( let Self::Accumulating { assignments } = self else {
self.slot_readers.is_none() && self.slot_writers.is_none(), unreachable!("already finalized");
"already finalized" };
); assignments.push(v);
self.assignments.push(v); }
fn assignments(&self) -> &[Assignment] {
let Self::Finalized { assignments, .. } = self else {
unreachable!("Assignments::finalize should have been called");
};
assignments
} }
fn slot_readers(&self) -> &SlotToAssignmentIndexFullMap { fn slot_readers(&self) -> &SlotToAssignmentIndexFullMap {
self.slot_readers let Self::Finalized { slot_readers, .. } = self else {
.as_ref() unreachable!("Assignments::finalize should have been called");
.expect("Assignments::finalize should have been called") };
slot_readers
} }
fn slot_writers(&self) -> &SlotToAssignmentIndexFullMap { fn slot_writers(&self) -> &SlotToAssignmentIndexFullMap {
self.slot_writers let Self::Finalized { slot_writers, .. } = self else {
.as_ref() unreachable!("Assignments::finalize should have been called");
.expect("Assignments::finalize should have been called") };
slot_writers
}
fn assignment_immediate_predecessors(&self) -> &[Box<[usize]>] {
let Self::Finalized {
assignment_immediate_predecessors,
..
} = self
else {
unreachable!("Assignments::finalize should have been called");
};
assignment_immediate_predecessors
}
fn assignment_immediate_successors(&self) -> &[Box<[usize]>] {
let Self::Finalized {
assignment_immediate_successors,
..
} = self
else {
unreachable!("Assignments::finalize should have been called");
};
assignment_immediate_successors
} }
} }
@ -541,42 +598,47 @@ impl<'a> IntoNodeIdentifiers for &'a Assignments {
big_slots, big_slots,
} = self.slot_readers().len(); } = self.slot_readers().len();
AssignmentsNodeIdentifiers { AssignmentsNodeIdentifiers {
assignment_indexes: 0..self.assignments.len(), assignment_indexes: 0..self.assignments().len(),
small_slots: 0..small_slots.value, small_slots: 0..small_slots.value,
big_slots: 0..big_slots.value, big_slots: 0..big_slots.value,
} }
} }
} }
enum AssignmentsNeighborsDirected<'a> { struct AssignmentsNeighborsDirected<'a> {
AssignmentIndexes(std::slice::Iter<'a, usize>), assignment_indexes: std::slice::Iter<'a, usize>,
Slots { small_slots: std::collections::btree_set::Iter<'a, StatePartIndex<StatePartKindSmallSlots>>,
small_slots: std::collections::btree_set::Iter<'a, StatePartIndex<StatePartKindSmallSlots>>, big_slots: std::collections::btree_set::Iter<'a, StatePartIndex<StatePartKindBigSlots>>,
big_slots: std::collections::btree_set::Iter<'a, StatePartIndex<StatePartKindBigSlots>>,
},
} }
impl Iterator for AssignmentsNeighborsDirected<'_> { impl Iterator for AssignmentsNeighborsDirected<'_> {
type Item = AssignmentOrSlotIndex; type Item = AssignmentOrSlotIndex;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
match self { let Self {
AssignmentsNeighborsDirected::AssignmentIndexes(iter) => iter assignment_indexes,
.next() small_slots,
.copied() big_slots,
.map(AssignmentOrSlotIndex::AssignmentIndex), } = self;
AssignmentsNeighborsDirected::Slots { if let retval @ Some(_) = assignment_indexes
small_slots, .next()
big_slots, .copied()
} => small_slots .map(AssignmentOrSlotIndex::AssignmentIndex)
.next() {
.copied() retval
.map(AssignmentOrSlotIndex::SmallSlots) } else if let retval @ Some(_) = small_slots
.or_else(|| { .next()
big_slots .copied()
.next() .map(AssignmentOrSlotIndex::SmallSlots)
.copied() {
.map(AssignmentOrSlotIndex::BigSlots) retval
}), } else if let retval @ Some(_) = big_slots
.next()
.copied()
.map(AssignmentOrSlotIndex::BigSlots)
{
retval
} else {
None
} }
} }
} }
@ -604,25 +666,39 @@ impl<'a> IntoNeighborsDirected for &'a Assignments {
}; };
match n { match n {
AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => { AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => {
let assignment = &self.assignments[assignment_index]; let assignment = &self.assignments()[assignment_index];
let SlotSet(TypeParts { let (
small_slots, assignment_indexes,
big_slots, SlotSet(TypeParts {
}) = match d { small_slots,
Outgoing => &assignment.outputs, big_slots,
Incoming => &assignment.inputs, }),
) = match d {
Outgoing => (
&self.assignment_immediate_successors()[assignment_index],
&assignment.outputs,
),
Incoming => (
&self.assignment_immediate_predecessors()[assignment_index],
&assignment.inputs,
),
}; };
AssignmentsNeighborsDirected::Slots { AssignmentsNeighborsDirected {
assignment_indexes: assignment_indexes.iter(),
small_slots: small_slots.iter(), small_slots: small_slots.iter(),
big_slots: big_slots.iter(), big_slots: big_slots.iter(),
} }
} }
AssignmentOrSlotIndex::SmallSlots(slot) => { AssignmentOrSlotIndex::SmallSlots(slot) => AssignmentsNeighborsDirected {
AssignmentsNeighborsDirected::AssignmentIndexes(slot_map[slot].iter()) assignment_indexes: slot_map[slot].iter(),
} small_slots: Default::default(),
AssignmentOrSlotIndex::BigSlots(slot) => { big_slots: Default::default(),
AssignmentsNeighborsDirected::AssignmentIndexes(slot_map[slot].iter()) },
} AssignmentOrSlotIndex::BigSlots(slot) => AssignmentsNeighborsDirected {
assignment_indexes: slot_map[slot].iter(),
small_slots: Default::default(),
big_slots: Default::default(),
},
} }
} }
} }
@ -659,7 +735,7 @@ impl Visitable for Assignments {
fn visit_map(self: &Self) -> Self::Map { fn visit_map(self: &Self) -> Self::Map {
AssignmentsVisitMap { AssignmentsVisitMap {
assignments: vec![false; self.assignments.len()], assignments: vec![false; self.assignments().len()],
slots: DenseSlotSet::new(self.slot_readers().len()), slots: DenseSlotSet::new(self.slot_readers().len()),
} }
} }
@ -667,7 +743,7 @@ impl Visitable for Assignments {
fn reset_map(self: &Self, map: &mut Self::Map) { fn reset_map(self: &Self, map: &mut Self::Map) {
let AssignmentsVisitMap { assignments, slots } = map; let AssignmentsVisitMap { assignments, slots } = map;
assignments.clear(); assignments.clear();
assignments.resize(self.assignments.len(), false); assignments.resize(self.assignments().len(), false);
if slots.len() != self.slot_readers().len() { if slots.len() != self.slot_readers().len() {
*slots = DenseSlotSet::new(self.slot_readers().len()); *slots = DenseSlotSet::new(self.slot_readers().len());
} else { } else {
@ -898,12 +974,12 @@ impl Extend<CondBody> for SlotSet {
fn extend<T: IntoIterator<Item = CondBody>>(&mut self, iter: T) { fn extend<T: IntoIterator<Item = CondBody>>(&mut self, iter: T) {
iter.into_iter().for_each(|cond_body| match cond_body { iter.into_iter().for_each(|cond_body| match cond_body {
CondBody::IfTrue { cond } | CondBody::IfFalse { cond } => { CondBody::IfTrue { cond } | CondBody::IfFalse { cond } => {
cond.add_target_and_indexes_to_set(self); self.extend([cond.range]);
} }
CondBody::MatchArm { CondBody::MatchArm {
enum_expr, enum_expr,
variant_index, variant_index: _,
} => enum_expr.add_discriminant_and_indexes_to_set(self), } => enum_expr.add_discriminant_to_set(self),
}) })
} }
} }
@ -936,11 +1012,10 @@ impl SlotToAssignmentIndexFullMap {
small_slots, small_slots,
big_slots, big_slots,
} = len; } = len;
const VEC_NEW: Vec<usize> = Vec::new();
Self(TypeParts { Self(TypeParts {
small_slots: vec![VEC_NEW; small_slots.value.try_into().expect("length too big")] small_slots: vec![Vec::new(); small_slots.value.try_into().expect("length too big")]
.into_boxed_slice(), .into_boxed_slice(),
big_slots: vec![VEC_NEW; big_slots.value.try_into().expect("length too big")] big_slots: vec![Vec::new(); big_slots.value.try_into().expect("length too big")]
.into_boxed_slice(), .into_boxed_slice(),
}) })
} }
@ -1237,54 +1312,51 @@ impl Compiler {
static_part, static_part,
indexes, indexes,
} = expr; } = expr;
let layout = static_part.layout.with_anonymized_debug_info(); let retval = if indexes.as_ref().is_empty() {
let retval = CompiledValue { CompiledValue {
layout, layout: static_part.layout,
range: self.insns.allocate_variable(&layout.layout), range: static_part.range,
write: None, write: None,
}
} else {
let layout = static_part.layout.with_anonymized_debug_info();
let retval = CompiledValue {
layout,
range: self.insns.allocate_variable(&layout.layout),
write: None,
};
let TypeIndexRange {
small_slots,
big_slots,
} = retval.range;
self.add_assignment(
Interned::default(),
small_slots
.iter()
.zip(static_part.range.small_slots.iter())
.map(|(dest, base)| Insn::ReadSmallIndexed {
dest,
src: StatePartArrayIndexed {
base,
indexes: indexes.small_slots,
},
})
.chain(
big_slots
.iter()
.zip(static_part.range.big_slots.iter())
.map(|(dest, base)| Insn::ReadIndexed {
dest,
src: StatePartArrayIndexed {
base,
indexes: indexes.big_slots,
},
}),
),
source_location,
);
retval
}; };
let TypeIndexRange {
small_slots,
big_slots,
} = retval.range;
self.add_assignment(
Interned::default(),
small_slots
.iter()
.zip(static_part.range.small_slots.iter())
.map(|(dest, base)| {
if indexes.small_slots.is_empty() {
Insn::CopySmall { dest, src: base }
} else {
Insn::ReadSmallIndexed {
dest,
src: StatePartArrayIndexed {
base,
indexes: indexes.small_slots,
},
}
}
})
.chain(
big_slots
.iter()
.zip(static_part.range.big_slots.iter())
.map(|(dest, base)| {
if indexes.big_slots.is_empty() {
Insn::Copy { dest, src: base }
} else {
Insn::ReadIndexed {
dest,
src: StatePartArrayIndexed {
base,
indexes: indexes.big_slots,
},
}
}
}),
),
source_location,
);
self.compiled_exprs_to_values.insert(expr, retval); self.compiled_exprs_to_values.insert(expr, retval);
retval retval
} }
@ -2456,9 +2528,9 @@ impl Compiler {
source_location, source_location,
blocks: [then_block, else_block], blocks: [then_block, else_block],
}) => { }) => {
let cond = self let cond = self.compile_expr(*parent_module, Expr::canonical(cond));
.compile_expr(*parent_module, Expr::canonical(cond)) let cond = self.compiled_expr_to_value(cond, source_location);
.map_ty(Bool::from_canonical); let cond = cond.map_ty(Bool::from_canonical);
self.compile_block( self.compile_block(
parent_module, parent_module,
then_block, then_block,
@ -2481,9 +2553,9 @@ impl Compiler {
source_location, source_location,
blocks, blocks,
}) => { }) => {
let enum_expr = self let enum_expr = self.compile_expr(*parent_module, Expr::canonical(expr));
.compile_expr(*parent_module, Expr::canonical(expr)) let enum_expr = self.compiled_expr_to_value(enum_expr, source_location);
.map_ty(Enum::from_canonical); let enum_expr = enum_expr.map_ty(Enum::from_canonical);
for (variant_index, block) in blocks.into_iter().enumerate() { for (variant_index, block) in blocks.into_iter().enumerate() {
self.compile_block( self.compile_block(
parent_module, parent_module,
@ -2514,10 +2586,12 @@ impl Compiler {
annotations: _, annotations: _,
module_io, module_io,
}| { }| {
self.compile_value(TargetInInstantiatedModule { let target = TargetInInstantiatedModule {
instantiated_module: *module, instantiated_module: *module,
target: Target::from(module_io), target: Target::from(module_io),
}) };
self.decl_conditions.insert(target, Interned::default());
self.compile_value(target)
}, },
) )
.collect(); .collect();
@ -2537,8 +2611,7 @@ impl Compiler {
fn process_assignments(&mut self) { fn process_assignments(&mut self) {
self.assignments self.assignments
.finalize(self.insns.state_layout().len().ty); .finalize(self.insns.state_layout().len().ty);
let assignments_queue: Vec<usize> = match petgraph::algo::toposort(&self.assignments, None) let assignments_order: Vec<_> = match petgraph::algo::toposort(&self.assignments, None) {
{
Ok(nodes) => nodes Ok(nodes) => nodes
.into_iter() .into_iter()
.filter_map(|n| match n { .filter_map(|n| match n {
@ -2549,7 +2622,7 @@ impl Compiler {
Err(e) => match e.node_id() { Err(e) => match e.node_id() {
AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => panic!( AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => panic!(
"combinatorial logic cycle detected at: {}", "combinatorial logic cycle detected at: {}",
self.assignments.assignments[assignment_index].source_location, self.assignments.assignments()[assignment_index].source_location,
), ),
AssignmentOrSlotIndex::SmallSlots(slot) => panic!( AssignmentOrSlotIndex::SmallSlots(slot) => panic!(
"combinatorial logic cycle detected through: {}", "combinatorial logic cycle detected through: {}",
@ -2561,12 +2634,113 @@ impl Compiler {
), ),
}, },
}; };
todo!(); struct CondStackEntry<'a> {
cond: &'a Cond,
end_label_index: usize,
}
let mut cond_stack = Vec::<CondStackEntry<'_>>::new();
for assignment_index in assignments_order {
let Assignment {
inputs: _,
outputs: _,
conditions,
insns,
source_location,
} = &self.assignments.assignments()[assignment_index];
let mut same_len = 0;
for (index, (entry, cond)) in cond_stack.iter().zip(conditions).enumerate() {
if entry.cond != cond {
break;
}
same_len = index + 1;
}
while cond_stack.len() > same_len {
let CondStackEntry {
cond: _,
end_label_index,
} = cond_stack.pop().expect("just checked len");
self.insns.define_label_at_next_insn(end_label_index);
}
for cond in &conditions[cond_stack.len()..] {
let end_label_index = self.insns.new_label();
match cond.body {
CondBody::IfTrue { cond: cond_value }
| CondBody::IfFalse { cond: cond_value } => {
let (branch_if_zero, branch_if_non_zero) = match cond_value.range.len() {
TypeLen {
small_slots:
StatePartLen {
value: 1,
_phantom: _,
},
big_slots:
StatePartLen {
value: 0,
_phantom: _,
},
} => (
Insn::BranchIfSmallZero {
target: end_label_index,
value: cond_value.range.small_slots.start,
},
Insn::BranchIfSmallNonZero {
target: end_label_index,
value: cond_value.range.small_slots.start,
},
),
TypeLen {
small_slots:
StatePartLen {
value: 0,
_phantom: _,
},
big_slots:
StatePartLen {
value: 1,
_phantom: _,
},
} => (
Insn::BranchIfZero {
target: end_label_index,
value: cond_value.range.big_slots.start,
},
Insn::BranchIfNonZero {
target: end_label_index,
value: cond_value.range.big_slots.start,
},
),
_ => unreachable!(),
};
self.insns.push(
if let CondBody::IfTrue { .. } = cond.body {
branch_if_zero
} else {
branch_if_non_zero
},
cond.source_location,
);
}
CondBody::MatchArm {
enum_expr,
variant_index,
} => todo!(),
}
cond_stack.push(CondStackEntry {
cond,
end_label_index,
});
}
for insn in insns {
self.insns.push(*insn, *source_location);
}
}
} }
pub fn compile(mut self) -> Compiled<Bundle> { pub fn compile(mut self) -> Compiled<Bundle> {
let base_module = let base_module =
*self.compile_module(InstantiatedModule::Base(self.base_module).intern_sized()); *self.compile_module(InstantiatedModule::Base(self.base_module).intern_sized());
self.process_assignments(); self.process_assignments();
self.insns
.push(Insn::Return, self.base_module.source_location());
Compiled { Compiled {
insns: Insns::from(self.insns).intern_sized(), insns: Insns::from(self.insns).intern_sized(),
base_module, base_module,
@ -2588,7 +2762,7 @@ pub struct Compiled<T: BundleType> {
} }
impl<T: BundleType> Compiled<T> { impl<T: BundleType> Compiled<T> {
pub fn new(module: Module<T>) -> Self { pub fn new(module: Interned<Module<T>>) -> Self {
Self::from_canonical(Compiler::new(module.canonical().intern()).compile()) Self::from_canonical(Compiler::new(module.canonical().intern()).compile())
} }
pub fn canonical(self) -> Compiled<Bundle> { pub fn canonical(self) -> Compiled<Bundle> {
@ -2620,14 +2794,19 @@ impl<T: BundleType> Compiled<T> {
#[derive(Debug)] #[derive(Debug)]
pub struct Simulation<T: BundleType> { pub struct Simulation<T: BundleType> {
state: interpreter::State, state: interpreter::State,
compiled: Compiled<T>, base_module: CompiledModule,
base_module_io_ty: T,
} }
impl<T: BundleType> Simulation<T> { impl<T: BundleType> Simulation<T> {
pub fn new(module: Interned<Module<T>>) -> Self {
Self::from_compiled(Compiled::new(module))
}
pub fn from_compiled(compiled: Compiled<T>) -> Self { pub fn from_compiled(compiled: Compiled<T>) -> Self {
Self { Self {
state: interpreter::State::new(compiled.insns), state: interpreter::State::new(compiled.insns),
compiled, base_module: compiled.base_module,
base_module_io_ty: compiled.base_module_io_ty,
} }
} }
pub fn settle_step(&mut self) { pub fn settle_step(&mut self) {

View file

@ -7,6 +7,7 @@ use crate::{
ty::CanonicalType, ty::CanonicalType,
util::get_many_mut, util::get_many_mut,
}; };
use hashbrown::HashMap;
use num_bigint::BigInt; use num_bigint::BigInt;
use num_traits::{One, Signed, ToPrimitive, Zero}; use num_traits::{One, Signed, ToPrimitive, Zero};
use std::{ use std::{
@ -166,6 +167,83 @@ fn make_array_into_iter<T, const I: usize, const N: usize>(
retval retval
} }
impl fmt::Debug for Insn {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.debug_fmt::<InsnsBuildingDone>(f, None, None)
}
}
impl Insn {
fn debug_fmt<BK: InsnsBuildingKind>(
&self,
f: &mut fmt::Formatter<'_>,
labels: Option<&Labels>,
state_layout: Option<&StateLayout<BK>>,
) -> fmt::Result {
let (insn_name, fields) = self.fields_with_names();
write!(f, "{insn_name}")?;
if fields.len() == 0 {
return Ok(());
}
writeln!(f, " {{")?;
for (field_name, field) in fields {
write!(f, " {field_name}: ")?;
match field.kind {
InsnFieldKind::BranchTarget => match field.ty {
InsnFieldType::USize(&label_index) => {
if let Some(labels) = labels {
write!(f, "L{label_index}")?;
if let Some(label) = labels.labels.get(label_index) {
if let Some(address) = label.address {
write!(f, " (at {address})")?;
} else {
write!(f, " (not yet defined)")?;
}
} else {
write!(f, " (invalid)")?;
}
writeln!(f, ",")?;
continue;
}
}
InsnFieldType::SmallSlot(_)
| InsnFieldType::BigSlot(_)
| InsnFieldType::SmallSlotArrayIndexed(_)
| InsnFieldType::BigSlotArrayIndexed(_)
| InsnFieldType::SmallUInt(_)
| InsnFieldType::SmallSInt(_)
| InsnFieldType::InternedBigInt(_)
| InsnFieldType::U8(_)
| InsnFieldType::Empty(_) => {}
},
InsnFieldKind::Input | InsnFieldKind::Output | InsnFieldKind::Immediate => {}
}
match field.ty {
InsnFieldType::SmallSlot(v) => {
v.debug_fmt(f, ",", " // ", "", state_layout)?;
}
InsnFieldType::BigSlot(v) => {
v.debug_fmt(f, ",", " // ", "", state_layout)?;
}
InsnFieldType::SmallSlotArrayIndexed(v) => {
v.debug_fmt(f, ",", " // ", "", state_layout)?;
}
InsnFieldType::BigSlotArrayIndexed(v) => {
v.debug_fmt(f, ",", " // ", "", state_layout)?;
}
InsnFieldType::SmallUInt(v) => fmt::Debug::fmt(v, f)?,
InsnFieldType::SmallSInt(v) => fmt::Debug::fmt(v, f)?,
InsnFieldType::InternedBigInt(v) => fmt::Debug::fmt(v, f)?,
InsnFieldType::U8(v) => fmt::Debug::fmt(v, f)?,
InsnFieldType::USize(v) => fmt::Debug::fmt(v, f)?,
InsnFieldType::Empty(v) => fmt::Debug::fmt(v, f)?,
}
writeln!(f, ",")?;
}
write!(f, "}}")
}
}
macro_rules! impl_insns { macro_rules! impl_insns {
( (
#[insn = $Insn:ident, next_macro = $next_macro:ident, branch_macro = $branch_macro:ident] #[insn = $Insn:ident, next_macro = $next_macro:ident, branch_macro = $branch_macro:ident]
@ -191,7 +269,7 @@ macro_rules! impl_insns {
})? => $block:block })? => $block:block
)* )*
) => { ) => {
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[derive(Copy, Clone, Eq, PartialEq, Hash)]
$vis enum $Insn { $vis enum $Insn {
$( $(
$(#[$insn_meta])* $(#[$insn_meta])*
@ -249,6 +327,28 @@ macro_rules! impl_insns {
)* )*
} }
} }
$vis fn fields_with_names<'a>(&'a self) -> (&'static str, std::array::IntoIter<(&'static str, InsnField<InsnFieldTypeTransformRef<'a>>), { $Insn::MAX_FIELDS }>) {
match self {
$(
$Insn::$insn_name $({
$($field_name,)*
})? => (
stringify!($insn_name),
make_array_into_iter([
$($((stringify!($field_name), InsnField {
ty: <$field_ty as InsnFieldTrait>::variant($field_name),
kind: InsnFieldKind::$field_kind,
}),)*)?
],
|| ("", InsnField {
ty: InsnFieldType::empty(),
kind: InsnFieldKind::Immediate,
}),
),
),
)*
}
}
$vis fn fields_mut<'a>(&'a mut self) -> std::array::IntoIter<InsnField<InsnFieldTypeTransformRefMut<'a>>, { $Insn::MAX_FIELDS }> { $vis fn fields_mut<'a>(&'a mut self) -> std::array::IntoIter<InsnField<InsnFieldTypeTransformRefMut<'a>>, { $Insn::MAX_FIELDS }> {
match self { match self {
$( $(
@ -339,6 +439,8 @@ pub(crate) trait InsnsBuildingKind: Copy + Eq + fmt::Debug + Hash + Default {
+ Default + Default
+ Deref<Target = [T]> + Deref<Target = [T]>
+ FromIterator<T>; + FromIterator<T>;
type Labels: Default;
fn labels(labels: &Self::Labels) -> Option<&Labels>;
} }
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
@ -346,6 +448,10 @@ pub(crate) struct InsnsBuildingDone;
impl InsnsBuildingKind for InsnsBuildingDone { impl InsnsBuildingKind for InsnsBuildingDone {
type Vec<T: fmt::Debug + Clone + Eq + Hash + Send + Sync + 'static> = Interned<[T]>; type Vec<T: fmt::Debug + Clone + Eq + Hash + Send + Sync + 'static> = Interned<[T]>;
type Labels = ();
fn labels(_labels: &Self::Labels) -> Option<&Labels> {
None
}
} }
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
@ -353,12 +459,27 @@ pub(crate) struct InsnsBuilding;
impl InsnsBuildingKind for InsnsBuilding { impl InsnsBuildingKind for InsnsBuilding {
type Vec<T: fmt::Debug + Clone + Eq + Hash + Send + Sync + 'static> = Vec<T>; type Vec<T: fmt::Debug + Clone + Eq + Hash + Send + Sync + 'static> = Vec<T>;
type Labels = Labels;
fn labels(labels: &Self::Labels) -> Option<&Labels> {
Some(labels)
}
}
struct Label {
address: Option<usize>,
}
#[derive(Default)]
pub(crate) struct Labels {
labels: Vec<Label>,
address_to_label_indexes_map: HashMap<usize, Vec<usize>>,
} }
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq, Hash)]
pub(crate) struct Insns<BK: InsnsBuildingKind> { pub(crate) struct Insns<BK: InsnsBuildingKind> {
insns: BK::Vec<Insn>, insns: BK::Vec<Insn>,
insn_source_locations: BK::Vec<SourceLocation>, insn_source_locations: BK::Vec<SourceLocation>,
labels: BK::Labels,
state_layout: StateLayout<BK>, state_layout: StateLayout<BK>,
} }
@ -368,21 +489,60 @@ impl<BK: InsnsBuildingKind> Insns<BK> {
} }
} }
struct InsnsDebug<'a> { struct InsnsDebug<'a, BK: InsnsBuildingKind> {
insns: &'a [Insn], insns: &'a [Insn],
insn_source_locations: &'a [SourceLocation], insn_source_locations: &'a [SourceLocation],
labels: &'a BK::Labels,
state_layout: &'a StateLayout<BK>,
} }
impl<'a> fmt::Debug for InsnsDebug<'a> { struct InsnDebug<'a, BK: InsnsBuildingKind> {
address: usize,
source_location: Option<SourceLocation>,
insn: &'a Insn,
labels: Option<&'a Labels>,
state_layout: &'a StateLayout<BK>,
}
impl<BK: InsnsBuildingKind> fmt::Debug for InsnDebug<'_, BK> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(label_indexes) = self
.labels
.and_then(|labels| labels.address_to_label_indexes_map.get(&self.address))
{
for &label_index in label_indexes {
writeln!(f, "L{label_index}:")?;
}
}
if let Some(source_location) = self.source_location {
writeln!(f, "// at: {source_location}")?;
}
self.insn.debug_fmt(f, self.labels, Some(self.state_layout))
}
}
impl<'a, BK: InsnsBuildingKind> fmt::Debug for InsnsDebug<'a, BK> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let labels = BK::labels(&self.labels);
let mut debug_list = f.debug_list(); let mut debug_list = f.debug_list();
let mut last_source_location = None; let mut last_source_location = None;
for (insn, source_location) in self.insns.iter().zip(self.insn_source_locations) { for (address, (insn, &source_location)) in self
if Some(source_location) != last_source_location { .insns
debug_list.entry(&format_args!("// at: {source_location}\n{insn:?}")); .iter()
} else { .zip(self.insn_source_locations)
debug_list.entry(insn); .enumerate()
} {
debug_list.entry(&InsnDebug {
address,
source_location: if Some(source_location) != last_source_location {
Some(source_location)
} else {
None
},
insn,
labels,
state_layout: self.state_layout,
});
last_source_location = Some(source_location); last_source_location = Some(source_location);
} }
debug_list.finish() debug_list.finish()
@ -394,15 +554,18 @@ impl<BK: InsnsBuildingKind> fmt::Debug for Insns<BK> {
let Self { let Self {
insns, insns,
insn_source_locations, insn_source_locations,
labels,
state_layout, state_layout,
} = self; } = self;
f.debug_struct("Insns") f.debug_struct("Insns")
.field("state_layout", state_layout) .field("state_layout", state_layout)
.field( .field(
"insns", "insns",
&InsnsDebug { &InsnsDebug::<BK> {
insns, insns,
insn_source_locations, insn_source_locations,
labels,
state_layout,
}, },
) )
.finish_non_exhaustive() .finish_non_exhaustive()
@ -418,6 +581,10 @@ pub(crate) trait StatePartKind:
type BorrowedState<'a>: 'a; type BorrowedState<'a>: 'a;
fn new_state(len: StatePartLen<Self>) -> Self::State; fn new_state(len: StatePartLen<Self>) -> Self::State;
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a>; fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a>;
fn part_debug_data<BK: InsnsBuildingKind>(
state_layout: &StateLayout<BK>,
part_index: StatePartIndex<Self>,
) -> Option<&Self::DebugData>;
} }
pub(crate) trait StatePartsValue { pub(crate) trait StatePartsValue {
@ -980,6 +1147,12 @@ make_state_part_kinds! {
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
state.borrow() state.borrow()
} }
fn part_debug_data<BK: InsnsBuildingKind>(
state_layout: &StateLayout<BK>,
part_index: StatePartIndex<Self>,
) -> Option<&Self::DebugData> {
state_layout.small_stack.debug_data.get(part_index.as_usize())
}
} }
#[state, field = big_stack] #[state, field = big_stack]
impl StatePartKind for StatePartKindBigStack { impl StatePartKind for StatePartKindBigStack {
@ -993,6 +1166,12 @@ make_state_part_kinds! {
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
state.borrow() state.borrow()
} }
fn part_debug_data<BK: InsnsBuildingKind>(
state_layout: &StateLayout<BK>,
part_index: StatePartIndex<Self>,
) -> Option<&Self::DebugData> {
state_layout.big_stack.debug_data.get(part_index.as_usize())
}
}*/ }*/
#[type, field = small_slots] #[type, field = small_slots]
impl StatePartKind for StatePartKindSmallSlots { impl StatePartKind for StatePartKindSmallSlots {
@ -1006,6 +1185,12 @@ make_state_part_kinds! {
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
state state
} }
fn part_debug_data<BK: InsnsBuildingKind>(
state_layout: &StateLayout<BK>,
part_index: StatePartIndex<Self>,
) -> Option<&Self::DebugData> {
state_layout.ty.small_slots.debug_data.get(part_index.as_usize())
}
} }
#[type, field = big_slots] #[type, field = big_slots]
impl StatePartKind for StatePartKindBigSlots { impl StatePartKind for StatePartKindBigSlots {
@ -1019,6 +1204,12 @@ make_state_part_kinds! {
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> { fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
state state
} }
fn part_debug_data<BK: InsnsBuildingKind>(
state_layout: &StateLayout<BK>,
part_index: StatePartIndex<Self>,
) -> Option<&Self::DebugData> {
state_layout.ty.big_slots.debug_data.get(part_index.as_usize())
}
} }
} }
@ -1163,12 +1354,57 @@ pub(crate) struct StatePartArrayIndex<K: StatePartKind> {
pub(crate) stride: StatePartLen<K>, pub(crate) stride: StatePartLen<K>,
} }
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) struct StatePartArrayIndexed<K: StatePartKind> { pub(crate) struct StatePartArrayIndexed<K: StatePartKind> {
pub(crate) base: StatePartIndex<K>, pub(crate) base: StatePartIndex<K>,
pub(crate) indexes: Interned<[StatePartArrayIndex<K>]>, pub(crate) indexes: Interned<[StatePartArrayIndex<K>]>,
} }
impl<K: StatePartKind> StatePartArrayIndexed<K> {
pub(crate) fn debug_fmt<BK: InsnsBuildingKind>(
&self,
f: &mut fmt::Formatter<'_>,
before_debug_info_text: &str,
comment_start: &str,
comment_end: &str,
state_layout: Option<&StateLayout<BK>>,
) -> fmt::Result {
if let Some(state_layout) = state_layout {
let Self { base, indexes } = *self;
if indexes.is_empty() {
base.debug_fmt(
f,
before_debug_info_text,
comment_start,
comment_end,
Some(state_layout),
)
} else {
base.debug_fmt(f, "", " /* ", " */ ", Some(state_layout))?;
for StatePartArrayIndex { index, len, stride } in indexes {
f.write_str("[")?;
index.debug_fmt(f, "", " /* ", " */ ", Some(state_layout))?;
write!(f, ", len={len}, stride={}]", stride.value)?;
}
f.write_str(before_debug_info_text)
}
} else {
let Self { base, indexes } = self;
f.debug_struct("StatePartArrayIndexed")
.field("base", base)
.field("indexes", indexes)
.finish()?;
f.write_str(before_debug_info_text)
}
}
}
impl<K: StatePartKind + fmt::Debug> fmt::Debug for StatePartArrayIndexed<K> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.debug_fmt::<InsnsBuildingDone>(f, "", "", "", None)
}
}
impl<K: StatePartKind> From<StatePartIndex<K>> for StatePartArrayIndexed<K> { impl<K: StatePartKind> From<StatePartIndex<K>> for StatePartArrayIndexed<K> {
fn from(base: StatePartIndex<K>) -> Self { fn from(base: StatePartIndex<K>) -> Self {
Self { Self {
@ -1226,11 +1462,28 @@ impl<K: StatePartKind> StatePartIndex<K> {
_phantom: PhantomData, _phantom: PhantomData,
} }
} }
pub(crate) fn debug_fmt<BK: InsnsBuildingKind>(
&self,
f: &mut fmt::Formatter<'_>,
before_debug_info_text: &str,
comment_start: &str,
comment_end: &str,
state_layout: Option<&StateLayout<BK>>,
) -> fmt::Result {
write!(f, "StatePartIndex<{}>({})", K::NAME, self.value)?;
f.write_str(before_debug_info_text)?;
if let Some(state_layout) = state_layout {
if let Some(debug_data) = K::part_debug_data(state_layout, *self) {
write!(f, "{comment_start}{debug_data:?}{comment_end}")?;
}
}
Ok(())
}
} }
impl<K: StatePartKind> fmt::Debug for StatePartIndex<K> { impl<K: StatePartKind> fmt::Debug for StatePartIndex<K> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "StatePartIndex<{}>({})", K::NAME, self.value) self.debug_fmt::<InsnsBuildingDone>(f, "", "", "", None)
} }
} }
@ -1641,6 +1894,7 @@ impl Insns<InsnsBuilding> {
Self { Self {
insns: Vec::new(), insns: Vec::new(),
insn_source_locations: Vec::new(), insn_source_locations: Vec::new(),
labels: Labels::default(),
state_layout: StateLayout::empty(), state_layout: StateLayout::empty(),
} }
} }
@ -1663,18 +1917,62 @@ impl Insns<InsnsBuilding> {
) -> TypeIndexRange { ) -> TypeIndexRange {
self.state_layout.ty.allocate(layout) self.state_layout.ty.allocate(layout)
} }
pub(crate) fn new_label(&mut self) -> usize {
let retval = self.labels.labels.len();
self.labels.labels.push(Label { address: None });
retval
}
#[track_caller]
pub(crate) fn define_label_at_next_insn(&mut self, label_index: usize) {
let address = self.next_insn_pc();
let label = &mut self.labels.labels[label_index];
assert!(label.address.is_none(), "label already defined");
label.address = Some(address);
self.labels
.address_to_label_indexes_map
.entry(address)
.or_default()
.push(label_index);
}
} }
impl From<Insns<InsnsBuilding>> for Insns<InsnsBuildingDone> { impl From<Insns<InsnsBuilding>> for Insns<InsnsBuildingDone> {
fn from(input: Insns<InsnsBuilding>) -> Self { fn from(input: Insns<InsnsBuilding>) -> Self {
let Insns { let Insns {
insns, mut insns,
insn_source_locations, insn_source_locations,
labels,
state_layout, state_layout,
} = input; } = input;
for insn in &mut insns {
for field in insn.fields_mut() {
match field.kind {
InsnFieldKind::BranchTarget => match field.ty {
InsnFieldType::USize(value) => {
*value = labels.labels[*value]
.address
.expect("label address not set");
}
InsnFieldType::SmallSlot(_)
| InsnFieldType::BigSlot(_)
| InsnFieldType::SmallSlotArrayIndexed(_)
| InsnFieldType::BigSlotArrayIndexed(_)
| InsnFieldType::SmallUInt(_)
| InsnFieldType::SmallSInt(_)
| InsnFieldType::InternedBigInt(_)
| InsnFieldType::U8(_)
| InsnFieldType::Empty(_) => {
unreachable!()
}
},
InsnFieldKind::Input | InsnFieldKind::Output | InsnFieldKind::Immediate => {}
}
}
}
Insns { Insns {
insns: Intern::intern_owned(insns), insns: Intern::intern_owned(insns),
insn_source_locations: Intern::intern_owned(insn_source_locations), insn_source_locations: Intern::intern_owned(insn_source_locations),
labels: (),
state_layout: state_layout.into(), state_layout: state_layout.into(),
} }
} }
@ -2182,6 +2480,60 @@ impl_insns! {
state.big_slots[dest].clone_from(&value); state.big_slots[dest].clone_from(&value);
next!(); next!();
} }
Branch {
#[kind = BranchTarget]
target: usize,
} => {
branch!(target);
}
BranchIfZero {
#[kind = BranchTarget]
target: usize,
#[kind = Input]
value: StatePartIndex<StatePartKindBigSlots>,
} => {
if state.big_slots[value].is_zero() {
branch!(target);
} else {
next!();
}
}
BranchIfNonZero {
#[kind = BranchTarget]
target: usize,
#[kind = Input]
value: StatePartIndex<StatePartKindBigSlots>,
} => {
if state.big_slots[value].is_zero() {
next!();
} else {
branch!(target);
}
}
BranchIfSmallZero {
#[kind = BranchTarget]
target: usize,
#[kind = Input]
value: StatePartIndex<StatePartKindSmallSlots>,
} => {
if state.small_slots[value] == 0 {
branch!(target);
} else {
next!();
}
}
BranchIfSmallNonZero {
#[kind = BranchTarget]
target: usize,
#[kind = Input]
value: StatePartIndex<StatePartKindSmallSlots>,
} => {
if state.small_slots[value] == 0 {
next!();
} else {
branch!(target);
}
}
Return => { Return => {
break; break;
} }

View file

@ -0,0 +1,524 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use fayalite::{prelude::*, sim::Simulation};
#[hdl_module(outline_generated)]
pub fn connect_const() {
#[hdl]
let o: UInt<8> = m.output();
connect(o, 5u8);
}
#[test]
fn test_connect_const() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(connect_const());
sim.settle_step();
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug
!= r#"Simulation {
state: State {
insns: Insns {
state_layout: StateLayout {
ty: TypeLayout {
small_slots: StatePartAllocationLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartAllocationLayout<BigSlots> {
len: 2,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(connect_const: connect_const).connect_const::o",
ty: UInt<8>,
},
SlotDebugData {
name: "",
ty: UInt<8>,
},
],
..
},
},
},
insns: [
// at: module-XXXXXXXXXX.rs:1:1
Const {
dest: StatePartIndex<BigSlots>(1), // SlotDebugData { name: "", ty: UInt<8> },
value: 5,
},
// at: module-XXXXXXXXXX.rs:3:1
Copy {
dest: StatePartIndex<BigSlots>(0), // SlotDebugData { name: "InstantiatedModule(connect_const: connect_const).connect_const::o", ty: UInt<8> },
src: StatePartIndex<BigSlots>(1), // SlotDebugData { name: "", ty: UInt<8> },
},
// at: module-XXXXXXXXXX.rs:1:1
Return,
],
..
},
pc: 2,
small_slots: StatePart {
value: [],
},
big_slots: StatePart {
value: [
5,
5,
],
},
},
base_module: CompiledModule {
module_io: [
CompiledValue {
layout: CompiledTypeLayout {
ty: UInt<8>,
layout: TypeLayout {
small_slots: StatePartAllocationLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartAllocationLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(connect_const: connect_const).connect_const::o",
ty: UInt<8>,
},
],
..
},
},
body: Scalar,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 1 },
},
write: None,
},
],
},
base_module_io_ty: connect_const {
o: UInt<8>,
},
}"# {
panic!();
}
}
#[hdl_module(outline_generated)]
pub fn mod1_child() {
#[hdl]
let i: UInt<4> = m.input();
#[hdl]
let o: SInt<2> = m.output();
#[hdl]
let i2: SInt<2> = m.input();
#[hdl]
let o2: UInt<4> = m.output();
connect(o, i.cast_to_static());
connect(o2, i2.cast_to_static());
#[hdl]
if i.cmp_gt(5_hdl_u4) {
connect(o2, 0xF_hdl_u4);
}
}
#[hdl_module(outline_generated)]
pub fn mod1() {
#[hdl]
let child = instance(mod1_child());
#[hdl]
let o: mod1_child = m.output(Expr::ty(child));
connect(o, child);
}
#[test]
fn test_mod1() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(mod1());
sim.settle_step();
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
if sim_debug
!= r#"Simulation {
state: State {
insns: Insns {
state_layout: StateLayout {
ty: TypeLayout {
small_slots: StatePartAllocationLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartAllocationLayout<BigSlots> {
len: 17,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(mod1: mod1).mod1::o.i",
ty: UInt<4>,
},
SlotDebugData {
name: "InstantiatedModule(mod1: mod1).mod1::o.o",
ty: SInt<2>,
},
SlotDebugData {
name: "InstantiatedModule(mod1: mod1).mod1::o.i2",
ty: SInt<2>,
},
SlotDebugData {
name: "InstantiatedModule(mod1: mod1).mod1::o.o2",
ty: UInt<4>,
},
SlotDebugData {
name: "InstantiatedModule(mod1: mod1).mod1::child.i",
ty: UInt<4>,
},
SlotDebugData {
name: "InstantiatedModule(mod1: mod1).mod1::child.o",
ty: SInt<2>,
},
SlotDebugData {
name: "InstantiatedModule(mod1: mod1).mod1::child.i2",
ty: SInt<2>,
},
SlotDebugData {
name: "InstantiatedModule(mod1: mod1).mod1::child.o2",
ty: UInt<4>,
},
SlotDebugData {
name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i",
ty: UInt<4>,
},
SlotDebugData {
name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o",
ty: SInt<2>,
},
SlotDebugData {
name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i2",
ty: SInt<2>,
},
SlotDebugData {
name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o2",
ty: UInt<4>,
},
SlotDebugData {
name: "",
ty: SInt<2>,
},
SlotDebugData {
name: "",
ty: UInt<4>,
},
SlotDebugData {
name: "",
ty: UInt<4>,
},
SlotDebugData {
name: "",
ty: Bool,
},
SlotDebugData {
name: "",
ty: UInt<4>,
},
],
..
},
},
},
insns: [
// at: module-XXXXXXXXXX.rs:4:1
Copy {
dest: StatePartIndex<BigSlots>(6), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.i2", ty: SInt<2> },
src: StatePartIndex<BigSlots>(2), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::o.i2", ty: SInt<2> },
},
Copy {
dest: StatePartIndex<BigSlots>(4), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.i", ty: UInt<4> },
src: StatePartIndex<BigSlots>(0), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::o.i", ty: UInt<4> },
},
// at: module-XXXXXXXXXX.rs:2:1
Copy {
dest: StatePartIndex<BigSlots>(10), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i2", ty: SInt<2> },
src: StatePartIndex<BigSlots>(6), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.i2", ty: SInt<2> },
},
Copy {
dest: StatePartIndex<BigSlots>(8), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i", ty: UInt<4> },
src: StatePartIndex<BigSlots>(4), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.i", ty: UInt<4> },
},
// at: module-XXXXXXXXXX-2.rs:1:1
Const {
dest: StatePartIndex<BigSlots>(16), // SlotDebugData { name: "", ty: UInt<4> },
value: 15,
},
Const {
dest: StatePartIndex<BigSlots>(14), // SlotDebugData { name: "", ty: UInt<4> },
value: 5,
},
CmpLt {
dest: StatePartIndex<BigSlots>(15), // SlotDebugData { name: "", ty: Bool },
lhs: StatePartIndex<BigSlots>(14), // SlotDebugData { name: "", ty: UInt<4> },
rhs: StatePartIndex<BigSlots>(8), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i", ty: UInt<4> },
},
CastToUInt {
dest: StatePartIndex<BigSlots>(13), // SlotDebugData { name: "", ty: UInt<4> },
src: StatePartIndex<BigSlots>(10), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i2", ty: SInt<2> },
dest_width: 4,
},
// at: module-XXXXXXXXXX-2.rs:7:1
Copy {
dest: StatePartIndex<BigSlots>(11), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o2", ty: UInt<4> },
src: StatePartIndex<BigSlots>(13), // SlotDebugData { name: "", ty: UInt<4> },
},
// at: module-XXXXXXXXXX-2.rs:8:1
BranchIfZero {
target: 11,
value: StatePartIndex<BigSlots>(15), // SlotDebugData { name: "", ty: Bool },
},
// at: module-XXXXXXXXXX-2.rs:9:1
Copy {
dest: StatePartIndex<BigSlots>(11), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o2", ty: UInt<4> },
src: StatePartIndex<BigSlots>(16), // SlotDebugData { name: "", ty: UInt<4> },
},
// at: module-XXXXXXXXXX.rs:2:1
Copy {
dest: StatePartIndex<BigSlots>(7), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.o2", ty: UInt<4> },
src: StatePartIndex<BigSlots>(11), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o2", ty: UInt<4> },
},
// at: module-XXXXXXXXXX.rs:4:1
Copy {
dest: StatePartIndex<BigSlots>(3), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::o.o2", ty: UInt<4> },
src: StatePartIndex<BigSlots>(7), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.o2", ty: UInt<4> },
},
// at: module-XXXXXXXXXX-2.rs:1:1
CastToSInt {
dest: StatePartIndex<BigSlots>(12), // SlotDebugData { name: "", ty: SInt<2> },
src: StatePartIndex<BigSlots>(8), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::i", ty: UInt<4> },
dest_width: 2,
},
// at: module-XXXXXXXXXX-2.rs:6:1
Copy {
dest: StatePartIndex<BigSlots>(9), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o", ty: SInt<2> },
src: StatePartIndex<BigSlots>(12), // SlotDebugData { name: "", ty: SInt<2> },
},
// at: module-XXXXXXXXXX.rs:2:1
Copy {
dest: StatePartIndex<BigSlots>(5), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.o", ty: SInt<2> },
src: StatePartIndex<BigSlots>(9), // SlotDebugData { name: "InstantiatedModule(mod1.child: mod1_child).mod1_child::o", ty: SInt<2> },
},
// at: module-XXXXXXXXXX.rs:4:1
Copy {
dest: StatePartIndex<BigSlots>(1), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::o.o", ty: SInt<2> },
src: StatePartIndex<BigSlots>(5), // SlotDebugData { name: "InstantiatedModule(mod1: mod1).mod1::child.o", ty: SInt<2> },
},
// at: module-XXXXXXXXXX.rs:1:1
Return,
],
..
},
pc: 17,
small_slots: StatePart {
value: [],
},
big_slots: StatePart {
value: [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
5,
0,
15,
],
},
},
base_module: CompiledModule {
module_io: [
CompiledValue {
layout: CompiledTypeLayout {
ty: Bundle {
#[hdl(flip)] /* offset = 0 */
i: UInt<4>,
/* offset = 4 */
o: SInt<2>,
#[hdl(flip)] /* offset = 6 */
i2: SInt<2>,
/* offset = 8 */
o2: UInt<4>,
},
layout: TypeLayout {
small_slots: StatePartAllocationLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartAllocationLayout<BigSlots> {
len: 4,
debug_data: [
SlotDebugData {
name: "InstantiatedModule(mod1: mod1).mod1::o.i",
ty: UInt<4>,
},
SlotDebugData {
name: "InstantiatedModule(mod1: mod1).mod1::o.o",
ty: SInt<2>,
},
SlotDebugData {
name: "InstantiatedModule(mod1: mod1).mod1::o.i2",
ty: SInt<2>,
},
SlotDebugData {
name: "InstantiatedModule(mod1: mod1).mod1::o.o2",
ty: UInt<4>,
},
],
..
},
},
body: Bundle {
fields: [
CompiledBundleField {
offset: TypeIndex {
small_slots: StatePartIndex<SmallSlots>(0),
big_slots: StatePartIndex<BigSlots>(0),
},
ty: CompiledTypeLayout {
ty: UInt<4>,
layout: TypeLayout {
small_slots: StatePartAllocationLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartAllocationLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: UInt<4>,
},
],
..
},
},
body: Scalar,
},
},
CompiledBundleField {
offset: TypeIndex {
small_slots: StatePartIndex<SmallSlots>(0),
big_slots: StatePartIndex<BigSlots>(1),
},
ty: CompiledTypeLayout {
ty: SInt<2>,
layout: TypeLayout {
small_slots: StatePartAllocationLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartAllocationLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: SInt<2>,
},
],
..
},
},
body: Scalar,
},
},
CompiledBundleField {
offset: TypeIndex {
small_slots: StatePartIndex<SmallSlots>(0),
big_slots: StatePartIndex<BigSlots>(2),
},
ty: CompiledTypeLayout {
ty: SInt<2>,
layout: TypeLayout {
small_slots: StatePartAllocationLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartAllocationLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: SInt<2>,
},
],
..
},
},
body: Scalar,
},
},
CompiledBundleField {
offset: TypeIndex {
small_slots: StatePartIndex<SmallSlots>(0),
big_slots: StatePartIndex<BigSlots>(3),
},
ty: CompiledTypeLayout {
ty: UInt<4>,
layout: TypeLayout {
small_slots: StatePartAllocationLayout<SmallSlots> {
len: 0,
debug_data: [],
..
},
big_slots: StatePartAllocationLayout<BigSlots> {
len: 1,
debug_data: [
SlotDebugData {
name: "",
ty: UInt<4>,
},
],
..
},
},
body: Scalar,
},
},
],
},
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 0, len: 4 },
},
write: None,
},
],
},
base_module_io_ty: mod1 {
o: mod1_child {
i: UInt<4>,
o: SInt<2>,
i2: SInt<2>,
o2: UInt<4>,
},
},
}"# {
panic!();
}
}