Simulation::settle_step() works for simple modules
All checks were successful
/ deps (push) Successful in 18s
/ test (push) Successful in 4m49s

This commit is contained in:
Jacob Lifshay 2024-11-13 21:20:15 -08:00
parent d7d8e2e7ce
commit 2e9d5c1835
Signed by: programmerjake
SSH key fingerprint: SHA256:B1iRVvUJkvd7upMIiMqn6OyxvD2SgJkAH3ZnUOj6z+c
3 changed files with 1221 additions and 166 deletions

View file

@ -40,13 +40,13 @@ mod interpreter;
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
enum CondBody {
IfTrue {
cond: CompiledExpr<Bool>,
cond: CompiledValue<Bool>,
},
IfFalse {
cond: CompiledExpr<Bool>,
cond: CompiledValue<Bool>,
},
MatchArm {
enum_expr: CompiledExpr<Enum>,
enum_expr: CompiledValue<Enum>,
variant_index: usize,
},
}
@ -267,8 +267,8 @@ impl<T: Type> CompiledValue<T> {
}
impl CompiledValue<Enum> {
fn add_discriminant_to_set(self, offset: TypeIndex, inputs: &mut SlotSet) {
inputs.extend([self.range.offset(offset)]);
fn add_discriminant_to_set(self, inputs: &mut SlotSet) {
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> {
fn field_by_index(self, field_index: usize) -> CompiledExpr<CanonicalType> {
CompiledExpr {
@ -446,48 +433,118 @@ enum AssignmentIO {
},
}
#[derive(Debug, Default)]
struct Assignments {
assignments: Vec<Assignment>,
slot_readers: Option<SlotToAssignmentIndexFullMap>,
slot_writers: Option<SlotToAssignmentIndexFullMap>,
#[derive(Debug)]
enum Assignments {
Accumulating {
assignments: Vec<Assignment>,
},
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 {
fn finalize(&mut self, slots_len: TypeLen) {
assert!(
self.slot_readers.is_none() && self.slot_writers.is_none(),
"already finalized"
);
let Self::Accumulating { assignments } = self else {
unreachable!("already finalized");
};
let assignments = mem::take(assignments).into_boxed_slice();
let mut slot_readers = 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
.keys_for_assignment(assignment_index)
.extend([&assignment.inputs]);
slot_writers
.keys_for_assignment(assignment_index)
.extend([&assignment.outputs]);
let SlotSet(TypeParts {
small_slots,
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.slot_writers = Some(slot_writers);
*self = Self::Finalized {
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) {
assert!(
self.slot_readers.is_none() && self.slot_writers.is_none(),
"already finalized"
);
self.assignments.push(v);
let Self::Accumulating { assignments } = self else {
unreachable!("already finalized");
};
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 {
self.slot_readers
.as_ref()
.expect("Assignments::finalize should have been called")
let Self::Finalized { slot_readers, .. } = self else {
unreachable!("Assignments::finalize should have been called");
};
slot_readers
}
fn slot_writers(&self) -> &SlotToAssignmentIndexFullMap {
self.slot_writers
.as_ref()
.expect("Assignments::finalize should have been called")
let Self::Finalized { slot_writers, .. } = self else {
unreachable!("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,
} = self.slot_readers().len();
AssignmentsNodeIdentifiers {
assignment_indexes: 0..self.assignments.len(),
assignment_indexes: 0..self.assignments().len(),
small_slots: 0..small_slots.value,
big_slots: 0..big_slots.value,
}
}
}
enum AssignmentsNeighborsDirected<'a> {
AssignmentIndexes(std::slice::Iter<'a, usize>),
Slots {
small_slots: std::collections::btree_set::Iter<'a, StatePartIndex<StatePartKindSmallSlots>>,
big_slots: std::collections::btree_set::Iter<'a, StatePartIndex<StatePartKindBigSlots>>,
},
struct AssignmentsNeighborsDirected<'a> {
assignment_indexes: std::slice::Iter<'a, usize>,
small_slots: std::collections::btree_set::Iter<'a, StatePartIndex<StatePartKindSmallSlots>>,
big_slots: std::collections::btree_set::Iter<'a, StatePartIndex<StatePartKindBigSlots>>,
}
impl Iterator for AssignmentsNeighborsDirected<'_> {
type Item = AssignmentOrSlotIndex;
fn next(&mut self) -> Option<Self::Item> {
match self {
AssignmentsNeighborsDirected::AssignmentIndexes(iter) => iter
.next()
.copied()
.map(AssignmentOrSlotIndex::AssignmentIndex),
AssignmentsNeighborsDirected::Slots {
small_slots,
big_slots,
} => small_slots
.next()
.copied()
.map(AssignmentOrSlotIndex::SmallSlots)
.or_else(|| {
big_slots
.next()
.copied()
.map(AssignmentOrSlotIndex::BigSlots)
}),
let Self {
assignment_indexes,
small_slots,
big_slots,
} = self;
if let retval @ Some(_) = assignment_indexes
.next()
.copied()
.map(AssignmentOrSlotIndex::AssignmentIndex)
{
retval
} else if let retval @ Some(_) = small_slots
.next()
.copied()
.map(AssignmentOrSlotIndex::SmallSlots)
{
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 {
AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => {
let assignment = &self.assignments[assignment_index];
let SlotSet(TypeParts {
small_slots,
big_slots,
}) = match d {
Outgoing => &assignment.outputs,
Incoming => &assignment.inputs,
let assignment = &self.assignments()[assignment_index];
let (
assignment_indexes,
SlotSet(TypeParts {
small_slots,
big_slots,
}),
) = 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(),
big_slots: big_slots.iter(),
}
}
AssignmentOrSlotIndex::SmallSlots(slot) => {
AssignmentsNeighborsDirected::AssignmentIndexes(slot_map[slot].iter())
}
AssignmentOrSlotIndex::BigSlots(slot) => {
AssignmentsNeighborsDirected::AssignmentIndexes(slot_map[slot].iter())
}
AssignmentOrSlotIndex::SmallSlots(slot) => AssignmentsNeighborsDirected {
assignment_indexes: slot_map[slot].iter(),
small_slots: Default::default(),
big_slots: Default::default(),
},
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 {
AssignmentsVisitMap {
assignments: vec![false; self.assignments.len()],
assignments: vec![false; self.assignments().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) {
let AssignmentsVisitMap { assignments, slots } = map;
assignments.clear();
assignments.resize(self.assignments.len(), false);
assignments.resize(self.assignments().len(), false);
if slots.len() != self.slot_readers().len() {
*slots = DenseSlotSet::new(self.slot_readers().len());
} else {
@ -898,12 +974,12 @@ impl Extend<CondBody> for SlotSet {
fn extend<T: IntoIterator<Item = CondBody>>(&mut self, iter: T) {
iter.into_iter().for_each(|cond_body| match cond_body {
CondBody::IfTrue { cond } | CondBody::IfFalse { cond } => {
cond.add_target_and_indexes_to_set(self);
self.extend([cond.range]);
}
CondBody::MatchArm {
enum_expr,
variant_index,
} => enum_expr.add_discriminant_and_indexes_to_set(self),
variant_index: _,
} => enum_expr.add_discriminant_to_set(self),
})
}
}
@ -936,11 +1012,10 @@ impl SlotToAssignmentIndexFullMap {
small_slots,
big_slots,
} = len;
const VEC_NEW: Vec<usize> = Vec::new();
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(),
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(),
})
}
@ -1237,54 +1312,51 @@ impl Compiler {
static_part,
indexes,
} = expr;
let layout = static_part.layout.with_anonymized_debug_info();
let retval = CompiledValue {
layout,
range: self.insns.allocate_variable(&layout.layout),
write: None,
let retval = if indexes.as_ref().is_empty() {
CompiledValue {
layout: static_part.layout,
range: static_part.range,
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);
retval
}
@ -2456,9 +2528,9 @@ impl Compiler {
source_location,
blocks: [then_block, else_block],
}) => {
let cond = self
.compile_expr(*parent_module, Expr::canonical(cond))
.map_ty(Bool::from_canonical);
let cond = self.compile_expr(*parent_module, Expr::canonical(cond));
let cond = self.compiled_expr_to_value(cond, source_location);
let cond = cond.map_ty(Bool::from_canonical);
self.compile_block(
parent_module,
then_block,
@ -2481,9 +2553,9 @@ impl Compiler {
source_location,
blocks,
}) => {
let enum_expr = self
.compile_expr(*parent_module, Expr::canonical(expr))
.map_ty(Enum::from_canonical);
let enum_expr = self.compile_expr(*parent_module, Expr::canonical(expr));
let enum_expr = self.compiled_expr_to_value(enum_expr, source_location);
let enum_expr = enum_expr.map_ty(Enum::from_canonical);
for (variant_index, block) in blocks.into_iter().enumerate() {
self.compile_block(
parent_module,
@ -2514,10 +2586,12 @@ impl Compiler {
annotations: _,
module_io,
}| {
self.compile_value(TargetInInstantiatedModule {
let target = TargetInInstantiatedModule {
instantiated_module: *module,
target: Target::from(module_io),
})
};
self.decl_conditions.insert(target, Interned::default());
self.compile_value(target)
},
)
.collect();
@ -2537,8 +2611,7 @@ impl Compiler {
fn process_assignments(&mut self) {
self.assignments
.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
.into_iter()
.filter_map(|n| match n {
@ -2549,7 +2622,7 @@ impl Compiler {
Err(e) => match e.node_id() {
AssignmentOrSlotIndex::AssignmentIndex(assignment_index) => panic!(
"combinatorial logic cycle detected at: {}",
self.assignments.assignments[assignment_index].source_location,
self.assignments.assignments()[assignment_index].source_location,
),
AssignmentOrSlotIndex::SmallSlots(slot) => panic!(
"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> {
let base_module =
*self.compile_module(InstantiatedModule::Base(self.base_module).intern_sized());
self.process_assignments();
self.insns
.push(Insn::Return, self.base_module.source_location());
Compiled {
insns: Insns::from(self.insns).intern_sized(),
base_module,
@ -2588,7 +2762,7 @@ pub struct Compiled<T: BundleType> {
}
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())
}
pub fn canonical(self) -> Compiled<Bundle> {
@ -2620,14 +2794,19 @@ impl<T: BundleType> Compiled<T> {
#[derive(Debug)]
pub struct Simulation<T: BundleType> {
state: interpreter::State,
compiled: Compiled<T>,
base_module: CompiledModule,
base_module_io_ty: 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 {
Self {
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) {

View file

@ -7,6 +7,7 @@ use crate::{
ty::CanonicalType,
util::get_many_mut,
};
use hashbrown::HashMap;
use num_bigint::BigInt;
use num_traits::{One, Signed, ToPrimitive, Zero};
use std::{
@ -166,6 +167,83 @@ fn make_array_into_iter<T, const I: usize, const N: usize>(
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 {
(
#[insn = $Insn:ident, next_macro = $next_macro:ident, branch_macro = $branch_macro:ident]
@ -191,7 +269,7 @@ macro_rules! impl_insns {
})? => $block:block
)*
) => {
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
$vis enum $Insn {
$(
$(#[$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 }> {
match self {
$(
@ -339,6 +439,8 @@ pub(crate) trait InsnsBuildingKind: Copy + Eq + fmt::Debug + Hash + Default {
+ Default
+ Deref<Target = [T]>
+ FromIterator<T>;
type Labels: Default;
fn labels(labels: &Self::Labels) -> Option<&Labels>;
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
@ -346,6 +448,10 @@ pub(crate) struct InsnsBuildingDone;
impl InsnsBuildingKind for InsnsBuildingDone {
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)]
@ -353,12 +459,27 @@ pub(crate) struct InsnsBuilding;
impl InsnsBuildingKind for InsnsBuilding {
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)]
pub(crate) struct Insns<BK: InsnsBuildingKind> {
insns: BK::Vec<Insn>,
insn_source_locations: BK::Vec<SourceLocation>,
labels: BK::Labels,
state_layout: StateLayout<BK>,
}
@ -368,21 +489,60 @@ impl<BK: InsnsBuildingKind> Insns<BK> {
}
}
struct InsnsDebug<'a> {
struct InsnsDebug<'a, BK: InsnsBuildingKind> {
insns: &'a [Insn],
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 {
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 last_source_location = None;
for (insn, source_location) in self.insns.iter().zip(self.insn_source_locations) {
if Some(source_location) != last_source_location {
debug_list.entry(&format_args!("// at: {source_location}\n{insn:?}"));
} else {
debug_list.entry(insn);
}
for (address, (insn, &source_location)) in self
.insns
.iter()
.zip(self.insn_source_locations)
.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);
}
debug_list.finish()
@ -394,15 +554,18 @@ impl<BK: InsnsBuildingKind> fmt::Debug for Insns<BK> {
let Self {
insns,
insn_source_locations,
labels,
state_layout,
} = self;
f.debug_struct("Insns")
.field("state_layout", state_layout)
.field(
"insns",
&InsnsDebug {
&InsnsDebug::<BK> {
insns,
insn_source_locations,
labels,
state_layout,
},
)
.finish_non_exhaustive()
@ -418,6 +581,10 @@ pub(crate) trait StatePartKind:
type BorrowedState<'a>: 'a;
fn new_state(len: StatePartLen<Self>) -> Self::State;
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 {
@ -980,6 +1147,12 @@ make_state_part_kinds! {
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
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]
impl StatePartKind for StatePartKindBigStack {
@ -993,6 +1166,12 @@ make_state_part_kinds! {
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
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]
impl StatePartKind for StatePartKindSmallSlots {
@ -1006,6 +1185,12 @@ make_state_part_kinds! {
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
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]
impl StatePartKind for StatePartKindBigSlots {
@ -1019,6 +1204,12 @@ make_state_part_kinds! {
fn borrow_state<'a>(state: &'a mut Self::State) -> Self::BorrowedState<'a> {
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>,
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub(crate) struct StatePartArrayIndexed<K: StatePartKind> {
pub(crate) base: StatePartIndex<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> {
fn from(base: StatePartIndex<K>) -> Self {
Self {
@ -1226,11 +1462,28 @@ impl<K: StatePartKind> StatePartIndex<K> {
_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> {
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 {
insns: Vec::new(),
insn_source_locations: Vec::new(),
labels: Labels::default(),
state_layout: StateLayout::empty(),
}
}
@ -1663,18 +1917,62 @@ impl Insns<InsnsBuilding> {
) -> TypeIndexRange {
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> {
fn from(input: Insns<InsnsBuilding>) -> Self {
let Insns {
insns,
mut insns,
insn_source_locations,
labels,
state_layout,
} = 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: Intern::intern_owned(insns),
insn_source_locations: Intern::intern_owned(insn_source_locations),
labels: (),
state_layout: state_layout.into(),
}
}
@ -2182,6 +2480,60 @@ impl_insns! {
state.big_slots[dest].clone_from(&value);
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 => {
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!();
}
}