simple combinatorial simulation works!
This commit is contained in:
parent
2e9d5c1835
commit
414a2d74f1
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
{
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue