/* 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 jpcsp.Memory; import jpcsp.Allegrex.compiler.Compiler; import jpcsp.memory.IMemoryWriter; import jpcsp.memory.MemoryWriter; /** * @author gid15 * */ public class Memset extends AbstractNativeCodeSequence { // Memset CodeBlock static public void call() { int dstAddr = getGprA0(); int c = getGprA1() & 0xFF; int n = getGprA2(); getMemory().memsetWithVideoCheck(dstAddr, (byte) c, n); setGprV0(dstAddr); } // Memset CodeSequence static public void call(int dstAddrReg, int cReg, int nReg) { call(dstAddrReg, cReg, nReg, 0); } // Memset CodeSequence static public void call(int dstAddrReg, int cReg, int nReg, int endValue) { int dstAddr = getRegisterValue(dstAddrReg); int c = getRegisterValue(cReg); int n = getRegisterValue(nReg) - endValue; getMemory().memsetWithVideoCheck(dstAddr, (byte) c, n); setRegisterValue(dstAddrReg, dstAddr + n); setRegisterValue(nReg, endValue); } /** * Set memory range to a fixed value * @param dstAddrReg register number containing the start address * @param cReg register number containing the value * @param nStartReg register number giving the start value of the counter * @param nEndReg register number giving the end value of the counter * @param cLength 2: take only the lower 16bit of the value * 4: take the 32bit of the value */ static public void call(int dstAddrReg, int cReg, int nStartReg, int cLength, int nEndReg) { int dstAddr = getRegisterValue(dstAddrReg); int c = getRegisterValue(cReg); int nStart = getRegisterValue(nStartReg); int nEnd = getRegisterValue(nEndReg); int n = nEnd - nStart; if (n == 0) { return; } if (cLength == 2) { // Both bytes identical? if ((c & 0xFF) == ((c >> 8) & 0xFF)) { // This is equivalent to a normal memset getMemory().memsetWithVideoCheck(dstAddr, (byte) c, n * 2); } else { // We have currently no built-in memset for 16bit values // do it manually... Memory mem = getMemory(); int value32 = (c & 0xFFFF) | (c << 16); short value16 = (short) (c & 0xFFFF); if (n > 0 && (dstAddr & 3) != 0) { mem.write16(dstAddr, value16); dstAddr += 2; n--; } IMemoryWriter memoryWriter = MemoryWriter.getMemoryWriter(dstAddr, n * 2, 4); for (int i = 0; i < n; i += 2, dstAddr += 4) { memoryWriter.writeNext(value32); } memoryWriter.flush(); if ((n & 1) != 0) { mem.write16(dstAddr, value16); } } } else if (cLength == 4) { // All bytes identical? if ((c & 0xFF) == ((c >> 8) & 0xFF) && (c & 0xFFFF) == ((c >> 16) & 0xFFFF)) { // This is equivalent to a normal memset getMemory().memsetWithVideoCheck(dstAddr, (byte) c, n * 4); } else { IMemoryWriter memoryWriter = MemoryWriter.getMemoryWriter(dstAddr, n * 4, 4); for (int i = 0; i < n; i++) { memoryWriter.writeNext(c); } memoryWriter.flush(); } } else { Compiler.log.error("Memset.call: unsupported cLength=0x" + Integer.toHexString(cLength)); } setRegisterValue(dstAddrReg, getRegisterValue(dstAddrReg) + n * cLength); setRegisterValue(nStartReg, nEnd); } // Memset CodeSequence static public void callWithStep(int dstAddrReg, int cReg, int nReg, int endValue, int direction, int step) { int dstAddr = getRegisterValue(dstAddrReg); int c = getRegisterValue(cReg); int n = (endValue - getRegisterValue(nReg)) * direction * step; getMemory().memsetWithVideoCheck(dstAddr, (byte) c, n); setRegisterValue(dstAddrReg, dstAddr + n); setRegisterValue(nReg, endValue); } // Memset CodeSequence static public void callWithStepReg(int dstAddrReg, int cReg, int nReg, int endValueReg, int direction, int step) { int endValue = getRegisterValue(endValueReg); callWithStep(dstAddrReg, cReg, nReg, endValue, direction, step); } }