Simulation::settle_step() works for simple modules
This commit is contained in:
parent
a6e40839ac
commit
f54e55a143
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
524
crates/fayalite/tests/sim.rs
Normal file
524
crates/fayalite/tests/sim.rs
Normal 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!();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue