/******************************************************************************* * 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.arith; 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.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 BitFinder extends InstanceFactory { static final AttributeOption LOW_ONE = new AttributeOption("low1", Strings.getter("bitFinderLowOption", "1")); static final AttributeOption HIGH_ONE = new AttributeOption("high1", Strings.getter("bitFinderHighOption", "1")); static final AttributeOption LOW_ZERO = new AttributeOption("low0", Strings.getter("bitFinderLowOption", "0")); static final AttributeOption HIGH_ZERO = new AttributeOption("high0", Strings.getter("bitFinderHighOption", "0")); static final Attribute<AttributeOption> TYPE = Attributes.forOption("type", Strings.getter("bitFinderTypeAttr"), new AttributeOption[] { LOW_ONE, HIGH_ONE, LOW_ZERO, HIGH_ZERO }); public BitFinder() { super("BitFinder", Strings.getter("bitFinderComponent")); setAttributes(new Attribute[] { StdAttr.WIDTH, TYPE }, new Object[] { BitWidth.create(8), LOW_ONE }); setKeyConfigurator(new BitWidthConfigurator(StdAttr.WIDTH)); setIconName("bitfindr.gif"); } private int computeOutputBits(int maxBits) { int outWidth = 1; while ((1 << outWidth) <= maxBits) outWidth++; return outWidth; } @Override protected void configureNewInstance(Instance instance) { configurePorts(instance); instance.addAttributeListener(); } private void configurePorts(Instance instance) { BitWidth inWidth = instance.getAttributeValue(StdAttr.WIDTH); int outWidth = computeOutputBits(inWidth.getWidth() - 1); Port[] ps = new Port[3]; ps[0] = new Port(-20, 20, Port.OUTPUT, BitWidth.ONE); ps[1] = new Port(0, 0, Port.OUTPUT, BitWidth.create(outWidth)); ps[2] = new Port(-40, 0, Port.INPUT, inWidth); Object type = instance.getAttributeValue(TYPE); if (type == HIGH_ZERO) { ps[0].setToolTip(Strings.getter("bitFinderPresentTip", "0")); ps[1].setToolTip(Strings.getter("bitFinderIndexHighTip", "0")); } else if (type == LOW_ZERO) { ps[0].setToolTip(Strings.getter("bitFinderPresentTip", "0")); ps[1].setToolTip(Strings.getter("bitFinderIndexLowTip", "0")); } else if (type == HIGH_ONE) { ps[0].setToolTip(Strings.getter("bitFinderPresentTip", "1")); ps[1].setToolTip(Strings.getter("bitFinderIndexHighTip", "1")); } else { ps[0].setToolTip(Strings.getter("bitFinderPresentTip", "1")); ps[1].setToolTip(Strings.getter("bitFinderIndexLowTip", "1")); } ps[2].setToolTip(Strings.getter("bitFinderInputTip")); instance.setPorts(ps); } @Override public Bounds getOffsetBounds(AttributeSet attrs) { return Bounds.create(-40, -20, 40, 40); } @Override protected void instanceAttributeChanged(Instance instance, Attribute<?> attr) { if (attr == StdAttr.WIDTH) { configurePorts(instance); } else if (attr == TYPE) { instance.fireInvalidated(); } } @Override public void paintInstance(InstancePainter painter) { Graphics g = painter.getGraphics(); painter.drawBounds(); painter.drawPorts(); String top = Strings.get("bitFinderFindLabel"); String mid; String bot; Object type = painter.getAttributeValue(TYPE); if (type == HIGH_ZERO) { mid = Strings.get("bitFinderHighLabel"); bot = "0"; } else if (type == LOW_ZERO) { mid = Strings.get("bitFinderLowLabel"); bot = "0"; } else if (type == HIGH_ONE) { mid = Strings.get("bitFinderHighLabel"); bot = "1"; } else { mid = Strings.get("bitFinderLowLabel"); bot = "1"; } Bounds bds = painter.getBounds(); int x = bds.getX() + bds.getWidth() / 2; int y0 = bds.getY(); GraphicsUtil.drawCenteredText(g, top, x, y0 + 8); GraphicsUtil.drawCenteredText(g, mid, x, y0 + 20); GraphicsUtil.drawCenteredText(g, bot, x, y0 + 32); } @Override public void propagate(InstanceState state) { int width = state.getAttributeValue(StdAttr.WIDTH).getWidth(); int outWidth = computeOutputBits(width - 1); Object type = state.getAttributeValue(TYPE); Value[] bits = state.getPortValue(2).getAll(); Value want; int i; if (type == HIGH_ZERO) { want = Value.FALSE; for (i = bits.length - 1; i >= 0 && bits[i] == Value.TRUE; i--) { } } else if (type == LOW_ZERO) { want = Value.FALSE; for (i = 0; i < bits.length && bits[i] == Value.TRUE; i++) { } } else if (type == HIGH_ONE) { want = Value.TRUE; for (i = bits.length - 1; i >= 0 && bits[i] == Value.FALSE; i--) { } } else { want = Value.TRUE; for (i = 0; i < bits.length && bits[i] == Value.FALSE; i++) { } } Value present; Value index; if (i < 0 || i >= bits.length) { present = Value.FALSE; index = Value.createKnown(BitWidth.create(outWidth), 0); } else if (bits[i] == want) { present = Value.TRUE; index = Value.createKnown(BitWidth.create(outWidth), i); } else { present = Value.ERROR; index = Value.createError(BitWidth.create(outWidth)); } int delay = outWidth * Adder.PER_DELAY; state.setPort(0, present, delay); state.setPort(1, index, delay); } }