Package com.cburch.logisim.std.gates

Source Code of com.cburch.logisim.std.gates.CircuitDetermination$Value

/* Copyright (c) 2010, Carl Burch. License information is located in the
* com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */

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 {
  /** Ensures that all gates have only two inputs. */
  void convertToTwoInputs() { }

  /** Converts all gates to NANDs. Note that this will fail with an
   * exception if any XOR/XNOR gates are used. */
  void convertToNands() { }

  /** 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() { }
 
  /** A utility method for determining whether this fits the
   * pattern of a NAND representing a NOT. */
  boolean isNandNot() { return false; }
 
  //
  // static members
  //
  static class Gate extends CircuitDetermination {
    private ComponentFactory factory;
    private ArrayList<CircuitDetermination> inputs
      = new ArrayList<CircuitDetermination>();
   
    private Gate(ComponentFactory factory) { this.factory = factory; }
   
    ComponentFactory getFactory() { return factory; }
    ArrayList<CircuitDetermination> getInputs() { return inputs; }
   
    @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;
      }
    }
   
    @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;
    }
   
    private void notOutput() {
      Gate sub = new Gate(NandGate.FACTORY);
      sub.inputs = this.inputs;
      this.inputs = new ArrayList<CircuitDetermination>();
      inputs.add(sub);
      inputs.add(sub);
    }
     
    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);
        }
      }
    }
   
    @Override
    boolean isNandNot() {
      return factory == NandGate.FACTORY
        && inputs.size() == 2 && inputs.get(0) == inputs.get(1);
    }
   
    @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());
  }
 
  private static class Determine
      implements ExpressionVisitor<CircuitDetermination> {
    public CircuitDetermination visitAnd(Expression a, Expression b) {
      return binary(a.visit(this), b.visit(this), AndGate.FACTORY);
    }

    public CircuitDetermination visitOr(Expression a, Expression b) {
      return binary(a.visit(this), b.visit(this), OrGate.FACTORY);
    }

    public CircuitDetermination visitXor(Expression a, Expression b) {
      return binary(a.visit(this), b.visit(this), XorGate.FACTORY);
    }
   
    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 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 visitVariable(String name) {
      return new Input(name);
    }

    public CircuitDetermination visitConstant(int value) {
      return new Value(value);
    }          
  }
}
TOP

Related Classes of com.cburch.logisim.std.gates.CircuitDetermination$Value

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.