/*******************************************************************************
* 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.FontMetrics;
import java.awt.Graphics;
import java.io.File;
import java.io.IOException;
import java.util.WeakHashMap;
import com.cburch.hex.HexModel;
import com.cburch.hex.HexModelListener;
import com.cburch.logisim.circuit.CircuitState;
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.gui.hex.HexFile;
import com.cburch.logisim.gui.hex.HexFrame;
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.proj.Project;
import com.cburch.logisim.tools.MenuExtender;
import com.cburch.logisim.tools.key.BitWidthConfigurator;
import com.cburch.logisim.tools.key.JoinedConfigurator;
import com.cburch.logisim.util.GraphicsUtil;
import com.cburch.logisim.util.StringGetter;
abstract class Mem extends InstanceFactory {
// Note: The code is meant to be able to handle up to 32-bit addresses, but
// it
// hasn't been debugged thoroughly. There are two definite changes I would
// make if I were to extend the address bits: First, there would need to be
// some
// modification to the memory's graphical representation, because there
// isn't
// room in the box to include such long memory addresses with the current
// font
// size. And second, I'd alter the MemContents class's PAGE_SIZE_BITS
// constant
// to 14 so that its "page table" isn't quite so big.
static class MemListener implements HexModelListener {
Instance instance;
MemListener(Instance instance) {
this.instance = instance;
}
public void bytesChanged(HexModel source, long start, long numBytes,
int[] values) {
instance.fireInvalidated();
}
public void metainfoChanged(HexModel source) {
}
}
public static final int SymbolWidth = 200;
public static final Attribute<BitWidth> ADDR_ATTR = Attributes.forBitWidth(
"addrWidth", Strings.getter("ramAddrWidthAttr"), 2, 24);
public static final Attribute<BitWidth> DATA_ATTR = Attributes.forBitWidth(
"dataWidth", Strings.getter("ramDataWidthAttr"));
// port-related constants
static final int DATA = 0;
static final int ADDR = 1;
static final int MEM_INPUTS = 2;
// other constants
static final int DELAY = 10;
private WeakHashMap<Instance, File> currentInstanceFiles;
Mem(String name, StringGetter desc, int extraPorts) {
super(name, desc);
currentInstanceFiles = new WeakHashMap<Instance, File>();
setInstancePoker(MemPoker.class);
setKeyConfigurator(JoinedConfigurator.create(new BitWidthConfigurator(
ADDR_ATTR, 2, 24, 0), new BitWidthConfigurator(DATA_ATTR)));
setOffsetBounds(Bounds.create(-140, -40, 140, 80));
}
@Override
protected void configureNewInstance(Instance instance) {
configurePorts(instance);
}
abstract void configurePorts(Instance instance);
@Override
public abstract AttributeSet createAttributeSet();
protected void DrawAddress(InstancePainter painter, int xpos, int ypos,
int NrAddressBits) {
Graphics g = painter.getGraphics();
GraphicsUtil.switchToWidth(g, 2);
g.drawLine(xpos + 10, ypos + 10, xpos + 19, ypos + 10);
g.drawLine(xpos + 5, ypos + 5, xpos + 10, ypos + 10);
g.drawLine(xpos + 10, ypos + 30, xpos + 19, ypos + 30);
g.drawLine(xpos + 5, ypos + 25, xpos + 10, ypos + 30);
if (NrAddressBits > 2) {
for (int i = 0; i < 3; i++) {
g.drawLine(xpos + 15, ypos + 13 + i * 6, xpos + 15, ypos + 15
+ i * 6);
}
}
GraphicsUtil.switchToWidth(g, 5);
g.drawLine(xpos, ypos, xpos + 5, ypos + 5);
g.drawLine(xpos + 5, ypos + 5, xpos + 5, ypos + 25);
GraphicsUtil.switchToWidth(g, 1);
GraphicsUtil.drawText(g, "0", xpos + 22, ypos + 10,
GraphicsUtil.H_LEFT, GraphicsUtil.V_CENTER);
GraphicsUtil.drawText(g, Integer.toString(NrAddressBits - 1),
xpos + 22, ypos + 30, GraphicsUtil.H_LEFT,
GraphicsUtil.V_CENTER);
GraphicsUtil.drawText(g, "A", xpos + 50, ypos + 20,
GraphicsUtil.H_LEFT, GraphicsUtil.V_CENTER);
g.drawLine(xpos + 40, ypos + 5, xpos + 45, ypos + 10);
g.drawLine(xpos + 45, ypos + 10, xpos + 45, ypos + 17);
g.drawLine(xpos + 45, ypos + 17, xpos + 48, ypos + 20);
g.drawLine(xpos + 48, ypos + 20, xpos + 45, ypos + 23);
g.drawLine(xpos + 45, ypos + 23, xpos + 45, ypos + 30);
g.drawLine(xpos + 40, ypos + 35, xpos + 45, ypos + 30);
String size = Integer.toString((1 << NrAddressBits) - 1);
Font font = g.getFont();
FontMetrics fm = g.getFontMetrics(font);
int StrSize = fm.stringWidth(size);
g.drawLine(xpos + 60, ypos + 20, xpos + 60 + StrSize, ypos + 20);
GraphicsUtil.drawText(g, "0", xpos + 60 + (StrSize / 2), ypos + 19,
GraphicsUtil.H_CENTER, GraphicsUtil.V_BOTTOM);
GraphicsUtil.drawText(g, size, xpos + 60 + (StrSize / 2), ypos + 21,
GraphicsUtil.H_CENTER, GraphicsUtil.V_TOP);
painter.drawPort(ADDR);
}
public abstract int getControlHeight(AttributeSet attrs);
File getCurrentImage(Instance instance) {
return currentInstanceFiles.get(instance);
}
abstract HexFrame getHexFrame(Project proj, Instance instance,
CircuitState state);
@Override
protected Object getInstanceFeature(Instance instance, Object key) {
if (key == MenuExtender.class) {
return new MemMenu(this, instance);
}
return super.getInstanceFeature(instance, key);
}
protected String GetSizeLabel(int NrAddressBits) {
String[] Labels = { "", "k", "M", "G" };
int pass = 0;
int AddrBits = NrAddressBits;
while (AddrBits > 9) {
pass++;
AddrBits -= 10;
}
int size = 1 << AddrBits;
return Integer.toString(size) + Labels[pass];
}
abstract MemState getState(Instance instance, CircuitState state);
abstract MemState getState(InstanceState state);
public void loadImage(InstanceState instanceState, File imageFile)
throws IOException {
MemState s = this.getState(instanceState);
HexFile.open(s.getContents(), imageFile);
this.setCurrentImage(instanceState.getInstance(), imageFile);
}
@Override
public abstract void propagate(InstanceState state);
void setCurrentImage(Instance instance, File value) {
currentInstanceFiles.put(instance, value);
}
}