working on simulator
All checks were successful
/ deps (push) Successful in 17s
/ test (push) Successful in 4m50s

This commit is contained in:
Jacob Lifshay 2024-11-10 22:12:57 -08:00
parent 41ce9b3474
commit 96b3f1fee4
Signed by: programmerjake
SSH key fingerprint: SHA256:B1iRVvUJkvd7upMIiMqn6OyxvD2SgJkAH3ZnUOj6z+c
7 changed files with 1212 additions and 190 deletions

7
Cargo.lock generated
View file

@ -319,6 +319,7 @@ dependencies = [
"serde_json",
"tempfile",
"trybuild",
"vec_map",
"which",
]
@ -720,6 +721,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "vec_map"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
[[package]]
name = "version_check"
version = "0.9.4"

View file

@ -39,4 +39,5 @@ syn = { version = "2.0.66", features = ["full", "fold", "visit", "extra-traits"]
tempfile = "3.10.1"
thiserror = "1.0.61"
trybuild = "1.0"
vec_map = "0.8.2"
which = "6.0.1"

View file

@ -28,6 +28,7 @@ os_pipe.workspace = true
serde_json.workspace = true
serde.workspace = true
tempfile.workspace = true
vec_map.workspace = true
which.workspace = true
[dev-dependencies]

View file

@ -4,29 +4,28 @@
//! Fayalite Simulation
use crate::{
bundle::{Bundle, BundleField, BundleType},
enum_::Enum,
bundle::{BundleField, BundleType},
expr::{
target::{
Target, TargetBase, TargetPathArrayElement, TargetPathBundleField, TargetPathElement,
},
Expr,
ExprEnum,
},
int::Bool,
intern::{Intern, Interned, Memoize},
module::{
AnnotatedModuleIO, Block, Instance, Module, ModuleBody, NormalModuleBody, Stmt,
StmtConnect, StmtDeclaration, StmtFormal, StmtIf, StmtInstance, StmtMatch,
AnnotatedModuleIO, Block, ModuleBody, NormalModuleBody, Stmt, StmtConnect, StmtDeclaration,
StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire,
},
prelude::*,
sim::interpreter::{
Insn, Insns, InsnsBuilding, InsnsBuildingDone, SlotDebugData, StatePartLayout, TypeIndex,
TypeIndexRange, TypeLayout,
Insn, Insns, InsnsBuilding, InsnsBuildingDone, SlotDebugData, SmallUInt, StatePartIndex,
StatePartIndexMap, StatePartKind, StatePartKindBigSlots, StatePartKindSmallSlots,
StatePartLayout, StatePartLen, StatePartsValue, TypeIndex, TypeIndexRange, TypeLayout,
TypeLen, TypeParts, MIN_BITS_FOR_NEEDING_BIG,
},
source_location::SourceLocation,
ty::CanonicalType,
};
use hashbrown::HashMap;
use std::fmt;
use std::{fmt, marker::PhantomData, mem};
mod interpreter;
@ -35,17 +34,17 @@ enum CondStack {
Always,
IfTrue {
parent: Interned<CondStack>,
cond: Expr<Bool>,
cond: CompiledExpr<Bool>,
source_location: SourceLocation,
},
IfFalse {
parent: Interned<CondStack>,
cond: Expr<Bool>,
cond: CompiledExpr<Bool>,
source_location: SourceLocation,
},
MatchArm {
parent: Interned<CondStack>,
enum_expr: Expr<Enum>,
enum_expr: CompiledExpr<Enum>,
variant_index: usize,
source_location: SourceLocation,
},
@ -95,7 +94,7 @@ struct TargetInInstantiatedModule {
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
struct CompiledBundleField {
offset: TypeIndex,
ty: CompiledTypeLayout,
ty: CompiledTypeLayout<CanonicalType>,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
@ -103,7 +102,7 @@ enum CompiledTypeLayoutBody {
Scalar,
Array {
/// debug names are ignored, use parent's layout instead
element: Interned<CompiledTypeLayout>,
element: Interned<CompiledTypeLayout<CanonicalType>>,
},
Bundle {
/// debug names are ignored, use parent's layout instead
@ -112,13 +111,13 @@ enum CompiledTypeLayoutBody {
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
struct CompiledTypeLayout {
ty: CanonicalType,
struct CompiledTypeLayout<T: Type> {
ty: T,
layout: TypeLayout<InsnsBuildingDone>,
body: CompiledTypeLayoutBody,
}
impl CompiledTypeLayout {
impl<T: Type> CompiledTypeLayout<T> {
fn with_prefixed_debug_names(self, prefix: &str) -> Self {
let Self { ty, layout, body } = self;
Self {
@ -127,13 +126,13 @@ impl CompiledTypeLayout {
body,
}
}
fn get(ty: CanonicalType) -> Self {
fn get(ty: T) -> Self {
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
struct MyMemoize;
impl Memoize for MyMemoize {
type Input = CanonicalType;
type InputOwned = CanonicalType;
type Output = CompiledTypeLayout;
type Output = CompiledTypeLayout<CanonicalType>;
fn inner(self, input: &Self::Input) -> Self::Output {
match input {
@ -146,8 +145,10 @@ impl CompiledTypeLayout {
| CanonicalType::Reset(_)
| CanonicalType::Clock(_) => {
let mut layout = TypeLayout::empty();
let debug_data = SlotDebugData { name: "".intern() };
if input.bit_width() > interpreter::SmallUInt::BITS as usize {
let debug_data = SlotDebugData {
name: Interned::default(),
};
if input.bit_width() >= interpreter::MIN_BITS_FOR_NEEDING_BIG {
layout.big_slots = StatePartLayout::scalar(debug_data);
} else {
layout.small_slots = StatePartLayout::scalar(debug_data);
@ -205,24 +206,32 @@ impl CompiledTypeLayout {
}
}
}
MyMemoize.get_owned(ty)
let CompiledTypeLayout {
ty: _,
layout,
body,
} = MyMemoize.get_owned(ty.canonical());
Self { ty, layout, body }
}
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
struct CompiledValue {
layout: CompiledTypeLayout,
struct CompiledValue<T: Type> {
layout: CompiledTypeLayout<T>,
range: TypeIndexRange,
write: Option<(CompiledTypeLayout, TypeIndexRange)>,
write: Option<(CompiledTypeLayout<T>, TypeIndexRange)>,
}
impl CompiledValue {
fn map(
impl<T: Type> CompiledValue<T> {
fn map<U: Type>(
self,
mut f: impl FnMut(CompiledTypeLayout, TypeIndexRange) -> (CompiledTypeLayout, TypeIndexRange),
) -> Self {
mut f: impl FnMut(
CompiledTypeLayout<T>,
TypeIndexRange,
) -> (CompiledTypeLayout<U>, TypeIndexRange),
) -> CompiledValue<U> {
let (layout, range) = f(self.layout, self.range);
Self {
CompiledValue {
layout,
range,
write: self.write.map(|(layout, range)| f(layout, range)),
@ -230,12 +239,98 @@ impl CompiledValue {
}
}
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
struct CompiledExprDynIndex {
index_slot: StatePartIndex<StatePartKindSmallSlots>,
len: TypeLen,
stride: TypeLen,
}
#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone)]
struct CompiledExpr<T: Type> {
static_part: CompiledValue<T>,
dyn_indexes: Interned<[CompiledExprDynIndex]>,
}
impl<T: Type> From<CompiledValue<T>> for CompiledExpr<T> {
fn from(static_part: CompiledValue<T>) -> Self {
Self {
static_part,
dyn_indexes: Interned::default(),
}
}
}
impl<T: Type> CompiledExpr<T> {
fn map_ty<U: Type>(self, mut f: impl FnMut(T) -> U) -> CompiledExpr<U> {
let Self {
static_part,
dyn_indexes,
} = self;
CompiledExpr {
static_part: static_part.map(|CompiledTypeLayout { ty, layout, body }, range| {
(
CompiledTypeLayout {
ty: f(ty),
layout,
body,
},
range,
)
}),
dyn_indexes,
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
struct SlotSet(TypeParts<Self>);
impl SlotSet {
fn is_empty(&self) -> bool {
let Self(TypeParts {
small_slots,
big_slots,
}) = self;
small_slots.is_empty() && big_slots.is_empty()
}
}
impl StatePartsValue for SlotSet {
type Value<K: StatePartKind> = Vec<StatePartIndex<K>>;
}
#[derive(Debug)]
struct Assignment {
inputs: SlotSet,
insns: Vec<Insn>,
}
#[derive(Debug, Default)]
struct StatePartAssignments<K: StatePartKind> {
written_slot_to_assignment_indexes_map: StatePartIndexMap<K, Vec<usize>>,
}
#[derive(Debug, Default)]
struct SlotAssignments {
assignments: Vec<Assignment>,
parts: TypeParts<Self>,
}
impl StatePartsValue for SlotAssignments {
type Value<K: StatePartKind> = StatePartAssignments<K>;
}
#[derive(Debug)]
pub struct Compiler {
insns: Insns<InsnsBuilding>,
base_module: Interned<Module<Bundle>>,
modules: HashMap<InstantiatedModule, CompiledModule>,
compiled_values: HashMap<TargetInInstantiatedModule, CompiledValue>,
compiled_values: HashMap<TargetInInstantiatedModule, CompiledValue<CanonicalType>>,
compiled_exprs: HashMap<Expr<CanonicalType>, CompiledExpr<CanonicalType>>,
compiled_exprs_to_values: HashMap<CompiledExpr<CanonicalType>, CompiledValue<CanonicalType>>,
expanded_to_big: HashMap<Expr<CanonicalType>, CompiledValue<CanonicalType>>,
slots_assignments: SlotAssignments,
}
impl Compiler {
@ -245,13 +340,20 @@ impl Compiler {
base_module,
modules: HashMap::new(),
compiled_values: HashMap::new(),
compiled_exprs: HashMap::new(),
compiled_exprs_to_values: HashMap::new(),
expanded_to_big: HashMap::new(),
slots_assignments: SlotAssignments::default(),
}
}
fn compile_value(&mut self, target: TargetInInstantiatedModule) -> CompiledValue {
fn compile_value(
&mut self,
target: TargetInInstantiatedModule,
) -> CompiledValue<CanonicalType> {
if let Some(&retval) = self.compiled_values.get(&target) {
return retval;
}
match target.target {
let retval = match target.target {
Target::Base(base) => {
let unprefixed_layout = CompiledTypeLayout::get(base.canonical_ty());
let layout = unprefixed_layout.with_prefixed_debug_names(&format!(
@ -319,7 +421,494 @@ impl Compiler {
TargetPathElement::DynArrayElement(_) => unreachable!(),
}
}
};
self.compiled_values.insert(target, retval);
retval
}
fn compiled_expr_to_value(
&mut self,
expr: CompiledExpr<CanonicalType>,
) -> CompiledValue<CanonicalType> {
if let Some(&retval) = self.compiled_exprs_to_values.get(&expr) {
return retval;
}
let CompiledExpr {
static_part: mut retval,
dyn_indexes,
} = expr;
for CompiledExprDynIndex {
index_slot,
len,
stride,
} in dyn_indexes
{
todo!();
}
self.compiled_exprs_to_values.insert(expr, retval);
retval
}
fn simple_nary_expr<const N: usize>(
&mut self,
dest_ty: CanonicalType,
inputs: [Expr<CanonicalType>; N],
make_insns: impl FnOnce(
&mut Self,
CompiledValue<CanonicalType>,
&mut [CompiledValue<CanonicalType>; N],
) -> Vec<Insn>,
) -> CompiledValue<CanonicalType> {
let mut inputs = inputs.map(|input| {
let input = self.compile_expr(input);
self.compiled_expr_to_value(input)
});
let layout = CompiledTypeLayout::get(dest_ty);
let range = self.insns.allocate_variable(&layout.layout);
let retval = CompiledValue {
layout,
range,
write: None,
};
let insns = make_insns(self, retval, &mut inputs);
let mut inputs_set = SlotSet::default();
for input in inputs {
let TypeIndexRange {
small_slots,
big_slots,
} = input.range;
inputs_set.0.small_slots.extend(small_slots.iter());
inputs_set.0.big_slots.extend(big_slots.iter());
}
let assignment_index = self.slots_assignments.assignments.len();
self.slots_assignments.assignments.push(Assignment {
inputs: inputs_set,
insns,
});
let TypeIndexRange {
small_slots,
big_slots,
} = range;
for i in small_slots.iter() {
self.slots_assignments
.parts
.small_slots
.written_slot_to_assignment_indexes_map
.entry(i)
.or_insert_with(Vec::new)
.push(assignment_index);
}
for i in big_slots.iter() {
self.slots_assignments
.parts
.big_slots
.written_slot_to_assignment_indexes_map
.entry(i)
.or_insert_with(Vec::new)
.push(assignment_index);
}
retval
}
fn expand_to_big(&mut self, expr: Expr<CanonicalType>) -> CompiledValue<CanonicalType> {
if let Some(&retval) = self.expanded_to_big.get(&expr) {
return retval;
}
let input = self.compile_expr(expr);
let input = self.compiled_expr_to_value(input);
let retval = match input.range.len() {
TypeLen {
small_slots:
StatePartLen {
value: 0,
_phantom: _,
},
big_slots: _,
} => input,
len => {
assert_eq!(
Some(StatePartLen {
value: 1,
_phantom: PhantomData,
}),
len.only_small()
);
let signed = match Expr::ty(expr) {
CanonicalType::UInt(_) => false,
CanonicalType::SInt(_) => true,
CanonicalType::Bool(_) => false,
CanonicalType::Enum(_) => false,
CanonicalType::Array(_) => unreachable!(),
CanonicalType::Bundle(_) => unreachable!(),
CanonicalType::AsyncReset(_) => false,
CanonicalType::SyncReset(_) => false,
CanonicalType::Reset(_) => false,
CanonicalType::Clock(_) => false,
};
self.simple_nary_expr(
if signed {
SInt::new_dyn(MIN_BITS_FOR_NEEDING_BIG).canonical()
} else {
UInt::new_dyn(MIN_BITS_FOR_NEEDING_BIG).canonical()
},
[expr],
|_this, dest, [input]| {
let dest = dest.range.big_slots.start;
let src = input.range.small_slots.start;
let unused_bit_count =
interpreter::SmallUInt::BITS as u8 - Expr::ty(expr).bit_width() as u8;
if signed {
vec![Insn::SExtSmallToBig {
dest,
src,
unused_bit_count,
}]
} else {
vec![Insn::ZExtSmallToBig {
dest,
src,
unused_bit_count,
}]
}
},
)
}
};
self.expanded_to_big.insert(expr, retval);
retval
}
fn simple_nary_small_or_big_expr<const N: usize>(
&mut self,
dest_ty: CanonicalType,
inputs: [Expr<CanonicalType>; N],
make_insns_small: impl FnOnce(
StatePartIndex<StatePartKindSmallSlots>,
[StatePartIndex<StatePartKindSmallSlots>; N],
) -> Vec<Insn>,
make_insns_big: impl FnOnce(
StatePartIndex<StatePartKindBigSlots>,
[StatePartIndex<StatePartKindBigSlots>; N],
) -> Vec<Insn>,
make_insns_big_to_small: impl FnOnce(
StatePartIndex<StatePartKindSmallSlots>,
[StatePartIndex<StatePartKindBigSlots>; N],
) -> Vec<Insn>,
) -> CompiledValue<CanonicalType> {
self.simple_nary_expr(dest_ty, inputs, |this, dest, compiled_inputs| {
let all_inputs_only_small = compiled_inputs
.iter()
.all(|input| input.range.len().only_small().is_some());
if all_inputs_only_small {
if dest.range.len().only_small().is_some() {
// all small
assert_eq!(dest.range.len().small_slots.value, 1);
return make_insns_small(
dest.range.small_slots.start,
compiled_inputs.map(
|CompiledValue {
layout,
range,
write: _,
}| {
assert_eq!(range.small_slots.len().value, 1);
range.small_slots.start
},
),
);
} else {
// inputs small, dest big -- expand inputs to big
for (&input, compiled_input) in inputs.iter().zip(&mut *compiled_inputs) {
*compiled_input = this.expand_to_big(input);
}
}
}
let big_inputs = compiled_inputs.map(
|CompiledValue {
layout,
range:
TypeIndexRange {
small_slots,
big_slots,
},
write: _,
}| {
assert_eq!(small_slots.len().value, 0);
assert_eq!(big_slots.len().value, 1);
big_slots.start
},
);
if dest.range.len().only_small().is_some() {
// inputs big, dest small
assert_eq!(dest.range.len().small_slots.value, 1);
return make_insns_big_to_small(dest.range.small_slots.start, big_inputs);
}
let TypeIndexRange {
small_slots,
big_slots,
} = dest.range;
assert_eq!(small_slots.len().value, 0);
assert_eq!(big_slots.len().value, 1);
make_insns_big(big_slots.start, big_inputs)
})
}
fn compile_expr(&mut self, expr: Expr<CanonicalType>) -> CompiledExpr<CanonicalType> {
if let Some(&retval) = self.compiled_exprs.get(&expr) {
return retval;
}
let retval: CompiledExpr<_> = match *Expr::expr_enum(expr) {
ExprEnum::UIntLiteral(expr) => self
.simple_nary_small_or_big_expr(
Bool.canonical(),
[],
|dest, []| {
vec![Insn::ConstSmall {
dest,
value: expr.to_bigint().try_into().expect("const too big"),
}]
},
|dest, []| {
vec![Insn::ConstBig {
dest,
value: expr.to_bigint().intern_sized(),
}]
},
|_, _| unreachable!(),
)
.into(),
ExprEnum::SIntLiteral(expr) => self
.simple_nary_small_or_big_expr(
Bool.canonical(),
[],
|dest, []| {
vec![Insn::ConstSmall {
dest,
value: expr.to_bigint().try_into().expect("const too big"),
}]
},
|dest, []| {
vec![Insn::ConstBig {
dest,
value: expr.to_bigint().intern_sized(),
}]
},
|_, _| unreachable!(),
)
.into(),
ExprEnum::BoolLiteral(expr) => self
.simple_nary_small_or_big_expr(
Bool.canonical(),
[],
|dest, []| {
vec![Insn::ConstSmall {
dest,
value: expr as SmallUInt,
}]
},
|_, _| unreachable!(),
|_, _| unreachable!(),
)
.into(),
ExprEnum::BundleLiteral(expr) => todo!(),
ExprEnum::ArrayLiteral(expr) => todo!(),
ExprEnum::EnumLiteral(expr) => todo!(),
ExprEnum::Uninit(expr) => todo!(),
ExprEnum::NotU(expr) => todo!(),
ExprEnum::NotS(expr) => todo!(),
ExprEnum::NotB(expr) => todo!(),
ExprEnum::Neg(expr) => self
.simple_nary_small_or_big_expr(
expr.ty().canonical(),
[Expr::canonical(expr.arg())],
|dest, [src]| vec![Insn::NegSmall { dest, src }],
|dest, [src]| vec![Insn::NegBig { dest, src }],
|_, _| unreachable!(),
)
.into(),
ExprEnum::BitAndU(expr) => todo!(),
ExprEnum::BitAndS(expr) => todo!(),
ExprEnum::BitAndB(expr) => todo!(),
ExprEnum::BitOrU(expr) => todo!(),
ExprEnum::BitOrS(expr) => todo!(),
ExprEnum::BitOrB(expr) => todo!(),
ExprEnum::BitXorU(expr) => todo!(),
ExprEnum::BitXorS(expr) => todo!(),
ExprEnum::BitXorB(expr) => todo!(),
ExprEnum::AddU(expr) => todo!(),
ExprEnum::AddS(expr) => todo!(),
ExprEnum::SubU(expr) => todo!(),
ExprEnum::SubS(expr) => todo!(),
ExprEnum::MulU(expr) => todo!(),
ExprEnum::MulS(expr) => todo!(),
ExprEnum::DivU(expr) => todo!(),
ExprEnum::DivS(expr) => todo!(),
ExprEnum::RemU(expr) => todo!(),
ExprEnum::RemS(expr) => todo!(),
ExprEnum::DynShlU(expr) => todo!(),
ExprEnum::DynShlS(expr) => todo!(),
ExprEnum::DynShrU(expr) => todo!(),
ExprEnum::DynShrS(expr) => todo!(),
ExprEnum::FixedShlU(expr) => todo!(),
ExprEnum::FixedShlS(expr) => todo!(),
ExprEnum::FixedShrU(expr) => todo!(),
ExprEnum::FixedShrS(expr) => todo!(),
ExprEnum::CmpLtB(expr) => todo!(),
ExprEnum::CmpLeB(expr) => todo!(),
ExprEnum::CmpGtB(expr) => todo!(),
ExprEnum::CmpGeB(expr) => todo!(),
ExprEnum::CmpEqB(expr) => todo!(),
ExprEnum::CmpNeB(expr) => todo!(),
ExprEnum::CmpLtU(expr) => todo!(),
ExprEnum::CmpLeU(expr) => todo!(),
ExprEnum::CmpGtU(expr) => todo!(),
ExprEnum::CmpGeU(expr) => todo!(),
ExprEnum::CmpEqU(expr) => todo!(),
ExprEnum::CmpNeU(expr) => todo!(),
ExprEnum::CmpLtS(expr) => todo!(),
ExprEnum::CmpLeS(expr) => todo!(),
ExprEnum::CmpGtS(expr) => todo!(),
ExprEnum::CmpGeS(expr) => todo!(),
ExprEnum::CmpEqS(expr) => todo!(),
ExprEnum::CmpNeS(expr) => todo!(),
ExprEnum::CastUIntToUInt(expr) => todo!(),
ExprEnum::CastUIntToSInt(expr) => todo!(),
ExprEnum::CastSIntToUInt(expr) => todo!(),
ExprEnum::CastSIntToSInt(expr) => todo!(),
ExprEnum::CastBoolToUInt(expr) => todo!(),
ExprEnum::CastBoolToSInt(expr) => todo!(),
ExprEnum::CastUIntToBool(expr) => todo!(),
ExprEnum::CastSIntToBool(expr) => todo!(),
ExprEnum::CastBoolToSyncReset(expr) => todo!(),
ExprEnum::CastUIntToSyncReset(expr) => todo!(),
ExprEnum::CastSIntToSyncReset(expr) => todo!(),
ExprEnum::CastBoolToAsyncReset(expr) => todo!(),
ExprEnum::CastUIntToAsyncReset(expr) => todo!(),
ExprEnum::CastSIntToAsyncReset(expr) => todo!(),
ExprEnum::CastSyncResetToBool(expr) => todo!(),
ExprEnum::CastSyncResetToUInt(expr) => todo!(),
ExprEnum::CastSyncResetToSInt(expr) => todo!(),
ExprEnum::CastSyncResetToReset(expr) => todo!(),
ExprEnum::CastAsyncResetToBool(expr) => todo!(),
ExprEnum::CastAsyncResetToUInt(expr) => todo!(),
ExprEnum::CastAsyncResetToSInt(expr) => todo!(),
ExprEnum::CastAsyncResetToReset(expr) => todo!(),
ExprEnum::CastResetToBool(expr) => todo!(),
ExprEnum::CastResetToUInt(expr) => todo!(),
ExprEnum::CastResetToSInt(expr) => todo!(),
ExprEnum::CastBoolToClock(expr) => todo!(),
ExprEnum::CastUIntToClock(expr) => todo!(),
ExprEnum::CastSIntToClock(expr) => todo!(),
ExprEnum::CastClockToBool(expr) => todo!(),
ExprEnum::CastClockToUInt(expr) => todo!(),
ExprEnum::CastClockToSInt(expr) => todo!(),
ExprEnum::FieldAccess(expr) => todo!(),
ExprEnum::VariantAccess(expr) => todo!(),
ExprEnum::ArrayIndex(expr) => todo!(),
ExprEnum::DynArrayIndex(expr) => todo!(),
ExprEnum::ReduceBitAndU(expr) => todo!(),
ExprEnum::ReduceBitAndS(expr) => todo!(),
ExprEnum::ReduceBitOrU(expr) => todo!(),
ExprEnum::ReduceBitOrS(expr) => todo!(),
ExprEnum::ReduceBitXorU(expr) => todo!(),
ExprEnum::ReduceBitXorS(expr) => todo!(),
ExprEnum::SliceUInt(expr) => todo!(),
ExprEnum::SliceSInt(expr) => todo!(),
ExprEnum::CastToBits(expr) => todo!(),
ExprEnum::CastBitsTo(expr) => todo!(),
ExprEnum::ModuleIO(expr) => todo!(),
ExprEnum::Instance(expr) => todo!(),
ExprEnum::Wire(expr) => todo!(),
ExprEnum::Reg(expr) => todo!(),
ExprEnum::MemPort(expr) => todo!(),
};
self.compiled_exprs.insert(expr, retval);
retval
}
fn compile_connect(
&mut self,
parent_module: Interned<InstantiatedModule>,
cond_stack: Interned<CondStack>,
lhs: Expr<CanonicalType>,
mut rhs: Expr<CanonicalType>,
source_location: SourceLocation,
) {
if Expr::ty(lhs) != Expr::ty(rhs) || !Expr::ty(lhs).is_passive() {
match Expr::ty(lhs) {
CanonicalType::UInt(lhs_ty) => {
rhs = Expr::canonical(Expr::<UInt>::from_canonical(rhs).cast_to(lhs_ty));
}
CanonicalType::SInt(lhs_ty) => {
rhs = Expr::canonical(Expr::<SInt>::from_canonical(rhs).cast_to(lhs_ty));
}
CanonicalType::Bool(_) => unreachable!(),
CanonicalType::Array(lhs_ty) => {
let CanonicalType::Array(rhs_ty) = Expr::ty(rhs) else {
unreachable!();
};
assert_eq!(lhs_ty.len(), rhs_ty.len());
let lhs = Expr::<Array>::from_canonical(lhs);
let rhs = Expr::<Array>::from_canonical(rhs);
for index in 0..lhs_ty.len() {
self.compile_connect(
parent_module,
cond_stack,
lhs[index],
rhs[index],
source_location,
);
}
return;
}
CanonicalType::Enum(lhs_ty) => {
let CanonicalType::Enum(rhs_ty) = Expr::ty(rhs) else {
unreachable!();
};
todo!("handle connect with different enum types");
}
CanonicalType::Bundle(lhs_ty) => {
let CanonicalType::Bundle(rhs_ty) = Expr::ty(rhs) else {
unreachable!();
};
assert_eq!(lhs_ty.fields().len(), rhs_ty.fields().len());
let lhs = Expr::<Bundle>::from_canonical(lhs);
let rhs = Expr::<Bundle>::from_canonical(rhs);
for (
field_index,
(
BundleField {
name,
flipped,
ty: _,
},
rhs_field,
),
) in lhs_ty.fields().into_iter().zip(rhs_ty.fields()).enumerate()
{
assert_eq!(name, rhs_field.name);
assert_eq!(flipped, rhs_field.flipped);
let mut lhs_expr =
crate::expr::ops::FieldAccess::new_by_index(lhs, field_index).to_expr();
let mut rhs_expr =
crate::expr::ops::FieldAccess::new_by_index(rhs, field_index).to_expr();
if flipped {
mem::swap(&mut lhs_expr, &mut rhs_expr);
}
self.compile_connect(
parent_module,
cond_stack,
lhs_expr,
rhs_expr,
source_location,
);
}
return;
}
CanonicalType::AsyncReset(_) => unreachable!(),
CanonicalType::SyncReset(_) => unreachable!(),
CanonicalType::Reset(_) => unreachable!(),
CanonicalType::Clock(_) => unreachable!(),
}
}
let lhs = self.compile_expr(lhs);
let rhs = self.compile_expr(rhs);
let rhs = self.compiled_expr_to_value(rhs);
todo!();
}
fn compile_block(
&mut self,
@ -337,7 +926,7 @@ impl Compiler {
lhs,
rhs,
source_location,
}) => todo!(),
}) => self.compile_connect(parent_module, cond_stack, lhs, rhs, source_location),
Stmt::Formal(StmtFormal {
kind,
clk,
@ -351,6 +940,9 @@ impl Compiler {
source_location,
blocks: [then_block, else_block],
}) => {
let cond = self
.compile_expr(Expr::canonical(cond))
.map_ty(Bool::from_canonical);
self.compile_block(
parent_module,
then_block,
@ -377,13 +969,16 @@ impl Compiler {
source_location,
blocks,
}) => {
let enum_expr = self
.compile_expr(Expr::canonical(expr))
.map_ty(Enum::from_canonical);
for (variant_index, block) in blocks.into_iter().enumerate() {
self.compile_block(
parent_module,
block,
CondStack::MatchArm {
parent: cond_stack,
enum_expr: expr,
enum_expr,
variant_index,
source_location,
}
@ -392,19 +987,51 @@ impl Compiler {
}
}
Stmt::Declaration(declaration) => match declaration {
StmtDeclaration::Wire(wire) => todo!(),
StmtDeclaration::Reg(reg) => todo!(),
StmtDeclaration::Wire(StmtWire { annotations, wire }) => {
self.compile_value(TargetInInstantiatedModule {
instantiated_module: *parent_module,
target: wire.into(),
});
}
StmtDeclaration::Reg(StmtReg { annotations, reg }) => {
self.compile_value(TargetInInstantiatedModule {
instantiated_module: *parent_module,
target: reg.into(),
});
todo!();
}
StmtDeclaration::Instance(StmtInstance {
annotations,
instance,
}) => {
self.compile_module(
let CompiledValue {
layout:
CompiledTypeLayout {
ty: value_ty,
layout: ty_layout,
body: CompiledTypeLayoutBody::Bundle { fields },
},
range: value_range,
write: None,
} = self.compile_value(TargetInInstantiatedModule {
instantiated_module: *parent_module,
target: instance.into(),
})
else {
unreachable!();
};
let CompiledModule { module_io } = *self.compile_module(
InstantiatedModule::Child {
parent: parent_module,
instance: instance.intern_sized(),
}
.intern_sized(),
);
for (module_io, CompiledBundleField { offset, ty }) in
module_io.into_iter().zip(fields)
{
todo!();
}
todo!()
}
},
@ -452,7 +1079,7 @@ impl Compiler {
#[derive(Debug)]
struct CompiledModule {
module_io: Interned<[CompiledValue]>,
module_io: Interned<[CompiledValue<CanonicalType>]>,
}
#[derive(Debug)]

File diff suppressed because it is too large Load diff

View file

@ -24,7 +24,8 @@ pub use scoped_ref::ScopedRef;
#[doc(inline)]
pub use misc::{
interned_bit, iter_eq_by, BitSliceWriteWithBase, DebugAsDisplay, DebugAsRawString, MakeMutSlice,
get_many_mut, interned_bit, iter_eq_by, BitSliceWriteWithBase, DebugAsDisplay,
DebugAsRawString, MakeMutSlice,
};
pub mod job_server;

View file

@ -155,3 +155,19 @@ impl fmt::UpperHex for BitSliceWriteWithBase<'_> {
self.fmt_with_base::<4, true>(f)
}
}
#[inline]
#[track_caller]
pub fn get_many_mut<T, const N: usize>(slice: &mut [T], indexes: [usize; N]) -> [&mut T; N] {
for i in 0..N {
for j in 0..i {
assert!(indexes[i] != indexes[j], "duplicate index");
}
assert!(indexes[i] < slice.len(), "index out of bounds");
}
// Safety: checked that no indexes are duplicates and no indexes are out of bounds
unsafe {
let base = slice.as_mut_ptr(); // convert to a raw pointer before loop to avoid aliasing with &mut [T]
std::array::from_fn(|i| &mut *base.add(indexes[i]))
}
}