Fanout 0.1.0

dotnet add package Fanout --version 0.1.0
                    
NuGet\Install-Package Fanout -Version 0.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Fanout" Version="0.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Fanout" Version="0.1.0" />
                    
Directory.Packages.props
<PackageReference Include="Fanout" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Fanout --version 0.1.0
                    
#r "nuget: Fanout, 0.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Fanout@0.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Fanout&version=0.1.0
                    
Install as a Cake Addin
#tool nuget:?package=Fanout&version=0.1.0
                    
Install as a Cake Tool

Fanout

A gate-level digital logic simulator for .NET. Eight primitive gates, three-valued logic, and an event-driven propagation loop — and everything else in the library, up to shift registers and ripple counters, is built from nothing but those gates wired together.

CI NuGet License: MIT

Documentación en castellano: es/README.md.

What it is

Fanout simulates a circuit the way the circuit actually behaves: a value changes on a wire, the gates that wire reaches are re-evaluated, and whatever changes as a result propagates onward, until nothing is changing any more. There is no clock in the simulator, no time step, and no event calendar. There is a queue of gates that have something new to look at.

What makes that work is the third logic state. Every wire starts unknown, not zero, and a gate is evaluated only once it has enough information to produce an answer. "Enough" is less than "all", which is the interesting part:

An AND gate with one input already low has a known output. It does not wait for the others.

That single rule — evaluate on a controlling value — is why a circuit can settle with half of it still undriven, why a cross-coupled latch resolves the moment one side is forced, and why the simulator can tell you that a latch has no state yet instead of quietly inventing a zero.

Install

dotnet add package Fanout

A first circuit

using Fanout;
using Fanout.Combinational;

var circuit = new Circuit();
var adder = new RippleCarryAdder(width: 4);

// Top-level ports, wired to the adder's named inputs.
var a = new Port[4];
var b = new Port[4];

for (int i = 0; i < 4; i++)
{
    a[i] = circuit.AddInput();
    a[i].ConnectTo(adder, "A", i);

    b[i] = circuit.AddInput();
    b[i].ConnectTo(adder, "B", i);
}

var carryIn = circuit.AddInput();
carryIn.ConnectTo(adder, "CIN");

// Drive 9 + 6 + 0 and settle.
SetBus(a, 9);
SetBus(b, 6);
carryIn.SetState(LogicState.Zero);

int rounds = circuit.Run();

// SUM = 1111, COUT = 0, settled in `rounds` propagation rounds.
Console.WriteLine(adder.Output("SUM", 3).State);   // One
Console.WriteLine(adder.Output("COUT").State);     // Zero

static void SetBus(Port[] bus, int value)
{
    for (int i = 0; i < bus.Length; i++)
    {
        bus[i].SetState(((value >> i) & 1) == 0 ? LogicState.Zero : LogicState.One);
    }
}

dotnet run --project samples/Fanout.Demo runs a longer version of this: an adder, a counter, a shift register, and a table of how propagation depth grows with a carry chain.

What is in the box

Namespace Contents
Fanout LogicState, Gate, InputPin, OutputPin, Net, Port, Module, Circuit, ModuleLayout
Fanout.Gates And, Or, Not, Nand, Nor, Xor, Xnor, BufferGate
Fanout.Combinational FullAdder, RippleCarryAdder, AddSubtractor, Multiplexer, Demultiplexer
Fanout.Sequential NandSRLatch, NorSRLatch, DLatch, DLatchPrimitive, DFlipFlop, SimpleDFlipFlop, TFlipFlop, SimpleTFlipFlop, JKFlipFlop, SimpleJKFlipFlop, ShiftRegister, ParallelRegister, ShiftLoadRegister, RippleCounter

Every block above the gate level is assembled from gates and from other blocks — the JK flip-flop is eight NANDs, an AND and two inverters, and the ripple counter is a chain of those. Nothing is shortcut with behavioural code, with one deliberate exception (DLatchPrimitive) kept as the worked example of extending Gate directly.

Documentation

What it is good for, and what it is not

It is good for understanding and for building circuits you can reason about: a teaching aid, a reference implementation, a way to check that a design does what you drew. The blocks are small enough to read end to end, and the propagation rule is one paragraph long.

It is not a production EDA tool. It has no timing model, so a real circuit's hazards and glitches are invisible here — Run reports the settled result and nothing else. It has no multi-driver resolution, no high-impedance state, and no netlist import. And it holds every gate as a graph of .NET objects, which puts a practical ceiling on circuit size well below what a packed representation would reach. docs/scaling.md works that number out honestly rather than leaving it implied.

Provenance

The original was written in 2005 against .NET 2.0 and Visual Studio 2005, and sat unpublished for twenty years. This release ports it to .NET 8, translates it to English, replaces the non-generic collections, fixes the defects listed in CHANGELOG.md, and adds the test suite it never had. The propagation design — three states, controlling-value evaluation, the double-buffered work queue — is unchanged, because it was right the first time.

Licence

MIT. See LICENSE.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0 107 9/11/2026

First public release: a .NET 8 port of a gate-level digital logic simulator written in 2005. Full changelog: https://github.com/diegolarrosa/Fanout/blob/main/CHANGELOG.md