/* 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; import jpcsp.Emulator; /** * General Purpose Registers, handles integer operations like ALU, shifter, etc. * * @author hli */ public class GprState { public static final int NUMBER_REGISTERS = 32; // Use fields to store the 32 registers, and not an array like // int[] gpr = new int[32] // This allows the Java JIT to produce more efficient code by avoiding the array bounds checks on "gpr". public final int _zr = 0; public int _at; public int _v0; public int _v1; public int _a0; public int _a1; public int _a2; public int _a3; public int _t0; public int _t1; public int _t2; public int _t3; public int _t4; public int _t5; public int _t6; public int _t7; public int _s0; public int _s1; public int _s2; public int _s3; public int _s4; public int _s5; public int _s6; public int _s7; public int _t8; public int _t9; public int _k0; public int _k1; public int _gp; public int _sp; public int _fp; public int _ra; public void reset() { _at = 0; _v0 = 0; _v1 = 0; _a0 = 0; _a1 = 0; _a2 = 0; _a3 = 0; _t0 = 0; _t1 = 0; _t2 = 0; _t3 = 0; _t4 = 0; _t5 = 0; _t6 = 0; _t7 = 0; _s0 = 0; _s1 = 0; _s2 = 0; _s3 = 0; _s4 = 0; _s5 = 0; _s6 = 0; _s7 = 0; _t8 = 0; _t9 = 0; _k0 = 0; _k1 = 0; _gp = 0; _sp = 0; _fp = 0; _ra = 0; } public void resetAll() { _at = 0; _v0 = 0; _v1 = 0; _a0 = 0; _a1 = 0; _a2 = 0; _a3 = 0; _t0 = 0; _t1 = 0; _t2 = 0; _t3 = 0; _t4 = 0; _t5 = 0; _t6 = 0; _t7 = 0; _s0 = 0; _s1 = 0; _s2 = 0; _s3 = 0; _s4 = 0; _s5 = 0; _s6 = 0; _s7 = 0; _t8 = 0; _t9 = 0; _k0 = 0; _k1 = 0; _gp = 0; _sp = 0; _fp = 0; _ra = 0; } public GprState() { } public void copy(GprState that) { _at = that._at; _v0 = that._v0; _v1 = that._v1; _a0 = that._a0; _a1 = that._a1; _a2 = that._a2; _a3 = that._a3; _t0 = that._t0; _t1 = that._t1; _t2 = that._t2; _t3 = that._t3; _t4 = that._t4; _t5 = that._t5; _t6 = that._t6; _t7 = that._t7; _s0 = that._s0; _s1 = that._s1; _s2 = that._s2; _s3 = that._s3; _s4 = that._s4; _s5 = that._s5; _s6 = that._s6; _s7 = that._s7; _t8 = that._t8; _t9 = that._t9; _k0 = that._k0; _k1 = that._k1; _gp = that._gp; _sp = that._sp; _fp = that._fp; _ra = that._ra; } public GprState(GprState that) { _at = that._at; _v0 = that._v0; _v1 = that._v1; _a0 = that._a0; _a1 = that._a1; _a2 = that._a2; _a3 = that._a3; _t0 = that._t0; _t1 = that._t1; _t2 = that._t2; _t3 = that._t3; _t4 = that._t4; _t5 = that._t5; _t6 = that._t6; _t7 = that._t7; _s0 = that._s0; _s1 = that._s1; _s2 = that._s2; _s3 = that._s3; _s4 = that._s4; _s5 = that._s5; _s6 = that._s6; _s7 = that._s7; _t8 = that._t8; _t9 = that._t9; _k0 = that._k0; _k1 = that._k1; _gp = that._gp; _sp = that._sp; _fp = that._fp; _ra = that._ra; } public int getRegister(int reg) { switch (reg) { case Common._zr: return 0; case Common._at: return _at; case Common._v0: return _v0; case Common._v1: return _v1; case Common._a0: return _a0; case Common._a1: return _a1; case Common._a2: return _a2; case Common._a3: return _a3; case Common._t0: return _t0; case Common._t1: return _t1; case Common._t2: return _t2; case Common._t3: return _t3; case Common._t4: return _t4; case Common._t5: return _t5; case Common._t6: return _t6; case Common._t7: return _t7; case Common._s0: return _s0; case Common._s1: return _s1; case Common._s2: return _s2; case Common._s3: return _s3; case Common._s4: return _s4; case Common._s5: return _s5; case Common._s6: return _s6; case Common._s7: return _s7; case Common._t8: return _t8; case Common._t9: return _t9; case Common._k0: return _k0; case Common._k1: return _k1; case Common._gp: return _gp; case Common._sp: return _sp; case Common._fp: return _fp; case Common._ra: return _ra; } Emulator.log.error(String.format("Unknown register %d", reg)); return 0; } public void setRegister(int reg, int value) { switch (reg) { case Common._zr: return; case Common._at: _at = value; return; case Common._v0: _v0 = value; return; case Common._v1: _v1 = value; return; case Common._a0: _a0 = value; return; case Common._a1: _a1 = value; return; case Common._a2: _a2 = value; return; case Common._a3: _a3 = value; return; case Common._t0: _t0 = value; return; case Common._t1: _t1 = value; return; case Common._t2: _t2 = value; return; case Common._t3: _t3 = value; return; case Common._t4: _t4 = value; return; case Common._t5: _t5 = value; return; case Common._t6: _t6 = value; return; case Common._t7: _t7 = value; return; case Common._s0: _s0 = value; return; case Common._s1: _s1 = value; return; case Common._s2: _s2 = value; return; case Common._s3: _s3 = value; return; case Common._s4: _s4 = value; return; case Common._s5: _s5 = value; return; case Common._s6: _s6 = value; return; case Common._s7: _s7 = value; return; case Common._t8: _t8 = value; return; case Common._t9: _t9 = value; return; case Common._k0: _k0 = value; return; case Common._k1: _k1 = value; return; case Common._gp: _gp = value; return; case Common._sp: _sp = value; return; case Common._fp: _fp = value; return; case Common._ra: _ra = value; return; } Emulator.log.error(String.format("Unknown register %d, value=0x%08X", reg, value)); } public void doUNK(String reason) { Emulator.log.error("Interpreter : " + reason); } public static final int extractBits(int x, int pos, int len) { return (x >>> pos) & ~(~0 << len); } public static final int insertBits(int x, int y, int lsb, int msb) { int mask = ~(~0 << (msb - lsb + 1)) << lsb; return (x & ~mask) | ((y << lsb) & mask); } public static final int signExtend(int value) { return (value << 16) >> 16; } public static final int signExtend8(int value) { return (value << 24) >> 24; } public static final int zeroExtend(int value) { return (value & 0xffff); } public static final int zeroExtend8(int value) { return (value & 0xff); } public static final int signedCompare(int i, int j) { return (i < j) ? 1 : 0; } public static final int unsignedCompare(long i, long j) { return ((i & 0xffffffffL) < (j & 0xffffffffL)) ? 1 : 0; } // not sure about it //public static final int unsignedCompare(int i, int j) { // return (i - j) >>> 31; //} public final void doSLL(int rd, int rt, int sa) { if (rd != 0) { setRegister(rd, getRegister(rt) << sa); } } public final void doSRL(int rd, int rt, int sa) { if (rd != 0) { setRegister(rd, getRegister(rt) >>> sa); } } public final void doSRA(int rd, int rt, int sa) { if (rd != 0) { setRegister(rd, getRegister(rt) >> sa); } } public final void doSLLV(int rd, int rt, int rs) { if (rd != 0) { setRegister(rd, getRegister(rt) << (getRegister(rs) & 31)); } } public final void doSRLV(int rd, int rt, int rs) { if (rd != 0) { setRegister(rd, getRegister(rt) >>> (getRegister(rs) & 31)); } } public final void doSRAV(int rd, int rt, int rs) { if (rd != 0) { setRegister(rd, getRegister(rt) >> (getRegister(rs) & 31)); } } public final void doADDU(int rd, int rs, int rt) { if (rd != 0) { setRegister(rd, getRegister(rs) + getRegister(rt)); } } public final void doSUBU(int rd, int rs, int rt) { if (rd != 0) { setRegister(rd, getRegister(rs) - getRegister(rt)); } } public final void doAND(int rd, int rs, int rt) { if (rd != 0) { setRegister(rd, getRegister(rs) & getRegister(rt)); } } public final void doOR(int rd, int rs, int rt) { if (rd != 0) { setRegister(rd, getRegister(rs) | getRegister(rt)); } } public final void doXOR(int rd, int rs, int rt) { if (rd != 0) { setRegister(rd, getRegister(rs) ^ getRegister(rt)); } } public final void doNOR(int rd, int rs, int rt) { if (rd != 0) { setRegister(rd, ~(getRegister(rs) | getRegister(rt))); } } public final void doSLT(int rd, int rs, int rt) { if (rd != 0) { setRegister(rd, signedCompare(getRegister(rs), getRegister(rt))); } } public final void doSLTU(int rd, int rs, int rt) { if (rd != 0) { setRegister(rd, unsignedCompare(getRegister(rs), getRegister(rt))); } } public final void doADDIU(int rt, int rs, int simm16) { if (rt != 0) { setRegister(rt, getRegister(rs) + simm16); } } public final void doSLTI(int rt, int rs, int simm16) { if (rt != 0) { setRegister(rt, signedCompare(getRegister(rs), simm16)); } } public final void doSLTIU(int rt, int rs, int simm16) { if (rt != 0) { setRegister(rt, unsignedCompare(getRegister(rs), simm16)); } } public final void doANDI(int rt, int rs, int uimm16) { if (rt != 0) { setRegister(rt, getRegister(rs) & uimm16); } } public final void doORI(int rt, int rs, int uimm16) { if (rt != 0) { setRegister(rt, getRegister(rs) | uimm16); } } public final void doXORI(int rt, int rs, int uimm16) { if (rt != 0) { setRegister(rt, getRegister(rs) ^ uimm16); } } public final void doLUI(int rt, int uimm16) { if (rt != 0) { setRegister(rt, uimm16 << 16); } } public final void doROTR(int rd, int rt, int sa) { if (rd != 0) { setRegister(rd, Integer.rotateRight(getRegister(rt), sa)); } } public final void doROTRV(int rd, int rt, int rs) { if (rd != 0) { // no need of "getRegister(rs) & 31", rotateRight does it for us setRegister(rd, Integer.rotateRight(getRegister(rt), getRegister(rs))); } } public final void doMOVZ(int rd, int rs, int rt) { if ((rd != 0) && (getRegister(rt) == 0)) { setRegister(rd, getRegister(rs)); } } public final void doMOVN(int rd, int rs, int rt) { if ((rd != 0) && (getRegister(rt) != 0)) { setRegister(rd, getRegister(rs)); } } public final void doCLZ(int rd, int rs) { if (rd != 0) { setRegister(rd, Integer.numberOfLeadingZeros(getRegister(rs))); } } public final void doCLO(int rd, int rs) { if (rd != 0) { setRegister(rd, Integer.numberOfLeadingZeros(~getRegister(rs))); } } public final void doMAX(int rd, int rs, int rt) { if (rd != 0) { setRegister(rd, Math.max(getRegister(rs), getRegister(rt))); } } public final void doMIN(int rd, int rs, int rt) { if (rd != 0) { setRegister(rd, Math.min(getRegister(rs), getRegister(rt))); } } public final void doEXT(int rt, int rs, int lsb, int msbd) { if (rt != 0) { setRegister(rt, extractBits(getRegister(rs), lsb, (msbd + 1))); } } public final void doINS(int rt, int rs, int lsb, int msb) { if (rt != 0) { setRegister(rt, insertBits(getRegister(rt), getRegister(rs), lsb, msb)); } } public final void doWSBH(int rd, int rt) { if (rd != 0) { setRegister(rd, Integer.rotateRight(Integer.reverseBytes(getRegister(rt)), 16)); } } public final void doWSBW(int rd, int rt) { if (rd != 0) { setRegister(rd, Integer.reverseBytes(getRegister(rt))); } } public final void doSEB(int rd, int rt) { if (rd != 0) { setRegister(rd, (byte)getRegister(rt)); } } public final void doBITREV(int rd, int rt) { if (rd != 0) { setRegister(rd, Integer.reverse(getRegister(rt))); } } public final void doSEH(int rd, int rt) { if (rd != 0) { setRegister(rd, (short)getRegister(rt)); } } }