/*******************************************************************************
* 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.wiring;
import java.awt.FontMetrics;
import java.awt.Graphics;
import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.AttributeOption;
import com.cburch.logisim.data.AttributeSet;
import com.cburch.logisim.data.Attributes;
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.tools.key.JoinedConfigurator;
import com.cburch.logisim.util.GraphicsUtil;
public class BitExtender extends InstanceFactory {
private static final Attribute<BitWidth> ATTR_IN_WIDTH = Attributes
.forBitWidth("in_width", Strings.getter("extenderInAttr"));
private static final Attribute<BitWidth> ATTR_OUT_WIDTH = Attributes
.forBitWidth("out_width", Strings.getter("extenderOutAttr"));
static final Attribute<AttributeOption> ATTR_TYPE = Attributes.forOption(
"type",
Strings.getter("extenderTypeAttr"),
new AttributeOption[] {
new AttributeOption("zero", "zero", Strings
.getter("extenderZeroType")),
new AttributeOption("one", "one", Strings
.getter("extenderOneType")),
new AttributeOption("sign", "sign", Strings
.getter("extenderSignType")),
new AttributeOption("input", "input", Strings
.getter("extenderInputType")), });
public static final BitExtender FACTORY = new BitExtender();
public BitExtender() {
super("Bit Extender", Strings.getter("extenderComponent"));
setIconName("extender.gif");
setAttributes(new Attribute[] { ATTR_IN_WIDTH, ATTR_OUT_WIDTH,
ATTR_TYPE },
new Object[] { BitWidth.create(8), BitWidth.create(16),
ATTR_TYPE.parse("sign") });
setFacingAttribute(StdAttr.FACING);
setKeyConfigurator(JoinedConfigurator.create(new BitWidthConfigurator(
ATTR_OUT_WIDTH), new BitWidthConfigurator(ATTR_IN_WIDTH, 1,
Value.MAX_WIDTH, 0)));
setOffsetBounds(Bounds.create(-40, -20, 40, 40));
}
//
// methods for instances
//
@Override
protected void configureNewInstance(Instance instance) {
configurePorts(instance);
instance.addAttributeListener();
}
private void configurePorts(Instance instance) {
Port p0 = new Port(0, 0, Port.OUTPUT, ATTR_OUT_WIDTH);
Port p1 = new Port(-40, 0, Port.INPUT, ATTR_IN_WIDTH);
String type = getType(instance.getAttributeSet());
if (type.equals("input")) {
instance.setPorts(new Port[] { p0, p1,
new Port(-20, -20, Port.INPUT, 1) });
} else {
instance.setPorts(new Port[] { p0, p1 });
}
}
private String getType(AttributeSet attrs) {
AttributeOption topt = attrs.getValue(ATTR_TYPE);
return (String) topt.getValue();
}
@Override
public boolean HDLSupportedComponent(String HDLIdentifier,
AttributeSet attrs) {
if (MyHDLGenerator == null)
MyHDLGenerator = new BitExtenderHDLGeneratorFactory();
return MyHDLGenerator.HDLTargetSupported(HDLIdentifier, attrs);
}
@Override
protected void instanceAttributeChanged(Instance instance, Attribute<?> attr) {
if (attr == ATTR_TYPE) {
configurePorts(instance);
instance.fireInvalidated();
} else {
instance.fireInvalidated();
}
}
//
// graphics methods
//
@Override
public void paintInstance(InstancePainter painter) {
Graphics g = painter.getGraphics();
FontMetrics fm = g.getFontMetrics();
int asc = fm.getAscent();
painter.drawBounds();
String s0;
String type = getType(painter.getAttributeSet());
if (type.equals("zero"))
s0 = Strings.get("extenderZeroLabel");
else if (type.equals("one"))
s0 = Strings.get("extenderOneLabel");
else if (type.equals("sign"))
s0 = Strings.get("extenderSignLabel");
else if (type.equals("input"))
s0 = Strings.get("extenderInputLabel");
else
s0 = "???"; // should never happen
String s1 = Strings.get("extenderMainLabel");
Bounds bds = painter.getBounds();
int x = bds.getX() + bds.getWidth() / 2;
int y0 = bds.getY() + (bds.getHeight() / 2 + asc) / 2;
int y1 = bds.getY() + (3 * bds.getHeight() / 2 + asc) / 2;
GraphicsUtil.drawText(g, s0, x, y0, GraphicsUtil.H_CENTER,
GraphicsUtil.V_BASELINE);
GraphicsUtil.drawText(g, s1, x, y1, GraphicsUtil.H_CENTER,
GraphicsUtil.V_BASELINE);
BitWidth w0 = painter.getAttributeValue(ATTR_OUT_WIDTH);
BitWidth w1 = painter.getAttributeValue(ATTR_IN_WIDTH);
painter.drawPort(0, "" + w0.getWidth(), Direction.WEST);
painter.drawPort(1, "" + w1.getWidth(), Direction.EAST);
if (type.equals("input"))
painter.drawPort(2);
}
@Override
public void propagate(InstanceState state) {
Value in = state.getPortValue(1);
BitWidth wout = state.getAttributeValue(ATTR_OUT_WIDTH);
String type = getType(state.getAttributeSet());
Value extend;
if (type.equals("one")) {
extend = Value.TRUE;
} else if (type.equals("sign")) {
int win = in.getWidth();
extend = win > 0 ? in.get(win - 1) : Value.ERROR;
} else if (type.equals("input")) {
extend = state.getPortValue(2);
if (extend.getWidth() != 1)
extend = Value.ERROR;
} else {
extend = Value.FALSE;
}
Value out = in.extendWidth(wout.getWidth(), extend);
state.setPort(0, out, 1);
}
}