/******************************************************************************* * 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.AttributeSet; import com.cburch.logisim.data.Attributes; import com.cburch.logisim.data.BitWidth; import com.cburch.logisim.data.Bounds; import com.cburch.logisim.data.Location; 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.IntegerConfigurator; import com.cburch.logisim.tools.key.JoinedConfigurator; import com.cburch.logisim.util.GraphicsUtil; public class BitAdder extends InstanceFactory { static final Attribute<Integer> NUM_INPUTS = Attributes.forIntegerRange( "inputs", Strings.getter("gateInputsAttr"), 1, 32); public BitAdder() { super("BitAdder", Strings.getter("bitAdderComponent")); setAttributes(new Attribute[] { StdAttr.WIDTH, NUM_INPUTS }, new Object[] { BitWidth.create(8), Integer.valueOf(1) }); setKeyConfigurator(JoinedConfigurator.create(new IntegerConfigurator( NUM_INPUTS, 1, 32, 0), new BitWidthConfigurator(StdAttr.WIDTH))); setIconName("bitadder.gif"); } private int computeOutputBits(int width, int inputs) { int maxBits = width * inputs; 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 inputs = instance.getAttributeValue(NUM_INPUTS).intValue(); int outWidth = computeOutputBits(inWidth.getWidth(), inputs); int y; int dy = 10; switch (inputs) { case 1: y = 0; break; case 2: y = -10; dy = 20; break; case 3: y = -10; break; default: y = ((inputs - 1) / 2) * -10; } Port[] ps = new Port[inputs + 1]; ps[0] = new Port(0, 0, Port.OUTPUT, BitWidth.create(outWidth)); ps[0].setToolTip(Strings.getter("bitAdderOutputManyTip")); for (int i = 0; i < inputs; i++) { ps[i + 1] = new Port(-40, y + i * dy, Port.INPUT, inWidth); ps[i + 1].setToolTip(Strings.getter("bitAdderInputTip")); } instance.setPorts(ps); } @Override public Bounds getOffsetBounds(AttributeSet attrs) { int inputs = attrs.getValue(NUM_INPUTS).intValue(); int h = Math.max(40, 10 * inputs); int y = inputs < 4 ? 20 : (((inputs - 1) / 2) * 10 + 5); return Bounds.create(-40, -y, 40, h); } @Override protected void instanceAttributeChanged(Instance instance, Attribute<?> attr) { if (attr == StdAttr.WIDTH) { configurePorts(instance); } else if (attr == NUM_INPUTS) { configurePorts(instance); instance.recomputeBounds(); } } @Override public void paintInstance(InstancePainter painter) { Graphics g = painter.getGraphics(); painter.drawBounds(); painter.drawPorts(); GraphicsUtil.switchToWidth(g, 2); Location loc = painter.getLocation(); int x = loc.getX() - 10; int y = loc.getY(); g.drawLine(x - 2, y - 5, x - 2, y + 5); g.drawLine(x + 2, y - 5, x + 2, y + 5); g.drawLine(x - 5, y - 2, x + 5, y - 2); g.drawLine(x - 5, y + 2, x + 5, y + 2); } @Override public void propagate(InstanceState state) { int width = state.getAttributeValue(StdAttr.WIDTH).getWidth(); int inputs = state.getAttributeValue(NUM_INPUTS).intValue(); // compute the number of 1 bits int minCount = 0; // number that are definitely 1 int maxCount = 0; // number that are definitely not 0 (incl X/Z) for (int i = 1; i <= inputs; i++) { Value v = state.getPortValue(i); Value[] bits = v.getAll(); for (int j = 0; j < bits.length; j++) { Value b = bits[j]; if (b == Value.TRUE) minCount++; if (b != Value.FALSE) maxCount++; } } // compute which output bits should be error bits int unknownMask = 0; for (int i = minCount + 1; i <= maxCount; i++) { unknownMask |= (minCount ^ i); } Value[] out = new Value[computeOutputBits(width, inputs)]; for (int i = 0; i < out.length; i++) { if (((unknownMask >> i) & 1) != 0) { out[i] = Value.ERROR; } else if (((minCount >> i) & 1) != 0) { out[i] = Value.TRUE; } else { out[i] = Value.FALSE; } } int delay = out.length * Adder.PER_DELAY; state.setPort(0, Value.create(out), delay); } }