/* Copyright (c) 2006, 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.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.Map;
import com.cburch.logisim.analyze.model.Expression;
import com.cburch.logisim.circuit.CircuitState;
import com.cburch.logisim.circuit.ExpressionComputer;
import com.cburch.logisim.comp.ComponentEvent;
import com.cburch.logisim.comp.ComponentFactory;
import com.cburch.logisim.comp.ComponentDrawContext;
import com.cburch.logisim.comp.EndData;
import com.cburch.logisim.comp.ManagedComponent;
import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.data.BitWidth;
import com.cburch.logisim.data.Bounds;
import com.cburch.logisim.data.Direction;
import com.cburch.logisim.data.Location;
import com.cburch.logisim.data.Value;
import com.cburch.logisim.file.Options;
import com.cburch.logisim.instance.StdAttr;
import com.cburch.logisim.proj.LogisimPreferences;
import com.cburch.logisim.tools.WireRepair;
import com.cburch.logisim.tools.WireRepairData;
class AbstractGate extends ManagedComponent
implements WireRepair, ExpressionComputer {
private AbstractGateFactory src;
public AbstractGate(Location loc, AttributeSet attrs, AbstractGateFactory src) {
super(loc, attrs, 4);
this.src = src;
if(attrs instanceof GateAttributes) {
((GateAttributes) attrs).gate = this;
}
setEnds();
}
public ComponentFactory getFactory() {
return src;
}
void setEnds() {
AttributeSet attrs = getAttributeSet();
Direction facing = (Direction) attrs.getValue(StdAttr.FACING);
int inputCount = ((Integer) attrs.getValue(GateAttributes.ATTR_INPUTS)).intValue();
BitWidth w = (BitWidth) attrs.getValue(StdAttr.WIDTH);
Bounds bounds = getBounds();
Location pt = getLocation();
EndData[] ends = new EndData[inputCount + 1];
ends[0] = new EndData(pt, w, EndData.OUTPUT_ONLY);
int wid;
int ht;
if(facing == Direction.NORTH || facing == Direction.SOUTH) {
wid = bounds.getHeight();
ht = bounds.getWidth();
} else {
wid = bounds.getWidth();
ht = bounds.getHeight();
}
int dx = wid;
int dy = -(ht / 2 - 5);
int ddy = (ht - 10) / (inputCount - 1);
if(facing == Direction.NORTH) {
for(int i = 1; i <= inputCount; i++) {
ends[i] = new EndData(pt.translate(dy, dx), w, EndData.INPUT_ONLY);
dy += ddy;
}
} else if(facing == Direction.SOUTH) {
for(int i = 1; i <= inputCount; i++) {
ends[i] = new EndData(pt.translate(dy, -dx), w, EndData.INPUT_ONLY);
dy += ddy;
}
} else if(facing == Direction.WEST) {
for(int i = 1; i <= inputCount; i++) {
ends[i] = new EndData(pt.translate( dx, dy), w, EndData.INPUT_ONLY);
dy += ddy;
}
} else {
for(int i = 1; i <= inputCount; i++) {
ends[i] = new EndData(pt.translate(-dx, dy), w, EndData.INPUT_ONLY);
dy += ddy;
}
}
setEnds(ends);
}
public void propagate(CircuitState state) {
AttributeSet attrs = getAttributeSet();
int inputCount = ((Integer) attrs.getValue(GateAttributes.ATTR_INPUTS)).intValue();
AttributeSet opts = state.getProject().getOptions().getAttributeSet();
boolean errorIfUndefined = opts.getValue(Options.ATTR_GATE_UNDEFINED)
.equals(Options.GATE_UNDEFINED_ERROR);
Value[] inputs = new Value[inputCount];
int num_inputs = 0;
int unknownMask = 0;
for(int i = 1; i <= inputCount; i++) {
Value v = state.getValue(getEndLocation(i));
if(v == Value.NIL) {
unknownMask = -1;
} else {
if(errorIfUndefined && !v.isFullyDefined()) {
for(int j = 0, w = v.getWidth(); j < w; j++) {
Value vj = v.get(j);
if(vj == Value.ERROR || vj == Value.UNKNOWN) {
unknownMask |= 1 << j;
}
}
}
inputs[num_inputs] = v;
num_inputs++;
}
}
Value out = null;
if(errorIfUndefined && unknownMask != 0) {
BitWidth width = (BitWidth) attrs.getValue(StdAttr.WIDTH);
int mask = width.getMask();
if((unknownMask & mask) == mask) {
out = Value.createError(width);
unknownMask = 0;
} else {
out = src.computeOutput(inputs, num_inputs, attrs);
Value[] outv = out.getAll();
for(int j = 0; j < outv.length; j++) {
if(((unknownMask >> j) & 1) != 0) outv[j] = Value.ERROR;
}
out = Value.create(outv);
}
} else {
out = src.computeOutput(inputs, num_inputs, attrs);
}
state.setValue(getEndLocation(0), out, this, GateAttributes.DELAY);
}
//
// user interface methods
//
public void draw(ComponentDrawContext context) {
AttributeSet attrs = (AttributeSet) getAttributeSet();
Location loc = getLocation();
Bounds bds = getBounds();
context.getGraphics().setColor(Color.BLACK);
drawBase(context, src, this, attrs, loc.getX(), loc.getY(),
bds.getWidth(), bds.getHeight());
if(!context.isPrintView() || context.getGateShape() == LogisimPreferences.SHAPE_RECTANGULAR) {
context.drawPins(this);
}
}
static void drawBase(ComponentDrawContext context,
AbstractGateFactory src, AbstractGate comp,
AttributeSet attrs, int x, int y, int width, int height) {
Direction facing = (Direction) attrs.getValue(StdAttr.FACING);
Graphics oldG = context.getGraphics();
if(facing != Direction.EAST && oldG instanceof Graphics2D) {
Graphics2D g2 = (Graphics2D) oldG.create();
g2.rotate(-facing.toRadians(), x, y);
context.setGraphics(g2);
if(facing == Direction.NORTH || facing == Direction.SOUTH) {
int t = width; width = height; height = t;
}
}
Integer inputs = (Integer) attrs.getValue(GateAttributes.ATTR_INPUTS);
if(context.getGateShape() == LogisimPreferences.SHAPE_RECTANGULAR) {
src.drawRectangular(context, comp, x, y, width, height);
} else if(context.getGateShape() == LogisimPreferences.SHAPE_DIN40700) {
src.drawDinShape(context, comp, x, y, width, height, inputs.intValue());
} else { // SHAPE_SHAPED
int don = src.hasDongle ? 10 : 0;
if(comp != null) {
src.drawInputLines(context, comp, inputs.intValue(),
x - width, y - (height - 10) / 2, width - don, height);
}
src.drawShape(context, comp, x - don, y, width - don, height);
if(src.hasDongle) {
context.drawDongle(x - 5, y);
}
}
context.setGraphics(oldG);
}
public Object getFeature(Object key) {
if(key == WireRepair.class) return this;
if(key == ExpressionComputer.class) return this;
return super.getFeature(key);
}
public boolean shouldRepairWire(WireRepairData data) {
return src.shouldRepairWire(this, data);
}
public void computeExpression(Map expressionMap) {
AttributeSet attrs = getAttributeSet();
int inputCount = ((Integer) attrs.getValue(GateAttributes.ATTR_INPUTS)).intValue();
Expression[] inputs = new Expression[inputCount];
int numInputs = 0;
for(int i = 1; i <= inputCount; i++) {
Expression e = (Expression) expressionMap.get(getEndLocation(i));
if(e != null) {
inputs[numInputs] = e;
++numInputs;
}
}
if(numInputs > 0) {
Expression out = src.computeExpression(inputs, numInputs);
expressionMap.put(getEndLocation(0), out);
}
}
void attributeValueChanged(Attribute attr, Object value) {
if(attr == StdAttr.WIDTH) {
setEnds();
} else if(attr == StdAttr.FACING || attr == GateAttributes.ATTR_SIZE
|| attr == GateAttributes.ATTR_INPUTS) {
recomputeBounds();
setEnds();
} else if(attr == GateAttributes.ATTR_XOR) {
fireComponentInvalidated(new ComponentEvent(this));
}
}
}
|