/*
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;
import jpcsp.Processor;
/**
* Branch Control Unit, handles branching and jumping operations
*
* @author hli
*
*/
public class BcuState extends LsuState {
public int pc;
public int npc;
@Override
public void reset() {
pc = 0;
npc = 0;
}
@Override
public void resetAll() {
super.resetAll();
pc = 0;
npc = 0;
}
public BcuState() {
pc = 0;
npc = 0;
}
public void copy(BcuState that) {
super.copy(that);
pc = that.pc;
npc = that.npc;
}
public BcuState(BcuState that) {
super(that);
pc = that.pc;
npc = that.npc;
}
public static int branchTarget(int npc, int simm16) {
return npc + (simm16 << 2);
}
public static int jumpTarget(int npc, int uimm26) {
return (npc & 0xf0000000) | (uimm26 << 2);
}
public int fetchOpcode() {
npc = pc + 4;
int opcode = memory.read32(pc);
// by default, the next instruction to emulate is at the next address
pc = npc;
return opcode;
}
public int nextOpcode() {
int opcode = memory.read32(pc);
// by default, the next instruction to emulate is at the next address
pc += 4;
return opcode;
}
public void nextPc() {
pc = npc;
npc = pc + 4;
}
public boolean doJR(int rs) {
npc = getRegister(rs);
return true;
}
public boolean doJALR(int rd, int rs) {
if (rd != 0) {
setRegister(rd, pc + 4);
}
npc = getRegister(rs);
return true;
}
public boolean doBLTZ(int rs, int simm16) {
npc = (getRegister(rs) < 0) ? branchTarget(pc, simm16) : (pc + 4);
return true;
}
public boolean doBGEZ(int rs, int simm16) {
npc = (getRegister(rs) >= 0) ? branchTarget(pc, simm16) : (pc + 4);
return true;
}
public boolean doBLTZL(int rs, int simm16) {
if (getRegister(rs) < 0) {
npc = branchTarget(pc, simm16);
return true;
}
pc += 4;
return false;
}
public boolean doBGEZL(int rs, int simm16) {
if (getRegister(rs) >= 0) {
npc = branchTarget(pc, simm16);
return true;
}
pc += 4;
return false;
}
public boolean doBLTZAL(int rs, int simm16) {
int target = pc + 4;
boolean t = (getRegister(rs) < 0);
_ra = target;
npc = t ? branchTarget(pc, simm16) : target;
return true;
}
public boolean doBGEZAL(int rs, int simm16) {
int target = pc + 4;
boolean t = (getRegister(rs) >= 0);
_ra = target;
npc = t ? branchTarget(pc, simm16) : target;
return true;
}
public boolean doBLTZALL(int rs, int simm16) {
boolean t = (getRegister(rs) < 0);
_ra = pc + 4;
if (t) {
npc = branchTarget(pc, simm16);
} else {
pc += 4;
}
return t;
}
public boolean doBGEZALL(int rs, int simm16) {
boolean t = (getRegister(rs) >= 0);
_ra = pc + 4;
if (t) {
npc = branchTarget(pc, simm16);
} else {
pc += 4;
}
return t;
}
public boolean doJ(int uimm26) {
npc = jumpTarget(pc, uimm26);
if (npc == pc - 4) {
Processor.log.info("Pausing emulator - jump to self (death loop)");
Emulator.PauseEmuWithStatus(Emulator.EMU_STATUS_JUMPSELF);
}
return true;
}
public boolean doJAL(int uimm26) {
_ra = pc + 4;
npc = jumpTarget(pc, uimm26);
return true;
}
public boolean doBEQ(int rs, int rt, int simm16) {
npc = (getRegister(rs) == getRegister(rt)) ? branchTarget(pc, simm16) : (pc + 4);
if (npc == pc - 4 && rs == rt) {
Processor.log.info("Pausing emulator - branch to self (death loop)");
Emulator.PauseEmuWithStatus(Emulator.EMU_STATUS_JUMPSELF);
}
return true;
}
public boolean doBNE(int rs, int rt, int simm16) {
npc = (getRegister(rs) != getRegister(rt)) ? branchTarget(pc, simm16) : (pc + 4);
return true;
}
public boolean doBLEZ(int rs, int simm16) {
npc = (getRegister(rs) <= 0) ? branchTarget(pc, simm16) : (pc + 4);
return true;
}
public boolean doBGTZ(int rs, int simm16) {
npc = (getRegister(rs) > 0) ? branchTarget(pc, simm16) : (pc + 4);
return true;
}
public boolean doBEQL(int rs, int rt, int simm16) {
if (getRegister(rs) == getRegister(rt)) {
npc = branchTarget(pc, simm16);
return true;
}
pc += 4;
return false;
}
public boolean doBNEL(int rs, int rt, int simm16) {
if (getRegister(rs) != getRegister(rt)) {
npc = branchTarget(pc, simm16);
return true;
}
pc += 4;
return false;
}
public boolean doBLEZL(int rs, int simm16) {
if (getRegister(rs) <= 0) {
npc = branchTarget(pc, simm16);
return true;
}
pc += 4;
return false;
}
public boolean doBGTZL(int rs, int simm16) {
if (getRegister(rs) > 0) {
npc = branchTarget(pc, simm16);
return true;
}
pc += 4;
return false;
}
}