/******************************************************************************* * 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.Font; import java.awt.Graphics; import java.awt.Window; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.util.NoSuchElementException; import java.util.StringTokenizer; import javax.swing.JLabel; import com.bfh.logisim.designrulecheck.CorrectLabel; import com.cburch.logisim.circuit.CircuitState; 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.Location; import com.cburch.logisim.data.Value; import com.cburch.logisim.gui.hex.HexFile; import com.cburch.logisim.gui.hex.HexFrame; import com.cburch.logisim.gui.main.Frame; import com.cburch.logisim.instance.Instance; import com.cburch.logisim.instance.InstanceLogger; 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.proj.Project; import com.cburch.logisim.util.GraphicsUtil; public class Ram extends Mem { static class ContentsAttribute extends Attribute<MemContents> { public ContentsAttribute() { super("contents", Strings.getter("romContentsAttr")); } @Override public java.awt.Component getCellEditor(Window source, MemContents value) { ContentsCell ret = new ContentsCell(source, value); ret.mouseClicked(null); return ret; } public MemContents parse(String value) { int lineBreak = value.indexOf('\n'); String first = lineBreak < 0 ? value : value .substring(0, lineBreak); String rest = lineBreak < 0 ? "" : value.substring(lineBreak + 1); StringTokenizer toks = new StringTokenizer(first); try { String header = toks.nextToken(); if (!header.equals("addr/data:")) { return null; } int addr = Integer.parseInt(toks.nextToken()); int data = Integer.parseInt(toks.nextToken()); MemContents ret = MemContents.create(addr, data); HexFile.open(ret, new StringReader(rest)); return ret; } catch (IOException e) { return null; } catch (NumberFormatException e) { return null; } catch (NoSuchElementException e) { return null; } } @Override public String toDisplayString(MemContents value) { return Strings.get("romContentsValue"); } @Override public String toStandardString(MemContents state) { int addr = state.getLogLength(); int data = state.getWidth(); StringWriter ret = new StringWriter(); ret.write("addr/data: " + addr + " " + data + "\n"); try { HexFile.save(ret, state); } catch (IOException e) { } return ret.toString(); } } @SuppressWarnings("serial") private static class ContentsCell extends JLabel implements MouseListener { Window source; MemContents contents; ContentsCell(Window source, MemContents contents) { super(Strings.get("romContentsValue")); this.source = source; this.contents = contents; addMouseListener(this); } public void mouseClicked(MouseEvent e) { if (contents == null) { return; } Project proj = source instanceof Frame ? ((Frame) source) .getProject() : null; HexFrame frame = RamAttributes.getHexFrame(contents, proj); frame.setVisible(true); frame.toFront(); } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e) { } public void mouseReleased(MouseEvent e) { } } public static class Logger extends InstanceLogger { @Override public String getLogName(InstanceState state, Object option) { String Label = state.getAttributeValue(StdAttr.LABEL); if (Label.equals("")) { Label = null; } if (option instanceof Integer) { String disp = Strings.get("ramComponent"); Location loc = state.getInstance().getLocation(); return (Label == null) ? disp + loc + "[" + option + "]" : Label + "[" + option + "]"; } else { return Label; } } @Override public Object[] getLogOptions(InstanceState state) { int addrBits = state.getAttributeValue(ADDR_ATTR).getWidth(); if (addrBits >= logOptions.length) { addrBits = logOptions.length - 1; } synchronized (logOptions) { Object[] ret = logOptions[addrBits]; if (ret == null) { ret = new Object[1 << addrBits]; logOptions[addrBits] = ret; for (int i = 0; i < ret.length; i++) { ret[i] = Integer.valueOf(i); } } return ret; } } @Override public Value getLogValue(InstanceState state, Object option) { if (option instanceof Integer) { MemState s = (MemState) state.getData(); int addr = ((Integer) option).intValue(); return Value.createKnown(BitWidth.create(s.getDataBits()), s .getContents().get(addr)); } else { return Value.NIL; } } } public static int ByteEnableIndex(AttributeSet Attrs) { Object trigger = Attrs.getValue(StdAttr.TRIGGER); boolean asynch = trigger.equals(StdAttr.TRIG_HIGH) || trigger.equals(StdAttr.TRIG_LOW); Object bus = Attrs.getValue(RamAttributes.ATTR_DBUS); boolean separate = bus == null ? false : bus .equals(RamAttributes.BUS_SEP); Object be = Attrs.getValue(RamAttributes.ATTR_ByteEnables); boolean byteEnables = be == null ? false : be .equals(RamAttributes.BUS_WITH_BYTEENABLES); if (byteEnables) { int ByteEnableIndex = (asynch) ? (separate) ? AByEnSep : AByEnBiDir : (separate) ? SByEnSep : SByEnBiDir; return ByteEnableIndex; } return -1; } public static int GetNrOfByteEnables(AttributeSet Attrs) { int NrOfBits = Attrs.getValue(Mem.DATA_ATTR).getWidth(); return (NrOfBits + 7) / 8; } public static Attribute<MemContents> CONTENTS_ATTR = new ContentsAttribute(); static final int OE = MEM_INPUTS + 0; static final int WE = MEM_INPUTS + 1; public static final int CLK = MEM_INPUTS + 2; static final int SDIN = MEM_INPUTS + 3; static final int ADIN = MEM_INPUTS + 2; static final int AByEnBiDir = MEM_INPUTS + 2; static final int AByEnSep = MEM_INPUTS + 3; static final int SByEnBiDir = MEM_INPUTS + 3; static final int SByEnSep = MEM_INPUTS + 4; private static Object[][] logOptions = new Object[9][]; public Ram() { super("RAM", Strings.getter("ramComponent"), 3); setIconName("ram.gif"); setInstanceLogger(Logger.class); } @Override protected void configureNewInstance(Instance instance) { super.configureNewInstance(instance); instance.addAttributeListener(); } @Override void configurePorts(Instance instance) { Object trigger = instance.getAttributeValue(StdAttr.TRIGGER); boolean asynch = trigger.equals(StdAttr.TRIG_HIGH) || trigger.equals(StdAttr.TRIG_LOW); Object bus = instance.getAttributeValue(RamAttributes.ATTR_DBUS); boolean separate = bus == null ? false : bus .equals(RamAttributes.BUS_SEP); Object be = instance.getAttributeValue(RamAttributes.ATTR_ByteEnables); boolean byteEnables = be == null ? false : be .equals(RamAttributes.BUS_WITH_BYTEENABLES); int NrOfByteEnables = GetNrOfByteEnables(instance.getAttributeSet()); int portCount = MEM_INPUTS; if (asynch) { portCount += 2; } else { portCount += 3; } if (separate) { portCount++; } if (byteEnables) { portCount += NrOfByteEnables; } Port[] ps = new Port[portCount]; ps[ADDR] = new Port(0, 10, Port.INPUT, ADDR_ATTR); ps[ADDR].setToolTip(Strings.getter("memAddrTip")); ps[OE] = new Port(0, 60, Port.INPUT, 1); ps[OE].setToolTip(Strings.getter("ramOETip")); ps[WE] = new Port(0, 50, Port.INPUT, 1); ps[WE].setToolTip(Strings.getter("ramWETip")); if (!asynch) { int ClockOffset = 70; if (byteEnables) { ClockOffset += NrOfByteEnables * 10; } ps[CLK] = new Port(0, ClockOffset, Port.INPUT, 1); ps[CLK].setToolTip(Strings.getter("ramClkTip")); } int ypos = (instance.getAttributeValue(Mem.DATA_ATTR).getWidth() == 1) ? getControlHeight(instance .getAttributeSet()) + 10 : getControlHeight(instance .getAttributeSet()); if (separate) { if (asynch) { ps[ADIN] = new Port(0, ypos, Port.INPUT, DATA_ATTR); ps[ADIN].setToolTip(Strings.getter("ramInTip")); } else { ps[SDIN] = new Port(0, ypos, Port.INPUT, DATA_ATTR); ps[SDIN].setToolTip(Strings.getter("ramInTip")); } ps[DATA] = new Port(SymbolWidth + 40, ypos, Port.OUTPUT, DATA_ATTR); ps[DATA].setToolTip(Strings.getter("memDataTip")); } else { ps[DATA] = new Port(SymbolWidth + 50, ypos, Port.INOUT, DATA_ATTR); ps[DATA].setToolTip(Strings.getter("ramBusTip")); } if (byteEnables) { int ByteEnableIndex = ByteEnableIndex(instance.getAttributeSet()); for (int i = 0; i < NrOfByteEnables; i++) { ps[ByteEnableIndex + i] = new Port(0, 70 + i * 10, Port.INPUT, 1); String Label = "ramByteEnableTip" + Integer.toString(NrOfByteEnables - i - 1); ps[ByteEnableIndex + i].setToolTip(Strings.getter(Label)); } } instance.setPorts(ps); } @Override public AttributeSet createAttributeSet() { return new RamAttributes(); } private void DrawConnections(Graphics g, int xpos, int ypos, boolean singleBit, boolean separate, boolean sync, boolean ByteEnabled, int bit) { Font font = g.getFont(); GraphicsUtil.switchToWidth(g, 2); if (separate) { if (singleBit) { g.drawLine(xpos, ypos + 10, xpos + 20, ypos + 10); g.drawLine(xpos + 20 + SymbolWidth, ypos + 10, xpos + 40 + SymbolWidth, ypos + 10); } else { g.drawLine(xpos + 5, ypos + 5, xpos + 10, ypos + 10); g.drawLine(xpos + 10, ypos + 10, xpos + 20, ypos + 10); g.drawLine(xpos + 20 + SymbolWidth, ypos + 10, xpos + 30 + SymbolWidth, ypos + 10); g.drawLine(xpos + 30 + SymbolWidth, ypos + 10, xpos + 35 + SymbolWidth, ypos + 5); g.setFont(font.deriveFont(7.0f)); GraphicsUtil .drawText(g, Integer.toString(bit), xpos + 17, ypos + 7, GraphicsUtil.H_RIGHT, GraphicsUtil.V_BASELINE); GraphicsUtil.drawText(g, Integer.toString(bit), xpos + 23 + SymbolWidth, ypos + 7, GraphicsUtil.H_LEFT, GraphicsUtil.V_BASELINE); g.setFont(font); } String ByteIndex = ""; if (ByteEnabled) { int Index = bit / 8; ByteIndex = "," + Integer.toString(Index + 4); } String DLabel = (sync) ? "A,1,3" + ByteIndex + "D" : "A,1" + ByteIndex + "D"; String QLabel = (sync) ? "A,2,3" + ByteIndex : "A,2" + ByteIndex; g.setFont(font.deriveFont(9.0f)); GraphicsUtil.drawText(g, DLabel, xpos + 23, ypos + 10, GraphicsUtil.H_LEFT, GraphicsUtil.V_CENTER); GraphicsUtil.drawText(g, QLabel, xpos + 17 + SymbolWidth, ypos + 10, GraphicsUtil.H_RIGHT, GraphicsUtil.V_CENTER); g.setFont(font); } else { g.drawLine(xpos + 24 + SymbolWidth, ypos + 2, xpos + 28 + SymbolWidth, ypos + 5); g.drawLine(xpos + 24 + SymbolWidth, ypos + 8, xpos + 28 + SymbolWidth, ypos + 5); g.drawLine(xpos + 20 + SymbolWidth, ypos + 5, xpos + 30 + SymbolWidth, ypos + 5); g.drawLine(xpos + 22 + SymbolWidth, ypos + 15, xpos + 26 + SymbolWidth, ypos + 12); g.drawLine(xpos + 22 + SymbolWidth, ypos + 15, xpos + 26 + SymbolWidth, ypos + 18); g.drawLine(xpos + 20 + SymbolWidth, ypos + 15, xpos + 30 + SymbolWidth, ypos + 15); g.drawLine(xpos + 30 + SymbolWidth, ypos + 5, xpos + 30 + SymbolWidth, ypos + 15); g.drawLine(xpos + 30 + SymbolWidth, ypos + 10, xpos + 40 + SymbolWidth, ypos + 10); if (singleBit) { g.drawLine(xpos + 40 + SymbolWidth, ypos + 10, xpos + 50 + SymbolWidth, ypos + 10); } else { g.drawLine(xpos + 40 + SymbolWidth, ypos + 10, xpos + 45 + SymbolWidth, ypos + 5); } g.setFont(font.deriveFont(7.0f)); GraphicsUtil.drawText(g, Integer.toString(bit), xpos + 33 + SymbolWidth, ypos + 7, GraphicsUtil.H_LEFT, GraphicsUtil.V_BASELINE); String ByteIndex = ""; if (ByteEnabled) { int Index = bit / 8; ByteIndex = "," + Integer.toString(Index + 4); } String DLabel = (sync) ? "A,1,3" + ByteIndex + "D" : "A,1" + ByteIndex + "D"; String QLabel = "A,2" + ByteIndex + " "; g.setFont(font.deriveFont(9.0f)); GraphicsUtil.drawText(g, DLabel, xpos + 17 + SymbolWidth, ypos + 13, GraphicsUtil.H_RIGHT, GraphicsUtil.V_CENTER); GraphicsUtil.drawText(g, QLabel, xpos + 17 + SymbolWidth, ypos + 5, GraphicsUtil.H_RIGHT, GraphicsUtil.V_CENTER); g.setFont(font); GraphicsUtil.switchToWidth(g, 1); g.drawLine(xpos + 11 + SymbolWidth, ypos + 4, xpos + 19 + SymbolWidth, ypos + 4); g.drawLine(xpos + 11 + SymbolWidth, ypos + 4, xpos + 15 + SymbolWidth, ypos + 8); g.drawLine(xpos + 15 + SymbolWidth, ypos + 8, xpos + 19 + SymbolWidth, ypos + 4); } GraphicsUtil.switchToWidth(g, 1); } private void DrawControlBlock(InstancePainter painter, int xpos, int ypos) { Object trigger = painter.getAttributeValue(StdAttr.TRIGGER); boolean asynch = trigger.equals(StdAttr.TRIG_HIGH) || trigger.equals(StdAttr.TRIG_LOW); boolean inverted = trigger.equals(StdAttr.TRIG_FALLING) || trigger.equals(StdAttr.TRIG_LOW); Object be = painter.getAttributeValue(RamAttributes.ATTR_ByteEnables); boolean byteEnables = be == null ? false : be .equals(RamAttributes.BUS_WITH_BYTEENABLES); int NrOfByteEnables = GetNrOfByteEnables(painter.getAttributeSet()); Graphics g = painter.getGraphics(); GraphicsUtil.switchToWidth(g, 2); AttributeSet attrs = painter.getAttributeSet(); g.drawLine(xpos + 20, ypos, xpos + 20 + SymbolWidth, ypos); g.drawLine(xpos + 20, ypos, xpos + 20, ypos + getControlHeight(attrs) - 10); g.drawLine(xpos + 20 + SymbolWidth, ypos, xpos + 20 + SymbolWidth, ypos + getControlHeight(attrs) - 10); g.drawLine(xpos + 20, ypos + getControlHeight(attrs) - 10, xpos + 30, ypos + getControlHeight(attrs) - 10); g.drawLine(xpos + 20 + SymbolWidth - 10, ypos + getControlHeight(attrs) - 10, xpos + 20 + SymbolWidth, ypos + getControlHeight(attrs) - 10); g.drawLine(xpos + 30, ypos + getControlHeight(attrs) - 10, xpos + 30, ypos + getControlHeight(attrs)); g.drawLine(xpos + 20 + SymbolWidth - 10, ypos + getControlHeight(attrs) - 10, xpos + 20 + SymbolWidth - 10, ypos + getControlHeight(attrs)); GraphicsUtil.drawCenteredText( g, "RAM " + GetSizeLabel(painter.getAttributeValue(Mem.ADDR_ATTR) .getWidth()) + " x " + Integer.toString(painter.getAttributeValue( Mem.DATA_ATTR).getWidth()), xpos + (SymbolWidth / 2) + 20, ypos + 5); if (asynch && inverted) { g.drawLine(xpos, ypos + 50, xpos + 12, ypos + 50); g.drawOval(xpos + 12, ypos + 46, 8, 8); } else { g.drawLine(xpos, ypos + 50, xpos + 20, ypos + 50); } GraphicsUtil.drawText(g, "M1 [Write Enable]", xpos + 33, ypos + 50, GraphicsUtil.H_LEFT, GraphicsUtil.V_CENTER); painter.drawPort(WE); if (asynch && inverted) { g.drawLine(xpos, ypos + 60, xpos + 12, ypos + 60); g.drawOval(xpos + 12, ypos + 56, 8, 8); } else { g.drawLine(xpos, ypos + 60, xpos + 20, ypos + 60); } GraphicsUtil.drawText(g, "M2 [Output Enable]", xpos + 33, ypos + 60, GraphicsUtil.H_LEFT, GraphicsUtil.V_CENTER); painter.drawPort(OE); if (!asynch) { int yoffset = 70; if (byteEnables) { yoffset += NrOfByteEnables * 10; } if (inverted) { g.drawLine(xpos, ypos + yoffset, xpos + 12, ypos + yoffset); g.drawOval(xpos + 12, ypos + yoffset - 4, 8, 8); } else { g.drawLine(xpos, ypos + yoffset, xpos + 20, ypos + yoffset); } GraphicsUtil.drawText(g, "C3", xpos + 33, ypos + yoffset, GraphicsUtil.H_LEFT, GraphicsUtil.V_CENTER); painter.drawClockSymbol(xpos + 20, ypos + yoffset); painter.drawPort(CLK); } if (byteEnables) { int ByteEnableIndex = ByteEnableIndex(painter.getAttributeSet()); GraphicsUtil.switchToWidth(g, 2); for (int i = 0; i < NrOfByteEnables; i++) { g.drawLine(xpos, ypos + 70 + i * 10, xpos + 20, ypos + 70 + i * 10); painter.drawPort(ByteEnableIndex + i); String Label = "M" + Integer.toString((NrOfByteEnables - i) + 3) + " [ByteEnable " + Integer.toString((NrOfByteEnables - i) - 1) + "]"; GraphicsUtil.drawText(g, Label, xpos + 33, ypos + 70 + i * 10, GraphicsUtil.H_LEFT, GraphicsUtil.V_CENTER); } } GraphicsUtil.switchToWidth(g, 1); DrawAddress(painter, xpos, ypos + 10, painter.getAttributeValue(Mem.ADDR_ATTR).getWidth()); } private void DrawDataBlock(InstancePainter painter, int xpos, int ypos, int bit, int NrOfBits) { Object busVal = painter.getAttributeValue(RamAttributes.ATTR_DBUS); int realypos = ypos + getControlHeight(painter.getAttributeSet()) + bit * 20; int realxpos = xpos + 20; boolean FirstBlock = bit == 0; boolean LastBlock = bit == (NrOfBits - 1); Graphics g = painter.getGraphics(); boolean separate = busVal == null ? false : busVal .equals(RamAttributes.BUS_SEP); Object trigger = painter.getAttributeValue(StdAttr.TRIGGER); boolean asynch = trigger.equals(StdAttr.TRIG_HIGH) || trigger.equals(StdAttr.TRIG_LOW); Object be = painter.getAttributeValue(RamAttributes.ATTR_ByteEnables); boolean byteEnables = be == null ? false : be .equals(RamAttributes.BUS_WITH_BYTEENABLES); GraphicsUtil.switchToWidth(g, 2); g.drawRect(realxpos, realypos, SymbolWidth, 20); DrawConnections(g, xpos, realypos, FirstBlock & LastBlock, separate, !asynch, byteEnables, bit); if (FirstBlock) { painter.drawPort(DATA); if (separate) { if (asynch) { painter.drawPort(ADIN); } else { painter.drawPort(SDIN); } } if (!LastBlock) { GraphicsUtil.switchToWidth(g, 5); if (separate) { g.drawLine(xpos, realypos, xpos + 5, realypos + 5); g.drawLine(xpos + 5, realypos + 5, xpos + 5, realypos + 20); g.drawLine(xpos + 40 + SymbolWidth, realypos, xpos + 35 + SymbolWidth, realypos + 5); g.drawLine(xpos + 35 + SymbolWidth, realypos + 5, xpos + 35 + SymbolWidth, realypos + 20); } else { g.drawLine(xpos + 50 + SymbolWidth, realypos, xpos + 45 + SymbolWidth, realypos + 5); g.drawLine(xpos + 45 + SymbolWidth, realypos + 5, xpos + 45 + SymbolWidth, realypos + 20); } } } else { GraphicsUtil.switchToWidth(g, 5); if (LastBlock) { if (separate) { g.drawLine(xpos + 5, realypos, xpos + 5, realypos + 5); g.drawLine(xpos + 35 + SymbolWidth, realypos, xpos + 35 + SymbolWidth, realypos + 5); } else { g.drawLine(xpos + 45 + SymbolWidth, realypos, xpos + 45 + SymbolWidth, realypos + 5); } } else { if (separate) { g.drawLine(xpos + 5, realypos, xpos + 5, realypos + 20); g.drawLine(xpos + 35 + SymbolWidth, realypos, xpos + 35 + SymbolWidth, realypos + 20); } else { g.drawLine(xpos + 45 + SymbolWidth, realypos, xpos + 45 + SymbolWidth, realypos + 20); } } } GraphicsUtil.switchToWidth(g, 1); } public int getControlHeight(AttributeSet attrs) { Object trigger = attrs.getValue(StdAttr.TRIGGER); boolean asynch = trigger.equals(StdAttr.TRIG_HIGH) || trigger.equals(StdAttr.TRIG_LOW); Object be = attrs.getValue(RamAttributes.ATTR_ByteEnables); boolean byteEnables = be == null ? false : be .equals(RamAttributes.BUS_WITH_BYTEENABLES); int result = 80; if (!asynch) { result += 10; } if (byteEnables) { int NrByteEnables = GetNrOfByteEnables(attrs); result += NrByteEnables * 10; } return result; } @Override public String getHDLName(AttributeSet attrs) { StringBuffer CompleteName = new StringBuffer(); CompleteName.append(CorrectLabel.getCorrectLabel(attrs .getValue(StdAttr.LABEL))); if (CompleteName.length() == 0) { CompleteName.append("RAM"); } return CompleteName.toString(); } @Override HexFrame getHexFrame(Project proj, Instance instance, CircuitState circState) { return RamAttributes.getHexFrame( instance.getAttributeValue(CONTENTS_ATTR), proj); } @Override public Bounds getOffsetBounds(AttributeSet attrs) { int len = attrs.getValue(Mem.DATA_ATTR).getWidth(); Object bus = attrs.getValue(RamAttributes.ATTR_DBUS); boolean separate = bus == null ? false : bus .equals(RamAttributes.BUS_SEP); int xoffset = (separate) ? 40 : 50; return Bounds.create(0, 0, SymbolWidth + xoffset, getControlHeight(attrs) + 20 * len); } @Override MemState getState(Instance instance, CircuitState state) { RamState ret = (RamState) instance.getData(state); if (ret == null) { MemContents contents = instance .getAttributeValue(Ram.CONTENTS_ATTR); ret = new RamState(instance, contents, new MemListener(instance)); instance.setData(state, ret); } else { ret.setRam(instance); } return ret; } @Override MemState getState(InstanceState state) { RamState ret = (RamState) state.getData(); if (ret == null) { MemContents contents = state.getInstance().getAttributeValue( Ram.CONTENTS_ATTR); Instance instance = state.getInstance(); ret = new RamState(instance, contents, new MemListener(instance)); state.setData(ret); } else { ret.setRam(state.getInstance()); } return ret; } @Override public boolean HDLSupportedComponent(String HDLIdentifier, AttributeSet attrs) { if (MyHDLGenerator == null) { MyHDLGenerator = new RamHDLGeneratorFactory(); } return MyHDLGenerator.HDLTargetSupported(HDLIdentifier, attrs); } @Override protected void instanceAttributeChanged(Instance instance, Attribute<?> attr) { super.instanceAttributeChanged(instance, attr); if ((attr == Mem.DATA_ATTR) || (attr == RamAttributes.ATTR_DBUS) || (attr == StdAttr.TRIGGER) || (attr == RamAttributes.ATTR_ByteEnables)) { if ((attr == Mem.DATA_ATTR) || (attr == StdAttr.TRIGGER)) { boolean disable_due_to_bits = instance.getAttributeValue( Mem.DATA_ATTR).getWidth() < 9; boolean disable_due_to_async = instance.getAttributeValue( StdAttr.TRIGGER).equals(StdAttr.TRIG_HIGH) || instance.getAttributeValue(StdAttr.TRIGGER).equals( StdAttr.TRIG_LOW); if (disable_due_to_bits || disable_due_to_async) { if (!instance.getAttributeValue( RamAttributes.ATTR_ByteEnables).equals( RamAttributes.BUS_WITHOUT_BYTEENABLES)) { instance.getAttributeSet().setValue( RamAttributes.ATTR_ByteEnables, RamAttributes.BUS_WITHOUT_BYTEENABLES); super.instanceAttributeChanged(instance, RamAttributes.ATTR_ByteEnables); } instance.setAttributeReadOnly( RamAttributes.ATTR_ByteEnables, true); super.instanceAttributeChanged(instance, RamAttributes.ATTR_ByteEnables); instance.setAttributeReadOnly( RamAttributes.ATTR_ByteEnables, true); super.instanceAttributeChanged(instance, RamAttributes.ATTR_ByteEnables); } else { if (instance.getAttributeSet().isReadOnly( RamAttributes.ATTR_ByteEnables)) { instance.setAttributeReadOnly( RamAttributes.ATTR_ByteEnables, false); super.instanceAttributeChanged(instance, RamAttributes.ATTR_ByteEnables); } } } instance.recomputeBounds(); configurePorts(instance); } } @Override public void paintInstance(InstancePainter painter) { Graphics g = painter.getGraphics(); Bounds bds = painter.getBounds(); int NrOfBits = painter.getAttributeValue(Mem.DATA_ATTR).getWidth(); // int addrb = painter.getAttributeValue(Mem.ADDR_ATTR).getWidth(); String Label = painter.getAttributeValue(StdAttr.LABEL); if (Label != null) { Font font = g.getFont(); g.setFont(painter.getAttributeValue(StdAttr.LABEL_FONT)); GraphicsUtil.drawCenteredText(g, Label, bds.getX() + bds.getWidth() / 2, bds.getY() - g.getFont().getSize()); g.setFont(font); } int xpos = bds.getX(); int ypos = bds.getY(); DrawControlBlock(painter, xpos, ypos); for (int i = 0; i < NrOfBits; i++) { DrawDataBlock(painter, xpos, ypos, i, NrOfBits); } /* Draw contents */ if (painter.getShowState()) { RamState state = (RamState) getState(painter); state.paint(painter.getGraphics(), bds.getX() + 20, bds.getY(), true, getControlHeight(painter.getAttributeSet())); } } @Override public void propagate(InstanceState state) { RamState myState = (RamState) getState(state); Object trigger = state.getAttributeValue(StdAttr.TRIGGER); Object bus = state.getAttributeValue(RamAttributes.ATTR_DBUS); boolean asynch = trigger.equals(StdAttr.TRIG_HIGH) || trigger.equals(StdAttr.TRIG_LOW); boolean edge = false; if (!asynch) { edge = myState.setClock(state.getPortValue(CLK), trigger); } boolean triggered = asynch || edge; boolean separate = bus == null ? false : bus .equals(RamAttributes.BUS_SEP); boolean outputEnabled = (!asynch || trigger.equals(StdAttr.TRIG_HIGH)) ? state .getPortValue(OE) != Value.FALSE : state.getPortValue(OE) == Value.FALSE; BitWidth dataBits = state.getAttributeValue(DATA_ATTR); /* Set the outputs in tri-state in case of combined bus */ if ((!separate && !outputEnabled) || (separate && asynch && !outputEnabled)) { state.setPort(DATA, Value.createUnknown(dataBits), DELAY); } if (!triggered && !asynch && outputEnabled) { state.setPort(DATA, Value.createKnown(dataBits, myState.GetCurrentData()), DELAY); } if (triggered) { Object be = state.getAttributeValue(RamAttributes.ATTR_ByteEnables); boolean byteEnables = be == null ? false : be .equals(RamAttributes.BUS_WITH_BYTEENABLES); int NrOfByteEnables = GetNrOfByteEnables(state.getAttributeSet()); int ByteEnableIndex = ByteEnableIndex(state.getAttributeSet()); boolean shouldStore = (!asynch || trigger.equals(StdAttr.TRIG_HIGH)) ? state .getPortValue(WE) != Value.FALSE : state.getPortValue(WE) == Value.FALSE; Value addrValue = state.getPortValue(ADDR); int addr = addrValue.toIntValue(); if (!addrValue.isFullyDefined() || addr < 0) { return; } if (addr != myState.getCurrent()) { myState.setCurrent(addr); myState.scrollToShow(addr); } if (shouldStore) { int dataValue = state.getPortValue( !separate ? DATA : (asynch) ? ADIN : SDIN).toIntValue(); int memValue = myState.getContents().get(addr); if (byteEnables) { int mask = 0xFF << (NrOfByteEnables - 1) * 8; for (int i = 0; i < NrOfByteEnables; i++) { Value bitvalue = state .getPortValue(ByteEnableIndex + i); boolean disabled = bitvalue == null ? false : bitvalue .equals(Value.FALSE); if (disabled) { dataValue &= ~mask; dataValue |= (memValue & mask); } mask >>= 8; } } myState.getContents().set(addr, dataValue); } int val = myState.getContents().get(addr); int currentValue = myState.GetCurrentData(); if (byteEnables) { int mask = 0xFF << (NrOfByteEnables - 1) * 8; for (int i = 0; i < NrOfByteEnables; i++) { Value bitvalue = state.getPortValue(ByteEnableIndex + i); boolean disabled = bitvalue == null ? false : bitvalue .equals(Value.FALSE); if (disabled) { val &= ~mask; val |= (currentValue & mask); } mask >>= 8; } } myState.SetCurrentData(val); if (outputEnabled) { state.setPort(DATA, Value.createKnown(dataBits, val), DELAY); } } } @Override public boolean RequiresNonZeroLabel() { return true; } }