mirror of
https://github.com/liuk7071/ChonkyStation.git
synced 2024-06-02 19:27:55 -04:00
[CPU] Many fixes
This commit is contained in:
parent
2fb4c68e87
commit
c9e13e0b33
|
@ -1,8 +1,8 @@
|
||||||
#include "interpreter.hpp"
|
#include "interpreter.hpp"
|
||||||
|
|
||||||
|
|
||||||
#define DONT_CRASH_ON_BAD_READWRITE
|
//#define DONT_CRASH_ON_BAD_READWRITE
|
||||||
#define DONT_CRASH_ON_BAD_JUMP
|
//#define DONT_CRASH_ON_BAD_JUMP
|
||||||
|
|
||||||
void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
// Handle interrupts
|
// Handle interrupts
|
||||||
|
@ -61,6 +61,7 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
#ifndef DONT_CRASH_ON_BAD_JUMP
|
#ifndef DONT_CRASH_ON_BAD_JUMP
|
||||||
Helpers::panic("Bad JR addr\n");
|
Helpers::panic("Bad JR addr\n");
|
||||||
#else
|
#else
|
||||||
|
core->exception(CpuCore::Exception::BadFetchAddr, true);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -70,14 +71,15 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
}
|
}
|
||||||
case CpuOpcodes::SPECIALOpcode::JALR: {
|
case CpuOpcodes::SPECIALOpcode::JALR: {
|
||||||
const u32 addr = gprs[instr.rs];
|
const u32 addr = gprs[instr.rs];
|
||||||
|
gprs[instr.rd] = core->nextPc;
|
||||||
if (addr & 3) {
|
if (addr & 3) {
|
||||||
#ifndef DONT_CRASH_ON_BAD_JUMP
|
#ifndef DONT_CRASH_ON_BAD_JUMP
|
||||||
Helpers::panic("Bad JALR addr\n");
|
Helpers::panic("Bad JALR addr\n");
|
||||||
#else
|
#else
|
||||||
|
core->exception(CpuCore::Exception::BadFetchAddr, true);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
gprs[CpuOpcodes::CpuReg::RA] = core->nextPc;
|
|
||||||
core->nextPc = addr;
|
core->nextPc = addr;
|
||||||
core->branched = true;
|
core->branched = true;
|
||||||
break;
|
break;
|
||||||
|
@ -157,8 +159,14 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CpuOpcodes::SPECIALOpcode::ADD: {
|
case CpuOpcodes::SPECIALOpcode::ADD: {
|
||||||
|
u32 a = gprs[instr.rs];
|
||||||
|
u32 b = gprs[instr.rt];
|
||||||
|
u32 res = a + b;
|
||||||
|
if (((a >> 31) == (b >> 31)) && ((a >> 31) != (res >> 31))) {
|
||||||
|
core->exception(CpuCore::Exception::Overflow, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
gprs[instr.rd] = gprs[instr.rs] + gprs[instr.rt];
|
gprs[instr.rd] = gprs[instr.rs] + gprs[instr.rt];
|
||||||
// TODO: overflow exception
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CpuOpcodes::SPECIALOpcode::ADDU: {
|
case CpuOpcodes::SPECIALOpcode::ADDU: {
|
||||||
|
@ -166,8 +174,14 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CpuOpcodes::SPECIALOpcode::SUB: {
|
case CpuOpcodes::SPECIALOpcode::SUB: {
|
||||||
gprs[instr.rd] = gprs[instr.rs] - gprs[instr.rt];
|
u32 a = gprs[instr.rs];
|
||||||
// TODO: overflow exception
|
u32 b = gprs[instr.rt];
|
||||||
|
u32 res = a - b;
|
||||||
|
if (((a ^ res) & (~b ^ res)) >> 31) {
|
||||||
|
core->exception(CpuCore::Exception::Overflow, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gprs[instr.rd] = res;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CpuOpcodes::SPECIALOpcode::SUBU: {
|
case CpuOpcodes::SPECIALOpcode::SUBU: {
|
||||||
|
@ -204,40 +218,29 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CpuOpcodes::Opcode::REGIMM: {
|
case CpuOpcodes::Opcode::REGIMM: {
|
||||||
switch (instr.regimmOpc & 0x11) {
|
bool ge = (instr.raw >> 16) & 1;
|
||||||
case CpuOpcodes::REGIMMOpcode::BLTZ: {
|
bool link = ((instr.raw >> 17) & 0xf) == 8;
|
||||||
if ((s32)gprs[instr.rs] < 0) {
|
|
||||||
|
s32 rs = (s32)gprs[instr.rs];
|
||||||
|
|
||||||
|
if (link) gprs[CpuReg::RA] = core->nextPc;
|
||||||
|
|
||||||
|
if (ge) {
|
||||||
|
if (rs >= 0) {
|
||||||
core->nextPc = core->pc + ((u32)(s16)instr.imm << 2);
|
core->nextPc = core->pc + ((u32)(s16)instr.imm << 2);
|
||||||
core->branched = true;
|
core->branched = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CpuOpcodes::REGIMMOpcode::BGEZ: {
|
else {
|
||||||
if ((s32)gprs[instr.rs] >= 0) {
|
if (rs < 0) {
|
||||||
core->nextPc = core->pc + ((u32)(s16)instr.imm << 2);
|
core->nextPc = core->pc + ((u32)(s16)instr.imm << 2);
|
||||||
core->branched = true;
|
core->branched = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CpuOpcodes::REGIMMOpcode::BLTZAL: {
|
|
||||||
gprs[CpuOpcodes::CpuReg::RA] = core->nextPc;
|
Helpers::panic("[ FATAL ] Invalid REGIMM instruction 0x%02x (raw: 0x%08x)\n", instr.regimmOpc.Value(), instr.raw);
|
||||||
if ((s32)gprs[instr.rs] < 0) {
|
|
||||||
core->nextPc = core->pc + ((u32)(s16)instr.imm << 2);
|
|
||||||
core->branched = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CpuOpcodes::REGIMMOpcode::BGEZAL: {
|
|
||||||
gprs[CpuOpcodes::CpuReg::RA] = core->nextPc;
|
|
||||||
if ((s32)gprs[instr.rs] >= 0) {
|
|
||||||
core->nextPc = core->pc + ((u32)(s16)instr.imm << 2);
|
|
||||||
core->branched = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
Helpers::panic("[ FATAL ] Invalid REGIMM instruction 0x%02x (raw: 0x%08x)\n", instr.regimmOpc.Value(), instr.raw);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CpuOpcodes::Opcode::J: {
|
case CpuOpcodes::Opcode::J: {
|
||||||
|
@ -246,7 +249,7 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CpuOpcodes::Opcode::JAL: {
|
case CpuOpcodes::Opcode::JAL: {
|
||||||
gprs[CpuOpcodes::CpuReg::RA] = core->nextPc;
|
gprs[CpuReg::RA] = core->nextPc;
|
||||||
core->nextPc = (core->pc & 0xf0000000) | (instr.jumpImm << 2);
|
core->nextPc = (core->pc & 0xf0000000) | (instr.jumpImm << 2);
|
||||||
core->branched = true;
|
core->branched = true;
|
||||||
break;
|
break;
|
||||||
|
@ -280,8 +283,14 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CpuOpcodes::Opcode::ADDI: {
|
case CpuOpcodes::Opcode::ADDI: {
|
||||||
gprs[instr.rt] = gprs[instr.rs] + (u32)(s16)instr.imm;
|
u32 a = gprs[instr.rs];
|
||||||
// TODO: overflow exception
|
u32 b = (u32)(s16)instr.imm;
|
||||||
|
u32 res = a + b;
|
||||||
|
if (((a >> 31) == (b >> 31)) && ((a >> 31) != (res >> 31))) {
|
||||||
|
core->exception(CpuCore::Exception::Overflow, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gprs[instr.rt] = res;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CpuOpcodes::Opcode::ADDIU: {
|
case CpuOpcodes::Opcode::ADDIU: {
|
||||||
|
@ -352,6 +361,9 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
if (addr & 1) {
|
if (addr & 1) {
|
||||||
#ifndef DONT_CRASH_ON_BAD_READWRITE
|
#ifndef DONT_CRASH_ON_BAD_READWRITE
|
||||||
Helpers::panic("Bad lh addr 0x%08x\n", addr);
|
Helpers::panic("Bad lh addr 0x%08x\n", addr);
|
||||||
|
#else
|
||||||
|
core->exception(CpuCore::Exception::BadFetchAddr, true);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
gprs[instr.rt] = (u32)(s16)mem->read<u16>(addr);
|
gprs[instr.rt] = (u32)(s16)mem->read<u16>(addr);
|
||||||
|
@ -361,8 +373,8 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
u32 address = gprs[instr.rs] + (u32)(s16)instr.imm;
|
u32 address = gprs[instr.rs] + (u32)(s16)instr.imm;
|
||||||
const int shift = ((address & 3) ^ 3) * 8;
|
const int shift = ((address & 3) ^ 3) * 8;
|
||||||
u32 dataTemp = mem->read<u32>(address & ~3);
|
u32 dataTemp = mem->read<u32>(address & ~3);
|
||||||
u32 rtTemp = gprs[instr.rt] & ~(0xffffffff >> shift);
|
u32 rtTemp = gprs[instr.rt] & ~(0xffffffff << shift);
|
||||||
dataTemp >>= shift;
|
dataTemp <<= shift;
|
||||||
gprs[instr.rt] = dataTemp | rtTemp;
|
gprs[instr.rt] = dataTemp | rtTemp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -371,6 +383,9 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
if (addr & 3) {
|
if (addr & 3) {
|
||||||
#ifndef DONT_CRASH_ON_BAD_READWRITE
|
#ifndef DONT_CRASH_ON_BAD_READWRITE
|
||||||
Helpers::panic("Bad lw addr 0x%08x\n", addr);
|
Helpers::panic("Bad lw addr 0x%08x\n", addr);
|
||||||
|
#else
|
||||||
|
core->exception(CpuCore::Exception::BadFetchAddr, true);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
gprs[instr.rt] = mem->read<u32>(addr);
|
gprs[instr.rt] = mem->read<u32>(addr);
|
||||||
|
@ -386,6 +401,9 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
if (addr & 1) {
|
if (addr & 1) {
|
||||||
#ifndef DONT_CRASH_ON_BAD_READWRITE
|
#ifndef DONT_CRASH_ON_BAD_READWRITE
|
||||||
Helpers::panic("Bad lhu addr 0x%08x\n", addr);
|
Helpers::panic("Bad lhu addr 0x%08x\n", addr);
|
||||||
|
#else
|
||||||
|
core->exception(CpuCore::Exception::BadFetchAddr, true);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
gprs[instr.rt] = mem->read<u16>(addr);
|
gprs[instr.rt] = mem->read<u16>(addr);
|
||||||
|
@ -395,8 +413,8 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
u32 address = gprs[instr.rs] + (u32)(s16)instr.imm;
|
u32 address = gprs[instr.rs] + (u32)(s16)instr.imm;
|
||||||
const int shift = (address & 3) * 8;
|
const int shift = (address & 3) * 8;
|
||||||
u32 dataTemp = mem->read<u32>(address & ~3);
|
u32 dataTemp = mem->read<u32>(address & ~3);
|
||||||
u32 rtTemp = gprs[instr.rt] & ~(0xffffffff << shift);
|
u32 rtTemp = gprs[instr.rt] & ~(0xffffffff >> shift);
|
||||||
dataTemp <<= shift;
|
dataTemp >>= shift;
|
||||||
gprs[instr.rt] = dataTemp | rtTemp;
|
gprs[instr.rt] = dataTemp | rtTemp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -412,6 +430,9 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
if (addr & 1) {
|
if (addr & 1) {
|
||||||
#ifndef DONT_CRASH_ON_BAD_READWRITE
|
#ifndef DONT_CRASH_ON_BAD_READWRITE
|
||||||
Helpers::panic("Bad sh addr 0x%08x\n", addr);
|
Helpers::panic("Bad sh addr 0x%08x\n", addr);
|
||||||
|
#else
|
||||||
|
core->exception(CpuCore::Exception::BadStoreAddr, true);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
mem->write<u16>(addr, gprs[instr.rt]);
|
mem->write<u16>(addr, gprs[instr.rt]);
|
||||||
|
@ -421,8 +442,8 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
u32 address = gprs[instr.rs] + (u32)(s16)instr.imm;
|
u32 address = gprs[instr.rs] + (u32)(s16)instr.imm;
|
||||||
const int shift = ((address & 3) ^ 3) * 8;
|
const int shift = ((address & 3) ^ 3) * 8;
|
||||||
u32 dataTemp = mem->read<u32>(address & ~3);
|
u32 dataTemp = mem->read<u32>(address & ~3);
|
||||||
u32 rtTemp = gprs[instr.rt] << shift;
|
u32 rtTemp = gprs[instr.rt] >> shift;
|
||||||
dataTemp &= ~(0xffffffff << shift);
|
dataTemp &= ~(0xffffffff >> shift);
|
||||||
mem->write<u32>(address & ~3, dataTemp | rtTemp);
|
mem->write<u32>(address & ~3, dataTemp | rtTemp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -432,6 +453,9 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
if (addr & 3) {
|
if (addr & 3) {
|
||||||
#ifndef DONT_CRASH_ON_BAD_READWRITE
|
#ifndef DONT_CRASH_ON_BAD_READWRITE
|
||||||
Helpers::panic("Bad sw addr 0x%08x\n", addr);
|
Helpers::panic("Bad sw addr 0x%08x\n", addr);
|
||||||
|
#else
|
||||||
|
core->exception(CpuCore::Exception::BadStoreAddr, true);
|
||||||
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
mem->write<u32>(addr, gprs[instr.rt]);
|
mem->write<u32>(addr, gprs[instr.rt]);
|
||||||
|
@ -441,8 +465,8 @@ void Interpreter::step(CpuCore* core, Memory* mem, Disassembler* disassembler) {
|
||||||
u32 address = gprs[instr.rs] + (u32)(s16)instr.imm;
|
u32 address = gprs[instr.rs] + (u32)(s16)instr.imm;
|
||||||
const int shift = (address & 3) * 8;
|
const int shift = (address & 3) * 8;
|
||||||
u32 dataTemp = mem->read<u32>(address & ~3);
|
u32 dataTemp = mem->read<u32>(address & ~3);
|
||||||
u32 rtTemp = gprs[instr.rt] >> shift;
|
u32 rtTemp = gprs[instr.rt] << shift;
|
||||||
dataTemp &= ~(0xffffffff >> shift);
|
dataTemp &= ~(0xffffffff << shift);
|
||||||
mem->write<u32>(address & ~3, dataTemp | rtTemp);
|
mem->write<u32>(address & ~3, dataTemp | rtTemp);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ struct COP0 {
|
||||||
case (u32)COP0Reg::BDA: return 0;
|
case (u32)COP0Reg::BDA: return 0;
|
||||||
case (u32)COP0Reg::JumpDest: return 0;
|
case (u32)COP0Reg::JumpDest: return 0;
|
||||||
case (u32)COP0Reg::DCIC: return 0;
|
case (u32)COP0Reg::DCIC: return 0;
|
||||||
case (u32)COP0Reg::BadVAddr: return 0;
|
case (u32)COP0Reg::BadVAddr: return badVaddr;
|
||||||
case (u32)COP0Reg::BDAM: return 0;
|
case (u32)COP0Reg::BDAM: return 0;
|
||||||
case (u32)COP0Reg::BPCM: return 0;
|
case (u32)COP0Reg::BPCM: return 0;
|
||||||
case (u32)COP0Reg::Status: return status.raw;
|
case (u32)COP0Reg::Status: return status.raw;
|
||||||
|
@ -168,8 +168,8 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace CpuOpcodes {
|
namespace CpuReg {
|
||||||
enum CpuReg {
|
enum {
|
||||||
R0 = 0, AT = 1, V0 = 2, V1 = 3,
|
R0 = 0, AT = 1, V0 = 2, V1 = 3,
|
||||||
A0 = 4, A1 = 5, A2 = 6, A3 = 7,
|
A0 = 4, A1 = 5, A2 = 6, A3 = 7,
|
||||||
T0 = 8, T1 = 9, T2 = 10, T3 = 11,
|
T0 = 8, T1 = 9, T2 = 10, T3 = 11,
|
||||||
|
@ -180,7 +180,9 @@ enum CpuReg {
|
||||||
GP = 28, SP = 29, S8 = 30, RA = 31,
|
GP = 28, SP = 29, S8 = 30, RA = 31,
|
||||||
LO = 32, HI = 33
|
LO = 32, HI = 33
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace CpuOpcodes {
|
||||||
enum Opcode {
|
enum Opcode {
|
||||||
SPECIAL = 0x00,
|
SPECIAL = 0x00,
|
||||||
REGIMM = 0x01,
|
REGIMM = 0x01,
|
||||||
|
|
Loading…
Reference in a new issue