Package com.cburch.logisim.circuit

Source Code of com.cburch.logisim.circuit.CircuitState

/* 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.circuit;

import java.util.Collection;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import com.cburch.logisim.circuit.Propagator.SetData;
import com.cburch.logisim.comp.Component;
import com.cburch.logisim.comp.ComponentDrawContext;
import com.cburch.logisim.comp.ComponentState;
import com.cburch.logisim.data.BitWidth;
import com.cburch.logisim.data.Location;
import com.cburch.logisim.data.Value;
import com.cburch.logisim.instance.Instance;
import com.cburch.logisim.instance.InstanceData;
import com.cburch.logisim.instance.InstanceFactory;
import com.cburch.logisim.instance.InstanceState;
import com.cburch.logisim.proj.Project;
import com.cburch.logisim.std.wiring.Clock;
import com.cburch.logisim.std.wiring.Pin;
import com.cburch.logisim.util.ArraySet;
import com.cburch.logisim.util.SmallSet;

public class CircuitState implements InstanceData {
  private class MyCircuitListener implements CircuitListener {
    public void circuitChanged(CircuitEvent event) {
      int action = event.getAction();
      if (action == CircuitEvent.ACTION_ADD) {
        Component comp = (Component) event.getData();
        if (comp instanceof Wire) {
          Wire w = (Wire) comp;
          markPointAsDirty(w.getEnd0());
          markPointAsDirty(w.getEnd1());
        } else {
          markComponentAsDirty(comp);
        }
      } else if (action == CircuitEvent.ACTION_REMOVE) {
        Component comp = (Component) event.getData();
        if (comp.getFactory() instanceof SubcircuitFactory) {
          // disconnect from tree
          CircuitState substate = (CircuitState) getData(comp);
          if (substate != null && substate.parentComp == comp) {
            substates.remove(substate);
            substate.parentState = null;
            substate.parentComp = null;
          }
        }

        if (comp instanceof Wire) {
          Wire w = (Wire) comp;
          markPointAsDirty(w.getEnd0());
          markPointAsDirty(w.getEnd1());
        } else {
          if (base != null) base.checkComponentEnds(CircuitState.this, comp);
          dirtyComponents.remove(comp);
        }
      } else if (action == CircuitEvent.ACTION_CLEAR) {
        substates.clear();
        wireData = null;
        componentData.clear();
        values.clear();
        dirtyComponents.clear();
        dirtyPoints.clear();
        causes.clear();
      } else if (action == CircuitEvent.ACTION_CHANGE) {
        Object data = event.getData();
        if (data instanceof Collection) {
          @SuppressWarnings("unchecked")
          Collection<Component> comps = (Collection<Component>) data;
          markComponentsDirty(comps);
          if (base != null) {
            for (Component comp : comps) {
              base.checkComponentEnds(CircuitState.this, comp);
            }
          }
        } else {
          Component comp = (Component) event.getData();
          markComponentAsDirty(comp);
          if (base != null) base.checkComponentEnds(CircuitState.this, comp);
        }
      } else if (action == CircuitEvent.ACTION_INVALIDATE) {
        Component comp = (Component) event.getData();
        markComponentAsDirty(comp);
        // TODO detemine if this should really be missing if (base != null) base.checkComponentEnds(CircuitState.this, comp);
      } else if (action == CircuitEvent.TRANSACTION_DONE) {
        ReplacementMap map = event.getResult().getReplacementMap(circuit);
        if (map != null) {
          for (Component comp : map.getReplacedComponents()) {
            Object compState = componentData.remove(comp);
            if (compState != null) {
              Class<?> compFactory = comp.getFactory().getClass();
              boolean found = false;
              for (Component repl : map.get(comp)) {
                if (repl.getFactory().getClass() == compFactory) {
                  found = true;
                  setData(repl, compState);
                  break;
                }
              }
              if (!found && compState instanceof CircuitState) {
                CircuitState sub = (CircuitState) compState;
                sub.parentState = null;
                substates.remove(sub);
              }
            }
          }
        }
      }
    }
  }

  private MyCircuitListener myCircuitListener = new MyCircuitListener();
  private Propagator base = null; // base of tree of CircuitStates
  private Project proj; // project where circuit lies
  private Circuit circuit; // circuit being simulated

  private CircuitState parentState = null; // parent in tree of CircuitStates
  private Component parentComp = null; // subcircuit component containing this state
  private ArraySet<CircuitState> substates = new ArraySet<CircuitState>();

  private CircuitWires.State wireData = null;
  private HashMap<Component,Object> componentData = new HashMap<Component,Object>();
  private Map<Location,Value> values = new HashMap<Location,Value>();
  private SmallSet<Component> dirtyComponents = new SmallSet<Component>();
  private SmallSet<Location> dirtyPoints = new SmallSet<Location>();
  HashMap<Location,SetData> causes = new HashMap<Location,SetData>();

  private static int lastId = 0;
  private int id = lastId++;

  public CircuitState(Project proj, Circuit circuit) {
    this.proj = proj;
    this.circuit = circuit;
    circuit.addCircuitListener(myCircuitListener);
  }
 
  public Project getProject() {
    return proj;
  }
 
  Component getSubcircuit() {
    return parentComp;
  }
 
  @Override
  public CircuitState clone() {
    return cloneState();
  }
 
  public CircuitState cloneState() {
    CircuitState ret = new CircuitState(proj, circuit);
    ret.copyFrom(this, new Propagator(ret));
    ret.parentComp = null;
    ret.parentState = null;
    return ret;
  }
 
  private void copyFrom(CircuitState src, Propagator base) {
    this.base = base;
    this.parentComp = src.parentComp;
    this.parentState = src.parentState;
    HashMap<CircuitState,CircuitState> substateData = new HashMap<CircuitState,CircuitState>();
    this.substates = new ArraySet<CircuitState>();
    for (CircuitState oldSub : src.substates) {
      CircuitState newSub = new CircuitState(src.proj, oldSub.circuit);
      newSub.copyFrom(oldSub, base);
      newSub.parentState = this;
      this.substates.add(newSub);
      substateData.put(oldSub, newSub);
    }
    for (Component key : src.componentData.keySet()) {
      Object oldValue = src.componentData.get(key);
      if (oldValue instanceof CircuitState) {
        Object newValue = substateData.get(oldValue);
        if (newValue != null) this.componentData.put(key, newValue);
        else this.componentData.remove(key);
      } else {
        Object newValue;
        if (oldValue instanceof ComponentState) {
          newValue = ((ComponentState) oldValue).clone();
        } else {
          newValue = oldValue;
        }
        this.componentData.put(key, newValue);
      }
    }
    for (Location key : src.causes.keySet()) {
      Propagator.SetData oldValue = src.causes.get(key);
      Propagator.SetData newValue = oldValue.cloneFor(this);
      this.causes.put(key, newValue);
    }
    if (src.wireData != null) {
      this.wireData = (CircuitWires.State) src.wireData.clone();
    }
    this.values.putAll(src.values);
    this.dirtyComponents.addAll(src.dirtyComponents);
    this.dirtyPoints.addAll(src.dirtyPoints);
  }

  @Override
  public String toString() {
    return "State" + id + "[" + circuit.getName() + "]";
  }

  //
  // public methods
  //
  public Circuit getCircuit() {
    return circuit;
  }
 
  public CircuitState getParentState() {
    return parentState;
  }
 
  public Set<CircuitState> getSubstates() { // returns Set of CircuitStates
    return substates;
  }

  public Propagator getPropagator() {
    if (base == null) {
      base = new Propagator(this);
      markAllComponentsDirty();
    }
    return base;
  }
 
  public void drawOscillatingPoints(ComponentDrawContext context) {
    if (base != null) base.drawOscillatingPoints(context);
  }

  public Object getData(Component comp) {
    return componentData.get(comp);
  }

  public void setData(Component comp, Object data) {
    if (data instanceof CircuitState) {
      CircuitState oldState = (CircuitState) componentData.get(comp);
      CircuitState newState = (CircuitState) data;
      if (oldState != newState) {
        // There's something new going on with this subcircuit.
        // Maybe the subcircuit is new, or perhaps it's being
        // removed.
        if (oldState != null && oldState.parentComp == comp) {
          // it looks like it's being removed
          substates.remove(oldState);
          oldState.parentState = null;
          oldState.parentComp = null;
        }
        if (newState != null && newState.parentState != this) {
          // this is the first time I've heard about this CircuitState
          substates.add(newState);
          newState.base = this.base;
          newState.parentState = this;
          newState.parentComp = comp;
          newState.markAllComponentsDirty();
        }
      }
    }
    componentData.put(comp, data);
  }

  public Value getValue(Location pt) {
    Value ret = values.get(pt);
    if (ret != null) return ret;

    BitWidth wid = circuit.getWidth(pt);
    return Value.createUnknown(wid);
  }

  public void setValue(Location pt, Value val, Component cause, int delay) {
    if (base != null) base.setValue(this, pt, val, cause, delay);
  }

  public void markComponentAsDirty(Component comp) {
    try {
      dirtyComponents.add(comp);
    } catch (RuntimeException e) {
      SmallSet<Component> set = new SmallSet<Component>();
      set.add(comp);
      dirtyComponents = set;
    }
  }

  public void markComponentsDirty(Collection<Component> comps) {
    dirtyComponents.addAll(comps);
  }

  public void markPointAsDirty(Location pt) {
    dirtyPoints.add(pt);
  }
 
  public InstanceState getInstanceState(Component comp) {
    Object factory = comp.getFactory();
    if (factory instanceof InstanceFactory) {
      return ((InstanceFactory) factory).createInstanceState(this, comp);
    } else {
      throw new RuntimeException("getInstanceState requires instance component");
    }
  }
 
  public InstanceState getInstanceState(Instance instance) {
    Object factory = instance.getFactory();
    if (factory instanceof InstanceFactory) {
      return ((InstanceFactory) factory).createInstanceState(this, instance);
    } else {
      throw new RuntimeException("getInstanceState requires instance component");
    }
  }

  //
  // methods for other classes within package
  //
  public boolean isSubstate() {
    return parentState != null;
  }

  void processDirtyComponents() {
    if (!dirtyComponents.isEmpty()) {
      // This seeming wasted copy is to avoid ConcurrentModifications
      // if we used an iterator instead.
      Object[] toProcess;
      RuntimeException firstException = null;
      for (int tries = 4; true; tries--) {
        try {
          toProcess = dirtyComponents.toArray();
          break;
        } catch (RuntimeException e) {
          if (firstException == null) firstException = e;
          if (tries == 0) {
            toProcess = new Object[0];
            dirtyComponents = new SmallSet<Component>();
            throw firstException;
          }
        }
      }
      dirtyComponents.clear();
      for (Object compObj : toProcess) {
        if (compObj instanceof Component) {
          Component comp = (Component) compObj;
          comp.propagate(this);
          if (comp.getFactory() instanceof Pin && parentState != null) {
            // should be propagated in superstate
            parentComp.propagate(parentState);
          }
        }
      }
    }

    CircuitState[] subs = new CircuitState[substates.size()];
    for (CircuitState substate : substates.toArray(subs)) {
      substate.processDirtyComponents();
    }
  }

  void processDirtyPoints() {
    HashSet<Location> dirty = new HashSet<Location>(dirtyPoints);
    dirtyPoints.clear();
    if (circuit.wires.isMapVoided()) {
      for (int i = 3; i >= 0; i--) {
        try {
          dirty.addAll(circuit.wires.points.getSplitLocations());
          break;
        } catch (ConcurrentModificationException e) {
          // try again...
          try { Thread.sleep(1); } catch (InterruptedException e2) { }
          if (i == 0) e.printStackTrace();
        }
      }
    }
    if (!dirty.isEmpty()) {
      circuit.wires.propagate(this, dirty);
    }

    CircuitState[] subs = new CircuitState[substates.size()];
    for (CircuitState substate : substates.toArray(subs)) {
      substate.processDirtyPoints();
    }
  }
 
  void reset() {
    wireData = null;
    for (Iterator<Component> it = componentData.keySet().iterator(); it.hasNext(); ) {
      Component comp = it.next();
      if (!(comp.getFactory() instanceof SubcircuitFactory)) it.remove();
    }
    values.clear();
    dirtyComponents.clear();
    dirtyPoints.clear();
    causes.clear();
    markAllComponentsDirty();
   
    for (CircuitState sub : substates) {
      sub.reset();
    }
  }

  boolean tick(int ticks) {
    boolean ret = false;
    for (Component clock : circuit.getClocks()) {
      ret |= Clock.tick(this, ticks, clock);
    }

    CircuitState[] subs = new CircuitState[substates.size()];
    for (CircuitState substate : substates.toArray(subs)) {
      ret |= substate.tick(ticks);
    }
    return ret;
  }

  CircuitWires.State getWireData() {
    return wireData;
  }

  void setWireData(CircuitWires.State data) {
    wireData = data;
  }

  Value getComponentOutputAt(Location p) {
    // for CircuitWires - to get values, ignoring wires' contributions
    Propagator.SetData cause_list = causes.get(p);
    return Propagator.computeValue(cause_list);
  }

  Value getValueByWire(Location p) {
    return values.get(p);
  }

  void setValueByWire(Location p, Value v) {
    // for CircuitWires - to set value at point
    boolean changed;
    if (v == Value.NIL) {
      Object old = values.remove(p);
      changed = (old != null && old != Value.NIL);
    } else {
      Object old = values.put(p, v);
      changed = !v.equals(old);
    }
    if (changed) {
      boolean found = false;
      for (Component comp : circuit.getComponents(p)) {
        if (!(comp instanceof Wire) && !(comp instanceof Splitter)) {
          found = true;
          markComponentAsDirty(comp);
        }
      }
      // NOTE: this will cause a double-propagation on components
      // whose outputs have just changed.
     
      if (found && base != null) base.locationTouched(this, p);
    }
  }

  //
  // private methods
  //
  private void markAllComponentsDirty() {
    dirtyComponents.addAll(circuit.getNonWires());
  }
}
TOP

Related Classes of com.cburch.logisim.circuit.CircuitState

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.