using System.Linq.Expressions; namespace StoneRed.LogicSimulator.Simulation; /// /// A synchronous cycle-based circuit simulator that evaluates all gates every cycle. /// Provides deterministic timing and predictable evaluation order (gate 0 to N). /// /// /// This simulator evaluates all gates synchronously each step, making it simpler and more /// predictable than . It's ideal for synchronous digital /// designs where deterministic timing is important. Less efficient for sparse circuits /// but has uniform performance characteristics. /// public sealed class CycleCircuitSimulator : SimulatorBase { private int[] nextInputMasks = []; private Action computeOutputs = (_, _, _) => { }; private int[] previousOutputMasks = []; private int[] previousInputMasks = []; /// /// Ensures internal storage arrays are properly sized for the current gate count. /// protected override void EnsureStorage() { base.EnsureStorage(); if (nextInputMasks.Length != gateKinds.Count) { nextInputMasks = new int[gateKinds.Count]; previousOutputMasks = new int[gateKinds.Count]; previousInputMasks = new int[gateKinds.Count]; } } /// /// Resets the circuit to initial state, clearing all input and output buffers. /// public override void Reset() { base.Reset(); Array.Clear(nextInputMasks); Array.Clear(previousOutputMasks); Array.Clear(previousInputMasks); } /// /// Executes one simulation cycle by evaluating all gates synchronously, /// then propagating outputs to inputs for the next cycle. /// public override void Step() { EnsureCompiled(); if (!initialized) { Reset(); } (outputMasks, previousOutputMasks) = (previousOutputMasks, outputMasks); computeOutputs(inputMasks, outputMasks, sourceStates); if (hasAnyWatchers) { Array.Copy(inputMasks, previousInputMasks, inputMasks.Length); } PropagateAndSwap(); if (hasAnyWatchers) { NotifyAllWatchers(previousInputMasks); } } private void PropagateAndSwap() { Array.Clear(nextInputMasks); for (int fromGate = 0; fromGate < gateKinds.Count; fromGate++) { if ((outputMasks[fromGate] & 1) == 0) { continue; } int start = edgeStart[fromGate]; int end = edgeStart[fromGate + 1]; for (int e = start; e < end; e++) { nextInputMasks[edgeToGate[e]] |= 1 << edgeToInputBit[e]; } } (inputMasks, nextInputMasks) = (nextInputMasks, inputMasks); } private bool PropagateAndSwapDetectChange() { Array.Clear(nextInputMasks); for (int fromGate = 0; fromGate < gateKinds.Count; fromGate++) { if ((outputMasks[fromGate] & 1) == 0) { continue; } int start = edgeStart[fromGate]; int end = edgeStart[fromGate + 1]; for (int e = start; e < end; e++) { nextInputMasks[edgeToGate[e]] |= 1 << edgeToInputBit[e]; } } bool changed = false; for (int i = 0; i < inputMasks.Length; i++) { if (inputMasks[i] != nextInputMasks[i]) { changed = true; break; } } (inputMasks, nextInputMasks) = (nextInputMasks, inputMasks); return changed; } /// /// Runs the simulation until inputs stabilize (no changes between cycles) or maxSteps is reached. /// /// Maximum number of cycles to execute. /// Output parameter containing the number of cycles executed. /// True if the circuit stabilized; false if maxSteps was exceeded. public override bool TryRunUntilStable(int maxSteps, out int steps) { steps = 0; if (maxSteps <= 0) { return false; } EnsureCompiled(); if (!initialized) { Reset(); } bool changed = true; while (changed && steps < maxSteps) { steps++; (outputMasks, previousOutputMasks) = (previousOutputMasks, outputMasks); computeOutputs(inputMasks, outputMasks, sourceStates); if (hasAnyWatchers) { Array.Copy(inputMasks, previousInputMasks, inputMasks.Length); } changed = PropagateAndSwapDetectChange(); if (hasAnyWatchers) { NotifyAllWatchers(previousInputMasks); } } return !changed; } /// /// Compiles a single evaluator that computes outputs for all gates in one call. /// All gate logic is combined into a single compiled lambda expression. /// protected override void CompileEngine() { ParameterExpression inputsParam = Expression.Parameter(typeof(int[]), "inputs"); ParameterExpression outputsParam = Expression.Parameter(typeof(int[]), "outputs"); ParameterExpression sourcesParam = Expression.Parameter(typeof(int[]), "sources"); ConstantExpression lutDataConst = Expression.Constant(lutData); List body = []; for (int i = 0; i < gateKinds.Count; i++) { ConstantExpression indexExpr = Expression.Constant(i); BinaryExpression inMask = Expression.ArrayIndex(inputsParam, indexExpr); Expression logicExpr = GenerateGateLogic(i, inMask, sourcesParam, indexExpr, lutDataConst); body.Add(Expression.Assign(Expression.ArrayAccess(outputsParam, indexExpr), logicExpr)); } computeOutputs = Expression.Lambda>(Expression.Block(body), inputsParam, outputsParam, sourcesParam).Compile(); } /// /// Creates a new instance of CycleCircuitSimulator for internal use (e.g., LUT computation). /// /// A new CycleCircuitSimulator instance. protected override SimulatorBase CreateInternalSimulator() { return new CycleCircuitSimulator(); } }