diff --git a/StoneRed.LogicSimulator.Simulation/CircuitDefinition.cs b/StoneRed.LogicSimulator.Simulation/CircuitDefinition.cs index cf7fd24..44b62ac 100644 --- a/StoneRed.LogicSimulator.Simulation/CircuitDefinition.cs +++ b/StoneRed.LogicSimulator.Simulation/CircuitDefinition.cs @@ -1,5 +1,9 @@ namespace StoneRed.LogicSimulator.Simulation; +/// +/// Defines a reusable circuit component that can be registered as a macro gate. +/// Circuit definitions specify gates, connections, input pins, output pins, and nested macro instances. +/// public sealed class CircuitDefinition { private readonly List gateKinds = []; @@ -8,14 +12,44 @@ public sealed class CircuitDefinition private readonly List outputPins = []; private readonly List macroInstances = []; + /// + /// Gets the read-only list of gate types in this circuit definition. + /// public IReadOnlyList GateKinds => gateKinds; + + /// + /// Gets the read-only list of connections between gates. + /// public IReadOnlyList<(int FromGate, int ToGate, byte ToInputBit)> Connections => connections; + + /// + /// Gets the read-only list of gate IDs designated as input pins. + /// public IReadOnlyList InputPins => inputPins; + + /// + /// Gets the read-only list of gate IDs designated as output pins. + /// public IReadOnlyList OutputPins => outputPins; + + /// + /// Gets the read-only list of nested macro instances within this definition. + /// public IReadOnlyList MacroInstances => macroInstances; + /// + /// Represents a nested macro gate instance within a circuit definition. + /// + /// The name of the macro gate to instantiate. + /// Array of gate IDs representing the input connections. + /// Array of gate IDs representing the output connections. public sealed record MacroInstanceDef(string Name, int[] Inputs, int[] Outputs); + /// + /// Adds a logic gate to the circuit definition. + /// + /// The type of gate to add. + /// The gate ID assigned to the newly created gate. public int AddGate(GateKind kind) { int id = gateKinds.Count; @@ -23,6 +57,10 @@ public sealed class CircuitDefinition return id; } + /// + /// Adds a Source gate and marks it as an input pin of this circuit. + /// + /// The gate ID of the newly created input pin. public int AddInputPin() { int id = AddGate(GateKind.Source); @@ -30,6 +68,10 @@ public sealed class CircuitDefinition return id; } + /// + /// Adds a Sink gate and marks it as an output pin of this circuit. + /// + /// The gate ID of the newly created output pin. public int AddOutputPin() { int id = AddGate(GateKind.Sink); @@ -37,6 +79,16 @@ public sealed class CircuitDefinition return id; } + /// + /// Adds a nested macro gate instance to the circuit definition. + /// Creates Buffer gates for inputs and Sink gates for outputs. + /// + /// The name of the macro gate to instantiate. + /// The number of input pins the macro requires. + /// The number of output pins the macro provides. + /// A containing the gate IDs for the instance's pins. + /// Thrown when name is null or whitespace. + /// Thrown when inputCount or outputCount is negative. public MacroInstanceDef AddMacroInstance(string name, int inputCount, int outputCount) { if (string.IsNullOrWhiteSpace(name)) @@ -65,6 +117,13 @@ public sealed class CircuitDefinition return instance; } + /// + /// Connects the output of one gate to the input of another gate. + /// + /// The gate ID whose output will be connected. + /// The gate ID that will receive the signal. + /// The input bit position (0-31) on the destination gate. + /// Thrown when gate IDs are invalid or toInputBit is not between 0 and 31. public void Connect(int fromGate, int toGate, int toInputBit) { if ((uint)fromGate >= (uint)gateKinds.Count) @@ -85,6 +144,11 @@ public sealed class CircuitDefinition connections.Add((fromGate, toGate, (byte)toInputBit)); } + /// + /// Validates the circuit definition for correctness. + /// Ensures proper gate types, valid connections, and no structural errors. + /// + /// Thrown when the circuit definition contains invalid structure or gate usage. public void Validate() { bool[] hasIncoming = new bool[gateKinds.Count]; diff --git a/StoneRed.LogicSimulator.Simulation/CycleCircuitSimulator.cs b/StoneRed.LogicSimulator.Simulation/CycleCircuitSimulator.cs index 208413b..89f4350 100644 --- a/StoneRed.LogicSimulator.Simulation/CycleCircuitSimulator.cs +++ b/StoneRed.LogicSimulator.Simulation/CycleCircuitSimulator.cs @@ -2,12 +2,25 @@ 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 = []; + /// + /// Ensures internal storage arrays are properly sized for the current gate count. + /// protected override void EnsureStorage() { base.EnsureStorage(); @@ -18,6 +31,9 @@ public sealed class CycleCircuitSimulator : SimulatorBase } } + /// + /// Resets the circuit to initial state, clearing all input and output buffers. + /// public override void Reset() { base.Reset(); @@ -25,6 +41,10 @@ public sealed class CycleCircuitSimulator : SimulatorBase Array.Clear(previousOutputMasks); } + /// + /// Executes one simulation cycle by evaluating all gates synchronously, + /// then propagating outputs to inputs for the next cycle. + /// public override void Step() { EnsureCompiled(); @@ -90,6 +110,12 @@ public sealed class CycleCircuitSimulator : SimulatorBase 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; @@ -119,6 +145,10 @@ public sealed class CycleCircuitSimulator : SimulatorBase 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"); @@ -139,6 +169,10 @@ public sealed class CycleCircuitSimulator : SimulatorBase 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(); diff --git a/StoneRed.LogicSimulator.Simulation/EventCircuitSimulator.cs b/StoneRed.LogicSimulator.Simulation/EventCircuitSimulator.cs index b6e1ce7..1172c52 100644 --- a/StoneRed.LogicSimulator.Simulation/EventCircuitSimulator.cs +++ b/StoneRed.LogicSimulator.Simulation/EventCircuitSimulator.cs @@ -2,12 +2,25 @@ using System.Linq.Expressions; namespace StoneRed.LogicSimulator.Simulation; +/// +/// An event-driven circuit simulator that uses queue-based change propagation. +/// Only gates with changed inputs are evaluated, making it efficient for circuits with localized activity. +/// +/// +/// This simulator uses a dirty-marking propagation queue. When a gate's output changes, +/// only the gates connected to it are queued for re-evaluation. This is more efficient +/// than for sparse circuits where most gates remain stable. +/// public sealed class EventCircuitSimulator : SimulatorBase { private Action[] gateEvaluators = []; private readonly Queue activeQueue = new(); private bool[] inQueue = []; + /// + /// Called when a gate is added to ensure internal arrays are properly sized. + /// + /// The ID of the newly added gate. protected override void OnGateAdded(int gateId) { if (inQueue.Length != gateKinds.Count) @@ -16,6 +29,9 @@ public sealed class EventCircuitSimulator : SimulatorBase } } + /// + /// Resets the circuit to initial state and queues all gates for initial evaluation. + /// public override void Reset() { base.Reset(); @@ -27,6 +43,10 @@ public sealed class EventCircuitSimulator : SimulatorBase } } + /// + /// Called when a source gate's value changes. Queues the source for propagation. + /// + /// The ID of the source gate that changed. protected override void OnSourceChanged(int gateId) { Enqueue(gateId); @@ -41,6 +61,10 @@ public sealed class EventCircuitSimulator : SimulatorBase } } + /// + /// Executes one simulation step by processing all pending changes in the queue. + /// Continues until the queue is empty (all changes have propagated). + /// public override void Step() { EnsureCompiled(); @@ -84,6 +108,12 @@ public sealed class EventCircuitSimulator : SimulatorBase } } + /// + /// Runs the simulation until the queue is empty (circuit is stable) or maxSteps is reached. + /// + /// Maximum number of steps to execute. + /// Output parameter containing the number of steps executed. + /// True if the circuit stabilized (queue is empty); false if maxSteps was exceeded. public override bool TryRunUntilStable(int maxSteps, out int steps) { steps = 0; @@ -106,6 +136,10 @@ public sealed class EventCircuitSimulator : SimulatorBase return activeQueue.Count == 0; } + /// + /// Compiles per-gate evaluators as separate compiled lambda expressions. + /// Each gate has its own evaluator function for efficient event-driven execution. + /// protected override void CompileEngine() { gateEvaluators = new Action[gateKinds.Count]; @@ -126,11 +160,18 @@ public sealed class EventCircuitSimulator : SimulatorBase } } + /// + /// Creates a new instance of EventCircuitSimulator for internal use (e.g., LUT computation). + /// + /// A new EventCircuitSimulator instance. protected override SimulatorBase CreateInternalSimulator() { return new EventCircuitSimulator(); } + /// + /// Ensures internal storage arrays are properly sized for the current gate count. + /// protected override void EnsureStorage() { base.EnsureStorage(); diff --git a/StoneRed.LogicSimulator.Simulation/GateKind.cs b/StoneRed.LogicSimulator.Simulation/GateKind.cs index eb0e5f3..8aea061 100644 --- a/StoneRed.LogicSimulator.Simulation/GateKind.cs +++ b/StoneRed.LogicSimulator.Simulation/GateKind.cs @@ -1,12 +1,46 @@ namespace StoneRed.LogicSimulator.Simulation; +/// +/// Defines the types of logic gates available in the circuit simulator. +/// public enum GateKind : byte { + /// + /// An input gate that can have its value set externally via . + /// Used as circuit inputs or constant values. + /// Source, + + /// + /// A NOT gate that inverts its input (0 → 1, 1 → 0). + /// Not, + + /// + /// A 2-input AND gate. Output is 1 only when both inputs are 1. + /// And2, + + /// + /// A 2-input OR gate. Output is 1 when at least one input is 1. + /// Or2, + + /// + /// A buffer gate that passes its input directly to the output. + /// Used for signal routing or as macro gate input pins. + /// Buffer, + + /// + /// A sink gate that receives input but produces no useful output. + /// Used as circuit outputs or macro gate output pins. + /// Sink, + + /// + /// A Look-Up Table gate implementing arbitrary combinational logic via a truth table. + /// Created using instead of . + /// Lut, } diff --git a/StoneRed.LogicSimulator.Simulation/ICircuitSimulator.cs b/StoneRed.LogicSimulator.Simulation/ICircuitSimulator.cs index f7ea9c5..4cd9521 100644 --- a/StoneRed.LogicSimulator.Simulation/ICircuitSimulator.cs +++ b/StoneRed.LogicSimulator.Simulation/ICircuitSimulator.cs @@ -1,16 +1,69 @@ namespace StoneRed.LogicSimulator.Simulation; /// -/// Represents a digital logic simulator. +/// Represents a digital logic circuit simulator that supports combinational logic gates, +/// look-up tables (LUTs), and hierarchical macro gates. /// public interface ICircuitSimulator { + /// + /// Gets the total number of gates in the circuit. + /// int GateCount { get; } + + /// + /// Adds a logic gate to the circuit. + /// + /// The type of gate to add (NOT, AND, OR, etc.). + /// The unique identifier of the newly created gate. + /// Thrown when attempting to add a LUT gate using this method. Use instead. int AddGate(GateKind kind); + + /// + /// Adds a Look-Up Table (LUT) gate that implements arbitrary combinational logic. + /// + /// The number of inputs (0-30). + /// The truth table array. Length must be 2^inputCount. Each element is the output (0 or 1) for the corresponding input pattern. + /// The unique identifier of the newly created LUT gate. + /// Thrown when inputCount is not between 0 and 30. + /// Thrown when table is null. + /// Thrown when table length doesn't match 2^inputCount. int AddLutGate(int inputCount, int[] table); + + /// + /// Connects the output of one gate to the input of another gate. + /// A single output can be connected to multiple inputs (fan-out). + /// + /// The gate ID whose output will be connected. + /// The gate ID that will receive the signal. + /// The input bit position (0-31) on the destination gate. + /// Thrown when gate IDs are invalid or toInputBit is not between 0 and 31. void ConnectGates(int fromGate, int toGate, int toInputBit); + + /// + /// Registers a reusable circuit definition as a macro gate that can be instantiated multiple times. + /// + /// The unique name for this macro gate. + /// The circuit definition containing gates and connections. void RegisterMacroGate(string name, CircuitDefinition definition); + + /// + /// Computes and caches a Look-Up Table representation of a registered macro gate for optimization. + /// This converts the macro's combinational logic into a truth table for faster simulation. + /// + /// The name of the registered macro gate. + /// Maximum simulation steps allowed to compute each output pattern. Default is 4096. + /// True if the LUT was successfully computed; false if the circuit didn't stabilize within maxSteps. + /// Thrown when the macro name is not registered. bool ComputeLut(string name, int maxSteps = 4096); + + /// + /// Adds an instance of a registered macro gate to the circuit. + /// If a LUT has been computed for this macro, the optimized version is used. + /// + /// The name of the registered macro gate. + /// A containing the gate IDs of the instance's inputs and outputs. + /// Thrown when the macro name is not registered. MacroInstance AddMacroGate(string name); /// @@ -20,10 +73,54 @@ public interface ICircuitSimulator /// void Reset(); + /// + /// Sets the input signal value on a Source gate. + /// Only gates of type can have their values set. + /// + /// The gate ID of the source gate. + /// The boolean value to set (true = 1, false = 0). + /// Thrown when gateId is invalid. + /// Thrown when the gate is not a Source gate. void SetSource(int gateId, bool value); + + /// + /// Reads the current output signal of a gate. + /// + /// The gate ID to read from. + /// True if the output is 1, false if 0. bool GetOutput(int gateId); + + /// + /// Executes one simulation step. The behavior depends on the implementation: + /// - EventCircuitSimulator: Processes all pending changes in the propagation queue. + /// - CycleCircuitSimulator: Evaluates all gates once synchronously. + /// void Step(); + + /// + /// Runs the simulation until all signals stabilize (no more changes occur). + /// + /// Maximum number of steps to execute before timing out. Default is 1024. + /// The number of steps executed before stabilization. + /// Thrown when the circuit does not stabilize within maxSteps. int RunUntilStable(int maxSteps = 1024); + + /// + /// Attempts to run the simulation until all signals stabilize. + /// + /// Maximum number of steps to execute. + /// Output parameter containing the number of steps executed. + /// True if the circuit stabilized; false if maxSteps was exceeded. bool TryRunUntilStable(int maxSteps, out int steps); + + /// + /// Subscribes to output changes on a specific gate. + /// The callback is invoked whenever the gate's output value changes. + /// + /// The gate ID to watch. + /// Action to invoke on change. Parameters are (gateId, newOutputMask). + /// An that unsubscribes the watcher when disposed. + /// Thrown when callback is null. + /// Thrown when gateId is invalid. IDisposable WatchGate(int gateId, Action callback); } diff --git a/StoneRed.LogicSimulator.Simulation/MacroInstance.cs b/StoneRed.LogicSimulator.Simulation/MacroInstance.cs index d6a761c..0b598c9 100644 --- a/StoneRed.LogicSimulator.Simulation/MacroInstance.cs +++ b/StoneRed.LogicSimulator.Simulation/MacroInstance.cs @@ -1,3 +1,10 @@ namespace StoneRed.LogicSimulator.Simulation; +/// +/// Represents an instance of a macro gate added to the circuit. +/// Contains the gate IDs of the instance's input and output pins. +/// +/// The name of the macro gate definition. +/// Array of gate IDs representing the input pins of this instance. +/// Array of gate IDs representing the output pins of this instance. public sealed record MacroInstance(string Name, int[] Inputs, int[] Outputs); diff --git a/StoneRed.LogicSimulator.Simulation/SimulatorBase.cs b/StoneRed.LogicSimulator.Simulation/SimulatorBase.cs index 56c9a6e..5a45d46 100644 --- a/StoneRed.LogicSimulator.Simulation/SimulatorBase.cs +++ b/StoneRed.LogicSimulator.Simulation/SimulatorBase.cs @@ -2,6 +2,10 @@ using System.Linq.Expressions; namespace StoneRed.LogicSimulator.Simulation; +/// +/// Abstract base class providing common functionality for circuit simulator implementations. +/// Handles gate storage, connections, macro gates, LUT compilation, and gate watching. +/// public abstract class SimulatorBase : ICircuitSimulator { protected readonly List gateKinds = []; @@ -31,12 +35,33 @@ public abstract class SimulatorBase : ICircuitSimulator protected bool hasAnyWatchers; protected int nextWatcherId; + /// + /// Internal record representing a gate watcher subscription. + /// + /// Unique identifier for this watcher. + /// The gate being watched. + /// The callback to invoke on changes. protected sealed record GateWatcherEntry(int Id, int GateId, Action Callback); + + /// + /// Internal record representing a compiled LUT for a macro gate. + /// + /// Number of input pins. + /// Number of output pins. + /// Truth tables for each output (indexed by input pattern). protected sealed record MacroLut(int InputCount, int OutputCount, int[][] OutputTables); + + /// + /// Internal record storing macro gate definition and optional compiled LUT. + /// + /// The circuit definition of the macro. + /// Optional compiled LUT representation for optimization. protected sealed record MacroInfo(CircuitDefinition Definition, MacroLut? Lut); + /// public int GateCount => gateKinds.Count; + /// public int AddGate(GateKind kind) { if (kind == GateKind.Lut) @@ -53,8 +78,14 @@ public abstract class SimulatorBase : ICircuitSimulator return id; } + /// + /// Called when a gate is added. Override to perform implementation-specific initialization. + /// + /// The ID of the newly added gate. protected virtual void OnGateAdded(int gateId) { } + /// + /// public int AddLutGate(int inputCount, int[] table) { if (inputCount is < 0 or > 30) @@ -77,6 +108,7 @@ public abstract class SimulatorBase : ICircuitSimulator return id; } + /// public void ConnectGates(int fromGate, int toGate, int toInputBit) { if ((uint)fromGate >= (uint)gateKinds.Count) @@ -99,6 +131,7 @@ public abstract class SimulatorBase : ICircuitSimulator initialized = false; } + /// public void RegisterMacroGate(string name, CircuitDefinition definition) { definition.Validate(); @@ -107,6 +140,7 @@ public abstract class SimulatorBase : ICircuitSimulator initialized = false; } + /// public virtual void Reset() { EnsureStorage(); @@ -116,9 +150,13 @@ public abstract class SimulatorBase : ICircuitSimulator initialized = true; } + /// public abstract void Step(); + + /// public abstract bool TryRunUntilStable(int maxSteps, out int steps); + /// public int RunUntilStable(int maxSteps = 1024) { if (!TryRunUntilStable(maxSteps, out int steps)) @@ -128,6 +166,7 @@ public abstract class SimulatorBase : ICircuitSimulator return steps; } + /// public virtual void SetSource(int gateId, bool value) { EnsureStorage(); @@ -150,14 +189,21 @@ public abstract class SimulatorBase : ICircuitSimulator } } + /// + /// Called when a source gate's value changes. Override to perform implementation-specific handling. + /// + /// The ID of the source gate that changed. protected virtual void OnSourceChanged(int gateId) { } + /// public bool GetOutput(int gateId) { EnsureStorage(); return (outputMasks[gateId] & 1) != 0; } + /// + /// public IDisposable WatchGate(int gateId, Action callback) { ArgumentNullException.ThrowIfNull(callback); @@ -199,6 +245,10 @@ public abstract class SimulatorBase : ICircuitSimulator hasAnyWatchers = allWatchers.Count > 0; } + /// + /// Notifies all registered watchers of gates that changed between the previous and current output states. + /// + /// The output states from before the change. protected void NotifyAllWatchers(int[] previousOutputMasks) { for (int i = 0; i < gatesWithWatchers.Length; i++) @@ -216,6 +266,10 @@ public abstract class SimulatorBase : ICircuitSimulator } } + /// + /// Notifies watchers of a specific gate that its output has changed. + /// + /// The ID of the gate that changed. protected void NotifyGateWatchers(int gateId) { if (gateId >= watcherCache.Length) @@ -236,6 +290,9 @@ public abstract class SimulatorBase : ICircuitSimulator } } + /// + /// Ensures that internal storage arrays are allocated and sized correctly for the current gate count. + /// protected virtual void EnsureStorage() { int n = gateKinds.Count; @@ -250,6 +307,10 @@ public abstract class SimulatorBase : ICircuitSimulator sourceInitialized = new bool[n]; } + /// + /// Ensures the simulator is compiled (netlist, LUTs, and engine are ready). + /// Triggers compilation if not already done. + /// protected void EnsureCompiled() { EnsureStorage(); @@ -264,8 +325,31 @@ public abstract class SimulatorBase : ICircuitSimulator compiled = true; } + /// + /// Compiles the simulation engine. Implemented by derived classes to build their specific evaluation logic. + /// protected abstract void CompileEngine(); + /// + /// Generates the expression tree for evaluating a single gate's logic. + /// Used during compilation to build gate evaluators. + /// + /// The ID of the gate to generate logic for. + /// Expression representing the gate's input mask. + /// Expression representing the source states array. + /// Expression representing the gate index. + /// Expression representing the LUT data array. + /// An expression that evaluates to the gate's output value. + /// + /// Generates the expression tree for evaluating a single gate's logic. + /// Used during compilation to build gate evaluators. + /// + /// The ID of the gate to generate logic for. + /// Expression representing the gate's input mask. + /// Expression representing the source states array. + /// Expression representing the gate index. + /// Expression representing the LUT data array. + /// An expression that evaluates to the gate's output value. protected Expression GenerateGateLogic( int gateId, Expression inMask, @@ -286,6 +370,10 @@ public abstract class SimulatorBase : ICircuitSimulator }; } + /// + /// Compiles the connection netlist into optimized adjacency list structures for fast propagation. + /// Creates edgeStart, edgeToGate, and edgeToInputBit arrays. + /// private void CompileNetlist() { int n = gateKinds.Count; @@ -311,6 +399,10 @@ public abstract class SimulatorBase : ICircuitSimulator } } + /// + /// Compiles LUT gate data into flat arrays for efficient lookup during simulation. + /// Creates lutOffsets, lutMasks, and lutData arrays. + /// private void CompileLuts() { int n = gateKinds.Count; @@ -344,6 +436,7 @@ public abstract class SimulatorBase : ICircuitSimulator } } + /// public bool ComputeLut(string name, int maxSteps = 4096) { if (!macroGates.TryGetValue(name, out MacroInfo? macro)) @@ -358,8 +451,25 @@ public abstract class SimulatorBase : ICircuitSimulator return lut is not null; } + /// + /// Creates an internal simulator instance for LUT computation or other internal operations. + /// Implemented by derived classes to return the appropriate simulator type. + /// + /// A new simulator instance of the same type as the current implementation. protected abstract SimulatorBase CreateInternalSimulator(); + /// + /// Attempts to build a LUT representation of a macro gate by simulating all input patterns. + /// + /// The circuit definition to convert to LUT. + /// Maximum steps per pattern simulation. + /// A MacroLut if successful; null if the circuit didn't stabilize for any pattern. + /// + /// Attempts to build a LUT representation of a macro gate by simulating all input patterns. + /// + /// The circuit definition to convert to LUT. + /// Maximum steps per pattern simulation. + /// A MacroLut if successful; null if the circuit didn't stabilize for any pattern. private MacroLut? TryBuildMacroLut(CircuitDefinition definition, int maxSteps) { int inputCount = definition.InputPins.Count; @@ -407,6 +517,7 @@ public abstract class SimulatorBase : ICircuitSimulator return new MacroLut(inputCount, outputCount, outputTables); } + /// public MacroInstance AddMacroGate(string name) { if (!macroGates.TryGetValue(name, out MacroInfo? macro)) @@ -425,6 +536,13 @@ public abstract class SimulatorBase : ICircuitSimulator return new MacroInstance(name, MapPins(macro.Definition.InputPins, map), MapPins(macro.Definition.OutputPins, map)); } + /// + /// Adds a macro gate instance using its pre-computed LUT representation. + /// Creates buffer gates for inputs and LUT gates for each output. + /// + /// The name of the macro gate. + /// The compiled LUT data. + /// A MacroInstance with the input and output gate IDs. private MacroInstance AddMacroGateFromLut(string name, MacroLut lut) { int[] inputs = new int[lut.InputCount]; @@ -449,6 +567,14 @@ public abstract class SimulatorBase : ICircuitSimulator return new MacroInstance(name, inputs, outputs); } + /// + /// Copies gates and connections from a circuit definition to a simulator instance. + /// Handles macro instances recursively and maps gate IDs appropriately. + /// + /// The simulator to copy gates and connections to. + /// The circuit definition to copy from. + /// Function to transform gate kinds during copying (e.g., Source to Buffer). + /// An array mapping original gate IDs to new gate IDs in the destination. protected static int[] CopyDefinitionGatesAndConnections(SimulatorBase destination, CircuitDefinition definition, Func mapKind) { int gateCount = definition.GateKinds.Count; @@ -486,6 +612,12 @@ public abstract class SimulatorBase : ICircuitSimulator return map; } + /// + /// Maps a list of pin IDs from one gate ID space to another using a mapping array. + /// + /// The original pin IDs. + /// The ID mapping array. + /// An array of mapped pin IDs. protected static int[] MapPins(IReadOnlyList pins, int[] map) { int[] result = new int[pins.Count]; @@ -497,6 +629,9 @@ public abstract class SimulatorBase : ICircuitSimulator return result; } + /// + /// Internal class implementing IDisposable for gate watcher unsubscription. + /// private sealed class GateWatcherSubscription(SimulatorBase simulator, int id) : IDisposable { public void Dispose()