summaryrefslogtreecommitdiff
path: root/libpcsxcore
diff options
context:
space:
mode:
authoriCatButler <i.am.catbutler@gmail.com>2016-03-25 16:25:15 +0000
committeriCatButler <i.am.catbutler@gmail.com>2016-03-25 16:25:15 +0000
commit7767ea4acbae995cd8e6302bdb7c97e89748dfd8 (patch)
treeb4a3025b703f8f3f383626aa5a651b2954c3a512 /libpcsxcore
parent106f6594c9e2ad601deb7ad9bdf5eab8a568c01b (diff)
downloadpcsxr-7767ea4acbae995cd8e6302bdb7c97e89748dfd8.tar.gz
Initial upload of PGXP.
Diffstat (limited to 'libpcsxcore')
-rwxr-xr-xlibpcsxcore/gpu.c2
-rwxr-xr-xlibpcsxcore/gte.c31
-rwxr-xr-xlibpcsxcore/ix86/iR3000A.c47
-rw-r--r--libpcsxcore/pgxp_gte.c437
-rw-r--r--libpcsxcore/pgxp_gte.h58
-rwxr-xr-xlibpcsxcore/plugins.c3
-rwxr-xr-xlibpcsxcore/plugins.h2
-rwxr-xr-xlibpcsxcore/r3000a.c1
8 files changed, 551 insertions, 30 deletions
diff --git a/libpcsxcore/gpu.c b/libpcsxcore/gpu.c
index 324c2a00..61a7b3dc 100755
--- a/libpcsxcore/gpu.c
+++ b/libpcsxcore/gpu.c
@@ -19,6 +19,7 @@
#include "psxhw.h"
#include "gpu.h"
#include "psxdma.h"
+#include "pgxp_gte.h"
#define GPUSTATUS_ODDLINES 0x80000000
#define GPUSTATUS_DMABITS 0x60000000 // Two bits
@@ -142,6 +143,7 @@ void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU
#endif
break;
}
+ GPU_pgxpMemory(madr, PGXP_GetMem());
GPU_writeDataMem(ptr, size);
#if 0
diff --git a/libpcsxcore/gte.c b/libpcsxcore/gte.c
index 599672c9..04a3968c 100755
--- a/libpcsxcore/gte.c
+++ b/libpcsxcore/gte.c
@@ -7,6 +7,7 @@
#include "gte.h"
#include "psxmem.h"
+#include "pgxp_gte.h"
#define GTE_SF(op) ((op >> 19) & 1)
#define GTE_MX(op) ((op >> 17) & 3)
@@ -251,6 +252,7 @@ static void CTC2(u32 value, int reg) {
void gteMFC2() {
if (!_Rt_) return;
psxRegs.GPR.r[_Rt_] = MFC2(_Rd_);
+ PGXP_MFC2(_Rt_, _Rd_, psxRegs.CP2D.p[_Rd_].d);
}
void gteCFC2() {
@@ -259,6 +261,7 @@ void gteCFC2() {
}
void gteMTC2() {
+ PGXP_MTC2(_Rt_, _Rd_, psxRegs.GPR.p[_Rt_].d);
MTC2(psxRegs.GPR.r[_Rt_], _Rd_);
}
@@ -269,11 +272,15 @@ void gteCTC2() {
#define _oB_ (psxRegs.GPR.r[_Rs_] + _Imm_)
void gteLWC2() {
- MTC2(psxMemRead32(_oB_), _Rt_);
+ u32 val = psxMemRead32(_oB_);
+ PGXP_LWC2(_oB_, _Rt_, val);
+ MTC2(val, _Rt_);
}
void gteSWC2() {
- psxMemWrite32(_oB_, MFC2(_Rt_));
+ u32 val = MFC2(_Rt_);
+ PGXP_SWC2(_oB_, _Rt_, val);
+ psxMemWrite32(_oB_, val);
}
inline s64 gte_shift(s64 a, int sf) {
@@ -490,10 +497,9 @@ int docop2(int op) {
SX2 = Lm_G1(F((s64) OFX + ((s64) IR1 * h_over_sz3) * (Config.Widescreen ? 0.75 : 1)) >> 16);
SY2 = Lm_G2(F((s64) OFY + ((s64) IR2 * h_over_sz3)) >> 16);
- GPU_addVertex(SX2, SY2,
- Lm_G1_ia((s64) OFX + (s64)(IR1 * h_over_sz3) * (Config.Widescreen ? 0.75 : 1)),
- Lm_G2_ia((s64) OFY + (s64)(IR2 * h_over_sz3)),
- ((s64)SZ3));
+ PGXP_pushSXYZ2s(Lm_G1_ia((s64)OFX + (s64)(IR1 * h_over_sz3) * (Config.Widescreen ? 0.75 : 1)),
+ Lm_G2_ia((s64)OFY + (s64)(IR2 * h_over_sz3)),
+ SZ3);
MAC0 = F((s64) DQB + ((s64) DQA * h_over_sz3));
IR0 = Lm_H(m_mac0, 1);
@@ -503,8 +509,10 @@ int docop2(int op) {
#ifdef GTE_LOG
GTELOG("%08x NCLIP", op);
#endif
-
- MAC0 = F((s64) (SX0 * SY1) + (SX1 * SY2) + (SX2 * SY0) - (SX0 * SY2) - (SX1 * SY0) - (SX2 * SY1));
+ if (PGXP_NLCIP_valid())
+ MAC0 = F(PGXP_NCLIP());
+ else
+ MAC0 = F((s64) (SX0 * SY1) + (SX1 * SY2) + (SX2 * SY0) - (SX0 * SY2) - (SX1 * SY0) - (SX2 * SY1));
return 1;
case 0x0c:
@@ -879,10 +887,9 @@ int docop2(int op) {
SX2 = Lm_G1(F((s64) OFX + ((s64) IR1 * h_over_sz3) * (Config.Widescreen ? 0.75 : 1)) >> 16);
SY2 = Lm_G2(F((s64) OFY + ((s64) IR2 * h_over_sz3)) >> 16);
- GPU_addVertex(SX2, SY2,
- Lm_G1_ia((s64) OFX + (s64)(IR1 * h_over_sz3) * (Config.Widescreen ? 0.75 : 1)),
- Lm_G2_ia((s64) OFY + (s64)(IR2 * h_over_sz3)),
- ((s64)SZ3));
+ PGXP_pushSXYZ2s(Lm_G1_ia((s64)OFX + (s64)(IR1 * h_over_sz3) * (Config.Widescreen ? 0.75 : 1)),
+ Lm_G2_ia((s64)OFY + (s64)(IR2 * h_over_sz3)),
+ SZ3);
}
MAC0 = F((s64) DQB + ((s64) DQA * h_over_sz3));
diff --git a/libpcsxcore/ix86/iR3000A.c b/libpcsxcore/ix86/iR3000A.c
index d7f68890..d18c47ec 100755
--- a/libpcsxcore/ix86/iR3000A.c
+++ b/libpcsxcore/ix86/iR3000A.c
@@ -25,6 +25,7 @@
#include "ix86.h"
#include <sys/mman.h>
+#include "pgxp_gte.h"
#ifndef MAP_ANONYMOUS
#define MAP_ANONYMOUS MAP_ANON
@@ -1546,14 +1547,15 @@ static void recLW() {
// SysPrintf("unhandled r32 %x\n", addr);
}
+ PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode
iPushOfB();
- CALLFunc((u32)psxMemRead32);
+ CALLFunc((u32)PGXP_psxMemRead32Trace);
if (_Rt_) {
iRegs[_Rt_].state = ST_UNK;
MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX);
}
// ADD32ItoR(ESP, 4);
- resp+= 4;
+ resp+= 8;
}
extern u32 LWL_MASK[4];
@@ -1601,12 +1603,13 @@ void recLWL() {
if (_Imm_) ADD32ItoR(EAX, _Imm_);
}
PUSH32R (EAX);
+ PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode
AND32ItoR(EAX, ~3);
PUSH32R (EAX);
- CALLFunc((u32)psxMemRead32);
+ CALLFunc((u32)PGXP_psxMemRead32Trace);
if (_Rt_) {
- ADD32ItoR(ESP, 4);
+ ADD32ItoR(ESP, 8);
POP32R (EDX);
AND32ItoR(EDX, 0x3); // shift = addr & 3;
@@ -1629,7 +1632,7 @@ void recLWL() {
MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX);
} else {
// ADD32ItoR(ESP, 8);
- resp+= 8;
+ resp+= 12;
}
}
@@ -1756,12 +1759,13 @@ void recLWR() {
if (_Imm_) ADD32ItoR(EAX, _Imm_);
}
PUSH32R (EAX);
+ PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode
AND32ItoR(EAX, ~3);
PUSH32R (EAX);
- CALLFunc((u32)psxMemRead32);
+ CALLFunc((u32)PGXP_psxMemRead32Trace);
if (_Rt_) {
- ADD32ItoR(ESP, 4);
+ ADD32ItoR(ESP, 8);
POP32R (EDX);
AND32ItoR(EDX, 0x3); // shift = addr & 3;
@@ -1785,7 +1789,7 @@ void recLWR() {
MOV32RtoM((u32)&psxRegs.GPR.r[_Rt_], EAX);
} else {
// ADD32ItoR(ESP, 8);
- resp+= 8;
+ resp+= 12;
}
}
@@ -1978,15 +1982,16 @@ static void recSW() {
// SysPrintf("unhandled w32 %x\n", addr);
}
+ PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode
if (IsConst(_Rt_)) {
PUSH32I (iRegs[_Rt_].k);
} else {
PUSH32M ((u32)&psxRegs.GPR.r[_Rt_]);
}
iPushOfB();
- CALLFunc((u32)psxMemWrite32);
+ CALLFunc((u32)PGXP_psxMemWrite32Trace);
// ADD32ItoR(ESP, 8);
- resp+= 8;
+ resp+= 12;
}
//#endif
@@ -2104,12 +2109,13 @@ void recSWL() {
if (_Imm_) ADD32ItoR(EAX, _Imm_);
}
PUSH32R (EAX);
+ PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode
AND32ItoR(EAX, ~3);
PUSH32R (EAX);
- CALLFunc((u32)psxMemRead32);
+ CALLFunc((u32)PGXP_psxMemRead32Trace);
- ADD32ItoR(ESP, 4);
+ ADD32ItoR(ESP, 8);
POP32R (EDX);
AND32ItoR(EDX, 0x3); // shift = addr & 3;
@@ -2126,6 +2132,8 @@ void recSWL() {
}
SHR32CLtoR(EDX); // _rRt_ >> SWL_SHIFT[shift]
+ PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode
+
OR32RtoR (EAX, EDX);
PUSH32R (EAX);
@@ -2137,9 +2145,9 @@ void recSWL() {
AND32ItoR(EAX, ~3);
PUSH32R (EAX);
- CALLFunc((u32)psxMemWrite32);
+ CALLFunc((u32)PGXP_psxMemWrite32Trace);
// ADD32ItoR(ESP, 8);
- resp+= 8;
+ resp+= 12;
}
extern u32 SWR_MASK[4];
@@ -2186,12 +2194,13 @@ void recSWR() {
if (_Imm_) ADD32ItoR(EAX, _Imm_);
}
PUSH32R (EAX);
+ PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode
AND32ItoR(EAX, ~3);
PUSH32R (EAX);
- CALLFunc((u32)psxMemRead32);
+ CALLFunc((u32)PGXP_psxMemRead32Trace);
- ADD32ItoR(ESP, 4);
+ ADD32ItoR(ESP, 8);
POP32R (EDX);
AND32ItoR(EDX, 0x3); // shift = addr & 3;
@@ -2208,6 +2217,8 @@ void recSWR() {
}
SHL32CLtoR(EDX); // _rRt_ << SWR_SHIFT[shift]
+ PUSH32I(psxRegs.code); // iCB: Needed to extract reg and opcode
+
OR32RtoR (EAX, EDX);
PUSH32R (EAX);
@@ -2219,9 +2230,9 @@ void recSWR() {
AND32ItoR(EAX, ~3);
PUSH32R (EAX);
- CALLFunc((u32)psxMemWrite32);
+ CALLFunc((u32)PGXP_psxMemWrite32Trace);
// ADD32ItoR(ESP, 8);
- resp += 8;
+ resp += 12;
}
/*REC_FUNC(SLL);
diff --git a/libpcsxcore/pgxp_gte.c b/libpcsxcore/pgxp_gte.c
new file mode 100644
index 00000000..4b22c778
--- /dev/null
+++ b/libpcsxcore/pgxp_gte.c
@@ -0,0 +1,437 @@
+/***************************************************************************
+* Copyright (C) 2016 by iCatButler *
+* *
+* This program 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 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program 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 this program; if not, write to the *
+* Free Software Foundation, Inc., *
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+***************************************************************************/
+
+/**************************************************************************
+* pgxp_gte.c
+* PGXP - Parallel/Precision Geometry Xform Pipeline
+*
+* Created on: 12 Mar 2016
+* Author: iCatButler
+***************************************************************************/
+
+#include "pgxp_gte.h"
+#include "psxmem.h"
+
+typedef struct
+{
+ float x;
+ float y;
+ float z;
+ unsigned int valid;
+ unsigned int count;
+} precise_value;
+
+typedef union
+{
+ struct
+ {
+ s16 x;
+ s16 y;
+ };
+ u32 word;
+} low_value;
+
+#define tolerance 1.0f
+
+precise_value GTE_reg[32];
+precise_value CPU_reg[32];
+
+precise_value Mem[2048 * 1024 / 4]; // mirror 2MB in 32-bit words
+precise_value Scratch[2048 * 1024 / 4]; // mirror 2MB in 32-bit words
+
+void PGXP_Init()
+{
+ memset(Mem, 0, sizeof(Mem));
+}
+
+char* PGXP_GetMem()
+{
+ return (char*)(Mem);
+}
+
+#define VRAM 0
+#define SCRATCH 1
+
+precise_value* ReadMem(u32 addr)
+{
+ u32 memType;
+ uint32_t paddr = addr;
+ int* ip = NULL;
+
+ switch (paddr >> 20)
+ {
+ case 0x800:
+ case 0x801:
+ case 0xa00:
+ case 0xa01:
+ case 0x000:
+ case 0x001:
+ memType = VRAM;
+ break;
+ case 0x1f8:
+ memType = SCRATCH;
+ break;
+ default:
+ return NULL;
+ }
+
+#ifdef GTE_LOG
+ //GTE_LOG("PGXP_Read %x [%x] |", addr, paddr);
+#endif
+ if (memType == VRAM)
+ {
+ paddr = (paddr & 0x1FFFFF) >> 2;
+ return &Mem[paddr];
+ }
+ else if (memType == SCRATCH)
+ {
+ paddr = (paddr & 0x1FFFFF) >> 2;
+ return &Scratch[paddr];
+ }
+
+ return NULL;
+}
+
+void WriteMem(precise_value value, u32 addr)
+{
+ u32 memType;
+ uint32_t paddr = addr;
+ int* ip = NULL;
+
+ switch (paddr >> 20)
+ {
+ case 0x800:
+ case 0x801:
+ case 0xa00:
+ case 0xa01:
+ case 0x000:
+ case 0x001:
+ memType = VRAM;
+ break;
+ case 0x1f8:
+ memType = SCRATCH;
+ break;
+ default:
+ if (value.valid)
+ *ip = 5;
+ return;
+ }
+
+#ifdef GTE_LOG
+ GTE_LOG("PGXP_Write %x [%x] |", addr, paddr);
+#endif
+
+ // Store to RAM
+ if (memType == VRAM)
+ {
+ paddr = (paddr & 0x1FFFFF) >> 2;
+ Mem[paddr] = value;
+ }
+ else if (memType == SCRATCH)
+ {
+ paddr = (paddr & 0x1FFFFF) >> 2;// (paddr & 0x3FFF) >> 2;
+ Scratch[paddr] = value;
+ }
+}
+
+#define SX0 (GTE_reg[ 12 ].x)
+#define SY0 (GTE_reg[ 12 ].y)
+#define SX1 (GTE_reg[ 13 ].x)
+#define SY1 (GTE_reg[ 13 ].y)
+#define SX2 (GTE_reg[ 14 ].x)
+#define SY2 (GTE_reg[ 14 ].y)
+
+#define SXY0 (GTE_reg[ 12 ])
+#define SXY1 (GTE_reg[ 13 ])
+#define SXY2 (GTE_reg[ 14 ])
+#define SXYP (GTE_reg[ 15 ])
+
+unsigned int PGXP_validate(float high, s16 low)
+{
+ if (fabs(high - (float)(low)) < tolerance)
+ return 1;
+ return 0;
+}
+
+// Check that value is still within tolerance of low precision value and invalidate if not
+precise_value PGXP_validateXY(precise_value *high, u32 low)
+{
+ low_value temp;
+ precise_value ret;
+
+ ret.valid = 0;
+ temp.word = low;
+
+ if (!high)
+ return ret;
+
+ high->valid = (high->valid && PGXP_validate(high->x, temp.x) && PGXP_validate(high->y, temp.y));
+
+ // Cheat
+ //if (!high->valid)
+ //{
+ // high->x = temp.x;
+ // high->y = temp.y;
+ // high->valid = 1;
+ //}
+
+ return *high;
+}
+
+u32 PGXP_compareXY(precise_value high, u32 low)
+{
+ low_value temp;
+ temp.word = low;
+
+ if (PGXP_validate(high.x, temp.x) && PGXP_validate(high.y, temp.y))
+ return 1;
+ return 0;
+}
+
+precise_value PGXP_copyXY(u32 low)
+{
+ low_value temp;
+ precise_value ret;
+
+ ret.valid = 0;
+ temp.word = low;
+
+ ret.x = temp.x;
+ ret.y = temp.y;
+ ret.count = 0;
+ ret.valid = 1;
+
+ return ret;
+}
+
+void PGXP_pushSXYZ2f(float _x, float _y, float _z)
+{
+ static unsigned int uCount = 0;
+ // push values down FIFO
+ SXY0 = SXY1;
+ SXY1 = SXY2;
+
+ SXY2.x = _x;
+ SXY2.y = _y;
+ SXY2.z = _z;
+ SXY2.valid = 1;
+ SXY2.count = uCount++;
+
+#ifdef GTE_LOG
+ GTE_LOG("PGPR_PUSH (%f, %f) %u %u|", SXY2.x, SXY2.y, SXY2.valid, SXY2.count);
+#endif
+}
+
+void PGXP_pushSXYZ2s(s64 _x, s64 _y, s64 _z)
+{
+ float fx = (float)(_x) / (float)(1 << 16);
+ float fy = (float)(_y) / (float)(1 << 16);
+ float fz = (float)(_z);
+
+ PGXP_pushSXYZ2f(fx, fy, fz);
+}
+
+int PGXP_NLCIP_valid()
+{
+ if (SXY0.valid && SXY1.valid && SXY2.valid)
+ return 1;
+ return 0;
+}
+
+float PGXP_NCLIP()
+{
+ float nclip = ((SX0 * SY1) + (SX1 * SY2) + (SX2 * SY0) - (SX0 * SY2) - (SX1 * SY0) - (SX2 * SY1));
+
+ // ensure fractional values are not incorrectly rounded to 0
+ if (fabs(nclip) < 1.0f)
+ nclip += (nclip < 0.f ? -2 : 2);
+
+ return nclip;
+}
+
+static precise_value PGXP_MFC2_int(u32 reg)
+{
+ switch (reg)
+ {
+ case 15:
+ GTE_reg[reg] = SXYP = SXY2;
+ break;
+ }
+
+ return GTE_reg[reg];
+}
+
+
+static void PGXP_MTC2_int(precise_value value, u32 reg)
+{
+ switch(reg)
+ {
+ case 15:
+ // push FIFO
+ SXY0 = SXY1;
+ SXY1 = SXY2;
+ SXY2 = value;
+ SXYP = SXY2;
+ break;
+
+ case 31:
+ return;
+ }
+
+ GTE_reg[reg] = value;
+}
+
+// copy GTE data reg to GPR reg (MFC2)
+void PGXP_MFC2(u32 gpr, u32 gtr, u32 value)
+{
+ if (!gpr) return;
+#ifdef GTE_LOG
+ GTE_LOG("PGXP_MFC2 [%x] [%x] %x (%u %u)|", gpr, gtr, value, GTE_reg[gtr].valid, GTE_reg[gtr].count);
+#endif
+
+ CPU_reg[gpr] = PGXP_validateXY(&GTE_reg[gtr], value);
+}
+
+// copy GPR reg to GTE data reg (MTC2)
+void PGXP_MTC2(u32 gpr, u32 gtr, u32 value)
+{
+#ifdef GTE_LOG
+ GTE_LOG("PGXP_MTC2 [%x] [%x] %x (%u %u)|", gpr, gtr, value, CPU_reg[gtr].valid, CPU_reg[gtr].count);
+#endif
+ PGXP_MTC2_int(PGXP_validateXY(&CPU_reg[gpr], value), gtr);
+}
+
+// copy memory to GTE reg
+void PGXP_LWC2(u32 addr, u32 gtr, u32 value)
+{
+#ifdef GTE_LOG
+ precise_value* pp = ReadMem(addr);
+ precise_value p;
+ low_value temp;
+ temp.word = value;
+
+ p.x = p.y = p.valid = 0;
+
+ if (pp)
+ p = *pp;
+
+ GTE_LOG("PGXP_LWC2 %x [%x] %x (%d, %d) (%f, %f) %u %u|", addr, gtr, value, temp.x, temp.y, p.x, p.y, p.valid, p.count);
+#endif
+ PGXP_MTC2_int(PGXP_validateXY(ReadMem(addr), value), gtr);
+}
+
+//copy GTE reg to memory
+void PGXP_SWC2(u32 addr, u32 gtr, u32 value)
+{
+#ifdef GTE_LOG
+ low_value temp;
+ temp.word = value;
+
+ if (PGXP_compareXY(GTE_reg[gtr], value))
+ GTE_LOG("PGPR_SWC2 %x [%x] %x (%d, %d) (%f, %f) %u %u|", addr, gtr, value, temp.x, temp.y, GTE_reg[gtr].x, GTE_reg[gtr].y, GTE_reg[gtr].valid, GTE_reg[gtr].count);
+#endif
+ WriteMem(PGXP_validateXY(&GTE_reg[gtr], value), addr);
+}
+
+// ltore 32bit word
+void PGPR_L32(u32 addr, u32 code, u32 value)
+{
+ u32 reg = ((code >> 16) & 0x1F); // The rt part of the instruction register
+ u32 op = ((code >> 26));
+ precise_value p;
+
+ low_value temp;
+ temp.word = value;
+
+ p.x = p.y = p.valid = p.count = 0;
+
+ switch (op)
+ {
+ case 34: //LWL
+ CPU_reg[reg] = PGXP_validateXY(ReadMem(addr), value);
+ break;
+ case 35: //LW
+ CPU_reg[reg] = PGXP_validateXY(ReadMem(addr), value);
+ break;
+ case 37: //LWR
+ CPU_reg[reg] = PGXP_validateXY(ReadMem(addr), value);
+ break;
+ case 50: //LWC2 (GTE vertex reads)
+ GTE_reg[reg] = PGXP_validateXY(ReadMem(addr), value);
+ break;
+ default:
+ // invalidate register
+ // WriteMem(p, addr);
+ break;
+ }
+
+#ifdef GTE_LOG
+ GTE_LOG("PGPR_L32 %u: %x %x[%x %x] (%d, %d) (%f, %f) %x %u|", op, addr, value, code, reg, temp.x, temp.y, CPU_reg[reg].x, CPU_reg[reg].y, CPU_reg[reg].valid, CPU_reg[reg].count);
+#endif
+}
+
+// store 32bit word
+void PGPR_S32(u32 addr, u32 code, u32 value)
+{
+ u32 reg = ((code >> 16) & 0x1F); // The rt part of the instruction register
+ u32 op = ((code >> 26));
+ precise_value p;
+
+ low_value temp;
+ temp.word = value;
+
+ p.x = p.y = p.valid = p.count = 0;
+
+#ifdef GTE_LOG
+ GTE_LOG("PGPR_S32 %u: %x %x[%x %x] (%d, %d) (%f, %f) %x %u|", op, addr, value, code, reg, temp.x, temp.y, CPU_reg[reg].x, CPU_reg[reg].y, CPU_reg[reg].valid, CPU_reg[reg].count);
+#endif
+
+ switch (op)
+ {
+ case 42: //SWL
+ WriteMem(PGXP_validateXY(&CPU_reg[reg], value), addr);
+ break;
+ case 43: //SW
+ WriteMem(PGXP_validateXY(&CPU_reg[reg], value), addr);
+ break;
+ case 46: //SWR
+ WriteMem(PGXP_validateXY(&CPU_reg[reg], value), addr);
+ break;
+ case 58: //SWC2 (GTE vertex writes)
+ WriteMem(PGXP_validateXY(&GTE_reg[reg], value), addr);
+ break;
+ default:
+ // invalidate memory
+ // WriteMem(p, addr);
+ break;
+ }
+}
+
+u32 PGXP_psxMemRead32Trace(u32 mem, u32 code)
+{
+ u32 value = psxMemRead32(mem);
+ PGPR_L32(mem, code, value);
+ return value;
+}
+
+void PGXP_psxMemWrite32Trace(u32 mem, u32 value, u32 code)
+{
+ PGPR_S32(mem, code, value);
+ psxMemWrite32(mem, value);
+} \ No newline at end of file
diff --git a/libpcsxcore/pgxp_gte.h b/libpcsxcore/pgxp_gte.h
new file mode 100644
index 00000000..c97c5b29
--- /dev/null
+++ b/libpcsxcore/pgxp_gte.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+* Copyright (C) 2016 by iCatButler *
+* *
+* This program 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 2 of the License, or *
+* (at your option) any later version. *
+* *
+* This program 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 this program; if not, write to the *
+* Free Software Foundation, Inc., *
+* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
+***************************************************************************/
+
+/**************************************************************************
+* pgxp_gte.h
+* PGXP - Parallel/Precision Geometry Xform Pipeline
+*
+* Created on: 12 Mar 2016
+* Author: iCatButler
+***************************************************************************/
+
+#ifndef _PGXP_GTE_H_
+#define _PGXP_GTE_H_
+
+#include "psxcommon.h"
+
+void PGXP_Init(); // initialise memory
+char* PGXP_GetMem(); // return pointer to precision memory
+
+// -- GTE functions
+// Transforms
+void PGXP_pushSXYZ2f(float _x, float _y, float _z);
+void PGXP_pushSXYZ2s(s64 _x, s64 _y, s64 _z);
+int PGXP_NLCIP_valid();
+float PGXP_NCLIP();
+
+// Data transfer tracking
+void PGXP_MFC2(u32 gpr, u32 gtr, u32 value); // copy GTE reg to GPR reg (MFC2)
+void PGXP_MTC2(u32 gpr, u32 gtr, u32 value); // copy GPR reg to GTR reg (MTC2)
+void PGXP_LWC2(u32 addr, u32 gtr, u32 value); // copy memory to GTE reg
+void PGXP_SWC2(u32 addr, u32 gtr, u32 value); // copy GTE reg to memory
+
+// -- CPU functions
+// Data transfer tracking
+void PGPR_L32(u32 addr, u32 code, u32 value); // load 32bit word
+void PGPR_S32(u32 addr, u32 code, u32 value); // store 32bit word
+
+// Memory Read/Write hooks
+u32 PGXP_psxMemRead32Trace(u32 mem, u32 code);
+void PGXP_psxMemWrite32Trace(u32 mem, u32 value, u32 code);
+
+#endif /* _PGXP_GTE_H_ */
diff --git a/libpcsxcore/plugins.c b/libpcsxcore/plugins.c
index 05770154..54c7e468 100755
--- a/libpcsxcore/plugins.c
+++ b/libpcsxcore/plugins.c
@@ -54,6 +54,7 @@ GPUvBlank GPU_vBlank;
GPUvisualVibration GPU_visualVibration;
GPUcursor GPU_cursor;
GPUaddVertex GPU_addVertex;
+GPUpgxpMemory GPU_pgxpMemory;
CDRinit CDR_init;
CDRshutdown CDR_shutdown;
@@ -214,6 +215,7 @@ void CALLBACK GPU__vBlank(int val) {}
void CALLBACK GPU__visualVibration(unsigned long iSmall, unsigned long iBig) {}
void CALLBACK GPU__cursor(int player, int x, int y) {}
void CALLBACK GPU__addVertex(short sx,short sy,s64 fx,s64 fy,s64 fz) {}
+void CALLBACK GPU__pgxpMemory(unsigned char* pMem, unsigned int count, unsigned int addr, unsigned char* pVRAM) {}
#define LoadGpuSym1(dest, name) \
LoadSym(GPU_##dest, GPU##dest, name, TRUE);
@@ -259,6 +261,7 @@ static int LoadGPUplugin(const char *GPUdll) {
LoadGpuSym0(visualVibration, "GPUvisualVibration");
LoadGpuSym0(cursor, "GPUcursor");
LoadGpuSym0(addVertex, "GPUaddVertex");
+ LoadGpuSym0(pgxpMemory, "GPUpgxpMemory");
LoadGpuSym0(configure, "GPUconfigure");
LoadGpuSym0(test, "GPUtest");
LoadGpuSym0(about, "GPUabout");
diff --git a/libpcsxcore/plugins.h b/libpcsxcore/plugins.h
index f8cfdf44..8f2cc189 100755
--- a/libpcsxcore/plugins.h
+++ b/libpcsxcore/plugins.h
@@ -96,6 +96,7 @@ typedef void (CALLBACK* GPUvBlank)(int);
typedef void (CALLBACK* GPUvisualVibration)(uint32_t, uint32_t);
typedef void (CALLBACK* GPUcursor)(int, int, int);
typedef void (CALLBACK* GPUaddVertex)(short,short,s64,s64,s64);
+typedef void (CALLBACK* GPUpgxpMemory)(unsigned int, unsigned char*);
// GPU function pointers
extern GPUupdateLace GPU_updateLace;
@@ -125,6 +126,7 @@ extern GPUvBlank GPU_vBlank;
extern GPUvisualVibration GPU_visualVibration;
extern GPUcursor GPU_cursor;
extern GPUaddVertex GPU_addVertex;
+extern GPUpgxpMemory GPU_pgxpMemory;
// CD-ROM Functions
typedef long (CALLBACK* CDRinit)(void);
diff --git a/libpcsxcore/r3000a.c b/libpcsxcore/r3000a.c
index fe908ecb..cb2f4025 100755
--- a/libpcsxcore/r3000a.c
+++ b/libpcsxcore/r3000a.c
@@ -44,6 +44,7 @@ int psxInit() {
Log = 0;
if (psxMemInit() == -1) return -1;
+ PGXP_Init();
return psxCpu->Init();
}