Compare commits
	
		
			4 commits
		
	
	
		
			3abba7f9eb
			...
			fd45465d35
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| fd45465d35 | |||
| 5e0548db26 | |||
| 12b3ba57f1 | |||
| 965fe53077 | 
					 6 changed files with 2967 additions and 64 deletions
				
			
		| 
						 | 
					@ -770,7 +770,10 @@ impl<'a, P: Pass> PassArgs<'a, P> {
 | 
				
			||||||
        fallback_error_source_location: Option<SourceLocation>,
 | 
					        fallback_error_source_location: Option<SourceLocation>,
 | 
				
			||||||
    ) -> Result<(), DeduceResetsError> {
 | 
					    ) -> Result<(), DeduceResetsError> {
 | 
				
			||||||
        assert_eq!(a.layout, b.layout);
 | 
					        assert_eq!(a.layout, b.layout);
 | 
				
			||||||
        assert_eq!(a.ty, b.ty);
 | 
					        assert!(
 | 
				
			||||||
 | 
					            a.ty.can_connect(b.ty),
 | 
				
			||||||
 | 
					            "can't connect types! a:\n{a:?}\nb:\n{b:?}"
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
        for (a_node_index, b_node_index) in a.node_indexes.into_iter().zip(b.node_indexes) {
 | 
					        for (a_node_index, b_node_index) in a.node_indexes.into_iter().zip(b.node_indexes) {
 | 
				
			||||||
            self.state.reset_graph.union(
 | 
					            self.state.reset_graph.union(
 | 
				
			||||||
                a_node_index,
 | 
					                a_node_index,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,9 @@
 | 
				
			||||||
// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
					// SPDX-License-Identifier: LGPL-3.0-or-later
 | 
				
			||||||
// See Notices.txt for copyright information
 | 
					// See Notices.txt for copyright information
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    expr::{Expr, ToExpr},
 | 
					    clock::Clock,
 | 
				
			||||||
    int::Bool,
 | 
					    expr::{ops, Expr, ToExpr},
 | 
				
			||||||
 | 
					    int::{Bool, SInt, UInt},
 | 
				
			||||||
    source_location::SourceLocation,
 | 
					    source_location::SourceLocation,
 | 
				
			||||||
    ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties},
 | 
					    ty::{impl_match_variant_as_self, CanonicalType, StaticType, Type, TypeProperties},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -11,7 +12,19 @@ mod sealed {
 | 
				
			||||||
    pub trait ResetTypeSealed {}
 | 
					    pub trait ResetTypeSealed {}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait ResetType: StaticType<MaskType = Bool> + sealed::ResetTypeSealed {
 | 
					pub trait ResetType:
 | 
				
			||||||
 | 
					    StaticType<MaskType = Bool>
 | 
				
			||||||
 | 
					    + sealed::ResetTypeSealed
 | 
				
			||||||
 | 
					    + ops::ExprCastTo<Bool>
 | 
				
			||||||
 | 
					    + ops::ExprCastTo<Reset>
 | 
				
			||||||
 | 
					    + ops::ExprCastTo<SyncReset>
 | 
				
			||||||
 | 
					    + ops::ExprCastTo<AsyncReset>
 | 
				
			||||||
 | 
					    + ops::ExprCastTo<Clock>
 | 
				
			||||||
 | 
					    + ops::ExprCastTo<UInt<1>>
 | 
				
			||||||
 | 
					    + ops::ExprCastTo<SInt<1>>
 | 
				
			||||||
 | 
					    + ops::ExprCastTo<UInt>
 | 
				
			||||||
 | 
					    + ops::ExprCastTo<SInt>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
    fn dispatch<D: ResetTypeDispatch>(input: D::Input<Self>, dispatch: D) -> D::Output<Self>;
 | 
					    fn dispatch<D: ResetTypeDispatch>(input: D::Input<Self>, dispatch: D) -> D::Output<Self>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -21,6 +21,7 @@ use crate::{
 | 
				
			||||||
        StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, TargetInInstantiatedModule,
 | 
					        StmtFormal, StmtIf, StmtInstance, StmtMatch, StmtReg, StmtWire, TargetInInstantiatedModule,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    prelude::*,
 | 
					    prelude::*,
 | 
				
			||||||
 | 
					    reset::{ResetType, ResetTypeDispatch},
 | 
				
			||||||
    sim::{
 | 
					    sim::{
 | 
				
			||||||
        interpreter::{
 | 
					        interpreter::{
 | 
				
			||||||
            Insn, InsnField, InsnFieldKind, InsnFieldType, Insns, InsnsBuilding, InsnsBuildingDone,
 | 
					            Insn, InsnField, InsnFieldKind, InsnFieldType, Insns, InsnsBuilding, InsnsBuildingDone,
 | 
				
			||||||
| 
						 | 
					@ -208,6 +209,14 @@ impl<T: Type> CompiledValue<T> {
 | 
				
			||||||
    fn write(self) -> (CompiledTypeLayout<T>, TypeIndexRange) {
 | 
					    fn write(self) -> (CompiledTypeLayout<T>, TypeIndexRange) {
 | 
				
			||||||
        self.write.unwrap_or((self.layout, self.range))
 | 
					        self.write.unwrap_or((self.layout, self.range))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    fn write_value(self) -> Self {
 | 
				
			||||||
 | 
					        let (layout, range) = self.write();
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            layout,
 | 
				
			||||||
 | 
					            range,
 | 
				
			||||||
 | 
					            write: None,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    fn map<U: Type>(
 | 
					    fn map<U: Type>(
 | 
				
			||||||
        self,
 | 
					        self,
 | 
				
			||||||
        mut f: impl FnMut(
 | 
					        mut f: impl FnMut(
 | 
				
			||||||
| 
						 | 
					@ -1180,6 +1189,29 @@ impl Assignment {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					struct RegisterReset {
 | 
				
			||||||
 | 
					    is_async: bool,
 | 
				
			||||||
 | 
					    init: CompiledValue<CanonicalType>,
 | 
				
			||||||
 | 
					    rst: StatePartIndex<StatePartKindSmallSlots>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy)]
 | 
				
			||||||
 | 
					struct ClockTrigger {
 | 
				
			||||||
 | 
					    last_clk_was_low: StatePartIndex<StatePartKindSmallSlots>,
 | 
				
			||||||
 | 
					    clk: StatePartIndex<StatePartKindSmallSlots>,
 | 
				
			||||||
 | 
					    clk_triggered: StatePartIndex<StatePartKindSmallSlots>,
 | 
				
			||||||
 | 
					    source_location: SourceLocation,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug)]
 | 
				
			||||||
 | 
					struct Register {
 | 
				
			||||||
 | 
					    value: CompiledValue<CanonicalType>,
 | 
				
			||||||
 | 
					    clk_triggered: StatePartIndex<StatePartKindSmallSlots>,
 | 
				
			||||||
 | 
					    reset: Option<RegisterReset>,
 | 
				
			||||||
 | 
					    source_location: SourceLocation,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct Compiler {
 | 
					pub struct Compiler {
 | 
				
			||||||
    insns: Insns<InsnsBuilding>,
 | 
					    insns: Insns<InsnsBuilding>,
 | 
				
			||||||
| 
						 | 
					@ -1192,7 +1224,12 @@ pub struct Compiler {
 | 
				
			||||||
    decl_conditions: HashMap<TargetInInstantiatedModule, Interned<[Cond]>>,
 | 
					    decl_conditions: HashMap<TargetInInstantiatedModule, Interned<[Cond]>>,
 | 
				
			||||||
    compiled_values_to_dyn_array_indexes:
 | 
					    compiled_values_to_dyn_array_indexes:
 | 
				
			||||||
        HashMap<CompiledValue<UInt>, StatePartIndex<StatePartKindSmallSlots>>,
 | 
					        HashMap<CompiledValue<UInt>, StatePartIndex<StatePartKindSmallSlots>>,
 | 
				
			||||||
 | 
					    compiled_value_bool_dest_is_small_map:
 | 
				
			||||||
 | 
					        HashMap<CompiledValue<CanonicalType>, StatePartIndex<StatePartKindSmallSlots>>,
 | 
				
			||||||
    assignments: Assignments,
 | 
					    assignments: Assignments,
 | 
				
			||||||
 | 
					    clock_triggers: Vec<ClockTrigger>,
 | 
				
			||||||
 | 
					    compiled_value_to_clock_trigger_map: HashMap<CompiledValue<Clock>, ClockTrigger>,
 | 
				
			||||||
 | 
					    registers: Vec<Register>,
 | 
				
			||||||
    traces: Vec<SimTrace<()>>,
 | 
					    traces: Vec<SimTrace<()>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1211,7 +1248,11 @@ impl Compiler {
 | 
				
			||||||
            compiled_exprs_to_values: HashMap::new(),
 | 
					            compiled_exprs_to_values: HashMap::new(),
 | 
				
			||||||
            decl_conditions: HashMap::new(),
 | 
					            decl_conditions: HashMap::new(),
 | 
				
			||||||
            compiled_values_to_dyn_array_indexes: HashMap::new(),
 | 
					            compiled_values_to_dyn_array_indexes: HashMap::new(),
 | 
				
			||||||
 | 
					            compiled_value_bool_dest_is_small_map: HashMap::new(),
 | 
				
			||||||
            assignments: Assignments::default(),
 | 
					            assignments: Assignments::default(),
 | 
				
			||||||
 | 
					            clock_triggers: Vec::new(),
 | 
				
			||||||
 | 
					            compiled_value_to_clock_trigger_map: HashMap::new(),
 | 
				
			||||||
 | 
					            registers: Vec::new(),
 | 
				
			||||||
            traces: Vec::new(),
 | 
					            traces: Vec::new(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1664,6 +1705,48 @@ impl Compiler {
 | 
				
			||||||
            .insert(compiled_value, retval);
 | 
					            .insert(compiled_value, retval);
 | 
				
			||||||
        retval
 | 
					        retval
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    fn compiled_value_bool_dest_is_small(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        compiled_value: CompiledValue<CanonicalType>,
 | 
				
			||||||
 | 
					        source_location: SourceLocation,
 | 
				
			||||||
 | 
					    ) -> StatePartIndex<StatePartKindSmallSlots> {
 | 
				
			||||||
 | 
					        if let Some(&retval) = self
 | 
				
			||||||
 | 
					            .compiled_value_bool_dest_is_small_map
 | 
				
			||||||
 | 
					            .get(&compiled_value)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            return retval;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let retval = match compiled_value.range.len() {
 | 
				
			||||||
 | 
					            TypeLen::A_SMALL_SLOT => compiled_value.range.small_slots.start,
 | 
				
			||||||
 | 
					            TypeLen::A_BIG_SLOT => {
 | 
				
			||||||
 | 
					                let debug_data = SlotDebugData {
 | 
				
			||||||
 | 
					                    name: Interned::default(),
 | 
				
			||||||
 | 
					                    ty: Bool.canonical(),
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                let dest = self
 | 
				
			||||||
 | 
					                    .insns
 | 
				
			||||||
 | 
					                    .allocate_variable(&TypeLayout {
 | 
				
			||||||
 | 
					                        small_slots: StatePartLayout::scalar(debug_data),
 | 
				
			||||||
 | 
					                        big_slots: StatePartLayout::empty(),
 | 
				
			||||||
 | 
					                    })
 | 
				
			||||||
 | 
					                    .small_slots
 | 
				
			||||||
 | 
					                    .start;
 | 
				
			||||||
 | 
					                self.add_assignment(
 | 
				
			||||||
 | 
					                    Interned::default(),
 | 
				
			||||||
 | 
					                    vec![Insn::IsNonZeroDestIsSmall {
 | 
				
			||||||
 | 
					                        dest,
 | 
				
			||||||
 | 
					                        src: compiled_value.range.big_slots.start,
 | 
				
			||||||
 | 
					                    }],
 | 
				
			||||||
 | 
					                    source_location,
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					                dest
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            _ => unreachable!(),
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        self.compiled_value_bool_dest_is_small_map
 | 
				
			||||||
 | 
					            .insert(compiled_value, retval);
 | 
				
			||||||
 | 
					        retval
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    fn compile_expr(
 | 
					    fn compile_expr(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        instantiated_module: InstantiatedModule,
 | 
					        instantiated_module: InstantiatedModule,
 | 
				
			||||||
| 
						 | 
					@ -2626,6 +2709,125 @@ impl Compiler {
 | 
				
			||||||
            source_location,
 | 
					            source_location,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    fn compile_clock(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        clk: CompiledValue<Clock>,
 | 
				
			||||||
 | 
					        source_location: SourceLocation,
 | 
				
			||||||
 | 
					    ) -> ClockTrigger {
 | 
				
			||||||
 | 
					        if let Some(&retval) = self.compiled_value_to_clock_trigger_map.get(&clk) {
 | 
				
			||||||
 | 
					            return retval;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let mut alloc_small_slot = |part_name: &str| {
 | 
				
			||||||
 | 
					            self.insns
 | 
				
			||||||
 | 
					                .state_layout
 | 
				
			||||||
 | 
					                .ty
 | 
				
			||||||
 | 
					                .small_slots
 | 
				
			||||||
 | 
					                .allocate(&StatePartLayout::scalar(SlotDebugData {
 | 
				
			||||||
 | 
					                    name: Interned::default(),
 | 
				
			||||||
 | 
					                    ty: Bool.canonical(),
 | 
				
			||||||
 | 
					                }))
 | 
				
			||||||
 | 
					                .start
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        let last_clk_was_low = alloc_small_slot("last_clk_was_low");
 | 
				
			||||||
 | 
					        let clk_triggered = alloc_small_slot("clk_triggered");
 | 
				
			||||||
 | 
					        let retval = ClockTrigger {
 | 
				
			||||||
 | 
					            last_clk_was_low,
 | 
				
			||||||
 | 
					            clk: self.compiled_value_bool_dest_is_small(
 | 
				
			||||||
 | 
					                clk.map_ty(CanonicalType::Clock),
 | 
				
			||||||
 | 
					                source_location,
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					            clk_triggered,
 | 
				
			||||||
 | 
					            source_location,
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        self.add_assignment(
 | 
				
			||||||
 | 
					            Interned::default(),
 | 
				
			||||||
 | 
					            [Insn::AndSmall {
 | 
				
			||||||
 | 
					                dest: clk_triggered,
 | 
				
			||||||
 | 
					                lhs: retval.clk,
 | 
				
			||||||
 | 
					                rhs: last_clk_was_low,
 | 
				
			||||||
 | 
					            }],
 | 
				
			||||||
 | 
					            source_location,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        self.clock_triggers.push(retval);
 | 
				
			||||||
 | 
					        self.compiled_value_to_clock_trigger_map.insert(clk, retval);
 | 
				
			||||||
 | 
					        retval
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn compile_stmt_reg<R: ResetType>(
 | 
				
			||||||
 | 
					        &mut self,
 | 
				
			||||||
 | 
					        stmt_reg: StmtReg<R>,
 | 
				
			||||||
 | 
					        instantiated_module: InstantiatedModule,
 | 
				
			||||||
 | 
					        value: CompiledValue<CanonicalType>,
 | 
				
			||||||
 | 
					    ) {
 | 
				
			||||||
 | 
					        let StmtReg { annotations, reg } = stmt_reg;
 | 
				
			||||||
 | 
					        let clk = self.compile_expr(instantiated_module, Expr::canonical(reg.clock_domain().clk));
 | 
				
			||||||
 | 
					        let clk = self
 | 
				
			||||||
 | 
					            .compiled_expr_to_value(clk, reg.source_location())
 | 
				
			||||||
 | 
					            .map_ty(Clock::from_canonical);
 | 
				
			||||||
 | 
					        let clk = self.compile_clock(clk, reg.source_location());
 | 
				
			||||||
 | 
					        struct Dispatch;
 | 
				
			||||||
 | 
					        impl ResetTypeDispatch for Dispatch {
 | 
				
			||||||
 | 
					            type Input<T: ResetType> = ();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            type Output<T: ResetType> = bool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fn reset(self, _input: Self::Input<Reset>) -> Self::Output<Reset> {
 | 
				
			||||||
 | 
					                unreachable!()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fn sync_reset(self, _input: Self::Input<SyncReset>) -> Self::Output<SyncReset> {
 | 
				
			||||||
 | 
					                false
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            fn async_reset(self, _input: Self::Input<AsyncReset>) -> Self::Output<AsyncReset> {
 | 
				
			||||||
 | 
					                true
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        let reset = if let Some(init) = reg.init() {
 | 
				
			||||||
 | 
					            let init = self.compile_expr(instantiated_module, init);
 | 
				
			||||||
 | 
					            let init = self.compiled_expr_to_value(init, reg.source_location());
 | 
				
			||||||
 | 
					            let rst =
 | 
				
			||||||
 | 
					                self.compile_expr(instantiated_module, Expr::canonical(reg.clock_domain().rst));
 | 
				
			||||||
 | 
					            let rst = self.compiled_expr_to_value(rst, reg.source_location());
 | 
				
			||||||
 | 
					            let rst = self.compiled_value_bool_dest_is_small(rst, reg.source_location());
 | 
				
			||||||
 | 
					            let is_async = R::dispatch((), Dispatch);
 | 
				
			||||||
 | 
					            if is_async {
 | 
				
			||||||
 | 
					                let cond = Expr::canonical(reg.clock_domain().rst.cast_to(Bool));
 | 
				
			||||||
 | 
					                let cond = self.compile_expr(instantiated_module, cond);
 | 
				
			||||||
 | 
					                let cond = self.compiled_expr_to_value(cond, reg.source_location());
 | 
				
			||||||
 | 
					                let cond = cond.map_ty(Bool::from_canonical);
 | 
				
			||||||
 | 
					                // write to the register's current value since asynchronous reset is combinational
 | 
				
			||||||
 | 
					                let lhs = CompiledValue {
 | 
				
			||||||
 | 
					                    layout: value.layout,
 | 
				
			||||||
 | 
					                    range: value.range,
 | 
				
			||||||
 | 
					                    write: None,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                .into();
 | 
				
			||||||
 | 
					                self.compile_simple_connect(
 | 
				
			||||||
 | 
					                    [Cond {
 | 
				
			||||||
 | 
					                        body: CondBody::IfTrue { cond },
 | 
				
			||||||
 | 
					                        source_location: reg.source_location(),
 | 
				
			||||||
 | 
					                    }][..]
 | 
				
			||||||
 | 
					                        .intern(),
 | 
				
			||||||
 | 
					                    lhs,
 | 
				
			||||||
 | 
					                    init,
 | 
				
			||||||
 | 
					                    reg.source_location(),
 | 
				
			||||||
 | 
					                );
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            Some(RegisterReset {
 | 
				
			||||||
 | 
					                is_async,
 | 
				
			||||||
 | 
					                init,
 | 
				
			||||||
 | 
					                rst,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            None
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					        self.registers.push(Register {
 | 
				
			||||||
 | 
					            value,
 | 
				
			||||||
 | 
					            clk_triggered: clk.clk_triggered,
 | 
				
			||||||
 | 
					            reset,
 | 
				
			||||||
 | 
					            source_location: reg.source_location(),
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    fn compile_declaration(
 | 
					    fn compile_declaration(
 | 
				
			||||||
        &mut self,
 | 
					        &mut self,
 | 
				
			||||||
        declaration: StmtDeclaration,
 | 
					        declaration: StmtDeclaration,
 | 
				
			||||||
| 
						 | 
					@ -2644,17 +2846,17 @@ impl Compiler {
 | 
				
			||||||
            target: target_base.into(),
 | 
					            target: target_base.into(),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        self.decl_conditions.insert(target, conditions);
 | 
					        self.decl_conditions.insert(target, conditions);
 | 
				
			||||||
        self.compile_value(target);
 | 
					        let compiled_value = self.compile_value(target);
 | 
				
			||||||
        match declaration {
 | 
					        match declaration {
 | 
				
			||||||
            StmtDeclaration::Wire(StmtWire { annotations, wire }) => {}
 | 
					            StmtDeclaration::Wire(StmtWire { annotations, wire }) => {}
 | 
				
			||||||
            StmtDeclaration::Reg(StmtReg { annotations, reg }) => {
 | 
					            StmtDeclaration::Reg(_) => {
 | 
				
			||||||
                todo!();
 | 
					                unreachable!("Reset types were already replaced by SyncReset or AsyncReset");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            StmtDeclaration::RegSync(StmtReg { annotations, reg }) => {
 | 
					            StmtDeclaration::RegSync(stmt_reg) => {
 | 
				
			||||||
                todo!();
 | 
					                self.compile_stmt_reg(stmt_reg, *parent_module, compiled_value)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            StmtDeclaration::RegAsync(StmtReg { annotations, reg }) => {
 | 
					            StmtDeclaration::RegAsync(stmt_reg) => {
 | 
				
			||||||
                todo!();
 | 
					                self.compile_stmt_reg(stmt_reg, *parent_module, compiled_value)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            StmtDeclaration::Instance(StmtInstance {
 | 
					            StmtDeclaration::Instance(StmtInstance {
 | 
				
			||||||
                annotations,
 | 
					                annotations,
 | 
				
			||||||
| 
						 | 
					@ -2938,10 +3140,109 @@ impl Compiler {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    fn process_clocks(&mut self) -> Interned<[StatePartIndex<StatePartKindSmallSlots>]> {
 | 
				
			||||||
 | 
					        mem::take(&mut self.clock_triggers)
 | 
				
			||||||
 | 
					            .into_iter()
 | 
				
			||||||
 | 
					            .map(
 | 
				
			||||||
 | 
					                |ClockTrigger {
 | 
				
			||||||
 | 
					                     last_clk_was_low,
 | 
				
			||||||
 | 
					                     clk,
 | 
				
			||||||
 | 
					                     clk_triggered,
 | 
				
			||||||
 | 
					                     source_location,
 | 
				
			||||||
 | 
					                 }| {
 | 
				
			||||||
 | 
					                    self.insns.push(
 | 
				
			||||||
 | 
					                        Insn::NotSmall {
 | 
				
			||||||
 | 
					                            dest: last_clk_was_low,
 | 
				
			||||||
 | 
					                            src: clk,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        source_location,
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                    clk_triggered
 | 
				
			||||||
 | 
					                },
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					            .collect()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    fn process_registers(&mut self) {
 | 
				
			||||||
 | 
					        for Register {
 | 
				
			||||||
 | 
					            value,
 | 
				
			||||||
 | 
					            clk_triggered,
 | 
				
			||||||
 | 
					            reset,
 | 
				
			||||||
 | 
					            source_location,
 | 
				
			||||||
 | 
					        } in mem::take(&mut self.registers)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            let write_to_current_value = |value_to_write: CompiledValue<CanonicalType>| {
 | 
				
			||||||
 | 
					                let TypeIndexRange {
 | 
				
			||||||
 | 
					                    small_slots,
 | 
				
			||||||
 | 
					                    big_slots,
 | 
				
			||||||
 | 
					                } = value.range;
 | 
				
			||||||
 | 
					                small_slots
 | 
				
			||||||
 | 
					                    .iter()
 | 
				
			||||||
 | 
					                    .zip(value_to_write.range.small_slots.iter())
 | 
				
			||||||
 | 
					                    .map(|(base, src)| Insn::CopySmall { dest: base, src })
 | 
				
			||||||
 | 
					                    .chain(
 | 
				
			||||||
 | 
					                        big_slots
 | 
				
			||||||
 | 
					                            .iter()
 | 
				
			||||||
 | 
					                            .zip(value_to_write.range.big_slots.iter())
 | 
				
			||||||
 | 
					                            .map(|(base, src)| Insn::Copy { dest: base, src }),
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            match reset {
 | 
				
			||||||
 | 
					                Some(RegisterReset {
 | 
				
			||||||
 | 
					                    is_async,
 | 
				
			||||||
 | 
					                    init,
 | 
				
			||||||
 | 
					                    rst,
 | 
				
			||||||
 | 
					                }) => {
 | 
				
			||||||
 | 
					                    let reg_end = self.insns.new_label();
 | 
				
			||||||
 | 
					                    let reg_reset = self.insns.new_label();
 | 
				
			||||||
 | 
					                    let branch_if_reset = Insn::BranchIfSmallNonZero {
 | 
				
			||||||
 | 
					                        target: reg_reset,
 | 
				
			||||||
 | 
					                        value: rst,
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    let branch_if_not_triggered = Insn::BranchIfSmallZero {
 | 
				
			||||||
 | 
					                        target: reg_end,
 | 
				
			||||||
 | 
					                        value: clk_triggered,
 | 
				
			||||||
 | 
					                    };
 | 
				
			||||||
 | 
					                    if is_async {
 | 
				
			||||||
 | 
					                        self.insns.push(branch_if_reset, source_location);
 | 
				
			||||||
 | 
					                        self.insns.push(branch_if_not_triggered, source_location);
 | 
				
			||||||
 | 
					                    } else {
 | 
				
			||||||
 | 
					                        self.insns.push(branch_if_not_triggered, source_location);
 | 
				
			||||||
 | 
					                        self.insns.push(branch_if_reset, source_location);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    for insn in write_to_current_value(value.write_value()) {
 | 
				
			||||||
 | 
					                        self.insns.push(insn, source_location);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    self.insns
 | 
				
			||||||
 | 
					                        .push(Insn::Branch { target: reg_end }, source_location);
 | 
				
			||||||
 | 
					                    self.insns.define_label_at_next_insn(reg_reset);
 | 
				
			||||||
 | 
					                    for insn in write_to_current_value(init) {
 | 
				
			||||||
 | 
					                        self.insns.push(insn, source_location);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    self.insns.define_label_at_next_insn(reg_end);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                None => {
 | 
				
			||||||
 | 
					                    let reg_end = self.insns.new_label();
 | 
				
			||||||
 | 
					                    self.insns.push(
 | 
				
			||||||
 | 
					                        Insn::BranchIfSmallZero {
 | 
				
			||||||
 | 
					                            target: reg_end,
 | 
				
			||||||
 | 
					                            value: clk_triggered,
 | 
				
			||||||
 | 
					                        },
 | 
				
			||||||
 | 
					                        source_location,
 | 
				
			||||||
 | 
					                    );
 | 
				
			||||||
 | 
					                    for insn in write_to_current_value(value.write_value()) {
 | 
				
			||||||
 | 
					                        self.insns.push(insn, source_location);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                    self.insns.define_label_at_next_insn(reg_end);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    pub fn compile(mut self) -> Compiled<Bundle> {
 | 
					    pub fn compile(mut self) -> Compiled<Bundle> {
 | 
				
			||||||
        let base_module =
 | 
					        let base_module =
 | 
				
			||||||
            *self.compile_module(InstantiatedModule::Base(self.base_module).intern_sized());
 | 
					            *self.compile_module(InstantiatedModule::Base(self.base_module).intern_sized());
 | 
				
			||||||
        self.process_assignments();
 | 
					        self.process_assignments();
 | 
				
			||||||
 | 
					        self.process_registers();
 | 
				
			||||||
 | 
					        let clocks_triggered = self.process_clocks();
 | 
				
			||||||
        self.insns
 | 
					        self.insns
 | 
				
			||||||
            .push(Insn::Return, self.base_module.source_location());
 | 
					            .push(Insn::Return, self.base_module.source_location());
 | 
				
			||||||
        Compiled {
 | 
					        Compiled {
 | 
				
			||||||
| 
						 | 
					@ -2956,6 +3257,7 @@ impl Compiler {
 | 
				
			||||||
                self.original_base_module.source_location(),
 | 
					                self.original_base_module.source_location(),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            traces: Intern::intern_owned(self.traces),
 | 
					            traces: Intern::intern_owned(self.traces),
 | 
				
			||||||
 | 
					            clocks_triggered,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -2972,6 +3274,7 @@ pub struct Compiled<T: BundleType> {
 | 
				
			||||||
    base_module: CompiledModule,
 | 
					    base_module: CompiledModule,
 | 
				
			||||||
    io: Instance<T>,
 | 
					    io: Instance<T>,
 | 
				
			||||||
    traces: Interned<[SimTrace<()>]>,
 | 
					    traces: Interned<[SimTrace<()>]>,
 | 
				
			||||||
 | 
					    clocks_triggered: Interned<[StatePartIndex<StatePartKindSmallSlots>]>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: BundleType> Compiled<T> {
 | 
					impl<T: BundleType> Compiled<T> {
 | 
				
			||||||
| 
						 | 
					@ -2984,12 +3287,14 @@ impl<T: BundleType> Compiled<T> {
 | 
				
			||||||
            base_module,
 | 
					            base_module,
 | 
				
			||||||
            io,
 | 
					            io,
 | 
				
			||||||
            traces,
 | 
					            traces,
 | 
				
			||||||
 | 
					            clocks_triggered,
 | 
				
			||||||
        } = self;
 | 
					        } = self;
 | 
				
			||||||
        Compiled {
 | 
					        Compiled {
 | 
				
			||||||
            insns,
 | 
					            insns,
 | 
				
			||||||
            base_module,
 | 
					            base_module,
 | 
				
			||||||
            io: Instance::from_canonical(io.canonical()),
 | 
					            io: Instance::from_canonical(io.canonical()),
 | 
				
			||||||
            traces,
 | 
					            traces,
 | 
				
			||||||
 | 
					            clocks_triggered,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    pub fn from_canonical(canonical: Compiled<Bundle>) -> Self {
 | 
					    pub fn from_canonical(canonical: Compiled<Bundle>) -> Self {
 | 
				
			||||||
| 
						 | 
					@ -2998,12 +3303,14 @@ impl<T: BundleType> Compiled<T> {
 | 
				
			||||||
            base_module,
 | 
					            base_module,
 | 
				
			||||||
            io,
 | 
					            io,
 | 
				
			||||||
            traces,
 | 
					            traces,
 | 
				
			||||||
 | 
					            clocks_triggered,
 | 
				
			||||||
        } = canonical;
 | 
					        } = canonical;
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            insns,
 | 
					            insns,
 | 
				
			||||||
            base_module,
 | 
					            base_module,
 | 
				
			||||||
            io: Instance::from_canonical(io.canonical()),
 | 
					            io: Instance::from_canonical(io.canonical()),
 | 
				
			||||||
            traces,
 | 
					            traces,
 | 
				
			||||||
 | 
					            clocks_triggered,
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -3621,6 +3928,7 @@ struct SimulationImpl {
 | 
				
			||||||
    traces: Box<[SimTrace<BitVec>]>,
 | 
					    traces: Box<[SimTrace<BitVec>]>,
 | 
				
			||||||
    trace_writers: Vec<TraceWriterState<DynTraceWriterDecls>>,
 | 
					    trace_writers: Vec<TraceWriterState<DynTraceWriterDecls>>,
 | 
				
			||||||
    instant: SimInstant,
 | 
					    instant: SimInstant,
 | 
				
			||||||
 | 
					    clocks_triggered: Interned<[StatePartIndex<StatePartKindSmallSlots>]>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl SimulationImpl {
 | 
					impl SimulationImpl {
 | 
				
			||||||
| 
						 | 
					@ -3683,6 +3991,7 @@ impl SimulationImpl {
 | 
				
			||||||
            )),
 | 
					            )),
 | 
				
			||||||
            trace_writers: vec![],
 | 
					            trace_writers: vec![],
 | 
				
			||||||
            instant: SimInstant::START,
 | 
					            instant: SimInstant::START,
 | 
				
			||||||
 | 
					            clocks_triggered: compiled.clocks_triggered,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        let io_target = Target::from(compiled.io);
 | 
					        let io_target = Target::from(compiled.io);
 | 
				
			||||||
        for (BundleField { name, .. }, value) in compiled
 | 
					        for (BundleField { name, .. }, value) in compiled
 | 
				
			||||||
| 
						 | 
					@ -3802,7 +4111,7 @@ impl SimulationImpl {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    fn advance_time(&mut self, duration: SimDuration) {
 | 
					    fn advance_time(&mut self, duration: SimDuration) {
 | 
				
			||||||
        self.settle_step();
 | 
					        self.settle();
 | 
				
			||||||
        self.instant += duration;
 | 
					        self.instant += duration;
 | 
				
			||||||
        self.for_each_trace_writer_storing_error(|this, mut trace_writer_state| {
 | 
					        self.for_each_trace_writer_storing_error(|this, mut trace_writer_state| {
 | 
				
			||||||
            match &mut trace_writer_state {
 | 
					            match &mut trace_writer_state {
 | 
				
			||||||
| 
						 | 
					@ -3816,11 +4125,12 @@ impl SimulationImpl {
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    fn settle_step(&mut self) {
 | 
					    fn settle(&mut self) {
 | 
				
			||||||
        assert!(
 | 
					        assert!(
 | 
				
			||||||
            self.uninitialized_inputs.is_empty(),
 | 
					            self.uninitialized_inputs.is_empty(),
 | 
				
			||||||
            "didn't initialize all inputs",
 | 
					            "didn't initialize all inputs",
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					        for _ in 0..100000 {
 | 
				
			||||||
            if !self.needs_settle {
 | 
					            if !self.needs_settle {
 | 
				
			||||||
                return;
 | 
					                return;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -3832,7 +4142,10 @@ impl SimulationImpl {
 | 
				
			||||||
                self.read_traces::<true>();
 | 
					                self.read_traces::<true>();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            self.made_initial_step = true;
 | 
					            self.made_initial_step = true;
 | 
				
			||||||
        self.needs_settle = false;
 | 
					            self.needs_settle = self
 | 
				
			||||||
 | 
					                .clocks_triggered
 | 
				
			||||||
 | 
					                .iter()
 | 
				
			||||||
 | 
					                .any(|i| self.state.small_slots[*i] != 0);
 | 
				
			||||||
            self.for_each_trace_writer_storing_error(|this, trace_writer_state| {
 | 
					            self.for_each_trace_writer_storing_error(|this, trace_writer_state| {
 | 
				
			||||||
                Ok(match trace_writer_state {
 | 
					                Ok(match trace_writer_state {
 | 
				
			||||||
                    TraceWriterState::Decls(trace_writer_decls) => TraceWriterState::Running(
 | 
					                    TraceWriterState::Decls(trace_writer_decls) => TraceWriterState::Running(
 | 
				
			||||||
| 
						 | 
					@ -3848,6 +4161,8 @@ impl SimulationImpl {
 | 
				
			||||||
                })
 | 
					                })
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        panic!("settle(): took too many steps");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    fn get_io(&self, target: Target) -> CompiledValue<CanonicalType> {
 | 
					    fn get_io(&self, target: Target) -> CompiledValue<CanonicalType> {
 | 
				
			||||||
        if let Some(&retval) = self.io_targets.get(&target) {
 | 
					        if let Some(&retval) = self.io_targets.get(&target) {
 | 
				
			||||||
| 
						 | 
					@ -3861,13 +4176,13 @@ impl SimulationImpl {
 | 
				
			||||||
        panic!("simulator read/write expression must not have dynamic array indexes");
 | 
					        panic!("simulator read/write expression must not have dynamic array indexes");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    fn read_bool_or_int<I: BoolOrIntType>(&mut self, io: Expr<I>) -> I::Value {
 | 
					    fn read_helper(&mut self, io: Expr<CanonicalType>) -> CompiledValue<CanonicalType> {
 | 
				
			||||||
        let Some(target) = io.target() else {
 | 
					        let Some(target) = io.target() else {
 | 
				
			||||||
            panic!("can't read from expression that's not a field/element of `Simulation::io()`");
 | 
					            panic!("can't read from expression that's not a field/element of `Simulation::io()`");
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        let compiled_value = self.get_io(*target);
 | 
					        let compiled_value = self.get_io(*target);
 | 
				
			||||||
        if self.made_initial_step {
 | 
					        if self.made_initial_step {
 | 
				
			||||||
            self.settle_step();
 | 
					            self.settle();
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            match target.flow() {
 | 
					            match target.flow() {
 | 
				
			||||||
                Flow::Source => {
 | 
					                Flow::Source => {
 | 
				
			||||||
| 
						 | 
					@ -3881,6 +4196,56 @@ impl SimulationImpl {
 | 
				
			||||||
                Flow::Duplex => unreachable!(),
 | 
					                Flow::Duplex => unreachable!(),
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        compiled_value
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    fn write_helper(&mut self, io: Expr<CanonicalType>) -> CompiledValue<CanonicalType> {
 | 
				
			||||||
 | 
					        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!(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if !self.made_initial_step {
 | 
				
			||||||
 | 
					            self.uninitialized_inputs.remove(&*target);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        self.needs_settle = true;
 | 
				
			||||||
 | 
					        compiled_value
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    fn read_bit(&mut self, io: Expr<CanonicalType>) -> bool {
 | 
				
			||||||
 | 
					        let compiled_value = self.read_helper(Expr::canonical(io));
 | 
				
			||||||
 | 
					        match compiled_value.range.len() {
 | 
				
			||||||
 | 
					            TypeLen::A_SMALL_SLOT => {
 | 
				
			||||||
 | 
					                self.state.small_slots[compiled_value.range.small_slots.start] != 0
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            TypeLen::A_BIG_SLOT => !self.state.big_slots[compiled_value.range.big_slots.start]
 | 
				
			||||||
 | 
					                .clone()
 | 
				
			||||||
 | 
					                .is_zero(),
 | 
				
			||||||
 | 
					            _ => unreachable!(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    fn write_bit(&mut self, io: Expr<CanonicalType>, value: bool) {
 | 
				
			||||||
 | 
					        let compiled_value = self.write_helper(io);
 | 
				
			||||||
 | 
					        match compiled_value.range.len() {
 | 
				
			||||||
 | 
					            TypeLen::A_SMALL_SLOT => {
 | 
				
			||||||
 | 
					                self.state.small_slots[compiled_value.range.small_slots.start] = value as _;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            TypeLen::A_BIG_SLOT => {
 | 
				
			||||||
 | 
					                self.state.big_slots[compiled_value.range.big_slots.start] = value.into()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            _ => unreachable!(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    fn read_bool_or_int<I: BoolOrIntType>(&mut self, io: Expr<I>) -> I::Value {
 | 
				
			||||||
 | 
					        let compiled_value = self.read_helper(Expr::canonical(io));
 | 
				
			||||||
        match compiled_value.range.len() {
 | 
					        match compiled_value.range.len() {
 | 
				
			||||||
            TypeLen::A_SMALL_SLOT => Expr::ty(io).value_from_int_wrapping(
 | 
					            TypeLen::A_SMALL_SLOT => Expr::ty(io).value_from_int_wrapping(
 | 
				
			||||||
                self.state.small_slots[compiled_value.range.small_slots.start],
 | 
					                self.state.small_slots[compiled_value.range.small_slots.start],
 | 
				
			||||||
| 
						 | 
					@ -3893,22 +4258,8 @@ impl SimulationImpl {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    fn write_bool_or_int<I: BoolOrIntType>(&mut self, io: Expr<I>, value: I::Value) {
 | 
					    fn write_bool_or_int<I: BoolOrIntType>(&mut self, io: Expr<I>, value: I::Value) {
 | 
				
			||||||
        let Some(target) = io.target() else {
 | 
					        let compiled_value = self.write_helper(Expr::canonical(io));
 | 
				
			||||||
            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();
 | 
					        let value: BigInt = value.into();
 | 
				
			||||||
        if !self.made_initial_step {
 | 
					 | 
				
			||||||
            self.uninitialized_inputs.remove(&*target);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        self.needs_settle = true;
 | 
					 | 
				
			||||||
        match compiled_value.range.len() {
 | 
					        match compiled_value.range.len() {
 | 
				
			||||||
            TypeLen::A_SMALL_SLOT => {
 | 
					            TypeLen::A_SMALL_SLOT => {
 | 
				
			||||||
                self.state.small_slots[compiled_value.range.small_slots.start] =
 | 
					                self.state.small_slots[compiled_value.range.small_slots.start] =
 | 
				
			||||||
| 
						 | 
					@ -3985,13 +4336,13 @@ impl SimulationImpl {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn close(mut self) -> std::io::Result<()> {
 | 
					    fn close(mut self) -> std::io::Result<()> {
 | 
				
			||||||
        if self.made_initial_step {
 | 
					        if self.made_initial_step {
 | 
				
			||||||
            self.settle_step();
 | 
					            self.settle();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        self.close_all_trace_writers()
 | 
					        self.close_all_trace_writers()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    fn flush_traces(&mut self) -> std::io::Result<()> {
 | 
					    fn flush_traces(&mut self) -> std::io::Result<()> {
 | 
				
			||||||
        if self.made_initial_step {
 | 
					        if self.made_initial_step {
 | 
				
			||||||
            self.settle_step();
 | 
					            self.settle();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        self.for_each_trace_writer_getting_error(
 | 
					        self.for_each_trace_writer_getting_error(
 | 
				
			||||||
            |this, trace_writer: TraceWriterState<DynTraceWriterDecls>| match trace_writer {
 | 
					            |this, trace_writer: TraceWriterState<DynTraceWriterDecls>| match trace_writer {
 | 
				
			||||||
| 
						 | 
					@ -4082,6 +4433,7 @@ impl<T: BundleType> fmt::Debug for Simulation<T> {
 | 
				
			||||||
                    traces,
 | 
					                    traces,
 | 
				
			||||||
                    trace_writers,
 | 
					                    trace_writers,
 | 
				
			||||||
                    instant,
 | 
					                    instant,
 | 
				
			||||||
 | 
					                    clocks_triggered,
 | 
				
			||||||
                },
 | 
					                },
 | 
				
			||||||
            io,
 | 
					            io,
 | 
				
			||||||
        } = self;
 | 
					        } = self;
 | 
				
			||||||
| 
						 | 
					@ -4099,6 +4451,7 @@ impl<T: BundleType> fmt::Debug for Simulation<T> {
 | 
				
			||||||
            .field("traces", traces)
 | 
					            .field("traces", traces)
 | 
				
			||||||
            .field("trace_writers", trace_writers)
 | 
					            .field("trace_writers", trace_writers)
 | 
				
			||||||
            .field("instant", instant)
 | 
					            .field("instant", instant)
 | 
				
			||||||
 | 
					            .field("clocks_triggered", clocks_triggered)
 | 
				
			||||||
            .finish()
 | 
					            .finish()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -4143,8 +4496,8 @@ impl<T: BundleType> Simulation<T> {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    pub fn settle_step(&mut self) {
 | 
					    pub fn settle(&mut self) {
 | 
				
			||||||
        self.sim_impl.settle_step();
 | 
					        self.sim_impl.settle();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #[track_caller]
 | 
					    #[track_caller]
 | 
				
			||||||
    pub fn advance_time(&mut self, duration: SimDuration) {
 | 
					    pub fn advance_time(&mut self, duration: SimDuration) {
 | 
				
			||||||
| 
						 | 
					@ -4168,4 +4521,28 @@ impl<T: BundleType> Simulation<T> {
 | 
				
			||||||
        self.sim_impl
 | 
					        self.sim_impl
 | 
				
			||||||
            .write_bool_or_int(io, I::bits_to_value(Cow::Borrowed(&value)));
 | 
					            .write_bool_or_int(io, I::bits_to_value(Cow::Borrowed(&value)));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn write_clock(&mut self, io: Expr<Clock>, value: bool) {
 | 
				
			||||||
 | 
					        self.sim_impl.write_bit(Expr::canonical(io), value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn read_clock(&mut self, io: Expr<Clock>) -> bool {
 | 
				
			||||||
 | 
					        self.sim_impl.read_bit(Expr::canonical(io))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn write_bool(&mut self, io: Expr<Bool>, value: bool) {
 | 
				
			||||||
 | 
					        self.sim_impl.write_bit(Expr::canonical(io), value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn read_bool(&mut self, io: Expr<Bool>) -> bool {
 | 
				
			||||||
 | 
					        self.sim_impl.read_bit(Expr::canonical(io))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn write_reset<R: ResetType>(&mut self, io: Expr<R>, value: bool) {
 | 
				
			||||||
 | 
					        self.sim_impl.write_bit(Expr::canonical(io), value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    #[track_caller]
 | 
				
			||||||
 | 
					    pub fn read_reset<R: ResetType>(&mut self, io: Expr<R>) -> bool {
 | 
				
			||||||
 | 
					        self.sim_impl.read_bit(Expr::canonical(io))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2201,6 +2201,17 @@ impl_insns! {
 | 
				
			||||||
        state.small_slots[dest] = value;
 | 
					        state.small_slots[dest] = value;
 | 
				
			||||||
        next!();
 | 
					        next!();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    IsNonZeroDestIsSmall {
 | 
				
			||||||
 | 
					        #[kind = Output]
 | 
				
			||||||
 | 
					        dest: StatePartIndex<StatePartKindSmallSlots>,
 | 
				
			||||||
 | 
					        #[kind = Input]
 | 
				
			||||||
 | 
					        src: StatePartIndex<StatePartKindBigSlots>,
 | 
				
			||||||
 | 
					    } => {
 | 
				
			||||||
 | 
					        let src = &state.big_slots[src];
 | 
				
			||||||
 | 
					        let value = !src.is_zero();
 | 
				
			||||||
 | 
					        state.small_slots[dest] = value as SmallUInt;
 | 
				
			||||||
 | 
					        next!();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    CastToSInt {
 | 
					    CastToSInt {
 | 
				
			||||||
        #[kind = Output]
 | 
					        #[kind = Output]
 | 
				
			||||||
        dest: StatePartIndex<StatePartKindBigSlots>,
 | 
					        dest: StatePartIndex<StatePartKindBigSlots>,
 | 
				
			||||||
| 
						 | 
					@ -2237,6 +2248,18 @@ impl_insns! {
 | 
				
			||||||
        state.big_slots[dest] = value;
 | 
					        state.big_slots[dest] = value;
 | 
				
			||||||
        next!();
 | 
					        next!();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    AndSmall {
 | 
				
			||||||
 | 
					        #[kind = Output]
 | 
				
			||||||
 | 
					        dest: StatePartIndex<StatePartKindSmallSlots>,
 | 
				
			||||||
 | 
					        #[kind = Input]
 | 
				
			||||||
 | 
					        lhs: StatePartIndex<StatePartKindSmallSlots>,
 | 
				
			||||||
 | 
					        #[kind = Input]
 | 
				
			||||||
 | 
					        rhs: StatePartIndex<StatePartKindSmallSlots>,
 | 
				
			||||||
 | 
					    } => {
 | 
				
			||||||
 | 
					        let value = state.small_slots[lhs] & state.small_slots[rhs];
 | 
				
			||||||
 | 
					        state.small_slots[dest] = value;
 | 
				
			||||||
 | 
					        next!();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Or {
 | 
					    Or {
 | 
				
			||||||
        #[kind = Output]
 | 
					        #[kind = Output]
 | 
				
			||||||
        dest: StatePartIndex<StatePartKindBigSlots>,
 | 
					        dest: StatePartIndex<StatePartKindBigSlots>,
 | 
				
			||||||
| 
						 | 
					@ -2283,6 +2306,16 @@ impl_insns! {
 | 
				
			||||||
        state.big_slots[dest] = value;
 | 
					        state.big_slots[dest] = value;
 | 
				
			||||||
        next!();
 | 
					        next!();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    NotSmall {
 | 
				
			||||||
 | 
					        #[kind = Output]
 | 
				
			||||||
 | 
					        dest: StatePartIndex<StatePartKindSmallSlots>,
 | 
				
			||||||
 | 
					        #[kind = Input]
 | 
				
			||||||
 | 
					        src: StatePartIndex<StatePartKindSmallSlots>,
 | 
				
			||||||
 | 
					    } => {
 | 
				
			||||||
 | 
					        let value = !state.small_slots[src];
 | 
				
			||||||
 | 
					        state.small_slots[dest] = value;
 | 
				
			||||||
 | 
					        next!();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    Neg {
 | 
					    Neg {
 | 
				
			||||||
        #[kind = Output]
 | 
					        #[kind = Output]
 | 
				
			||||||
        dest: StatePartIndex<StatePartKindBigSlots>,
 | 
					        dest: StatePartIndex<StatePartKindBigSlots>,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -477,7 +477,7 @@ impl<W: io::Write> TraceWriter for VcdWriter<W> {
 | 
				
			||||||
    fn set_signal_uint(&mut self, id: TraceScalarId, value: &BitSlice) -> Result<(), Self::Error> {
 | 
					    fn set_signal_uint(&mut self, id: TraceScalarId, value: &BitSlice) -> Result<(), Self::Error> {
 | 
				
			||||||
        match value.len() {
 | 
					        match value.len() {
 | 
				
			||||||
            0 => self.writer.write_all(b"s0 ")?,
 | 
					            0 => self.writer.write_all(b"s0 ")?,
 | 
				
			||||||
            1 => write!(self.writer, "{} ", if value[0] { "1" } else { "0" })?,
 | 
					            1 => self.writer.write_all(if value[0] { b"1" } else { b"0" })?,
 | 
				
			||||||
            _ => {
 | 
					            _ => {
 | 
				
			||||||
                self.writer.write_all(b"b")?;
 | 
					                self.writer.write_all(b"b")?;
 | 
				
			||||||
                let mut any_ones = false;
 | 
					                let mut any_ones = false;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue