/******************************************************************************* * 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.memory; import java.awt.Color; import java.awt.Graphics; import com.bfh.logisim.designrulecheck.CorrectLabel; 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.util.GraphicsUtil; import com.cburch.logisim.util.StringUtil; public class Register extends InstanceFactory { public static void DrawRegister(InstancePainter painter, int x, int y, int nr_of_bits, boolean isLatch, boolean neg_active, boolean has_we, String value) { int dq_width = (nr_of_bits == 1) ? 3 : 5; int len = (nr_of_bits + 3) / 4; int wid = 7 * len + 2; int xoff = (60 - wid) / 2; Graphics g = painter.getGraphics(); if (painter.getShowState()) { g.setColor(Color.LIGHT_GRAY); g.fillRect(x + xoff, y + 1, wid, 16); g.setColor(Color.black); GraphicsUtil.drawCenteredText(g, value, x + 30, y + 8); g.setColor(Color.black); } GraphicsUtil.switchToWidth(g, 2); g.drawRect(x + 10, y + 20, 40, 60); if (nr_of_bits > 1) { g.drawLine(x + 15, y + 80, x + 15, y + 85); g.drawLine(x + 15, y + 85, x + 55, y + 85); g.drawLine(x + 55, y + 25, x + 55, y + 85); g.drawLine(x + 50, y + 25, x + 55, y + 25); if (nr_of_bits > 2) { g.drawLine(x + 20, y + 85, x + 20, y + 90); g.drawLine(x + 20, y + 90, x + 60, y + 90); g.drawLine(x + 60, y + 30, x + 60, y + 90); g.drawLine(x + 55, y + 30, x + 60, y + 30); } } GraphicsUtil.switchToWidth(g, 1); GraphicsUtil.switchToWidth(g, dq_width); g.drawLine(x, y + 30, x + 8, y + 30); g.drawLine(x + 52, y + 30, x + 60, y + 30); GraphicsUtil.switchToWidth(g, 1); GraphicsUtil.drawCenteredText(g, "D", x + 18, y + 30); GraphicsUtil.drawCenteredText(g, "Q", x + 41, y + 30); GraphicsUtil.switchToWidth(g, 3); g.drawLine(x + 30, y + 81, x + 30, y + 90); GraphicsUtil.switchToWidth(g, 1); g.setColor(Color.GRAY); GraphicsUtil.drawCenteredText(g, "R", x + 30, y + 70); g.setColor(Color.BLACK); if (has_we) { GraphicsUtil.drawCenteredText(g, "WE", x + 22, y + 50); GraphicsUtil.switchToWidth(g, 3); g.drawLine(x, y + 50, x + 10, y + 50); GraphicsUtil.switchToWidth(g, 1); } if (!isLatch) { GraphicsUtil.switchToWidth(g, 2); g.drawLine(x + 10, y + 65, x + 20, y + 70); g.drawLine(x + 10, y + 75, x + 20, y + 70); GraphicsUtil.switchToWidth(g, 1); } else { GraphicsUtil.drawCenteredText(g, "E", x + 18, y + 70); } if (!neg_active) { GraphicsUtil.switchToWidth(g, 3); g.drawLine(x, y + 70, x + 10, y + 70); GraphicsUtil.switchToWidth(g, 1); } else { GraphicsUtil.switchToWidth(g, 2); g.drawOval(x, y + 65, 10, 10); GraphicsUtil.switchToWidth(g, 1); } } static final int DELAY = 8; public static final int OUT = 0; static final int IN = 1; public static final int CK = 2; static final int CLR = 3; static final int EN = 4; static final int Xsize = 60; static final int Ysize = 90; public static final Attribute<Boolean> ATTR_SHOW_IN_TAB = Attributes .forBoolean("showInTab", Strings.getter("registerShowInTab")); public Register() { super("Register", Strings.getter("registerComponent")); setAttributes(new Attribute[] { StdAttr.WIDTH, StdAttr.TRIGGER, StdAttr.LABEL, StdAttr.LABEL_FONT, ATTR_SHOW_IN_TAB, }, new Object[] { BitWidth.create(8), StdAttr.TRIG_RISING, "", StdAttr.DEFAULT_LABEL_FONT, false, }); setKeyConfigurator(new BitWidthConfigurator(StdAttr.WIDTH)); setOffsetBounds(Bounds.create(0, 0, Xsize, Ysize)); setIconName("register.gif"); setInstancePoker(RegisterPoker.class); setInstanceLogger(RegisterLogger.class); Port[] ps = new Port[5]; ps[OUT] = new Port(60, 30, Port.OUTPUT, StdAttr.WIDTH); ps[IN] = new Port(0, 30, Port.INPUT, StdAttr.WIDTH); ps[CK] = new Port(0, 70, Port.INPUT, 1); ps[CLR] = new Port(30, 90, Port.INPUT, 1); ps[EN] = new Port(0, 50, Port.INPUT, 1); ps[OUT].setToolTip(Strings.getter("registerQTip")); ps[IN].setToolTip(Strings.getter("registerDTip")); ps[CK].setToolTip(Strings.getter("registerClkTip")); ps[CLR].setToolTip(Strings.getter("registerClrTip")); ps[EN].setToolTip(Strings.getter("registerEnableTip")); setPorts(ps); } @Override protected void configureNewInstance(Instance instance) { Bounds bds = instance.getBounds(); instance.setTextField(StdAttr.LABEL, StdAttr.LABEL_FONT, bds.getX() + bds.getWidth() / 2, bds.getY() - 3, GraphicsUtil.H_CENTER, GraphicsUtil.V_BASELINE); } @Override public String getHDLName(AttributeSet attrs) { StringBuffer CompleteName = new StringBuffer(); CompleteName.append(CorrectLabel.getCorrectLabel(this.getName()) .toUpperCase()); if ((attrs.getValue(StdAttr.TRIGGER) == StdAttr.TRIG_FALLING) || (attrs.getValue(StdAttr.TRIGGER) == StdAttr.TRIG_RISING)) { CompleteName.append("_FLIP_FLOP"); } else { CompleteName.append("_LATCH"); } return CompleteName.toString(); } @Override public boolean HDLSupportedComponent(String HDLIdentifier, AttributeSet attrs) { if (MyHDLGenerator == null) { MyHDLGenerator = new RegisterHDLGeneratorFactory(); } return MyHDLGenerator.HDLTargetSupported(HDLIdentifier, attrs); } @Override public void paintInstance(InstancePainter painter) { RegisterData state = (RegisterData) painter.getData(); BitWidth widthVal = painter.getAttributeValue(StdAttr.WIDTH); int width = widthVal == null ? 8 : widthVal.getWidth(); Location loc = painter.getLocation(); int x = loc.getX(); int y = loc.getY(); // determine text to draw in label String a; int val = state == null ? 0 : state.value; a = StringUtil.toHexString(width, val); Object Trigger = painter.getAttributeValue(StdAttr.TRIGGER); boolean IsLatch = Trigger.equals(StdAttr.TRIG_HIGH) || Trigger.equals(StdAttr.TRIG_LOW); boolean NegActive = Trigger.equals(StdAttr.TRIG_FALLING) || Trigger.equals(StdAttr.TRIG_LOW); DrawRegister(painter, x, y, width, IsLatch, NegActive, true, a); painter.drawLabel(); // draw input and output ports painter.drawPort(IN); painter.drawPort(OUT); painter.drawPort(CLR); painter.drawPort(EN); painter.drawPort(CK); } @Override public void propagate(InstanceState state) { RegisterData data = (RegisterData) state.getData(); if (data == null) { data = new RegisterData(); state.setData(data); } BitWidth dataWidth = state.getAttributeValue(StdAttr.WIDTH); Object triggerType = state.getAttributeValue(StdAttr.TRIGGER); boolean triggered = data.updateClock(state.getPortValue(CK), triggerType); if (state.getPortValue(CLR) == Value.TRUE) { data.value = 0; } else if (triggered && state.getPortValue(EN) != Value.FALSE) { Value in = state.getPortValue(IN); if (in.isFullyDefined()) { data.value = in.toIntValue(); } } state.setPort(OUT, Value.createKnown(dataWidth, data.value), DELAY); } }