mirror of
https://github.com/Stone-Red-Code/StoneRed.LogicSimulator.git
synced 2026-09-04 09:06:29 +02:00
Add XML docs
This commit is contained in:
@@ -2,6 +2,10 @@ using System.Linq.Expressions;
|
||||
|
||||
namespace StoneRed.LogicSimulator.Simulation;
|
||||
|
||||
/// <summary>
|
||||
/// Abstract base class providing common functionality for circuit simulator implementations.
|
||||
/// Handles gate storage, connections, macro gates, LUT compilation, and gate watching.
|
||||
/// </summary>
|
||||
public abstract class SimulatorBase : ICircuitSimulator
|
||||
{
|
||||
protected readonly List<GateKind> gateKinds = [];
|
||||
@@ -31,12 +35,33 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
protected bool hasAnyWatchers;
|
||||
protected int nextWatcherId;
|
||||
|
||||
/// <summary>
|
||||
/// Internal record representing a gate watcher subscription.
|
||||
/// </summary>
|
||||
/// <param name="Id">Unique identifier for this watcher.</param>
|
||||
/// <param name="GateId">The gate being watched.</param>
|
||||
/// <param name="Callback">The callback to invoke on changes.</param>
|
||||
protected sealed record GateWatcherEntry(int Id, int GateId, Action<int, int> Callback);
|
||||
|
||||
/// <summary>
|
||||
/// Internal record representing a compiled LUT for a macro gate.
|
||||
/// </summary>
|
||||
/// <param name="InputCount">Number of input pins.</param>
|
||||
/// <param name="OutputCount">Number of output pins.</param>
|
||||
/// <param name="OutputTables">Truth tables for each output (indexed by input pattern).</param>
|
||||
protected sealed record MacroLut(int InputCount, int OutputCount, int[][] OutputTables);
|
||||
|
||||
/// <summary>
|
||||
/// Internal record storing macro gate definition and optional compiled LUT.
|
||||
/// </summary>
|
||||
/// <param name="Definition">The circuit definition of the macro.</param>
|
||||
/// <param name="Lut">Optional compiled LUT representation for optimization.</param>
|
||||
protected sealed record MacroInfo(CircuitDefinition Definition, MacroLut? Lut);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int GateCount => gateKinds.Count;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int AddGate(GateKind kind)
|
||||
{
|
||||
if (kind == GateKind.Lut)
|
||||
@@ -53,8 +78,14 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
return id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a gate is added. Override to perform implementation-specific initialization.
|
||||
/// </summary>
|
||||
/// <param name="gateId">The ID of the newly added gate.</param>
|
||||
protected virtual void OnGateAdded(int gateId) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <inheritdoc/>
|
||||
public int AddLutGate(int inputCount, int[] table)
|
||||
{
|
||||
if (inputCount is < 0 or > 30)
|
||||
@@ -77,6 +108,7 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
return id;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RegisterMacroGate(string name, CircuitDefinition definition)
|
||||
{
|
||||
definition.Validate();
|
||||
@@ -107,6 +140,7 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void Reset()
|
||||
{
|
||||
EnsureStorage();
|
||||
@@ -116,9 +150,13 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract void Step();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public abstract bool TryRunUntilStable(int maxSteps, out int steps);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int RunUntilStable(int maxSteps = 1024)
|
||||
{
|
||||
if (!TryRunUntilStable(maxSteps, out int steps))
|
||||
@@ -128,6 +166,7 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
return steps;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public virtual void SetSource(int gateId, bool value)
|
||||
{
|
||||
EnsureStorage();
|
||||
@@ -150,14 +189,21 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a source gate's value changes. Override to perform implementation-specific handling.
|
||||
/// </summary>
|
||||
/// <param name="gateId">The ID of the source gate that changed.</param>
|
||||
protected virtual void OnSourceChanged(int gateId) { }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool GetOutput(int gateId)
|
||||
{
|
||||
EnsureStorage();
|
||||
return (outputMasks[gateId] & 1) != 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
/// <inheritdoc/>
|
||||
public IDisposable WatchGate(int gateId, Action<int, int> callback)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(callback);
|
||||
@@ -199,6 +245,10 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
hasAnyWatchers = allWatchers.Count > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Notifies all registered watchers of gates that changed between the previous and current output states.
|
||||
/// </summary>
|
||||
/// <param name="previousOutputMasks">The output states from before the change.</param>
|
||||
protected void NotifyAllWatchers(int[] previousOutputMasks)
|
||||
{
|
||||
for (int i = 0; i < gatesWithWatchers.Length; i++)
|
||||
@@ -216,6 +266,10 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Notifies watchers of a specific gate that its output has changed.
|
||||
/// </summary>
|
||||
/// <param name="gateId">The ID of the gate that changed.</param>
|
||||
protected void NotifyGateWatchers(int gateId)
|
||||
{
|
||||
if (gateId >= watcherCache.Length)
|
||||
@@ -236,6 +290,9 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that internal storage arrays are allocated and sized correctly for the current gate count.
|
||||
/// </summary>
|
||||
protected virtual void EnsureStorage()
|
||||
{
|
||||
int n = gateKinds.Count;
|
||||
@@ -250,6 +307,10 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
sourceInitialized = new bool[n];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures the simulator is compiled (netlist, LUTs, and engine are ready).
|
||||
/// Triggers compilation if not already done.
|
||||
/// </summary>
|
||||
protected void EnsureCompiled()
|
||||
{
|
||||
EnsureStorage();
|
||||
@@ -264,8 +325,31 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
compiled = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compiles the simulation engine. Implemented by derived classes to build their specific evaluation logic.
|
||||
/// </summary>
|
||||
protected abstract void CompileEngine();
|
||||
|
||||
/// <summary>
|
||||
/// Generates the expression tree for evaluating a single gate's logic.
|
||||
/// Used during compilation to build gate evaluators.
|
||||
/// </summary>
|
||||
/// <param name="gateId">The ID of the gate to generate logic for.</param>
|
||||
/// <param name="inMask">Expression representing the gate's input mask.</param>
|
||||
/// <param name="sourcesParam">Expression representing the source states array.</param>
|
||||
/// <param name="indexExpr">Expression representing the gate index.</param>
|
||||
/// <param name="lutDataConst">Expression representing the LUT data array.</param>
|
||||
/// <returns>An expression that evaluates to the gate's output value.</returns>
|
||||
/// <summary>
|
||||
/// Generates the expression tree for evaluating a single gate's logic.
|
||||
/// Used during compilation to build gate evaluators.
|
||||
/// </summary>
|
||||
/// <param name="gateId">The ID of the gate to generate logic for.</param>
|
||||
/// <param name="inMask">Expression representing the gate's input mask.</param>
|
||||
/// <param name="sourcesParam">Expression representing the source states array.</param>
|
||||
/// <param name="indexExpr">Expression representing the gate index.</param>
|
||||
/// <param name="lutDataConst">Expression representing the LUT data array.</param>
|
||||
/// <returns>An expression that evaluates to the gate's output value.</returns>
|
||||
protected Expression GenerateGateLogic(
|
||||
int gateId,
|
||||
Expression inMask,
|
||||
@@ -286,6 +370,10 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compiles the connection netlist into optimized adjacency list structures for fast propagation.
|
||||
/// Creates edgeStart, edgeToGate, and edgeToInputBit arrays.
|
||||
/// </summary>
|
||||
private void CompileNetlist()
|
||||
{
|
||||
int n = gateKinds.Count;
|
||||
@@ -311,6 +399,10 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compiles LUT gate data into flat arrays for efficient lookup during simulation.
|
||||
/// Creates lutOffsets, lutMasks, and lutData arrays.
|
||||
/// </summary>
|
||||
private void CompileLuts()
|
||||
{
|
||||
int n = gateKinds.Count;
|
||||
@@ -344,6 +436,7 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an internal simulator instance for LUT computation or other internal operations.
|
||||
/// Implemented by derived classes to return the appropriate simulator type.
|
||||
/// </summary>
|
||||
/// <returns>A new simulator instance of the same type as the current implementation.</returns>
|
||||
protected abstract SimulatorBase CreateInternalSimulator();
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to build a LUT representation of a macro gate by simulating all input patterns.
|
||||
/// </summary>
|
||||
/// <param name="definition">The circuit definition to convert to LUT.</param>
|
||||
/// <param name="maxSteps">Maximum steps per pattern simulation.</param>
|
||||
/// <returns>A MacroLut if successful; null if the circuit didn't stabilize for any pattern.</returns>
|
||||
/// <summary>
|
||||
/// Attempts to build a LUT representation of a macro gate by simulating all input patterns.
|
||||
/// </summary>
|
||||
/// <param name="definition">The circuit definition to convert to LUT.</param>
|
||||
/// <param name="maxSteps">Maximum steps per pattern simulation.</param>
|
||||
/// <returns>A MacroLut if successful; null if the circuit didn't stabilize for any pattern.</returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
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));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a macro gate instance using its pre-computed LUT representation.
|
||||
/// Creates buffer gates for inputs and LUT gates for each output.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the macro gate.</param>
|
||||
/// <param name="lut">The compiled LUT data.</param>
|
||||
/// <returns>A MacroInstance with the input and output gate IDs.</returns>
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies gates and connections from a circuit definition to a simulator instance.
|
||||
/// Handles macro instances recursively and maps gate IDs appropriately.
|
||||
/// </summary>
|
||||
/// <param name="destination">The simulator to copy gates and connections to.</param>
|
||||
/// <param name="definition">The circuit definition to copy from.</param>
|
||||
/// <param name="mapKind">Function to transform gate kinds during copying (e.g., Source to Buffer).</param>
|
||||
/// <returns>An array mapping original gate IDs to new gate IDs in the destination.</returns>
|
||||
protected static int[] CopyDefinitionGatesAndConnections(SimulatorBase destination, CircuitDefinition definition, Func<int, GateKind, GateKind> mapKind)
|
||||
{
|
||||
int gateCount = definition.GateKinds.Count;
|
||||
@@ -486,6 +612,12 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
return map;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps a list of pin IDs from one gate ID space to another using a mapping array.
|
||||
/// </summary>
|
||||
/// <param name="pins">The original pin IDs.</param>
|
||||
/// <param name="map">The ID mapping array.</param>
|
||||
/// <returns>An array of mapped pin IDs.</returns>
|
||||
protected static int[] MapPins(IReadOnlyList<int> pins, int[] map)
|
||||
{
|
||||
int[] result = new int[pins.Count];
|
||||
@@ -497,6 +629,9 @@ public abstract class SimulatorBase : ICircuitSimulator
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal class implementing IDisposable for gate watcher unsubscription.
|
||||
/// </summary>
|
||||
private sealed class GateWatcherSubscription(SimulatorBase simulator, int id) : IDisposable
|
||||
{
|
||||
public void Dispose()
|
||||
|
||||
Reference in New Issue
Block a user