/*
This file is part of jpcsp.
Jpcsp 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.
Jpcsp 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 Jpcsp. If not, see <http://www.gnu.org/licenses/>.
*/
package jpcsp.memory;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import jpcsp.Memory;
import jpcsp.MemoryMap;
public class DirectBufferMemory extends Memory {
private ByteBuffer byteBuffer;
private ShortBuffer shortBuffer;
private IntBuffer intBuffer;
private static final int clearBufferSize = 10 * 1024;
private ByteBuffer clearBuffer;
@Override
public boolean allocate() {
try {
byteBuffer = ByteBuffer.allocateDirect(MemoryMap.END_RAM + 1).order(ByteOrder.LITTLE_ENDIAN);
intBuffer = byteBuffer.asIntBuffer();
shortBuffer = byteBuffer.asShortBuffer();
clearBuffer = ByteBuffer.allocateDirect(clearBufferSize).order(byteBuffer.order());
} catch (OutOfMemoryError e) {
// Not enough memory provided for this VM, cannot use FastMemory model
Memory.log.warn("Cannot allocate DirectBufferMemory: add the option '-Xmx256m' to the Java Virtual Machine startup command to improve Performance");
Memory.log.info("The current Java Virtual Machine has been started using '-Xmx" + (Runtime.getRuntime().maxMemory() / (1024 * 1024)) + "m'");
return false;
}
return super.allocate();
}
@Override
public void Initialise() {
byteBuffer.clear();
intBuffer.clear();
shortBuffer.clear();
clearBuffer.clear();
for (int i = 0; i < clearBufferSize; i++) {
clearBuffer.put((byte) 0);
}
clearBuffer.clear();
for (int i = 0; i < MemoryMap.END_RAM; i += clearBufferSize) {
byteBuffer.put(clearBuffer);
}
clearBuffer.clear();
byteBuffer.clear();
}
// Slice the buffer and keep the byteorder
private static ByteBuffer slice(ByteBuffer buffer) {
return buffer.slice().order(buffer.order());
}
@Override
public void copyToMemory(int address, ByteBuffer source, int length) {
address &= addressMask;
source = slice(source);
source.limit(length);
ByteBuffer mem = slice(byteBuffer);
mem.position(address);
mem.put(source);
}
protected ByteBuffer getByteBuffer(int address, int length) {
address &= addressMask;
ByteBuffer mem = slice(byteBuffer);
mem.position(address);
mem.limit(address + length);
return slice(mem);
}
@Override
public Buffer getBuffer(int address, int length) {
return getByteBuffer(address, length);
}
@Override
public Buffer getMainMemoryByteBuffer() {
return slice(byteBuffer);
}
@Override
protected void memcpy(int destination, int source, int length, boolean checkOverlap) {
destination = normalizeAddress(destination);
source = normalizeAddress(source);
if (checkOverlap || !areOverlapping(destination, source, length)) {
// Direct copy if buffers do not overlap.
// ByteBuffer operations are handling correctly overlapping buffers.
ByteBuffer destinationBuffer = getByteBuffer(destination, length);
ByteBuffer sourceBuffer = getByteBuffer(source, length);
destinationBuffer.put(sourceBuffer);
} else {
// Buffers are overlapping and we have to copy them as they would not overlap.
IMemoryReader sourceReader = MemoryReader.getMemoryReader(source, length, 1);
for (int i = 0; i < length; i++) {
write8(destination + i, (byte) sourceReader.readNext());
}
}
}
@Override
public void memset(int address, byte data, int length) {
ByteBuffer destination = getByteBuffer(address, length);
ByteBuffer source;
if (data == 0) {
source = slice(clearBuffer);
} else {
source = ByteBuffer.allocateDirect(clearBufferSize);
for (int i = 0; i < clearBufferSize; i++) {
source.put(data);
}
source.clear();
}
while (length >= clearBufferSize) {
destination.put(source);
source.clear();
length -= clearBufferSize;
}
if (length > 0) {
source.limit(length);
destination.put(source);
}
}
@Override
public int read16(int address) {
address &= addressMask;
return ((int) shortBuffer.get(address >> 1)) & 0xFFFF;
}
@Override
public int read32(int address) {
address &= addressMask;
return intBuffer.get(address >> 2);
}
@Override
public int read8(int address) {
address &= addressMask;
return ((int) byteBuffer.get(address)) & 0xFF;
}
@Override
public void write16(int address, short data) {
address &= addressMask;
shortBuffer.put(address >> 1, data);
}
@Override
public void write32(int address, int data) {
address &= addressMask;
intBuffer.put(address >> 2, data);
}
@Override
public void write8(int address, byte data) {
address &= addressMask;
byteBuffer.put(address, data);
}
}