/* 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.IntBuffer; import jpcsp.Memory; import jpcsp.MemoryMap; import jpcsp.Allegrex.compiler.RuntimeContext; /** * @author gid15 * */ public class MemoryReader { private static int getMaxLength(int address) { int length; if (address >= MemoryMap.START_RAM && address <= MemoryMap.END_RAM) { length = MemoryMap.END_RAM - address + 1; } else if (address >= MemoryMap.START_VRAM && address <= MemoryMap.END_VRAM) { length = MemoryMap.END_VRAM - address + 1; } else if (address >= MemoryMap.START_SCRATCHPAD && address <= MemoryMap.END_SCRATCHPAD) { length = MemoryMap.END_SCRATCHPAD - address + 1; } else { length = 0; } return length; } private static IMemoryReader getFastMemoryReader(int address, int step) { int[] memoryInt = RuntimeContext.getMemoryInt(); switch (step) { case 1: return new MemoryReaderIntArray8(memoryInt, address); case 2: return new MemoryReaderIntArray16(memoryInt, address); case 4: return new MemoryReaderIntArray32(memoryInt, address); } // Default (generic) MemoryReader return new MemoryReaderGeneric(address, getMaxLength(address), step); } /** * Creates a MemoryReader to read values from memory. * * @param address the address where to start reading. * When step == 2, the address has to be 16-bit aligned ((address & 1) == 0). * When step == 4, the address has to be 32-bit aligned ((address & 3) == 0). * @param length the maximum number of bytes that can be read. * @param step when step == 1, read 8-bit values * when step == 2, read 16-bit values * when step == 4, read 32-bit values * other value for step are not allowed. * @return the MemoryReader */ public static IMemoryReader getMemoryReader(int address, int length, int step) { address &= Memory.addressMask; if (RuntimeContext.hasMemoryInt()) { return getFastMemoryReader(address, step); } if (!DebuggerMemory.isInstalled()) { Buffer buffer = Memory.getInstance().getBuffer(address, length); if (buffer instanceof IntBuffer) { IntBuffer intBuffer = (IntBuffer) buffer; switch (step) { case 1: return new MemoryReaderInt8(intBuffer, address); case 2: return new MemoryReaderInt16(intBuffer, address); case 4: return new MemoryReaderInt32(intBuffer, address); } } else if (buffer instanceof ByteBuffer) { ByteBuffer byteBuffer = (ByteBuffer) buffer; switch (step) { case 1: return new MemoryReaderByte8(byteBuffer, address); case 2: return new MemoryReaderByte16(byteBuffer, address); case 4: return new MemoryReaderByte32(byteBuffer, address); } } } // Default (generic) MemoryReader return new MemoryReaderGeneric(address, length, step); } /** * Creates a MemoryReader to read values from memory. * * @param address the address where to start reading. * When step == 2, the address has to be 16-bit aligned ((address & 1) == 0). * When step == 4, the address has to be 32-bit aligned ((address & 3) == 0). * @param step when step == 1, read 8-bit values * when step == 2, read 16-bit values * when step == 4, read 32-bit values * other value for step are not allowed. * @return the MemoryReader */ public static IMemoryReader getMemoryReader(int address, int step) { address &= Memory.addressMask; if (RuntimeContext.hasMemoryInt()) { return getFastMemoryReader(address, step); } return getMemoryReader(address, getMaxLength(address), step); } public static IMemoryReader getMemoryReader(int address, byte[] bytes, int offset, int length, int step) { switch (step) { case 1: return new MemoryReaderBytes8(address, bytes, offset, length); case 2: return new MemoryReaderBytes16(address, bytes, offset, length); case 4: return new MemoryReaderBytes32(address, bytes, offset, length); } return null; } public static IMemoryReader getMemoryReader(int address, int[] ints, int offset, int length) { return new MemoryReaderInts32(address, ints, offset, length); } // The Java JIT compiler is producing slightly faster code for "final" methods. // Added "final" here only for performance reasons. Can be removed if inheritance // of these classes is required. private final static class MemoryReaderGeneric implements IMemoryReader { private Memory mem; private int address; private int length; private int step; public MemoryReaderGeneric(int address, int length, int step) { this.address = address; this.length = length; this.step = step; mem = Memory.getInstance(); } @Override public final int readNext() { int n; if (length <= 0) { return 0; } switch (step) { case 1: n = mem.read8(address); break; case 2: n = mem.read16(address); break; case 4: n = mem.read32(address); break; default: n = 0; break; } address += step; length -= step; return n; } @Override public final void skip(int n) { address += n * step; length -= n * step; } @Override public int getCurrentAddress() { return address; } } private final static class MemoryReaderIntArray8 implements IMemoryReader { private int index; private int offset; private int value; private int[] buffer; public MemoryReaderIntArray8(int[] buffer, int addr) { this.buffer = buffer; offset = addr / 4; index = addr & 3; value = buffer[offset] >> (index << 3); } @Override public final int readNext() { int n; if (index == 4) { index = 0; offset++; value = buffer[offset]; } n = value & 0xFF; value >>= 8; index++; return n; } @Override public final void skip(int n) { if (n > 0) { index += n; offset += index >> 2; index &= 3; value = buffer[offset] >> (index << 3); } } @Override public int getCurrentAddress() { return (offset << 2) + index; } } private final static class MemoryReaderIntArray16 implements IMemoryReader { private int index; private int offset; private int value; private int[] buffer; public MemoryReaderIntArray16(int[] buffer, int addr) { this.buffer = buffer; offset = addr >> 2; index = (addr >> 1) & 1; if (index != 0) { value = buffer[offset]; } } @Override public final int readNext() { int n; if (index == 0) { value = buffer[offset]; n = value & 0xFFFF; index = 1; } else { index = 0; offset++; n = value >>> 16; } return n; } @Override public final void skip(int n) { if (n > 0) { index += n; offset += index >> 1; index &= 1; if (index != 0) { value = buffer[offset]; } } } @Override public int getCurrentAddress() { return (offset << 2) + (index << 1); } } private final static class MemoryReaderIntArray32 implements IMemoryReader { private int offset; private int[] buffer; public MemoryReaderIntArray32(int[] buffer, int addr) { offset = addr / 4; this.buffer = buffer; } @Override public final int readNext() { return buffer[offset++]; } @Override public final void skip(int n) { offset += n; } @Override public int getCurrentAddress() { return offset << 2; } } private final static class MemoryReaderInt8 implements IMemoryReader { private int index; private int value; private IntBuffer buffer; private int address; public MemoryReaderInt8(IntBuffer buffer, int index) { this.buffer = buffer; this.address = address & ~3; index = address & 0x03; if (buffer.capacity() > 0) { value = buffer.get() >> (index << 3); } } @Override public final int readNext() { int n; if (index == 4) { index = 0; value = buffer.get(); } n = value & 0xFF; value >>= 8; index++; return n; } @Override public final void skip(int n) { if (n > 0) { index += n; buffer.position(buffer.position() + (index >> 2)); index &= 3; value = buffer.get() >> (8 * index); } } @Override public int getCurrentAddress() { return address + (buffer.position() << 2) + index; } } private final static class MemoryReaderInt16 implements IMemoryReader { private int index; private int value; private IntBuffer buffer; private int address; public MemoryReaderInt16(IntBuffer buffer, int index) { this.buffer = buffer; this.address = address & ~3; this.index = (address & 0x02) >> 1; if (index != 0 && buffer.capacity() > 0) { value = buffer.get(); } } @Override public final int readNext() { int n; if (index == 0) { value = buffer.get(); n = value & 0xFFFF; index = 1; } else { index = 0; n = value >>> 16; } return n; } @Override public final void skip(int n) { if (n > 0) { index += n; buffer.position(buffer.position() + (index >> 1)); index &= 1; if (index != 0) { value = buffer.get(); } } } @Override public int getCurrentAddress() { return address + (buffer.position() << 2) + index; } } private final static class MemoryReaderInt32 implements IMemoryReader { private IntBuffer buffer; private int address; public MemoryReaderInt32(IntBuffer buffer, int address) { this.buffer = buffer; this.address = address; } @Override public final int readNext() { return buffer.get(); } @Override public final void skip(int n) { if (n > 0) { buffer.position(buffer.position() + n); } } @Override public int getCurrentAddress() { return address + (buffer.position() << 2); } } private final static class MemoryReaderByte8 implements IMemoryReader { private ByteBuffer buffer; private int address; public MemoryReaderByte8(ByteBuffer buffer, int address) { this.buffer = buffer; this.address = address; } @Override public final int readNext() { return (buffer.get()) & 0xFF; } @Override public final void skip(int n) { if (n > 0) { buffer.position(buffer.position() + n); } } @Override public int getCurrentAddress() { return address + buffer.position(); } } private final static class MemoryReaderByte16 implements IMemoryReader { private ByteBuffer buffer; private int address; public MemoryReaderByte16(ByteBuffer buffer, int address) { this.buffer = buffer; this.address = address; } @Override public final int readNext() { return (buffer.getShort()) & 0xFFFF; } @Override public final void skip(int n) { if (n > 0) { buffer.position(buffer.position() + (n << 1)); } } @Override public int getCurrentAddress() { return address + buffer.position(); } } private final static class MemoryReaderByte32 implements IMemoryReader { private ByteBuffer buffer; private int address; public MemoryReaderByte32(ByteBuffer buffer, int address) { this.buffer = buffer; this.address = address; } @Override public final int readNext() { return buffer.getInt(); } @Override public final void skip(int n) { if (n > 0) { buffer.position(buffer.position() + (n << 2)); } } @Override public int getCurrentAddress() { return address + buffer.position(); } } private final static class MemoryReaderBytes8 implements IMemoryReader { private int address; private final byte[] bytes; private int offset; private int maxOffset; public MemoryReaderBytes8(int address, byte[] bytes, int offset, int length) { this.address = address; this.bytes = bytes; this.offset = offset; maxOffset = offset + length; } @Override public int readNext() { if (offset >= maxOffset) { return 0; } address++; return bytes[offset++] & 0xFF; } @Override public void skip(int n) { offset += n; address += n; } @Override public int getCurrentAddress() { return address; } } private final static class MemoryReaderBytes16 implements IMemoryReader { private int address; private final byte[] bytes; private int offset; private int maxOffset; public MemoryReaderBytes16(int address, byte[] bytes, int offset, int length) { this.address = address; this.bytes = bytes; this.offset = offset; maxOffset = offset + length; } @Override public int readNext() { if (offset >= maxOffset) { return 0; } address += 2; return (bytes[offset++] & 0xFF) | ((bytes[offset++] & 0xFF) << 8); } @Override public void skip(int n) { offset += n * 2; address += n * 2; } @Override public int getCurrentAddress() { return address; } } private final static class MemoryReaderBytes32 implements IMemoryReader { private int address; private final byte[] bytes; private int offset; private int maxOffset; public MemoryReaderBytes32(int address, byte[] bytes, int offset, int length) { this.address = address; this.bytes = bytes; this.offset = offset; maxOffset = offset + length; } @Override public int readNext() { if (offset >= maxOffset) { return 0; } address += 4; return (bytes[offset++] & 0xFF) | ((bytes[offset++] & 0xFF) << 8) | ((bytes[offset++] & 0xFF) << 16) | ((bytes[offset++] & 0xFF) << 24); } @Override public void skip(int n) { offset += n * 4; address += n * 4; } @Override public int getCurrentAddress() { return address; } } private final static class MemoryReaderInts32 implements IMemoryReader { private int address; private final int[] ints; private int offset; private int maxOffset; public MemoryReaderInts32(int address, int[] ints, int offset, int length) { this.address = address; this.ints = ints; this.offset = offset; maxOffset = offset + (length >> 2); } @Override public int readNext() { if (offset >= maxOffset) { return 0; } address += 4; return ints[offset++]; } @Override public void skip(int n) { offset += n; address += n * 4; } @Override public int getCurrentAddress() { return address; } } }