/* 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.Allegrex.compiler.nativeCode; import org.apache.log4j.Logger; import jpcsp.Emulator; import jpcsp.Memory; import jpcsp.Allegrex.CpuState; import jpcsp.Allegrex.Decoder; import jpcsp.Allegrex.Common.Instruction; import jpcsp.Allegrex.compiler.Compiler; import jpcsp.Allegrex.compiler.RuntimeContext; import jpcsp.memory.IMemoryReader; import jpcsp.memory.MemoryReader; /** * @author gid15 * */ public abstract class AbstractNativeCodeSequence implements INativeCodeSequence { protected static Logger log = Emulator.log; protected static int[] toUpperCase = buildToUpperCase(); protected static int[] toLowerCase = buildToLowerCase(); static int[] buildToUpperCase() { int[] toUpperCase = new int[256]; for (int c = 0; c < toUpperCase.length; c++) { toUpperCase[c] = (c >= 0x61 && c <= 0x7A) ? c - 32 : c; } return toUpperCase; } static int[] buildToLowerCase() { int[] toLowerCase = new int[256]; for (int c = 0; c < toLowerCase.length; c++) { toLowerCase[c] = (c >= 0x41 && c <= 0x5A) ? c + 32 : c; } return toLowerCase; } static protected CpuState getCpu() { return RuntimeContext.cpu; } static protected Memory getMemory() { return RuntimeContext.memory; } static protected int getRegisterValue(int register) { return getCpu().getRegister(register); } static protected long getLong(int low, int high) { return (((long) high) << 32) | (low & 0xFFFFFFFFL); } static protected int getGprA0() { return getCpu()._a0; } static protected int getGprA1() { return getCpu()._a1; } static protected int getGprA2() { return getCpu()._a2; } static protected int getGprA3() { return getCpu()._a3; } static protected int getGprT0() { return getCpu()._t0; } static protected int getGprT1() { return getCpu()._t1; } static protected int getGprT2() { return getCpu()._t2; } static protected int getGprT3() { return getCpu()._t3; } static protected int getStackParam0() { return getMemory().read32(getGprSp()); } static protected int getStackParam1() { return getMemory().read32(getGprSp() + 4); } static protected int getStackParam2() { return getMemory().read32(getGprSp() + 8); } static protected int getGprSp() { return getCpu()._sp; } static protected void setGprV0(int v0) { getCpu()._v0 = v0; } static protected void setGprV0V1(long v0v1) { getCpu()._v0 = (int) v0v1; getCpu()._v1 = (int) (v0v1 >> 32); } static protected void setRegisterValue(int register, int value) { getCpu().setRegister(register, value); } static float[] getFpr() { return getCpu().fpr; } static protected float getFprF12() { return getFpr()[12]; } static protected void setFprF0(float f0) { getFpr()[0] = f0; } static protected float getFRegisterValue(int register) { return getFpr()[register]; } static public void strcpy(int dstAddr, int srcAddr) { int srcLength = getStrlen(srcAddr); getMemory().memcpy(dstAddr, srcAddr, srcLength + 1); } static public int strcmp(int src1Addr, int src2Addr) { if (src1Addr == 0) { if (src2Addr == 0) { return 0; } return -1; } if (src2Addr == 0) { return 1; } IMemoryReader memoryReader1 = MemoryReader.getMemoryReader(src1Addr, 1); IMemoryReader memoryReader2 = MemoryReader.getMemoryReader(src2Addr, 1); if (memoryReader1 != null && memoryReader2 != null) { while (true) { int c1 = memoryReader1.readNext(); int c2 = memoryReader2.readNext(); if (c1 != c2) { return c1 > c2 ? 1 : -1; } else if (c1 == 0) { // c1 == 0 and c2 == 0 break; } } } return 0; } static public int getStrlen(int srcAddr) { if (srcAddr == 0) { return 0; } int srcAddr3 = srcAddr & 3; // Reading 32-bit values is much faster IMemoryReader memoryReader = MemoryReader.getMemoryReader(srcAddr - srcAddr3, 4); if (memoryReader == null) { Compiler.log.warn("getStrlen: null MemoryReader"); return 0; } int value; int offset = 0; switch (srcAddr3) { case 1: value = memoryReader.readNext(); if ((value & 0x0000FF00) == 0) { return 0; } if ((value & 0x00FF0000) == 0) { return 1; } if ((value & 0xFF000000) == 0) { return 2; } offset = 3; break; case 2: value = memoryReader.readNext(); if ((value & 0x00FF0000) == 0) { return 0; } if ((value & 0xFF000000) == 0) { return 1; } offset = 2; break; case 3: value = memoryReader.readNext(); if ((value & 0xFF000000) == 0) { return 0; } offset = 1; break; } // Read 32-bit values and check for a null-byte while (true) { value = memoryReader.readNext(); if ((value & 0x000000FF) == 0) { return offset; } if ((value & 0x0000FF00) == 0) { return offset + 1; } if ((value & 0x00FF0000) == 0) { return offset + 2; } if ((value & 0xFF000000) == 0) { return offset + 3; } offset += 4; } } static protected int getStrlen(int srcAddr, int maxLength) { if (srcAddr == 0 || maxLength <= 0) { return 0; } int srcAddr3 = srcAddr & 3; // Reading 32-bit values is much faster IMemoryReader memoryReader = MemoryReader.getMemoryReader(srcAddr - srcAddr3, 4); if (memoryReader == null) { Compiler.log.warn("getStrlen: null MemoryReader"); return 0; } int value; int offset = 0; switch (srcAddr3) { case 1: value = memoryReader.readNext(); if ((value & 0x0000FF00) == 0) { return 0; } if ((value & 0x00FF0000) == 0) { return 1; } if ((value & 0xFF000000) == 0) { return Math.min(2, maxLength); } offset = 3; break; case 2: value = memoryReader.readNext(); if ((value & 0x00FF0000) == 0) { return 0; } if ((value & 0xFF000000) == 0) { return 1; } offset = 2; break; case 3: value = memoryReader.readNext(); if ((value & 0xFF000000) == 0) { return 0; } offset = 1; break; } // Read 32-bit values and check for a null-byte while (offset < maxLength) { value = memoryReader.readNext(); if ((value & 0x000000FF) == 0) { return offset; } if ((value & 0x0000FF00) == 0) { return offset + 1; } if ((value & 0x00FF0000) == 0) { return Math.min(offset + 2, maxLength); } if ((value & 0xFF000000) == 0) { return Math.min(offset + 3, maxLength); } offset += 4; } return maxLength; } static protected int getRelocatedAddress(int address1, int address2) { int address = (address1 << 16) + (short) address2; return address & Memory.addressMask; } static protected void interpret(int opcode) { Instruction insn = Decoder.instruction(opcode); insn.interpret(RuntimeContext.processor, opcode); } }