/* Memory.java
*
* This class models the main memory of a computer, with 64-bit elements (that is 8 byte).
* (c) 2006 Salvatore Scellato, Andrea Spadaccini
*
* This file is part of the EduMIPS64 project, and is released under the GNU
* General Public License.
*
* This program 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 2 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.edumips64.core;
import org.edumips64.core.is.HaltException;
import org.edumips64.core.is.Instruction;
import org.edumips64.utils.Converter;
import org.edumips64.utils.IrregularStringOfBitsException;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.logging.Logger;
/** This class models the main memory of a computer, with 64-bit elements (that is 8 byte).
* The Memory is composed of MemoryElement and its size is not limited.
*/
public class Memory {
// Data structures for the data and code memory. In both maps, the key is represented by the index of the element.
// The index is derived by taking the address of the given element and dividing it by its width (8 for the memory,
// 4 for the code).
// SortedMaps are used to have the map entries sorted by key (useful for string representation).
private SortedMap<Integer, MemoryElement> cells;
private SortedMap<Integer, Instruction> instructions;
private static final Logger logger = Logger.getLogger(Memory.class.getName());
// Keep track of non-BUBBLE instructions for code size purposes.
private int instructionCount = 0;
public Memory() {
logger.info("Building Memory: " + this.hashCode());
cells = new TreeMap<>();
instructions = new TreeMap<>();
logger.info("Memory built: " + this.hashCode());
}
/** Gets the number of instructions of the Symbol Table.
* @return an integer
*/
public int getInstructionsNumber() {
return instructionCount;
}
/** Gets the index of the given instruction
* @return the position of the instruction in the list, or -1 if the instruction doesn't exist.
*/
public int getInstructionIndex(Instruction to_find) {
int pos = 0;
for(Instruction i : instructions.values()) {
if (i.equals(to_find)) {
return pos;
}
pos++;
}
return -1;
}
/** Returns the MemoryElement at given address.
* Please note that an index is not an address, for addresses must be aligned to 8 byte and indexes do not.
* @param address address of the requested element
* @return MemoryElement with address equals to index*8
* @throws MemoryElementNotFoundException if given index is too large for this memory.
*/
public MemoryElement getCellByAddress(long address) throws MemoryElementNotFoundException {
int index = (int)(address / 8);
return getCellByIndex(index);
}
/** Returns the MemoryElement with the given index. If there is no MemoryElement at the given index, create one,
* add it to the map and return it.
* @param index index of the requested element
* @return MemoryElement
* @throws MemoryElementNotFoundException if the given index is out of
* bounds
*/
public MemoryElement getCellByIndex(int index) throws MemoryElementNotFoundException {
if (index >= CPU.DATALIMIT || index < 0) {
throw new MemoryElementNotFoundException();
}
if (!cells.containsKey(index)) {
cells.put(index, new MemoryElement(index * 8));
}
return cells.get(index);
}
/** This method resets the memory*/
public void reset() {
cells.clear();
instructions.clear();
instructionCount = 0;
}
public String toString() {
String tmp = "Data:\n";
for(MemoryElement m : cells.values()) {
tmp += m.toString() + "\n";
}
tmp += "\nCode:\n";
for (Instruction i : instructions.values()) {
tmp += i.toString() + "\n";
}
return tmp;
}
public void addInstruction(Instruction i, int address) throws SymbolTableOverflowException {
// TODO(lupino3): remove the limit.
if (address > CPU.CODELIMIT) {
logger.warning("Address exceeding the CPU code limit: " + address + " > " + CPU.CODELIMIT);
throw new SymbolTableOverflowException();
}
int listIndex = address / 4;
if (!i.isBubble() && !instructions.containsKey(listIndex)) {
instructionCount++;
}
instructions.put(listIndex, i);
}
// Returns null if there is no instruction at the given address.
public Instruction getInstruction(int address) {
int index = address / 4;
if (!instructions.containsKey(index)) {
return null;
}
return instructions.get(address / 4);
}
/** This method returns the instruction at the specified position.
* @return an Instruction object
* @param address a BitSet64 object holding the address of the Instruction
*/
public Instruction getInstruction(BitSet64 address) throws HaltException, IrregularStringOfBitsException {
try {
return instructions.get((int)(Converter.binToLong(address.getBinString(), false) / 4));
} catch (IndexOutOfBoundsException e) {
throw new HaltException();
}
}
}