0

I'm currently learning C# and WPF, and i'm trying to simulate a circuit of logic gates and flipflops, but it won't work.

Could someone please show me a possible way to achive this? (maybe a simple similar application?)

What i have tried so far:


Class:

    public class GateBase
    {
        public Type Type { get; set; }
        public GateBase Input1 { get; set; }
        public GateBase Input2 { get; set; }
        public List<GateBase> Outputs { get; set; }
        public bool Evaluated { get; set; }
        public bool Value { get; set; }
        public bool FlipFlop { get; set; }

        public GateBase(Type type = Type.OFF, Gate input1 = null, Gate input2 = null)
        {
            Type = type;
            Input1 = input1;
            Input2 = input2;
            Outputs = new List<GateBase>();
            Evaluated = false;
            Value = false;
            

            FlipFlop = false;

            switch (Type)
            {
                case Type.T:
                case Type.D:
                case Type.SR:
                case Type.JK: FlipFlop = true; break;
            }
        }

        public bool Evaluate()
        {
            if (!Evaluated)
            {
                bool input1 = false;
                bool input2 = false;

                if (Input1 != null)
                {
                    if (Input1.FlipFlop)
                        input1 = Input1.Value;
                    else
                        input1 = Input1.Evaluate();
                }

                if (Input2 != null)
                {
                    if (Input2.FlipFlop)
                        input2 = Input2.Value;
                    else
                        input2 = Input2.Evaluate();
                }

                switch (Type)
                {
                    case Type.OFF:
                        Value = false; break;
                    case Type.ON:
                        Value = true; break;
                    case Type.OUT:
                        Value = input1; break;
                    case Type.CON:
                        Value = input1; break;
                    case Type.NOT:
                        Value = input1; break;
                    case Type.AND:
                        Value = input1 & input2; break;
                    case Type.OR:
                        Value = input1 | input2; break;
                    case Type.XOR:
                        Value = input1 ^ input2; break;
                    case Type.NAND:
                        Value = !(input1 & input2); break;
                    case Type.NOR:
                        Value = !(input1 | input2); break;
                    case Type.XNOR:
                        Value = !(input1 ^ input2); break;
                    case Type.D:
                        Value = input1; break;
                    case Type.T:
                        Value = input1 ? Value : !Value; break;
                    case Type.SR:
                        Value = (input1 ^ input2) ? Value : Value; break;
                    case Type.JK:
                        Value = (input1 ^ input2) ? input1 : (input1 & input2) ? !Value : Value; break;
                    default: Value = false; break;
                }
            }
            Evaluated = true;
            return Value;
        }

        public void ResetOutputs()
        {
            Evaluated = false;
            foreach (Gate gate in Outputs)
            {
                if(!gate.FlipFlop)
                {
                    gate.ResetOutputs();
                }
            }
        }
    }

Loop:

  • Update all logic gates
  • Update all flipflops and unevaluate outputs of each flipflop (if they are not a flipflop)
     public List<GateBase> Gates { get; set; }
     while (loop)
            {
                bool evaluating = true;
                while (evaluating)
                {
                    evaluating = false;
                    foreach (Gate gate in Gates)
                    {
                        switch (gate.Type)
                        {
                            case Model.Type.ON:
                            case Model.Type.OFF:
                                gate.Value = gate.Evaluate();
                                break;
                            case Model.Type.OUT:
                            case Model.Type.CON:
                            case Model.Type.NOT:
                                if (gate.Input1 != null && (gate.Input1.Evaluated || gate.Input1.FlipFlop))
                                {
                                    gate.Value = gate.Evaluate();
                                }
                                break;
                            case Model.Type.AND:
                            case Model.Type.OR:
                            case Model.Type.XOR:
                            case Model.Type.NAND:
                            case Model.Type.NOR:
                            case Model.Type.XNOR:
                                if (gate.Input1 != null && gate.Input2 != null)
                                {
                                    if ((gate.Input1.Evaluated || gate.Input1.FlipFlop) && (gate.Input2.Evaluated || gate.Input2.FlipFlop))
                                    {
                                        gate.Value = gate.Evaluate();
                                    }
                                }
                                else
                                {
                                    evaluating = true;
                                }
                                break;
                        }
                    }
                }

                evaluating = true;
                while (evaluating)
                {
                    evaluating = false;
                    foreach (Gate gate in Gates)
                    {
                        switch (gate.Type)
                        {
                            case Model.Type.D:
                            case Model.Type.T:
                                if (gate.Input1 != null && (gate.Input1.Evaluated || gate.Input1.FlipFlop))
                                {
                                    gate.Value = gate.Evaluate();
                                    gate.ResetOutputs();
                                }
                                else
                                {
                                    evaluating = true;
                                }
                                break;
                            case Model.Type.SR:
                            case Model.Type.JK:
                                if (gate.Input1 != null && gate.Input2 != null)
                                {
                                    if ((gate.Input1.Evaluated || gate.Input1.FlipFlop) && (gate.Input2.Evaluated || gate.Input2.FlipFlop))
                                    {
                                        gate.Value = gate.Evaluate();
                                        gate.ResetOutputs();
                                    }
                                }
                                else
                                {
                                    evaluating = true;
                                }
                                break;

                        }
                    }
                }
            }

Problem:

If i'm using the JK-flipflop the results are not as expected. (but the T-flipflop works fine)


Here a link to the solution: Solution on GitHub

Thank You!

  • JL flip flops you need current state (value). I expect the toggle flip flop is also failing. The new value is based on the inputs AND the current value. – jdweng Apr 11 '21 at 15:57
  • I would simplify the code via utilizing OOP concepts. Split up your `GateBase` class into specific AND, OR, etc gate classes and inherit them all from `GateBase` or a common interface instead to keep possibility to hold them together in your list. The new classes would be much simpler and clearer. This will help you to understand OOP and find the problem too :) – cly Apr 11 '21 at 16:15

2 Answers2

0

You have no break for your switch cases inside the while loop, so if the case is Model.Type.AND it will fall all the way down to the Model.Type.XNOR and I assume this isn't intended. This might be your problem (or at least a part of it).

Just to give you an idea, this small example will output "no break". x = 3 will output the string from default.

using System;

public class Program
{
    public static void Main()
    {
        int x = 1;
        switch(x){
            case 0:
                Console.WriteLine("Break");
                break;
            case 1:
            case 2:
                Console.WriteLine("no break");
                break;
            case 3:
            default:
                Console.WriteLine("End!");
                break;
        }
    }
}

You can read more about the traditional switch here: switch C# reference from Micrsoft

bintreedev
  • 41
  • 3
  • Thank you for your answer, but it was actually intended. I'm switching on the type based on the number of inputs (OFF: ON: 0 inputs | OUT: CON: NOT: 1 input | AND - XNOR: 2 inputs) –  Apr 12 '21 at 07:30
0

Now i fixed a problem and it's working much better than before. (i was resetting the gates before all flipflops were updated)

But it's still not working 100% correct...

Changes in the Loop:

// new list
List<Gate> gatesToResetOutputs = new List<Gate>();

while(loop)
{
    while(evaluating gates)
    {
        ...
    }

    while(evaluating flipflops)
    {
        ...
        // instead of
        gate.ResetOutputs();
    
        // replace with
        gatesToResetOutputs.Add(gate);
        ...
    }

    // and at the end of the loop
    foreach(Gate gate in gatesToResetOutputs)
    {
        gate.ResetOutputs();
    }
}