Add new cycle and event based simulator for better performance and associated unit tests

This commit is contained in:
Stone_Red
2026-03-26 01:16:24 +01:00
parent b1b71a2392
commit aa6d13a46c
17 changed files with 1386 additions and 793 deletions
@@ -0,0 +1,157 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using StoneRed.LogicSimulator.Simulation;
namespace StoneRed.LogicSimulator.Tests;
[TestClass]
public class CycleSimulatorTests : SimulatorTestsBase
{
protected override ICircuitSimulator CreateSimulator()
{
return new CycleCircuitSimulator();
}
}
[TestClass]
public class EventSimulatorTests : SimulatorTestsBase
{
protected override ICircuitSimulator CreateSimulator()
{
return new EventCircuitSimulator();
}
}
public abstract class SimulatorTestsBase
{
protected abstract ICircuitSimulator CreateSimulator();
[TestMethod]
public void TestAndGate()
{
ICircuitSimulator sim = CreateSimulator();
int s1 = sim.AddGate(GateKind.Source);
int s2 = sim.AddGate(GateKind.Source);
int and = sim.AddGate(GateKind.And2);
int sink = sim.AddGate(GateKind.Sink);
sim.ConnectGates(s1, and, 0);
sim.ConnectGates(s2, and, 1);
sim.ConnectGates(and, sink, 0);
void Check(bool i1, bool i2, bool expected)
{
sim.SetSource(s1, i1);
sim.SetSource(s2, i2);
_ = sim.RunUntilStable();
Assert.AreEqual(expected, sim.GetOutput(sink), $"AND2 failed for {i1} & {i2}");
}
sim.Reset();
Check(false, false, false);
Check(false, true, false);
Check(true, false, false);
Check(true, true, true);
}
[TestMethod]
public void TestOrGate()
{
ICircuitSimulator sim = CreateSimulator();
int s1 = sim.AddGate(GateKind.Source);
int s2 = sim.AddGate(GateKind.Source);
int or = sim.AddGate(GateKind.Or2);
int sink = sim.AddGate(GateKind.Sink);
sim.ConnectGates(s1, or, 0);
sim.ConnectGates(s2, or, 1);
sim.ConnectGates(or, sink, 0);
void Check(bool i1, bool i2, bool expected)
{
sim.SetSource(s1, i1);
sim.SetSource(s2, i2);
_ = sim.RunUntilStable();
Assert.AreEqual(expected, sim.GetOutput(sink), $"OR2 failed for {i1} | {i2}");
}
sim.Reset();
Check(false, false, false);
Check(false, true, true);
Check(true, false, true);
Check(true, true, true);
}
[TestMethod]
public void TestNotGate()
{
ICircuitSimulator sim = CreateSimulator();
int s1 = sim.AddGate(GateKind.Source);
int not = sim.AddGate(GateKind.Not);
int sink = sim.AddGate(GateKind.Sink);
sim.ConnectGates(s1, not, 0);
sim.ConnectGates(not, sink, 0);
sim.Reset();
sim.SetSource(s1, false);
_ = sim.RunUntilStable();
Assert.IsTrue(sim.GetOutput(sink), "NOT(0) should be 1");
sim.SetSource(s1, true);
_ = sim.RunUntilStable();
Assert.IsFalse(sim.GetOutput(sink), "NOT(1) should be 0");
}
[TestMethod]
public void TestLutGate()
{
ICircuitSimulator sim = CreateSimulator();
int s1 = sim.AddGate(GateKind.Source);
int s2 = sim.AddGate(GateKind.Source);
int s3 = sim.AddGate(GateKind.Source);
// Majority function (2 or more high)
int[] table = { 0, 0, 0, 1, 0, 1, 1, 1 };
int lut = sim.AddLutGate(3, table);
int sink = sim.AddGate(GateKind.Sink);
sim.ConnectGates(s1, lut, 0);
sim.ConnectGates(s2, lut, 1);
sim.ConnectGates(s3, lut, 2);
sim.ConnectGates(lut, sink, 0);
sim.Reset();
_ = sim.RunUntilStable();
sim.SetSource(s1, true); sim.SetSource(s2, true); sim.SetSource(s3, false);
_ = sim.RunUntilStable();
Assert.IsTrue(sim.GetOutput(sink), "Majority(1,1,0) should be 1");
sim.SetSource(s1, false); sim.SetSource(s2, true); sim.SetSource(s3, false);
_ = sim.RunUntilStable();
Assert.IsFalse(sim.GetOutput(sink), "Majority(0,1,0) should be 0");
}
[TestMethod]
public void TestMacroCorrectness()
{
ICircuitSimulator sim = CreateSimulator();
CircuitDefinition def = new CircuitDefinition();
int inPin = def.AddInputPin();
int not = def.AddGate(GateKind.Not);
int outPin = def.AddOutputPin();
def.Connect(inPin, not, 0);
def.Connect(not, outPin, 0);
sim.RegisterMacroGate("NOT", def);
MacroInstance inst = sim.AddMacroGate("NOT");
int src = sim.AddGate(GateKind.Source);
int sink = sim.AddGate(GateKind.Sink);
sim.ConnectGates(src, inst.Inputs[0], 0);
sim.ConnectGates(inst.Outputs[0], sink, 0);
sim.Reset();
sim.SetSource(src, true);
_ = sim.RunUntilStable();
Assert.IsFalse(sim.GetOutput(sink), "Macro NOT(1) should be 0");
}
}