working on simulator
This commit is contained in:
parent
41ce9b3474
commit
96b3f1fee4
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
@ -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;
|
||||
|
|
|
@ -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]))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue