/* 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.HLE.modules; import org.apache.log4j.Logger; import java.util.HashMap; import java.util.Random; import jpcsp.HLE.HLEFunction; import jpcsp.HLE.HLEModule; import jpcsp.HLE.Modules; import jpcsp.HLE.TPointer; public class sceSfmt19937 extends HLEModule { public static Logger log = Modules.getLogger("sceSfmt19937"); protected final static int PSP_SFMT19937_LENGTH = 156; private HashMap<TPointer, sfmt19937Ctx> ctxMap = new HashMap<TPointer, sfmt19937Ctx>(); private static class sfmt19937Ctx { private int index; private int indexPos; private int[][] sfmt; private TPointer addr; private int seed; private int[] seedArray; public sfmt19937Ctx(TPointer ctxAddr, int seed) { this.index = 0; this.indexPos = 0; this.sfmt = new int[PSP_SFMT19937_LENGTH][4]; this.addr = ctxAddr; this.seed = seed; } public sfmt19937Ctx(TPointer ctxAddr, int[] seeds) { this.index = 0; this.indexPos = 0; this.sfmt = new int[PSP_SFMT19937_LENGTH][4]; this.addr = ctxAddr; this.seedArray = seeds; } private void generate() { // If using a seed array, just assign the first seed. if (this.seedArray != null) { this.seed = seedArray[0]; } // Store the current index. this.addr.setValue32(this.index); // Generate a SFMT19937 context with Random and write the values. Random rand = new Random(this.seed); for (int i = 0; i < PSP_SFMT19937_LENGTH; i++) { for (int j = 0; j < 4; j++) { sfmt[i][j] = rand.nextInt(); this.addr.setValue32(sfmt[i][j]); } } } private int getNextRand() { int r = sfmt[index][indexPos]; if ((this.indexPos + 1) < 4) { this.indexPos++; } else { this.indexPos = 0; this.index++; } return r; } private long getNextRand64() { long r1 = getNextRand(); long r2 = getNextRand(); return ((r1 << 32) | r2); } } @HLEFunction(nid = 0x161ACEB2, version = 500) public int sceSfmt19937InitGenRand(TPointer sfmtctx, int seed) { // Assign and store the current context. sfmt19937Ctx ctx = new sfmt19937Ctx(sfmtctx, seed); ctxMap.put(sfmtctx, ctx); return 0; } @HLEFunction(nid = 0xDD5A5D6C, version = 500) public int sceSfmt19937InitByArray(TPointer sfmtctx, TPointer seeds, int seedsLength) { // Read and store the seeds. int[] s = new int[seedsLength]; for (int i = 0; i < seedsLength; i++) { s[i] = seeds.getValue32(); } // Assign and store the current context. sfmt19937Ctx ctx = new sfmt19937Ctx(sfmtctx, s); ctxMap.put(sfmtctx, ctx); return 0; } @HLEFunction(nid = 0xB33FE749, version = 500) public int sceSfmt19937GenRand32(TPointer sfmtctx) { int result = 0; // Check if the context has been initialized. if (ctxMap.containsKey(sfmtctx)) { sfmt19937Ctx ctx = ctxMap.get(sfmtctx); ctx.generate(); result = ctx.getNextRand(); } return result; } @HLEFunction(nid = 0xD5AC9F99, version = 500) public long sceSfmt19937GenRand64(TPointer sfmtctx) { long result = 0; // Check if the context has been initialized. if (ctxMap.containsKey(sfmtctx)) { sfmt19937Ctx ctx = ctxMap.get(sfmtctx); ctx.generate(); result = ctx.getNextRand64(); } return result; } @HLEFunction(nid = 0xDB025BFA, version = 500) public int sceSfmt19937FillArray32(TPointer sfmtctx, TPointer array, int arrayLength) { // Check if the context has been initialized. if (ctxMap.containsKey(sfmtctx)) { sfmt19937Ctx ctx = ctxMap.get(sfmtctx); ctx.generate(); // Fill the array with the random values. for (int i = 0; i < arrayLength; i++) { array.setValue32(i, ctx.getNextRand()); } } return 0; } @HLEFunction(nid = 0xEE2938C4, version = 500) public int sceSfmt19937FillArray64(TPointer sfmtctx, TPointer array, int arrayLength) { // Check if the context has been initialized. if (ctxMap.containsKey(sfmtctx)) { sfmt19937Ctx ctx = ctxMap.get(sfmtctx); ctx.generate(); // Fill the array with the random values. for (int i = 0; i < arrayLength; i++) { array.setValue64(i, ctx.getNextRand64()); } } return 0; } }