/*
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 jpcsp.Memory;
import jpcsp.Allegrex.compiler.RuntimeContext;
/**
* @author gid15
*
*/
public class MemoryReaderWriter {
private static IMemoryReaderWriter getFastMemoryReaderWriter(int address, int step) {
int[] memoryInt = RuntimeContext.getMemoryInt();
// Implement the most common cases with dedicated classes.
switch (step) {
case 2: return new MemoryReaderWriterIntArray16(memoryInt, address);
case 4: return new MemoryReaderWriterIntArray32(memoryInt, address);
}
// No dedicated class available, use the generic one.
return new MemoryReaderWriterGeneric(address, step);
}
public static IMemoryReaderWriter getMemoryReaderWriter(int address, int length, int step) {
address &= Memory.addressMask;
if (RuntimeContext.hasMemoryInt()) {
return getFastMemoryReaderWriter(address, step);
}
// No dedicated class available, use the generic one.
return new MemoryReaderWriterGeneric(address, length, step);
}
public static IMemoryReaderWriter getMemoryReaderWriter(int address, int step) {
address &= Memory.addressMask;
if (RuntimeContext.hasMemoryInt()) {
return getFastMemoryReaderWriter(address, step);
}
// No dedicated class available, use the generic one.
return new MemoryReaderWriterGeneric(address, step);
}
private static final class MemoryReaderWriterGeneric implements IMemoryReaderWriter {
private IMemoryReader memoryReader;
private IMemoryWriter memoryWriter;
private int currentValue;
public MemoryReaderWriterGeneric(int address, int length, int step) {
memoryReader = MemoryReader.getMemoryReader(address, length, step);
memoryWriter = MemoryWriter.getMemoryWriter(address, length, step);
currentValue = memoryReader.readNext();
}
public MemoryReaderWriterGeneric(int address, int step) {
memoryReader = MemoryReader.getMemoryReader(address, step);
memoryWriter = MemoryWriter.getMemoryWriter(address, step);
currentValue = memoryReader.readNext();
}
@Override
public void writeNext(int value) {
memoryWriter.writeNext(value);
currentValue = memoryReader.readNext();
}
@Override
public void skip(int n) {
if (n > 0) {
memoryWriter.skip(n);
memoryReader.skip(n - 1);
currentValue = memoryReader.readNext();
}
}
@Override
public void flush() {
memoryWriter.flush();
}
@Override
public int getCurrentAddress() {
return memoryWriter.getCurrentAddress();
}
@Override
public int readCurrent() {
return currentValue;
}
}
private static final class MemoryReaderWriterIntArray32 implements IMemoryReaderWriter {
private int offset;
private final int[] buffer;
public MemoryReaderWriterIntArray32(int[] buffer, int addr) {
offset = addr >> 2;
this.buffer = buffer;
}
@Override
public void writeNext(int value) {
buffer[offset++] = value;
}
@Override
public void skip(int n) {
offset += n;
}
@Override
public void flush() {
}
@Override
public int getCurrentAddress() {
return offset << 2;
}
@Override
public int readCurrent() {
return buffer[offset];
}
}
private static final class MemoryReaderWriterIntArray16 implements IMemoryReaderWriter {
private int index;
private int offset;
private int value;
private final int[] buffer;
public MemoryReaderWriterIntArray16(int[] buffer, int addr) {
this.buffer = buffer;
offset = addr >> 2;
index = (addr >> 1) & 1;
if (index != 0) {
value = buffer[offset] & 0x0000FFFF;
}
}
@Override
public void writeNext(int n) {
if (index == 0) {
value = n & 0xFFFF;
index = 1;
} else {
buffer[offset++] = (n << 16) | value;
index = 0;
}
}
@Override
public void skip(int n) {
if (n > 0) {
flush();
index += n;
offset += index >> 1;
index &= 1;
if (index != 0) {
value = buffer[offset] & 0x0000FFFF;
}
}
}
@Override
public void flush() {
if (index != 0) {
buffer[offset] = (buffer[offset] & 0xFFFF0000) | value;
}
}
@Override
public int getCurrentAddress() {
return (offset << 2) + (index << 1);
}
@Override
public int readCurrent() {
if (index == 0) {
return buffer[offset] & 0xFFFF;
}
return buffer[offset] >>> 16;
}
}
}