/*******************************************************************************
* 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.plexers;
import java.awt.Color;
import java.awt.Graphics;
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.Value;
import com.cburch.logisim.instance.Instance;
import com.cburch.logisim.instance.InstanceFactory;
import com.cburch.logisim.instance.InstancePainter;
import com.cburch.logisim.instance.InstanceState;
import com.cburch.logisim.instance.Port;
import com.cburch.logisim.instance.StdAttr;
import com.cburch.logisim.tools.key.BitWidthConfigurator;
import com.cburch.logisim.util.GraphicsUtil;
public class PriorityEncoder extends InstanceFactory {
static final int OUT = 0;
static final int EN_IN = 1;
static final int EN_OUT = 2;
static final int GS = 3;
public PriorityEncoder() {
super("Priority Encoder", Strings.getter("priorityEncoderComponent"));
setAttributes(new Attribute[] { StdAttr.FACING, Plexers.ATTR_SELECT,
Plexers.ATTR_DISABLED }, new Object[] { Direction.EAST,
BitWidth.create(3), Plexers.DISABLED_ZERO });
setKeyConfigurator(new BitWidthConfigurator(Plexers.ATTR_SELECT, 1, 5,
0));
setIconName("priencod.gif");
setFacingAttribute(StdAttr.FACING);
}
@Override
protected void configureNewInstance(Instance instance) {
instance.addAttributeListener();
updatePorts(instance);
}
@Override
public Bounds getOffsetBounds(AttributeSet attrs) {
Direction dir = attrs.getValue(StdAttr.FACING);
BitWidth select = attrs.getValue(Plexers.ATTR_SELECT);
int inputs = 1 << select.getWidth();
int offs = -5 * inputs;
int len = 10 * inputs + 10;
if (dir == Direction.NORTH) {
return Bounds.create(offs, 0, len, 40);
} else if (dir == Direction.SOUTH) {
return Bounds.create(offs, -40, len, 40);
} else if (dir == Direction.WEST) {
return Bounds.create(0, offs, 40, len);
} else { // dir == Direction.EAST
return Bounds.create(-40, offs, 40, len);
}
}
@Override
public boolean HasThreeStateDrivers(AttributeSet attrs) {
return (attrs.getValue(Plexers.ATTR_DISABLED) == Plexers.DISABLED_FLOATING);
}
@Override
public boolean HDLSupportedComponent(String HDLIdentifier,
AttributeSet attrs) {
if (MyHDLGenerator == null)
MyHDLGenerator = new PriorityEncoderHDLGeneratorFactory();
return MyHDLGenerator.HDLTargetSupported(HDLIdentifier, attrs);
}
@Override
protected void instanceAttributeChanged(Instance instance, Attribute<?> attr) {
if (attr == StdAttr.FACING || attr == Plexers.ATTR_SELECT) {
instance.recomputeBounds();
updatePorts(instance);
} else if (attr == Plexers.ATTR_SELECT) {
updatePorts(instance);
} else if (attr == Plexers.ATTR_DISABLED) {
instance.fireInvalidated();
}
}
@Override
public void paintInstance(InstancePainter painter) {
Graphics g = painter.getGraphics();
Direction facing = painter.getAttributeValue(StdAttr.FACING);
painter.drawBounds();
Bounds bds = painter.getBounds();
g.setColor(Color.GRAY);
int x0;
int y0;
int halign;
if (facing == Direction.WEST) {
x0 = bds.getX() + bds.getWidth() - 3;
y0 = bds.getY() + 15;
halign = GraphicsUtil.H_RIGHT;
} else if (facing == Direction.NORTH) {
x0 = bds.getX() + 10;
y0 = bds.getY() + bds.getHeight() - 2;
halign = GraphicsUtil.H_CENTER;
} else if (facing == Direction.SOUTH) {
x0 = bds.getX() + 10;
y0 = bds.getY() + 12;
halign = GraphicsUtil.H_CENTER;
} else {
x0 = bds.getX() + 3;
y0 = bds.getY() + 15;
halign = GraphicsUtil.H_LEFT;
}
GraphicsUtil.drawText(g, "0", x0, y0, halign, GraphicsUtil.V_BASELINE);
g.setColor(Color.BLACK);
GraphicsUtil.drawCenteredText(g, "Pri",
bds.getX() + bds.getWidth() / 2, bds.getY() + bds.getHeight()
/ 2);
painter.drawPorts();
}
@Override
public void propagate(InstanceState state) {
BitWidth select = state.getAttributeValue(Plexers.ATTR_SELECT);
int n = 1 << select.getWidth();
boolean enabled = state.getPortValue(n + EN_IN) != Value.FALSE;
int out = -1;
Value outDefault;
if (enabled) {
outDefault = Value.createUnknown(select);
for (int i = n - 1; i >= 0; i--) {
if (state.getPortValue(i) == Value.TRUE) {
out = i;
break;
}
}
} else {
Object opt = state.getAttributeValue(Plexers.ATTR_DISABLED);
Value base = opt == Plexers.DISABLED_ZERO ? Value.FALSE
: Value.UNKNOWN;
outDefault = Value.repeat(base, select.getWidth());
}
if (out < 0) {
state.setPort(n + OUT, outDefault, Plexers.DELAY);
state.setPort(n + EN_OUT, enabled ? Value.TRUE : Value.FALSE,
Plexers.DELAY);
state.setPort(n + GS, Value.FALSE, Plexers.DELAY);
} else {
state.setPort(n + OUT, Value.createKnown(select, out),
Plexers.DELAY);
state.setPort(n + EN_OUT, Value.FALSE, Plexers.DELAY);
state.setPort(n + GS, Value.TRUE, Plexers.DELAY);
}
}
private void updatePorts(Instance instance) {
Object dir = instance.getAttributeValue(StdAttr.FACING);
BitWidth select = instance.getAttributeValue(Plexers.ATTR_SELECT);
int n = 1 << select.getWidth();
Port[] ps = new Port[n + 4];
if (dir == Direction.NORTH || dir == Direction.SOUTH) {
int x = -5 * n + 10;
int y = dir == Direction.NORTH ? 40 : -40;
for (int i = 0; i < n; i++) {
ps[i] = new Port(x + 10 * i, y, Port.INPUT, 1);
}
ps[n + OUT] = new Port(0, 0, Port.OUTPUT, select.getWidth());
ps[n + EN_IN] = new Port(x + 10 * n, y / 2, Port.INPUT, 1);
ps[n + EN_OUT] = new Port(x - 10, y / 2, Port.OUTPUT, 1);
ps[n + GS] = new Port(10, 0, Port.OUTPUT, 1);
} else {
int x = dir == Direction.EAST ? -40 : 40;
int y = -5 * n + 10;
for (int i = 0; i < n; i++) {
ps[i] = new Port(x, y + 10 * i, Port.INPUT, 1);
}
ps[n + OUT] = new Port(0, 0, Port.OUTPUT, select.getWidth());
ps[n + EN_IN] = new Port(x / 2, y + 10 * n, Port.INPUT, 1);
ps[n + EN_OUT] = new Port(x / 2, y - 10, Port.OUTPUT, 1);
ps[n + GS] = new Port(0, 10, Port.OUTPUT, 1);
}
for (int i = 0; i < n; i++) {
ps[i].setToolTip(Strings.getter("priorityEncoderInTip", "" + i));
}
ps[n + OUT].setToolTip(Strings.getter("priorityEncoderOutTip"));
ps[n + EN_IN].setToolTip(Strings.getter("priorityEncoderEnableInTip"));
ps[n + EN_OUT]
.setToolTip(Strings.getter("priorityEncoderEnableOutTip"));
ps[n + GS].setToolTip(Strings.getter("priorityEncoderGroupSignalTip"));
instance.setPorts(ps);
}
}