simple combinatorial simulation works!
All checks were successful
/ deps (push) Successful in 21s
/ test (push) Successful in 4m49s

This commit is contained in:
Jacob Lifshay 2024-11-14 20:28:43 -08:00
parent 2e9d5c1835
commit 414a2d74f1
Signed by: programmerjake
SSH key fingerprint: SHA256:B1iRVvUJkvd7upMIiMqn6OyxvD2SgJkAH3ZnUOj6z+c
6 changed files with 831 additions and 251 deletions

View file

@ -227,12 +227,29 @@ macro_rules! impl_int {
impl<Width: Size> BoolOrIntType for $name<Width> {
type Width = Width;
type Signed = ConstBool<$SIGNED>;
type Value = $value<Width>;
fn width(self) -> usize {
$name::width(self)
}
fn new(width: Width::SizeType) -> Self {
$name { width }
}
fn value_from_bigint_wrapping(self, v: BigInt) -> Self::Value {
$value::<Width>::from_bigint_wrapping(self, v)
}
fn bits_to_value(bits: Cow<'_, BitSlice>) -> Self::Value {
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
struct MemoizeBitsToValue;
impl Memoize for MemoizeBitsToValue {
type Input = BitSlice;
type InputOwned = BitVec;
type Output = Arc<BitVec>;
fn inner(self, input: &Self::Input) -> Self::Output {
Arc::new(input.to_bitvec())
}
}
$value::new(MemoizeBitsToValue.get_cow(bits))
}
fn bits_to_expr(bits: Cow<'_, BitSlice>) -> Expr<Self> {
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
struct MemoizeBitsToExpr;
@ -334,6 +351,24 @@ macro_rules! impl_int {
}
}
impl<Width: Size> PartialOrd for $value<Width> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<Width: Size> Ord for $value<Width> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.to_bigint().cmp(&other.to_bigint())
}
}
impl<Width: Size> From<$value<Width>> for BigInt {
fn from(v: $value<Width>) -> BigInt {
v.to_bigint()
}
}
impl<Width: Size> $value<Width> {
pub fn width(&self) -> usize {
if let Some(retval) = Width::KNOWN_VALUE {
@ -482,6 +517,19 @@ macro_rules! impl_prim_int {
$(#[$meta:meta])*
$prim_int:ident, $ty:ty
) => {
impl From<$prim_int> for <$ty as BoolOrIntType>::Value {
fn from(v: $prim_int) -> Self {
<$ty>::le_bytes_to_value_wrapping(
&v.to_le_bytes(),
<$ty as BoolOrIntType>::Width::VALUE,
)
}
}
impl From<NonZero<$prim_int>> for <$ty as BoolOrIntType>::Value {
fn from(v: NonZero<$prim_int>) -> Self {
v.get().into()
}
}
$(#[$meta])*
impl ToExpr for $prim_int {
type Type = $ty;
@ -498,10 +546,7 @@ macro_rules! impl_prim_int {
type Type = $ty;
fn to_expr(&self) -> Expr<Self::Type> {
<$ty>::le_bytes_to_expr_wrapping(
&self.get().to_le_bytes(),
<$ty as BoolOrIntType>::Width::VALUE,
)
self.get().to_expr()
}
}
};
@ -531,6 +576,15 @@ impl_prim_int!(
pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed {
type Width: Size;
type Signed: GenericConstBool;
type Value: Clone
+ Ord
+ std::hash::Hash
+ fmt::Debug
+ Send
+ Sync
+ 'static
+ ToExpr<Type = Self>
+ Into<BigInt>;
fn width(self) -> usize;
fn new(width: <Self::Width as Size>::SizeType) -> Self;
fn new_static() -> Self
@ -545,6 +599,10 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed {
fn as_same_width_uint(self) -> UIntType<Self::Width> {
UIntType::new(Self::Width::from_usize(self.width()))
}
fn value_from_int_wrapping(self, v: impl Into<BigInt>) -> Self::Value {
self.value_from_bigint_wrapping(v.into())
}
fn value_from_bigint_wrapping(self, v: BigInt) -> Self::Value;
fn bits_from_bigint_wrapping(self, v: BigInt) -> BitVec {
let width = self.width();
let mut bytes = v.to_signed_bytes_le();
@ -567,8 +625,9 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed {
BitSlice::<u8, Lsb0>::from_slice_mut(&mut bytes)[..bits.len()].clone_from_bitslice(bits);
BigInt::from_signed_bytes_le(&bytes)
}
fn bits_to_value(bits: Cow<'_, BitSlice>) -> Self::Value;
fn bits_to_expr(bits: Cow<'_, BitSlice>) -> Expr<Self>;
fn le_bytes_to_expr_wrapping(bytes: &[u8], bit_width: usize) -> Expr<Self> {
fn le_bytes_to_bits_wrapping(bytes: &[u8], bit_width: usize) -> BitVec {
let bitslice = BitSlice::<u8, Lsb0>::from_slice(bytes);
let bitslice = &bitslice[..bit_width.min(bitslice.len())];
let mut bits = BitVec::new();
@ -577,7 +636,17 @@ pub trait BoolOrIntType: Type + sealed::BoolOrIntTypeSealed {
bit_width,
Self::Signed::VALUE && bits.last().as_deref().copied().unwrap_or(false),
);
Self::bits_to_expr(Cow::Owned(bits))
bits
}
fn le_bytes_to_expr_wrapping(bytes: &[u8], bit_width: usize) -> Expr<Self> {
Self::bits_to_expr(Cow::Owned(Self::le_bytes_to_bits_wrapping(
bytes, bit_width,
)))
}
fn le_bytes_to_value_wrapping(bytes: &[u8], bit_width: usize) -> Self::Value {
Self::bits_to_value(Cow::Owned(Self::le_bytes_to_bits_wrapping(
bytes, bit_width,
)))
}
}
@ -629,6 +698,7 @@ impl sealed::BoolOrIntTypeSealed for Bool {}
impl BoolOrIntType for Bool {
type Width = ConstUsize<1>;
type Signed = ConstBool<false>;
type Value = bool;
fn width(self) -> usize {
1
@ -639,10 +709,19 @@ impl BoolOrIntType for Bool {
Bool
}
fn value_from_bigint_wrapping(self, v: BigInt) -> Self::Value {
v.bit(0)
}
fn bits_to_expr(bits: Cow<'_, BitSlice>) -> Expr<Self> {
assert_eq!(bits.len(), 1);
bits[0].to_expr()
}
fn bits_to_value(bits: Cow<'_, BitSlice>) -> Self::Value {
assert_eq!(bits.len(), 1);
bits[0]
}
}
impl Bool {

View file

@ -714,6 +714,18 @@ impl<T: BundleType> Instance<T> {
source_location,
}
}
pub fn from_canonical(v: Instance<Bundle>) -> Self {
let Instance {
scoped_name,
instantiated,
source_location,
} = v;
Self {
scoped_name,
instantiated: Module::from_canonical(*instantiated).intern_sized(),
source_location,
}
}
pub fn containing_module_name(self) -> Interned<str> {
self.containing_module_name_id().0
}

View file

@ -11,29 +11,33 @@ use crate::{
GetTarget, Target, TargetBase, TargetPathArrayElement, TargetPathBundleField,
TargetPathElement,
},
ExprEnum, Flow,
ExprEnum, Flow, ToLiteralBits,
},
int::BoolOrIntType,
intern::{Intern, Interned, Memoize},
module::{
AnnotatedModuleIO, Block, ModuleBody, NormalModuleBody, Stmt, StmtConnect, StmtDeclaration,
StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire,
AnnotatedModuleIO, Block, Id, ModuleBody, NameId, NormalModuleBody, ScopedNameId, Stmt,
StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg,
StmtWire,
},
prelude::*,
sim::interpreter::{
Insn, InsnField, InsnFieldKind, InsnFieldType, Insns, InsnsBuilding, InsnsBuildingDone,
SlotDebugData, SmallUInt, StatePartArrayIndex, StatePartArrayIndexed, StatePartIndex,
StatePartIndexRange, StatePartKind, StatePartKindBigSlots, StatePartKindSmallSlots,
StatePartLayout, StatePartLen, StatePartsValue, TypeArrayIndex, TypeArrayIndexes,
TypeIndex, TypeIndexRange, TypeLayout, TypeLen, TypeParts,
SlotDebugData, SmallUInt, State, StatePartArrayIndex, StatePartArrayIndexed,
StatePartIndex, StatePartIndexRange, StatePartKind, StatePartKindBigSlots,
StatePartKindSmallSlots, StatePartLayout, StatePartLen, StatePartsValue, TypeArrayIndex,
TypeArrayIndexes, TypeIndex, TypeIndexRange, TypeLayout, TypeLen, TypeParts,
},
ty::StaticType,
util::DebugAsDisplay,
};
use hashbrown::HashMap;
use hashbrown::{HashMap, HashSet};
use num_bigint::BigInt;
use num_traits::ToPrimitive;
use petgraph::visit::{
GraphBase, IntoNeighbors, IntoNeighborsDirected, IntoNodeIdentifiers, VisitMap, Visitable,
};
use std::{collections::BTreeSet, fmt, marker::PhantomData, mem, ops::IndexMut};
use std::{borrow::Cow, collections::BTreeSet, fmt, marker::PhantomData, mem, ops::IndexMut};
mod interpreter;
@ -2744,7 +2748,14 @@ impl Compiler {
Compiled {
insns: Insns::from(self.insns).intern_sized(),
base_module,
base_module_io_ty: self.base_module.io_ty(),
io: Instance::new_unchecked(
ScopedNameId(
NameId("<simulator>".intern(), Id::new()),
self.base_module.name_id(),
),
self.base_module,
self.base_module.source_location(),
),
}
}
}
@ -2758,7 +2769,7 @@ struct CompiledModule {
pub struct Compiled<T: BundleType> {
insns: Interned<Insns<InsnsBuildingDone>>,
base_module: CompiledModule,
base_module_io_ty: T,
io: Instance<T>,
}
impl<T: BundleType> Compiled<T> {
@ -2769,48 +2780,338 @@ impl<T: BundleType> Compiled<T> {
let Self {
insns,
base_module,
base_module_io_ty,
io,
} = self;
Compiled {
insns,
base_module,
base_module_io_ty: Bundle::from_canonical(base_module_io_ty.canonical()),
io: Instance::from_canonical(io.canonical()),
}
}
pub fn from_canonical(canonical: Compiled<Bundle>) -> Self {
let Compiled {
insns,
base_module,
base_module_io_ty,
io,
} = canonical;
Self {
insns,
base_module,
base_module_io_ty: T::from_canonical(base_module_io_ty.canonical()),
io: Instance::from_canonical(io.canonical()),
}
}
}
#[derive(Debug)]
pub struct Simulation<T: BundleType> {
struct SimulationImpl {
state: interpreter::State,
base_module: CompiledModule,
base_module_io_ty: T,
io: Expr<Bundle>,
uninitialized_inputs: HashSet<Target>,
io_targets: HashMap<Target, CompiledValue<CanonicalType>>,
made_initial_step: bool,
}
impl SimulationImpl {
fn parse_io(&mut self, target: Target, value: CompiledValue<CanonicalType>) {
self.io_targets.insert(target, value);
match value.layout.body {
CompiledTypeLayoutBody::Scalar => match target.flow() {
Flow::Source => {}
Flow::Sink => {
self.uninitialized_inputs.insert(target);
}
Flow::Duplex => unreachable!(),
},
CompiledTypeLayoutBody::Array { .. } => {
let value = value.map_ty(Array::from_canonical);
for index in 0..value.layout.ty.len() {
self.parse_io(
target.join(
TargetPathElement::from(TargetPathArrayElement { index })
.intern_sized(),
),
value.element(index),
);
}
}
CompiledTypeLayoutBody::Bundle { .. } => {
let value = value.map_ty(Bundle::from_canonical);
for BundleField { name, .. } in value.layout.ty.fields() {
self.parse_io(
target.join(
TargetPathElement::from(TargetPathBundleField { name }).intern_sized(),
),
value.field_by_name(name),
);
}
}
}
}
fn new(compiled: Compiled<Bundle>) -> Self {
let mut retval = Self {
state: State::new(compiled.insns),
io: compiled.io.to_expr(),
uninitialized_inputs: HashSet::new(),
io_targets: HashMap::new(),
made_initial_step: false,
};
let io_target = Target::from(compiled.io);
for (BundleField { name, .. }, value) in compiled
.io
.ty()
.fields()
.into_iter()
.zip(compiled.base_module.module_io)
{
retval.parse_io(
io_target
.join(TargetPathElement::from(TargetPathBundleField { name }).intern_sized()),
value,
);
}
retval
}
#[track_caller]
fn settle_step(&mut self) {
assert!(
self.uninitialized_inputs.is_empty(),
"didn't initialize all inputs",
);
self.state.setup_call(0);
self.state.run();
self.made_initial_step = true;
}
#[track_caller]
fn get_io(&self, target: Target) -> CompiledValue<CanonicalType> {
if let Some(&retval) = self.io_targets.get(&target) {
return retval;
}
if Some(&target) == self.io.target().as_deref()
|| Some(target.base()) != self.io.target().map(|v| v.base())
{
panic!("simulator read/write expression must be an array element/field of `Simulator::io()`");
};
panic!("simulator read/write expression must not have dynamic array indexes");
}
#[track_caller]
fn read_bool_or_int<I: BoolOrIntType>(&self, io: Expr<I>) -> I::Value {
let Some(target) = io.target() else {
panic!("can't read from expression that's not a field/element of `Simulation::io()`");
};
let compiled_value = self.get_io(*target);
if !self.made_initial_step {
match target.flow() {
Flow::Source => {
panic!("can't read from an output before the simulation has made any steps");
}
Flow::Sink => {
if self.uninitialized_inputs.contains(&*target) {
panic!("can't read from an uninitialized input");
}
}
Flow::Duplex => unreachable!(),
}
}
match compiled_value.range.len() {
TypeLen {
small_slots:
StatePartLen {
value: 1,
_phantom: _,
},
big_slots:
StatePartLen {
value: 0,
_phantom: _,
},
} => Expr::ty(io).value_from_int_wrapping(
self.state.small_slots[compiled_value.range.small_slots.start],
),
TypeLen {
small_slots:
StatePartLen {
value: 0,
_phantom: _,
},
big_slots:
StatePartLen {
value: 1,
_phantom: _,
},
} => Expr::ty(io).value_from_int_wrapping(
self.state.big_slots[compiled_value.range.big_slots.start].clone(),
),
_ => unreachable!(),
}
}
#[track_caller]
fn write_bool_or_int<I: BoolOrIntType>(&mut self, io: Expr<I>, value: I::Value) {
let Some(target) = io.target() else {
panic!("can't write to an expression that's not a field/element of `Simulation::io()`");
};
let compiled_value = self.get_io(*target);
match target.flow() {
Flow::Source => {
panic!("can't write to an output");
}
Flow::Sink => {}
Flow::Duplex => unreachable!(),
}
let value: BigInt = value.into();
if !self.made_initial_step {
self.uninitialized_inputs.remove(&*target);
}
match compiled_value.range.len() {
TypeLen {
small_slots:
StatePartLen {
value: 1,
_phantom: _,
},
big_slots:
StatePartLen {
value: 0,
_phantom: _,
},
} => {
self.state.small_slots[compiled_value.range.small_slots.start] =
value.to_u64().expect("value out of range");
}
TypeLen {
small_slots:
StatePartLen {
value: 0,
_phantom: _,
},
big_slots:
StatePartLen {
value: 1,
_phantom: _,
},
} => self.state.big_slots[compiled_value.range.big_slots.start] = value,
_ => unreachable!(),
}
}
}
pub struct Simulation<T: BundleType> {
sim_impl: SimulationImpl,
io: Expr<T>,
}
struct SortedSetDebug<'a, T>(&'a HashSet<T>);
impl<T: fmt::Debug> fmt::Debug for SortedSetDebug<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut entries = Vec::from_iter(self.0.iter().map(|v| {
if f.alternate() {
format!("{v:#?}")
} else {
format!("{v:?}")
}
}));
entries.sort();
f.debug_set()
.entries(entries.iter().map(DebugAsDisplay))
.finish()
}
}
struct SortedMapDebug<'a, K, V>(&'a HashMap<K, V>);
impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for SortedMapDebug<'_, K, V> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut entries = Vec::from_iter(self.0.iter().map(|(k, v)| {
if f.alternate() {
(format!("{k:#?}"), format!("{v:#?}"))
} else {
(format!("{k:?}"), format!("{v:?}"))
}
}));
entries.sort();
f.debug_map()
.entries(
entries
.iter()
.map(|(k, v)| (DebugAsDisplay(k), DebugAsDisplay(v))),
)
.finish()
}
}
impl<T: BundleType> fmt::Debug for Simulation<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let Self {
sim_impl:
SimulationImpl {
state,
io: _,
uninitialized_inputs,
io_targets,
made_initial_step,
},
io,
} = self;
f.debug_struct("Simulation")
.field("state", state)
.field("io", io)
.field(
"uninitialized_inputs",
&SortedSetDebug(uninitialized_inputs),
)
.field("io_targets", &SortedMapDebug(io_targets))
.field("made_initial_step", made_initial_step)
.finish()
}
}
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),
base_module: compiled.base_module,
base_module_io_ty: compiled.base_module_io_ty,
pub fn canonical(self) -> Simulation<Bundle> {
let Self { sim_impl, io } = self;
Simulation {
sim_impl,
io: Expr::as_bundle(io),
}
}
pub fn from_canonical(canonical: Simulation<Bundle>) -> Self {
let Simulation { sim_impl, io } = canonical;
Self {
sim_impl,
io: Expr::from_bundle(io),
}
}
pub fn io(&self) -> Expr<T> {
self.io.to_expr()
}
pub fn from_compiled(compiled: Compiled<T>) -> Self {
let sim_impl = SimulationImpl::new(compiled.canonical());
Self {
io: Expr::from_bundle(sim_impl.io),
sim_impl,
}
}
#[track_caller]
pub fn settle_step(&mut self) {
self.state.setup_call(0);
self.state.run();
self.sim_impl.settle_step();
}
#[track_caller]
pub fn read_bool_or_int<I: BoolOrIntType>(&self, io: Expr<I>) -> I::Value {
self.sim_impl.read_bool_or_int(io)
}
#[track_caller]
pub fn write_bool_or_int<I: BoolOrIntType>(
&mut self,
io: Expr<I>,
value: impl ToExpr<Type = I>,
) {
let value = value.to_expr();
assert_eq!(Expr::ty(io), Expr::ty(value), "type mismatch");
let value = value
.to_literal_bits()
.expect("the value that is being written to an input must be a literal");
self.sim_impl
.write_bool_or_int(io, I::bits_to_value(Cow::Borrowed(&value)));
}
}

View file

@ -1718,6 +1718,23 @@ impl<
}
}
impl<K: StatePartKind<State: Deref<Target: Index<usize, Output = T>>>, T> Index<StatePartIndex<K>>
for StatePart<K>
{
type Output = T;
fn index(&self, index: StatePartIndex<K>) -> &Self::Output {
&self.value[index.value as usize]
}
}
impl<K: StatePartKind<State: DerefMut<Target: IndexMut<usize, Output = T>>>, T>
IndexMut<StatePartIndex<K>> for StatePart<K>
{
fn index_mut(&mut self, index: StatePartIndex<K>) -> &mut Self::Output {
&mut self.value[index.value as usize]
}
}
impl<'a, K: StatePartKind<BorrowedState<'a>: Deref<Target: Index<usize, Output = T>>>, T>
Index<StatePartIndex<K>> for BorrowedStatePart<'a, K>
{

View file

@ -37,6 +37,18 @@ impl<T: Type> Wire<T> {
ty: ty.canonical(),
}
}
pub fn from_canonical(v: Wire<CanonicalType>) -> Self {
let Wire {
name,
source_location,
ty,
} = v;
Self {
name,
source_location,
ty: T::from_canonical(ty),
}
}
pub fn ty(&self) -> T {
self.ty
}

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
// See Notices.txt for copyright information
use fayalite::{prelude::*, sim::Simulation};
use fayalite::{int::UIntValue, prelude::*, sim::Simulation};
#[hdl_module(outline_generated)]
pub fn connect_const() {
@ -70,44 +70,55 @@ fn test_connect_const() {
],
},
},
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,
io: Instance {
name: <simulator>::connect_const,
instantiated: Module {
name: connect_const,
..
},
},
uninitialized_inputs: {},
io_targets: {
Instance {
name: <simulator>::connect_const,
instantiated: Module {
name: connect_const,
..
},
],
},
base_module_io_ty: connect_const {
o: UInt<8>,
}.o: 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,
},
},
made_initial_step: true,
}"# {
panic!();
}
assert_eq!(sim.read_bool_or_int(sim.io().o), UIntValue::from(5u8));
}
#[hdl_module(outline_generated)]
@ -137,10 +148,13 @@ pub fn mod1() {
connect(o, child);
}
#[hdl]
#[test]
fn test_mod1() {
let _n = SourceLocation::normalize_files_for_tests();
let mut sim = Simulation::new(mod1());
sim.write_bool_or_int(sim.io().o.i, 0xA_hdl_u4);
sim.write_bool_or_int(sim.io().o.i2, -2_hdl_i2);
sim.settle_step();
let sim_debug = format!("{sim:#?}");
println!("#######\n{sim_debug}\n#######");
@ -326,199 +340,344 @@ fn test_mod1() {
},
big_slots: StatePart {
value: [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
10,
-2,
-2,
15,
10,
-2,
-2,
15,
10,
-2,
-2,
15,
-2,
14,
5,
0,
1,
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>,
io: Instance {
name: <simulator>::mod1,
instantiated: Module {
name: mod1,
..
},
},
uninitialized_inputs: {},
io_targets: {
Instance {
name: <simulator>::mod1,
instantiated: Module {
name: mod1,
..
},
}.o: 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,
},
Instance {
name: <simulator>::mod1,
instantiated: Module {
name: mod1,
..
},
}.o.i: CompiledValue {
layout: 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: 1 },
},
write: None,
},
Instance {
name: <simulator>::mod1,
instantiated: Module {
name: mod1,
..
},
}.o.i2: CompiledValue {
layout: 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,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 2, len: 1 },
},
write: None,
},
Instance {
name: <simulator>::mod1,
instantiated: Module {
name: mod1,
..
},
}.o.o: CompiledValue {
layout: 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,
},
range: TypeIndexRange {
small_slots: StatePartIndexRange<SmallSlots> { start: 0, len: 0 },
big_slots: StatePartIndexRange<BigSlots> { start: 1, len: 1 },
},
write: None,
},
Instance {
name: <simulator>::mod1,
instantiated: Module {
name: mod1,
..
},
}.o.o2: CompiledValue {
layout: 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: 3, len: 1 },
},
write: None,
},
},
made_initial_step: true,
}"# {
panic!();
}
let expected = -2_hdl_i2;
assert_eq!(sim.read_bool_or_int(sim.io().o.o).to_expr(), expected);
let expected = 0xF_hdl_u4;
assert_eq!(sim.read_bool_or_int(sim.io().o.o2).to_expr(), expected);
}