diff options
| author | iCatButler <i.am.catbutler@gmail.com> | 2016-06-07 15:57:46 +0100 |
|---|---|---|
| committer | iCatButler <i.am.catbutler@gmail.com> | 2016-06-07 15:57:46 +0100 |
| commit | f70082329d751ee8a358437feb34134e283b27d8 (patch) | |
| tree | c97c99835067e9a20725943b4b4c63d44d4e3bdc /libpcsxcore/pgxp_cpu.c | |
| parent | 7ecfee1f664eeb92b653104f5f3c915cc6fe6bcb (diff) | |
| download | pcsxr-f70082329d751ee8a358437feb34134e283b27d8.tar.gz | |
Initial PGXP CPU commit
- Restructured project to base interface on PSX instructions
- Support for all relevant CPU arithmetic and logic instructions
- Debug output available via deferred PGXP calls
- Remove most dependencies on PCSXR
- Still very much a work in progress (lots of errors)
- Add extra debug information to GPU plugin (w values)
Diffstat (limited to 'libpcsxcore/pgxp_cpu.c')
| -rw-r--r-- | libpcsxcore/pgxp_cpu.c | 737 |
1 files changed, 737 insertions, 0 deletions
diff --git a/libpcsxcore/pgxp_cpu.c b/libpcsxcore/pgxp_cpu.c new file mode 100644 index 00000000..60e623e5 --- /dev/null +++ b/libpcsxcore/pgxp_cpu.c @@ -0,0 +1,737 @@ + +#include "pgxp_cpu.h" +#include "pgxp_value.h" +#include "pgxp_mem.h" + +// CPU registers +PGXP_value CPU_reg_mem[34]; +//PGXP_value CPU_Hi, CPU_Lo; + +PGXP_value* CPU_reg = CPU_reg_mem; + +// Instruction register decoding +#define op(_instr) (_instr >> 26) // The op part of the instruction register +#define func(_instr) ((_instr) & 0x3F) // The funct part of the instruction register +#define sa(_instr) ((_instr >> 6) & 0x1F) // The sa part of the instruction register +#define rd(_instr) ((_instr >> 11) & 0x1F) // The rd part of the instruction register +#define rt(_instr) ((_instr >> 16) & 0x1F) // The rt part of the instruction register +#define rs(_instr) ((_instr >> 21) & 0x1F) // The rs part of the instruction register +#define imm(_instr) (_instr & 0xFFFF) // The immediate part of the instruction register + +// invalidate register (invalid 8 bit read) +void InvalidLoad(u32 addr, u32 code, u32 value) +{ + u32 reg = ((code >> 16) & 0x1F); // The rt part of the instruction register + PGXP_value* pD = NULL; + PGXP_value p; + + p.x = p.y = -1337; // default values + + //p.valid = 0; + //p.count = value; + pD = ReadMem(addr); + + if (pD) + { + p.count = addr; + p = *pD; + } + else + { + p.count = value; + } + + p.valid = 0; + + // invalidate register + CPU_reg[reg] = p; +} + +// invalidate memory address (invalid 8 bit write) +void InvalidStore(u32 addr, u32 code, u32 value) +{ + u32 reg = ((code >> 16) & 0x1F); // The rt part of the instruction register + PGXP_value* pD = NULL; + PGXP_value p; + + pD = ReadMem(addr); + + p.x = p.y = -2337; + + if (pD) + p = *pD; + + p.valid = 0; + p.count = (reg * 1000) + value; + + // invalidate memory + WriteMem(&p, addr); +} + +//////////////////////////////////// +// Arithmetic with immediate value +//////////////////////////////////// +void PGXP_CPU_ADDI(u32 instr, u32 rtVal, u32 rsVal) +{ + // Rt = Rs + Imm (signed) + psx_value tempImm; + + Validate(&CPU_reg[rs(instr)], rsVal); + CPU_reg[rt(instr)] = CPU_reg[rs(instr)]; + + tempImm.w.h = imm(instr); + CPU_reg[rt(instr)].x += tempImm.sw.h; + // handle x overflow in to y? + + CPU_reg[rt(instr)].value = rtVal; +} + +void PGXP_CPU_ADDIU(u32 instr, u32 rtVal, u32 rsVal) +{ + // Rt = Rs + Imm (signed) (unsafe?) + psx_value tempImm; + + Validate(&CPU_reg[rs(instr)], rsVal); + CPU_reg[rt(instr)] = CPU_reg[rs(instr)]; + + tempImm.w.h = imm(instr); + CPU_reg[rt(instr)].x += tempImm.sw.h; + // handle x overflow in to y? + + CPU_reg[rt(instr)].value = rtVal; +} + +void PGXP_CPU_ANDI(u32 instr, u32 rtVal, u32 rsVal) +{ + // Rt = Rs & Imm + Validate(&CPU_reg[rs(instr)], rsVal); + CPU_reg[rt(instr)] = CPU_reg[rs(instr)]; + + CPU_reg[rt(instr)].y = 0.f; // remove upper 16-bits + + switch (imm(instr)) + { + case 0: + // if 0 then x == 0 + CPU_reg[rt(instr)].x = 0.f; + break; + case 0xFFFF: + // if saturated then x = x + break; + default: + // x is undefined, invalidate value + CPU_reg[rt(instr)].valid = 0; + } + + CPU_reg[rt(instr)].value = rtVal; +} + +void PGXP_CPU_ORI(u32 instr, u32 rtVal, u32 rsVal) +{ + // Rt = Rs | Imm + Validate(&CPU_reg[rs(instr)], rsVal); + CPU_reg[rt(instr)] = CPU_reg[rs(instr)]; + + // Invalidate on non-zero values for now + if (imm(instr) != 0) + CPU_reg[rt(instr)].valid = 0; + + CPU_reg[rt(instr)].value = rtVal; +} + +void PGXP_CPU_XORI(u32 instr, u32 rtVal, u32 rsVal) +{ + // Rt = Rs ^ Imm + Validate(&CPU_reg[rs(instr)], rsVal); + CPU_reg[rt(instr)] = CPU_reg[rs(instr)]; + + // Invalidate on non-zero values for now + if (imm(instr) != 0) + CPU_reg[rt(instr)].valid = 0; + + CPU_reg[rt(instr)].value = rtVal; +} + +void PGXP_CPU_SLTI(u32 instr, u32 rtVal, u32 rsVal) +{ + // Rt = Rs < Imm (signed) + psx_value tempImm; + + Validate(&CPU_reg[rs(instr)], rsVal); + CPU_reg[rt(instr)] = CPU_reg[rs(instr)]; + + tempImm.w.h = imm(instr); + CPU_reg[rt(instr)].y = 0.f; + CPU_reg[rt(instr)].x = (CPU_reg[rs(instr)].x < tempImm.sw.h) ? 1.f : 0.f; + + CPU_reg[rt(instr)].value = rtVal; +} + +void PGXP_CPU_SLTIU(u32 instr, u32 rtVal, u32 rsVal) +{ + // Rt = Rs < Imm (signed) + Validate(&CPU_reg[rs(instr)], rsVal); + CPU_reg[rt(instr)] = CPU_reg[rs(instr)]; + + CPU_reg[rt(instr)].y = 0.f; + CPU_reg[rt(instr)].x = (fabs(CPU_reg[rs(instr)].x) < (u32)imm(instr)) ? 1.f : 0.f; + + CPU_reg[rt(instr)].value = rtVal; +} + +//////////////////////////////////// +// Load Upper +//////////////////////////////////// +void PGXP_CPU_LUI(u32 instr, u32 rtVal) +{ + //Rt = Imm << 16 + CPU_reg[rt(instr)] = PGXP_value_zero; + CPU_reg[rt(instr)].y = (float)(s16)imm(instr); + CPU_reg[rt(instr)].hFlags = VALID_HALF; + CPU_reg[rt(instr)].value = rtVal; +} + +//////////////////////////////////// +// Register Arithmetic +//////////////////////////////////// +void PGXP_CPU_ADD(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal) +{ + // Rd = Rs + Rt (signed) + Validate(&CPU_reg[rs(instr)], rsVal); + Validate(&CPU_reg[rt(instr)], rtVal); + + // iCB: Only require one valid input + if (!(CPU_reg[rs(instr)].valid && CPU_reg[rt(instr)].valid) && (CPU_reg[rs(instr)].valid || CPU_reg[rt(instr)].valid)) + { + MakeValid(&CPU_reg[rs(instr)], rsVal); + MakeValid(&CPU_reg[rt(instr)], rtVal); + } + + CPU_reg[rd(instr)] = CPU_reg[rs(instr)]; + + CPU_reg[rd(instr)].x += CPU_reg[rt(instr)].x; + CPU_reg[rd(instr)].y += CPU_reg[rt(instr)].y; + + CPU_reg[rd(instr)].valid &= CPU_reg[rt(instr)].valid; + CPU_reg[rd(instr)].gFlags |= CPU_reg[rt(instr)].gFlags; + CPU_reg[rd(instr)].lFlags |= CPU_reg[rt(instr)].lFlags; + CPU_reg[rd(instr)].hFlags |= CPU_reg[rt(instr)].hFlags; + + CPU_reg[rd(instr)].value = rdVal; +} + +void PGXP_CPU_ADDU(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal) +{ + // Rd = Rs + Rt (signed) (unsafe?) + PGXP_CPU_ADD(instr, rdVal, rsVal, rtVal); +} + +void PGXP_CPU_SUB(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal) +{ + // Rd = Rs - Rt (signed) + Validate(&CPU_reg[rs(instr)], rsVal); + Validate(&CPU_reg[rt(instr)], rtVal); + + // iCB: Only require one valid input + //if (!(CPU_reg[rs(instr)].valid && CPU_reg[rt(instr)].valid) && (CPU_reg[rs(instr)].valid || CPU_reg[rt(instr)].valid)) + //{ + // MakeValid(&CPU_reg[rs(instr)], rsVal); + // MakeValid(&CPU_reg[rt(instr)], rtVal); + //} + + CPU_reg[rd(instr)] = CPU_reg[rs(instr)]; + + CPU_reg[rd(instr)].x -= CPU_reg[rt(instr)].x; + CPU_reg[rd(instr)].y -= CPU_reg[rt(instr)].y; + + CPU_reg[rd(instr)].valid &= CPU_reg[rt(instr)].valid; + CPU_reg[rd(instr)].gFlags |= CPU_reg[rt(instr)].gFlags; + CPU_reg[rd(instr)].lFlags |= CPU_reg[rt(instr)].lFlags; + CPU_reg[rd(instr)].hFlags |= CPU_reg[rt(instr)].hFlags; + + CPU_reg[rd(instr)].value = rdVal; +} + +void PGXP_CPU_SUBU(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal) +{ + // Rd = Rs - Rt (signed) (unsafe?) + PGXP_CPU_SUB(instr, rdVal, rsVal, rtVal); +} + +void PGXP_CPU_AND(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal) +{ + // Rd = Rs & Rt + psx_value vald, vals, valt; + + Validate(&CPU_reg[rs(instr)], rsVal); + Validate(&CPU_reg[rt(instr)], rtVal); + + // iCB: Only require one valid input + //if (!(CPU_reg[rs(instr)].valid && CPU_reg[rt(instr)].valid) && (CPU_reg[rs(instr)].valid || CPU_reg[rt(instr)].valid)) + //{ + // MakeValid(&CPU_reg[rs(instr)], rsVal); + // MakeValid(&CPU_reg[rt(instr)], rtVal); + //} + + vald.d = rdVal; + vals.d = rsVal; + valt.d = rtVal; + + // CPU_reg[rd(instr)].valid = CPU_reg[rs(instr)].valid && CPU_reg[rt(instr)].valid; + CPU_reg[rd(instr)].valid = 1; + + if (vald.w.l == 0) + { + CPU_reg[rd(instr)].x = 0.f; + CPU_reg[rd(instr)].lFlags = VALID_HALF; + } + else if (vald.w.l == vals.w.l) + { + CPU_reg[rd(instr)].x = CPU_reg[rs(instr)].x; + CPU_reg[rd(instr)].lFlags = CPU_reg[rs(instr)].lFlags; + CPU_reg[rd(instr)].valid &= CPU_reg[rs(instr)].valid; + } + else if (vald.w.l == valt.w.l) + { + CPU_reg[rd(instr)].x = CPU_reg[rt(instr)].x; + CPU_reg[rd(instr)].lFlags = CPU_reg[rt(instr)].lFlags; + CPU_reg[rd(instr)].valid &= CPU_reg[rt(instr)].valid; + } + else + { + CPU_reg[rd(instr)].valid = 0; + CPU_reg[rd(instr)].lFlags = 0; + } + + if (vald.w.h == 0) + { + CPU_reg[rd(instr)].y = 0.f; + CPU_reg[rd(instr)].hFlags = VALID_HALF; + } + else if (vald.w.h == vals.w.h) + { + CPU_reg[rd(instr)].y = CPU_reg[rs(instr)].y; + CPU_reg[rd(instr)].hFlags = CPU_reg[rs(instr)].hFlags; + CPU_reg[rd(instr)].valid &= CPU_reg[rs(instr)].valid; + } + else if (vald.w.h == valt.w.h) + { + CPU_reg[rd(instr)].y = CPU_reg[rt(instr)].y; + CPU_reg[rd(instr)].hFlags = CPU_reg[rt(instr)].hFlags; + CPU_reg[rd(instr)].valid &= CPU_reg[rt(instr)].valid; + } + else + { + CPU_reg[rd(instr)].valid = 0; + CPU_reg[rd(instr)].hFlags = 0; + } + + // iCB Hack: Force validity if even one half is valid + if ((CPU_reg[rd(instr)].hFlags & VALID_HALF) || (CPU_reg[rd(instr)].lFlags & VALID_HALF)) + CPU_reg[rd(instr)].valid = 1; + // /iCB Hack + + CPU_reg[rd(instr)].value = rdVal; +} + +void PGXP_CPU_OR(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal) +{ + // Rd = Rs | Rt + PGXP_CPU_AND(instr, rdVal, rsVal, rtVal); +} + +void PGXP_CPU_XOR(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal) +{ + // Rd = Rs ^ Rt + PGXP_CPU_AND(instr, rdVal, rsVal, rtVal); +} + +void PGXP_CPU_NOR(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal) +{ + // Rd = Rs NOR Rt + PGXP_CPU_AND(instr, rdVal, rsVal, rtVal); +} + +void PGXP_CPU_SLT(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal) +{ + // Rd = Rs < Rt (signed) + Validate(&CPU_reg[rs(instr)], rsVal); + Validate(&CPU_reg[rt(instr)], rtVal); + + // iCB: Only require one valid input + //if (!(CPU_reg[rs(instr)].valid && CPU_reg[rt(instr)].valid) && (CPU_reg[rs(instr)].valid || CPU_reg[rt(instr)].valid)) + //{ + // MakeValid(&CPU_reg[rs(instr)], rsVal); + // MakeValid(&CPU_reg[rt(instr)], rtVal); + //} + + CPU_reg[rd(instr)] = CPU_reg[rs(instr)]; + + // TODO: fix for single or double values? + CPU_reg[rd(instr)].y = 0.f; + CPU_reg[rd(instr)].x = (CPU_reg[rs(instr)].x < CPU_reg[rt(instr)].x) ? 1.f : 0.f; + + CPU_reg[rd(instr)].value = rdVal; +} + +void PGXP_CPU_SLTU(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal) +{ + // Rd = Rs < Rt (unsigned) + Validate(&CPU_reg[rs(instr)], rsVal); + Validate(&CPU_reg[rt(instr)], rtVal); + + // iCB: Only require one valid input + //if (!(CPU_reg[rs(instr)].valid && CPU_reg[rt(instr)].valid) && (CPU_reg[rs(instr)].valid || CPU_reg[rt(instr)].valid)) + //{ + // MakeValid(&CPU_reg[rs(instr)], rsVal); + // MakeValid(&CPU_reg[rt(instr)], rtVal); + //} + + CPU_reg[rd(instr)] = CPU_reg[rs(instr)]; + + CPU_reg[rd(instr)].y = 0.f; + CPU_reg[rd(instr)].x = (fabs(CPU_reg[rs(instr)].x) < fabs(CPU_reg[rt(instr)].x)) ? 1.f : 0.f; + + CPU_reg[rd(instr)].value = rdVal; +} + +//////////////////////////////////// +// Register mult/div +//////////////////////////////////// +void PGXP_CPU_MULT(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal) +{ + // Hi/Lo = Rs * Rt (signed) + Validate(&CPU_reg[rs(instr)], rsVal); + Validate(&CPU_reg[rt(instr)], rtVal); + + // iCB: Only require one valid input + if (!(CPU_reg[rs(instr)].valid && CPU_reg[rt(instr)].valid) && (CPU_reg[rs(instr)].valid || CPU_reg[rt(instr)].valid)) + { + MakeValid(&CPU_reg[rs(instr)], rsVal); + MakeValid(&CPU_reg[rt(instr)], rtVal); + } + + float vs = CPU_reg[rs(instr)].y + (CPU_reg[rs(instr)].x / (float)(1 << 16)); + float vt = CPU_reg[rt(instr)].y + (CPU_reg[rt(instr)].x / (float)(1 << 16)); + + CPU_Lo.x = 0;// CPU_reg[rs(instr)].x * CPU_reg[rt(instr)].x; + CPU_Hi.x = vs * vt;// CPU_reg[rs(instr)].y * CPU_reg[rt(instr)].y; + + CPU_Lo.valid = CPU_Hi.valid = CPU_reg[rs(instr)].valid && CPU_reg[rt(instr)].valid; + + CPU_Lo.value = loVal; + CPU_Hi.value = hiVal; +} + +void PGXP_CPU_MULTU(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal) +{ + // Hi/Lo = Rs * Rt (unsigned) + Validate(&CPU_reg[rs(instr)], rsVal); + Validate(&CPU_reg[rt(instr)], rtVal); + + // iCB: Only require one valid input + if (!(CPU_reg[rs(instr)].valid && CPU_reg[rt(instr)].valid) && (CPU_reg[rs(instr)].valid || CPU_reg[rt(instr)].valid)) + { + MakeValid(&CPU_reg[rs(instr)], rsVal); + MakeValid(&CPU_reg[rt(instr)], rtVal); + } + + float vs = fabs(CPU_reg[rs(instr)].y) + (fabs(CPU_reg[rs(instr)].x) / (float)(1 << 16)); + float vt = fabs(CPU_reg[rt(instr)].y) + (fabs(CPU_reg[rt(instr)].x) / (float)(1 << 16)); + + CPU_Lo.x = 0;// fabs(CPU_reg[rs(instr)].x) * fabs(CPU_reg[rt(instr)].x); + CPU_Hi.x = vs * vt;// fabs(CPU_reg[rs(instr)].y) * fabs(CPU_reg[rt(instr)].y); + + CPU_Lo.valid = CPU_Hi.valid = CPU_reg[rs(instr)].valid && CPU_reg[rt(instr)].valid; + + CPU_Lo.value = loVal; + CPU_Hi.value = hiVal; +} + +void PGXP_CPU_DIV(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal) +{ + // Hi = Rs / Rt (signed) + // Lo = Rs % Rt (signed) + Validate(&CPU_reg[rs(instr)], rsVal); + Validate(&CPU_reg[rt(instr)], rtVal); + + // iCB: Only require one valid input + //if (!(CPU_reg[rs(instr)].valid && CPU_reg[rt(instr)].valid) && (CPU_reg[rs(instr)].valid || CPU_reg[rt(instr)].valid)) + //{ + // MakeValid(&CPU_reg[rs(instr)], rsVal); + // MakeValid(&CPU_reg[rt(instr)], rtVal); + //} + + CPU_Lo.x = CPU_reg[rs(instr)].x / CPU_reg[rt(instr)].x; + CPU_Hi.x = fmod(CPU_reg[rs(instr)].x, CPU_reg[rt(instr)].x); + CPU_Lo.x -= CPU_Hi.x; + + CPU_Lo.valid = CPU_Hi.valid = CPU_reg[rs(instr)].valid && CPU_reg[rt(instr)].valid; + + CPU_Lo.value = loVal; + CPU_Hi.value = hiVal; +} + +void PGXP_CPU_DIVU(u32 instr, u32 hiVal, u32 loVal, u32 rsVal, u32 rtVal) +{ + // Hi = Rs / Rt (unsigned) + // Lo = Rs % Rt (unsigned) + Validate(&CPU_reg[rs(instr)], rsVal); + Validate(&CPU_reg[rt(instr)], rtVal); + + // iCB: Only require one valid input + //if (!(CPU_reg[rs(instr)].valid && CPU_reg[rt(instr)].valid) && (CPU_reg[rs(instr)].valid || CPU_reg[rt(instr)].valid)) + //{ + // MakeValid(&CPU_reg[rs(instr)], rsVal); + // MakeValid(&CPU_reg[rt(instr)], rtVal); + //} + + CPU_Lo.x = fabs(CPU_reg[rs(instr)].x) / fabs(CPU_reg[rt(instr)].x); + CPU_Hi.x = fmod(fabs(CPU_reg[rs(instr)].x), fabs(CPU_reg[rt(instr)].x)); + CPU_Lo.x -= CPU_Hi.x; + + CPU_Lo.valid = CPU_Hi.valid = CPU_reg[rs(instr)].valid && CPU_reg[rt(instr)].valid; + + CPU_Lo.value = loVal; + CPU_Hi.value = hiVal; +} + +//////////////////////////////////// +// Shift operations (sa) +//////////////////////////////////// +void PGXP_CPU_SLL(u32 instr, u32 rdVal, u32 rtVal) +{ + // Rd = Rt << Sa + Validate(&CPU_reg[rt(instr)], rtVal); + CPU_reg[rd(instr)] = CPU_reg[rt(instr)]; + + // Shift y into x? + if (sa(instr) == 16) + { + CPU_reg[rd(instr)].y = CPU_reg[rd(instr)].x; + CPU_reg[rd(instr)].x = 0; + CPU_reg[rd(instr)].hFlags = CPU_reg[rd(instr)].lFlags; + CPU_reg[rd(instr)].lFlags = 0; + } + else + { + // assume multiply with no overflow + CPU_reg[rd(instr)].x *= (float)(1 << sa(instr)); + CPU_reg[rd(instr)].y *= (float)(1 << sa(instr)); + } + + CPU_reg[rd(instr)].value = rdVal; +} + +void PGXP_CPU_SRL(u32 instr, u32 rdVal, u32 rtVal) +{ + // Rd = Rt >> Sa + Validate(&CPU_reg[rt(instr)], rtVal); + CPU_reg[rd(instr)] = CPU_reg[rt(instr)]; + + // Shift x into y? + if (sa(instr) == 16) + { + CPU_reg[rd(instr)].x = CPU_reg[rd(instr)].y; + CPU_reg[rd(instr)].y = 0; + CPU_reg[rd(instr)].lFlags = CPU_reg[rd(instr)].hFlags; + CPU_reg[rd(instr)].hFlags = 0; + } + else + { + // assume divide with no overflow + CPU_reg[rd(instr)].x /= (float)(1 << sa(instr)); + CPU_reg[rd(instr)].y /= (float)(1 << sa(instr)); + } + + CPU_reg[rd(instr)].value = rdVal; +} + +void PGXP_CPU_SRA(u32 instr, u32 rdVal, u32 rtVal) +{ + // Rd = Rt >> Sa + PGXP_CPU_SRL(instr, rdVal, rtVal); +} + +//////////////////////////////////// +// Shift operations variable +//////////////////////////////////// +void PGXP_CPU_SLLV(u32 instr, u32 rdVal, u32 rtVal, u32 rsVal) +{ + // Rd = Rt << Rs + Validate(&CPU_reg[rt(instr)], rtVal); + Validate(&CPU_reg[rs(instr)], rsVal); + + CPU_reg[rd(instr)] = CPU_reg[rt(instr)]; + + // Shift y into x? + if ((rsVal & 0x1F) == 16) + { + CPU_reg[rd(instr)].y = CPU_reg[rd(instr)].x; + CPU_reg[rd(instr)].x = 0; + CPU_reg[rd(instr)].hFlags = CPU_reg[rd(instr)].lFlags; + CPU_reg[rd(instr)].lFlags = 0; + } + else + { + // assume multiply with no overflow + CPU_reg[rd(instr)].x *= (float)(1 << (rsVal & 0x1F)); + CPU_reg[rd(instr)].y *= (float)(1 << (rsVal & 0x1F)); + } + + CPU_reg[rd(instr)].value = rdVal; +} + +void PGXP_CPU_SRLV(u32 instr, u32 rdVal, u32 rtVal, u32 rsVal) +{ + // Rd = Rt >> Sa + Validate(&CPU_reg[rt(instr)], rtVal); + Validate(&CPU_reg[rs(instr)], rsVal); + + CPU_reg[rd(instr)] = CPU_reg[rt(instr)]; + + // Shift x into y? + if ((rsVal & 0x1F) == 16) + { + CPU_reg[rd(instr)].x = CPU_reg[rd(instr)].y; + CPU_reg[rd(instr)].y = 0; + CPU_reg[rd(instr)].lFlags = CPU_reg[rd(instr)].hFlags; + CPU_reg[rd(instr)].hFlags = 0; + } + else + { + // assume divide with no overflow + CPU_reg[rd(instr)].x /= (float)(1 << (rsVal & 0x1F)); + CPU_reg[rd(instr)].y /= (float)(1 << (rsVal & 0x1F)); + } + + CPU_reg[rd(instr)].value = rdVal; +} + +void PGXP_CPU_SRAV(u32 instr, u32 rdVal, u32 rtVal, u32 rsVal) +{ + PGXP_CPU_SRLV(instr, rdVal, rtVal, rsVal); +} + +//////////////////////////////////// +// Move registers +//////////////////////////////////// +void PGXP_CPU_MFHI(u32 instr, u32 rdVal, u32 hiVal) +{ + // Rd = Hi + Validate(&CPU_Hi, hiVal); + + CPU_reg[rd(instr)] = CPU_Hi; +} + +void PGXP_CPU_MTHI(u32 instr, u32 hiVal, u32 rdVal) +{ + // Hi = Rd + Validate(&CPU_reg[rd(instr)], rdVal); + + CPU_Hi = CPU_reg[rd(instr)]; +} + +void PGXP_CPU_MFLO(u32 instr, u32 rdVal, u32 loVal) +{ + // Rd = Lo + Validate(&CPU_Lo, loVal); + + CPU_reg[rd(instr)] = CPU_Lo; +} + +void PGXP_CPU_MTLO(u32 instr, u32 loVal, u32 rdVal) +{ + // Lo = Rd + Validate(&CPU_reg[rd(instr)], rdVal); + + CPU_Lo = CPU_reg[rd(instr)]; +} + +//////////////////////////////////// +// Memory Access +//////////////////////////////////// + +// Load 32-bit word +void PGXP_CPU_LWL(u32 instr, u32 rtVal, u32 addr) +{ + // Rt = Mem[Rs + Im] + PGXP_CPU_LW(instr, rtVal, addr); +} + +void PGXP_CPU_LW(u32 instr, u32 rtVal, u32 addr) +{ + // Rt = Mem[Rs + Im] + ValidateAndCopyMem(&CPU_reg[rt(instr)], addr, rtVal); + //CPU_reg[rt(instr)] = PGXP_validateXY(ReadMem(addr), rtVal); +} + +void PGXP_CPU_LWR(u32 instr, u32 rtVal, u32 addr) +{ + // Rt = Mem[Rs + Im] + PGXP_CPU_LW(instr, rtVal, addr); +} + +// Load 16-bit +void PGXP_CPU_LH(u32 instr, u16 rtVal, u32 addr) +{ + // Rt = Mem[Rs + Im] (sign extended) + psx_value val; + val.sd = (s32)(s16)rtVal; + ValidateAndCopyMem16(&CPU_reg[rt(instr)], addr, val.d); +} + +void PGXP_CPU_LHU(u32 instr, u16 rtVal, u32 addr) +{ + // Rt = Mem[Rs + Im] (zero extended) + psx_value val; + val.d = rtVal; + val.w.h = 0; + ValidateAndCopyMem16(&CPU_reg[rt(instr)], addr, val.d); +} + +// Load 8-bit +void PGXP_CPU_LB(u32 instr, u8 rtVal, u32 addr) +{ + InvalidLoad(addr, instr, 116); +} + +void PGXP_CPU_LBU(u32 instr, u8 rtVal, u32 addr) +{ + InvalidLoad(addr, instr, 116); +} + +// Store 32-bit word +void PGXP_CPU_SWL(u32 instr, u32 rtVal, u32 addr) +{ + // Mem[Rs + Im] = Rt + PGXP_CPU_SW(instr, rtVal, addr); +} + +void PGXP_CPU_SW(u32 instr, u32 rtVal, u32 addr) +{ + // Mem[Rs + Im] = Rt + Validate(&CPU_reg[rt(instr)], rtVal); + WriteMem(&CPU_reg[rt(instr)], addr); + //WriteMemOld(PGXP_validateXY(&CPU_reg[rt(instr)], rtVal), addr); +} + +void PGXP_CPU_SWR(u32 instr, u32 rtVal, u32 addr) +{ + // Mem[Rs + Im] = Rt + PGXP_CPU_SW(instr, rtVal, addr); +} + +// Store 16-bit +void PGXP_CPU_SH(u32 instr, u16 rtVal, u32 addr) +{ + Validate(&CPU_reg[rt(instr)], rtVal); + WriteMem16(&CPU_reg[rt(instr)], addr); +} + +// Store 8-bit +void PGXP_CPU_SB(u32 instr, u8 rtVal, u32 addr) +{ + InvalidStore(addr, instr, 208); +} + |
