Skip to content

Instantly share code, notes, and snippets.

@occar421
Last active August 29, 2015 14:08
Show Gist options
  • Save occar421/ecacb956eea12b840f3c to your computer and use it in GitHub Desktop.
Save occar421/ecacb956eea12b840f3c to your computer and use it in GitHub Desktop.
Reactive Extensions Logic Circuit 3

Reactive Extension Logic Circuit 3

Summary

This Gist is experimental logic circuit description with C#.
I think, using Reactive Extension(Rx), we can write electrical circuit easily.
Previous Gist Code

Files

LogicLine.cs

This class means logic wire. Logic gates are defined as operator override. "Vcc" and "GND" are defined. Factory method "CreateWithDefault" also defined.

Bus.cs

This class means logic bus, set of ligic wire. Logic gates, Vcc, GND and factory methods are defined like LogicLine class. Notice : Using ImmutableArray, Immuable Collection Package is required.

Component

If we define component once, we can use it everywhere.

  • HalfAdder.cs FullAdder.cs
    Half Adder and Full Adder are simple combinational logic circuits.
  • NbitAdder.cs
    NbitAdder is a group of FullAdder. Input and Output are Bus.
  • Selector.cs
    Selector is a simple selector. Nbit Selector is simple, too.

Circuit.cs

Circuit description sample. bus A, B are changed by timer and circuit results are changed immediately.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reactive.Linq;
using System.Collections.Immutable;
namespace LogicCircuit
{
using IBus = ImmutableArray<LogicLine>;
class Bus : IEnumerable<LogicLine>
{
IBus bus;
public Bus(IBus bus)
{
this.bus = bus;
}
public Bus(params LogicLine[] signals)
{
this.bus = ImmutableArray.Create(signals);
}
public Bus(Bus bus) : this(bus.ToArray()) { }
public LogicLine this[int index]
{
get
{
return bus[index];
}
}
public int Length
{
get
{
return bus.Length;
}
}
static public Bus CreateWithDefault(IList<bool> def, IList<LogicLine> stream)
{
if (def.Count != stream.Count)
{
throw new RankException();
}
return new Bus(stream.Select((x, i) => LogicLine.CreateWithDefault(def[i], x)).ToImmutableArray());
}
static public Bus Vcc(int length)
{
return new Bus(Enumerable.Repeat(LogicLine.Vcc, length).ToImmutableArray());
}
static public Bus GND(int length)
{
return new Bus(Enumerable.Repeat(LogicLine.GND, length).ToImmutableArray());
}
/// <summary>
/// AND gate
/// </summary>
static public Bus operator &(Bus A, Bus B)
{
if (A.Length != B.Length)
{
throw new RankException();
}
return new Bus(Enumerable.Zip(A.bus, B.bus, (a, b) => a & b).ToImmutableArray());
}
/// <summary>
/// OR gate
/// </summary>
static public Bus operator |(Bus A, Bus B)
{
if (A.Length != B.Length)
{
throw new RankException();
}
return new Bus(Enumerable.Zip(A.bus, B.bus, (a, b) => a | b).ToImmutableArray());
}
/// <summary>
/// NOT gate
/// </summary>
static public Bus operator !(Bus A)
{
return new Bus(A.bus.Select(x => !x).ToImmutableArray());
}
/// <summary>
/// XOR gate
/// </summary>
static public Bus operator ^(Bus A, Bus B)
{
if (A.Length != B.Length)
{
throw new RankException();
}
return new Bus(Enumerable.Zip(A.bus, B.bus, (a, b) => a ^ b).ToImmutableArray());
}
static public Bus Apply(Bus A, Func<LogicLine, LogicLine> component)
{
return new Bus(Enumerable.Range(0, A.Length).Select(i => component(A[i])).ToImmutableArray());
}
static public Bus Apply(Bus A, Bus B, Func<LogicLine, LogicLine, LogicLine> component)
{
if (A.Length != B.Length)
{
throw new RankException();
}
return new Bus(Enumerable.Range(0, A.Length).Select(i => component(A[i], B[i])).ToImmutableArray());
}
public IEnumerator<LogicLine> GetEnumerator()
{
return ((IEnumerable<LogicLine>)bus).GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((IEnumerable<LogicLine>)bus).GetEnumerator();
}
}
}
using System;
using System.Linq;
using System.Collections.Generic;
using System.Reactive.Linq;
namespace LogicCircuit
{
public class Circuit
{
public void Run()
{
var counter = Observable.Interval(TimeSpan.FromSeconds(1.0)).TakeWhile(i => i < 20);
var @default = Enumerable.Repeat(false, 4).ToArray();
var busA = Bus.CreateWithDefault(@default, Enumerable.Range(0, 4).Select(n => LogicLine.CreateWithDefault(false, counter.Select(i => (i >> n) % 2 == 1))).ToArray());
var busB = Bus.CreateWithDefault(@default, Enumerable.Range(0, 4).Select(n => LogicLine.CreateWithDefault(false, counter.Select(i => n == 2))).ToArray());
var sel = LogicLine.CreateWithDefault(true, counter.Select(x => x % 8 < 4));
var bus_A_plus_B = new LogicCircuit.Component.NbitAdder(busA, busB, LogicLine.GND);
var busSelector = new LogicCircuit.Component.NbitSelector(sel, busA, busB);
var signalSelector = new LogicCircuit.Component.Selector(sel, busA[2], busB[2]);
var array_A = new bool[4];
var array_B = new bool[4];
var array_Sum = new bool[4];
var overflow = false;
var selValue = false;
var array_Selected = new bool[4];
var selected = false;
foreach (var i in Enumerable.Range(0, 4))
{
busA[i].Subscribe(x => array_A[i] = x);
busB[i].Subscribe(x => array_B[i] = x);
bus_A_plus_B.S[i].Subscribe(x => array_Sum[i] = x);
busSelector[i].Subscribe(x => array_Selected[i] = x);
}
bus_A_plus_B.Cout.Subscribe(x => overflow = x);
sel.Subscribe(x => selValue = x);
signalSelector.Subscribe(x => selected = x);
counter.Delay(TimeSpan.FromSeconds(0.1)).Subscribe(_ =>
{
Console.Clear();
Console.WriteLine("busA value : " + array_A.ToInt());
Console.WriteLine("busB value : " + array_B.ToInt());
Console.WriteLine("---------------");
Console.WriteLine("Sum value : " + array_Sum.ToInt());
Console.WriteLine("SumOverflow: " + overflow);
Console.WriteLine("---------------");
Console.WriteLine("sel signal : " + selValue);
Console.WriteLine("Selectedbus: " + array_Selected.ToInt());
Console.WriteLine("Selected : " + selected);
}, () => Console.WriteLine("End."));
Console.Read();
}
}
static class Helper
{
static public int ToInt(this bool[] array)
{
return Convert.ToInt32(string.Concat(array.Reverse().Select(x => x ? '1' : '0')), 2);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LogicCircuit.Component
{
class FullAdder
{
/// <summary>
/// Carry out
/// </summary>
public LogicLine Cout { get; private set; }
/// <summary>
/// Sum
/// </summary>
public LogicLine S { get; private set; }
public FullAdder(LogicLine A, LogicLine B, LogicLine Cin)
{
var ha1 = new HalfAdder(A, B);
var ha2 = new HalfAdder(ha1.S, Cin);
Cout = ha1.C | ha2.C;
S = ha2.S;
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LogicCircuit.Component
{
class HalfAdder
{
/// <summary>
/// Carry
/// </summary>
public LogicLine C { get; private set; }
/// <summary>
/// Sum
/// </summary>
public LogicLine S { get; private set; }
public HalfAdder(LogicLine A, LogicLine B)
{
C = A & B;
S = A ^ B;
}
}
}
using System;
using System.Collections.Generic;
using System.Reactive.Linq;
namespace LogicCircuit
{
using ISignal = IObservable<bool>;
public class LogicLine : ISignal
{
ISignal signal;
public LogicLine(ISignal signal)
{
this.signal = signal.DistinctUntilChanged();
}
static public LogicLine CreateWithDefault(bool def, ISignal stream)
{
return new LogicLine(stream.StartWith(def));
}
public IDisposable Subscribe(IObserver<bool> observer)
{
return this.signal.Subscribe(observer);
}
static public readonly LogicLine Vcc = new LogicLine(Observable.Return(true));
static public readonly LogicLine GND = new LogicLine(Observable.Return(false));
/// <summary>
/// AND gate
/// </summary>
static public LogicLine operator &(LogicLine A, LogicLine B)
{
return new LogicLine(Observable.CombineLatest(A, B, (l, r) => l && r));
}
/// <summary>
/// OR gate
/// </summary>
static public LogicLine operator |(LogicLine A, LogicLine B)
{
return new LogicLine(Observable.CombineLatest(A, B, (l, r) => l || r));
}
/// <summary>
/// NOT gate
/// </summary>
static public LogicLine operator !(LogicLine A)
{
return new LogicLine(A.Select(x => !x));
}
/// <summary>
/// XOR gate
/// </summary>
static public LogicLine operator ^(LogicLine A, LogicLine B)
{
return new LogicLine(Observable.CombineLatest(A, B, (l, r) => l != r));
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LogicCircuit.Component
{
class NbitAdder
{
/// <summary>
/// Carry out
/// </summary>
public LogicLine Cout { get; private set; }
/// <summary>
/// Sum
/// </summary>
public Bus S { get; private set; }
public NbitAdder(Bus A, Bus B, LogicLine Cin)
{
var bassLength = Math.Min(A.Length, B.Length);
var fullAdders = new FullAdder[bassLength];
fullAdders[0] = new FullAdder(A[0], B[0], Cin);
for (int i = 1; i < bassLength; i++)
{
fullAdders[i] = new FullAdder(A[i], B[i], fullAdders[i - 1].Cout);
}
Cout = fullAdders[bassLength - 1].Cout;
S = new Bus(fullAdders.Select(x => x.S).ToArray());
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reactive.Linq;
namespace LogicCircuit.Component
{
class Selector : LogicLine
{
public Selector(LogicLine Sel, LogicLine A, LogicLine B)
: base(Sel.CombineLatest(A, B, (sel, a, b) => sel ? a : b))
{
}
}
class NbitSelector : Bus
{
public NbitSelector(LogicLine Sel, Bus A, Bus B)
: base(Bus.Apply(A, B, (a, b) => new Selector(Sel, a, b))) { }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment