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()