/*******************************************************************************
* openDLX - A DLX/MIPS processor simulator.
* Copyright (C) 2013 The openDLX project, University of Augsburg, Germany
* Project URL: <https://sourceforge.net/projects/opendlx>
* Development branch: <https://github.com/smetzlaff/openDLX>
*
*
* 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 3 of the License, or
* 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, see <LICENSE>. If not, see
* <http://www.gnu.org/licenses/>.
******************************************************************************/
package openDLX.asm;
/**
* This class manages a resizable byteArray and supports methods for writing and
* reading bytes(8bit),half words(16bit) and words(32bit). There is support for
* little endian mode and a marker for the entry point.
*
*/
public class MemoryBuffer {
private static final int LINE_WRAPPING = 0x10;
private static final int INITIAL_SIZE = 0xFF;
private byte[] byteArray;
private boolean littleEndian;
private int entryPoint;
private int dataBegin;
private int textBegin;
private int dataEnd;
private int textEnd;
/**
* create new MemoryBuffer with INITIAL_SIZE size and little endian mode
*/
public MemoryBuffer() {
byteArray = new byte[INITIAL_SIZE];
littleEndian = true;
entryPoint = 0;
textEnd = 0;
dataEnd = 0;
}
/**
* create new MemoryBuffer with initSize size but at least 4 and little
* endian mode
*
* @param initSize
*/
public MemoryBuffer(int initSize) {
if (initSize < 4)
initSize = 4;
byteArray = new byte[initSize];
littleEndian = true;
entryPoint = 0;
textEnd = 0;
dataEnd = 0;
}
/*
* ============================* Getter/Setter *============================
*/
/**
*
* @return true if in little endian mode else false
*/
public boolean isLittleEndian() {
return littleEndian;
}
/**
* set little endian mode to true or false
*
* @param littleEndian
*/
public void setLittleEndian(boolean littleEndian) {
this.littleEndian = littleEndian;
}
/**
*
* @return position of first instruction that should be executed
*/
public int getEntryPoint() {
return entryPoint;
}
/**
* set position of first instruction that should be executed
*
* @param entryPoint
*/
public void setEntyPoint(int entryPoint) {
if (entryPoint < 0)
entryPoint = 0;
this.entryPoint = entryPoint;
}
/**
*
* @return begin of data
*/
public int getDataBegin() {
return dataBegin;
}
/**
* set begin of data
*
* @param dataBegin
*/
public void setDataBegin(int dataBegin) {
if (dataBegin < 0)
dataBegin = 0;
this.dataBegin = dataBegin;
}
/**
*
* @return begin of text
*/
public int getTextBegin() {
return textBegin;
}
/**
* set begin of text
*
* @param textBegin
*/
public void setTextBegin(int textBegin) {
if (textBegin < 0)
textBegin = 0;
this.textBegin = textBegin;
}
/**
*
* @return end of data
*/
public int getDataEnd() {
return dataEnd;
}
/**
* Set the end pointer of the data section.
* The end pointer can only be increased. So the parameter is only set, if it is larger than the current end pointer of the data section.
*
* @param dataEnd textEnd is only set, if it is larger than the current end pointer of the data section.
*/
public void setDataEnd(int dataEnd) {
if (dataEnd > this.dataEnd)
{
this.dataEnd = dataEnd;
}
}
/**
*
* @return end of text
*/
public int getTextEnd() {
return textEnd;
}
/**
* Set the end pointer of the text section.
* The end pointer can only be increased. So the parameter is only set, if it is larger than the current end pointer of the text section.
*
* @param textEnd textEnd is only set, if it is larger than the current end pointer of the text section.
*/
public void setTextEnd(int textEnd) {
if(textEnd > this.textEnd)
{
this.textEnd = textEnd;
}
}
/**
*
* @return size of buffer
*/
public int size() {
return byteArray.length;
}
/*
* =============================* Read/Write *=============================
*/
/**
* read byte at position
*
* @param position
* @return byte at position
*/
public byte readByte(int position) {
return byteArray[position];
}
/**
* write byte to position
*
* @param position
* @param value
*/
public void writeByte(int position, byte value) {
if (position >= byteArray.length) {
reserve(2 * (position + 4 - position % 4));
}
byteArray[position] = value;
}
/**
* read half word at position
*
* @param position
* @return half word at position
*/
public short readHalf(int position) {
//little bit complicated because of sign extending when casting
int value;
if (littleEndian) {
value = ((int) readByte(position++) & 0xFF);
value += ((int) readByte(position) & 0xFF) << 8;
} else {
value = ((int) readByte(position++) & 0xFF) << 8;
value += ((int) readByte(position) & 0xFF);
}
return (short) value;
}
/**
* write half word to position
*
* @param position
* @param value
*/
public void writeHalf(int position, short value) {
if (littleEndian) {
writeByte(position, (byte) (value & 0xFF));
writeByte(position + 1, (byte) ((value >> 8) & 0xFF));
} else {
writeByte(position + 1, (byte) (value & 0xFF));
writeByte(position, (byte) ((value >> 8) & 0xFF));
}
}
/**
* read word at position
*
* @param position
* @return byte at position
*/
public int readWord(int position) {
//little bit complicated because of sign extending when casting
int value;
if (littleEndian) {
value = ((int) readByte(position++) & 0xFF);
value += ((int) readByte(position++) & 0xFF) << 8;
value += ((int) readByte(position++) & 0xFF) << 16;
value += ((int) readByte(position) & 0xFF) << 24;
} else {
value = ((int) readByte(position++) & 0xFF) << 24;
value += ((int) readByte(position++) & 0xFF) << 16;
value += ((int) readByte(position++) & 0xFF) << 8;
value += ((int) readByte(position) & 0xFF);
}
return value;
}
/**
* write word to position
*
* @param position
* @param value
*/
public void writeWord(int position, int value) {
if (littleEndian) {
writeByte(position, (byte) (value & 0xFF));
writeByte(position + 1, (byte) ((value >> 8) & 0xFF));
writeByte(position + 2, (byte) ((value >> 16) & 0xFF));
writeByte(position + 3, (byte) ((value >> 24) & 0xFF));
} else {
writeByte(position + 3, (byte) (value & 0xFF));
writeByte(position + 2, (byte) ((value >> 8) & 0xFF));
writeByte(position + 1, (byte) ((value >> 16) & 0xFF));
writeByte(position, (byte) ((value >> 24) & 0xFF));
}
}
/*
* =============================* Conversions *=============================
*/
/**
*
* @return byte array copy
*/
public byte[] toByteArray() {
byte[] tmp = new byte[byteArray.length];
System.arraycopy(byteArray, 0, tmp, 0, byteArray.length);
return tmp;
}
/**
* After LINE_WRAPPING bytes a newline is set. A byte count is written at
* the beginning of each line.
*
* @return string representation of memoryBuffer
*/
public String toString() {
StringBuffer strBuf = new StringBuffer(4 * this.size());
strBuf.append("entryPoint: 0x" + Integer.toHexString(getEntryPoint()) + "\n");
strBuf.append("dataBegin: 0x" + Integer.toHexString(getDataBegin()) + "\n");
strBuf.append("textBegin: 0x" + Integer.toHexString(getTextBegin()) + "\n");
for (int i = 0; i < size(); i++) {
if (i % LINE_WRAPPING == 0) {
strBuf.append("\n" + String.format("%1$04x", i) + ":");
}
strBuf.append(String.format(" %1$02x", byteArray[i]));
}
return strBuf.toString();
}
/*
* ==============================* Internals *==============================
*/
private void reserve(int size) {
if (size > byteArray.length) {
byte[] tmp = new byte[size];
System.arraycopy(byteArray, 0, tmp, 0, byteArray.length);
byteArray = tmp;
}
}
}