/******************************************************************************* * This file is part of logisim-evolution. * * logisim-evolution is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * logisim-evolution is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>. * * Original code by Carl Burch (http://www.cburch.com), 2011. * Subsequent modifications by : * + Haute École Spécialisée Bernoise * http://www.bfh.ch * + Haute École du paysage, d'ingénierie et d'architecture de Genève * http://hepia.hesge.ch/ * + Haute École d'Ingénierie et de Gestion du Canton de Vaud * http://www.heig-vd.ch/ * The project is currently maintained by : * + REDS Institute - HEIG-VD * Yverdon-les-Bains, Switzerland * http://reds.heig-vd.ch *******************************************************************************/ package com.cburch.logisim.std.gates; import java.util.ArrayList; import com.cburch.logisim.analyze.model.Expression; import com.cburch.logisim.analyze.model.ExpressionVisitor; import com.cburch.logisim.comp.ComponentFactory; /** * This represents the actual gate selection used corresponding to an * expression, without any correspondence to how they would be laid down in a * circuit. This intermediate representation permits easy manipulation of an * expression's translation. */ abstract class CircuitDetermination { private static class Determine implements ExpressionVisitor<CircuitDetermination> { private Gate binary(CircuitDetermination aret, CircuitDetermination bret, ComponentFactory factory) { if (aret instanceof Gate) { Gate a = (Gate) aret; if (a.factory == factory) { if (bret instanceof Gate) { Gate b = (Gate) bret; if (b.factory == factory) { a.inputs.addAll(b.inputs); return a; } } a.inputs.add(bret); return a; } } if (bret instanceof Gate) { Gate b = (Gate) bret; if (b.factory == factory) { b.inputs.add(aret); return b; } } Gate ret = new Gate(factory); ret.inputs.add(aret); ret.inputs.add(bret); return ret; } public CircuitDetermination visitAnd(Expression a, Expression b) { return binary(a.visit(this), b.visit(this), AndGate.FACTORY); } public CircuitDetermination visitConstant(int value) { return new Value(value); } public CircuitDetermination visitNot(Expression aBase) { CircuitDetermination aret = aBase.visit(this); if (aret instanceof Gate) { Gate a = (Gate) aret; if (a.factory == AndGate.FACTORY) { a.factory = NandGate.FACTORY; return a; } else if (a.factory == OrGate.FACTORY) { a.factory = NorGate.FACTORY; return a; } else if (a.factory == XorGate.FACTORY) { a.factory = XnorGate.FACTORY; return a; } } Gate ret = new Gate(NotGate.FACTORY); ret.inputs.add(aret); return ret; } public CircuitDetermination visitOr(Expression a, Expression b) { return binary(a.visit(this), b.visit(this), OrGate.FACTORY); } public CircuitDetermination visitVariable(String name) { return new Input(name); } public CircuitDetermination visitXor(Expression a, Expression b) { return binary(a.visit(this), b.visit(this), XorGate.FACTORY); } } // // static members // static class Gate extends CircuitDetermination { private ComponentFactory factory; private ArrayList<CircuitDetermination> inputs = new ArrayList<CircuitDetermination>(); private Gate(ComponentFactory factory) { this.factory = factory; } @Override void convertToNands() { // first recurse to clean up any children for (CircuitDetermination sub : inputs) { sub.convertToNands(); } // repair large XOR/XNORs to odd/even parity gates if (factory == NotGate.FACTORY) { inputs.add(inputs.get(0)); } else if (factory == AndGate.FACTORY) { notOutput(); } else if (factory == OrGate.FACTORY) { notAllInputs(); } else if (factory == NorGate.FACTORY) { notAllInputs(); // the order of these two lines is significant notOutput(); } else if (factory == NandGate.FACTORY) { ; } else { throw new IllegalArgumentException("Cannot handle " + factory.getDisplayName()); } factory = NandGate.FACTORY; } @Override void convertToTwoInputs() { if (inputs.size() <= 2) { for (CircuitDetermination a : inputs) { a.convertToTwoInputs(); } } else { ComponentFactory subFactory; if (factory == NorGate.FACTORY) subFactory = OrGate.FACTORY; else if (factory == NandGate.FACTORY) subFactory = AndGate.FACTORY; else subFactory = factory; int split = (inputs.size() + 1) / 2; CircuitDetermination a = convertToTwoInputsSub(0, split, subFactory); CircuitDetermination b = convertToTwoInputsSub(split, inputs.size(), subFactory); inputs.clear(); inputs.add(a); inputs.add(b); } } private CircuitDetermination convertToTwoInputsSub(int start, int stop, ComponentFactory subFactory) { if (stop - start == 1) { CircuitDetermination a = inputs.get(start); a.convertToTwoInputs(); return a; } else { int split = (start + stop + 1) / 2; CircuitDetermination a = convertToTwoInputsSub(start, split, subFactory); CircuitDetermination b = convertToTwoInputsSub(split, stop, subFactory); Gate ret = new Gate(subFactory); ret.inputs.add(a); ret.inputs.add(b); return ret; } } ComponentFactory getFactory() { return factory; } ArrayList<CircuitDetermination> getInputs() { return inputs; } @Override boolean isNandNot() { return factory == NandGate.FACTORY && inputs.size() == 2 && inputs.get(0) == inputs.get(1); } private void notAllInputs() { for (int i = 0; i < inputs.size(); i++) { CircuitDetermination old = inputs.get(i); if (old.isNandNot()) { inputs.set(i, ((Gate) old).inputs.get(0)); } else { Gate now = new Gate(NandGate.FACTORY); now.inputs.add(old); now.inputs.add(old); inputs.set(i, now); } } } private void notOutput() { Gate sub = new Gate(NandGate.FACTORY); sub.inputs = this.inputs; this.inputs = new ArrayList<CircuitDetermination>(); inputs.add(sub); inputs.add(sub); } @Override void repair() { // check whether we need to split ourself up. int num = inputs.size(); if (num > GateAttributes.MAX_INPUTS) { int newNum = (num + GateAttributes.MAX_INPUTS - 1) / GateAttributes.MAX_INPUTS; ArrayList<CircuitDetermination> oldInputs = inputs; inputs = new ArrayList<CircuitDetermination>(); ComponentFactory subFactory = factory; if (subFactory == NandGate.FACTORY) subFactory = AndGate.FACTORY; if (subFactory == NorGate.FACTORY) subFactory = OrGate.FACTORY; int per = num / newNum; int numExtra = num - per * newNum; int k = 0; for (int i = 0; i < newNum; i++) { Gate sub = new Gate(subFactory); int subCount = per + (i < numExtra ? 1 : 0); for (int j = 0; j < subCount; j++) { sub.inputs.add(oldInputs.get(k)); k++; } inputs.add(sub); } } // repair large XOR/XNORs to odd/even parity gates if (inputs.size() > 2) { if (factory == XorGate.FACTORY) { factory = OddParityGate.FACTORY; } else if (factory == XnorGate.FACTORY) { factory = EvenParityGate.FACTORY; } } // finally, recurse to clean up any children for (CircuitDetermination sub : inputs) { sub.repair(); } } } static class Input extends CircuitDetermination { private String name; private Input(String name) { this.name = name; } String getName() { return name; } } static class Value extends CircuitDetermination { private int value; private Value(int value) { this.value = value; } int getValue() { return value; } } static CircuitDetermination create(Expression expr) { if (expr == null) return null; return expr.visit(new Determine()); } /** * Converts all gates to NANDs. Note that this will fail with an exception * if any XOR/XNOR gates are used. */ void convertToNands() { } /** Ensures that all gates have only two inputs. */ void convertToTwoInputs() { } /** * A utility method for determining whether this fits the pattern of a NAND * representing a NOT. */ boolean isNandNot() { return false; } /** * Repairs two errors that may have cropped up in creating the circuit. * First, if there are gates with more inputs than their capacity, we repair * them. Second, any XOR/XNOR gates with more than 2 inputs should really be * Odd/Even Parity gates. */ void repair() { } }