/* Mednafen - Multi-system Emulator * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef PSXDEV_GTE_TESTING #include "psx.h" #include "gte.h" #endif static uint32 ReciprocalTable[0x8000] = { #include "gte_divrecip.inc" }; /* Notes: AVSZ3/AVSZ4: OTZ is MAC0 >> 12 OTZ overflow/underflow flag is set in an overflow condition even if MAC0 == 0. sf field bit has no effect? FLAG register: Bits present mask: 0xfffff000 Checksum bit can't be directly set, it's apparently calculated like (bool)(FLAGS & 0x7f87e000) Instructions effectively clear it 0 at start. (todo: test "invalid" instructions) X/Y FIFO [3] register write pushes a copy down to [2] */ #ifndef PSXDEV_GTE_TESTING namespace MDFN_IEN_PSX { #endif typedef struct { int16 MX[3][3]; int16 dummy; } __attribute__((__packed__)) gtematrix; typedef struct { union { struct { uint8 R; uint8 G; uint8 B; uint8 CD; }; uint8 Raw8[4]; }; } gtergb; typedef struct { int16 X; int16 Y; } gtexy; int16 Lm_B(unsigned int which, int32 value, int lm); uint8 Lm_C(unsigned int which, int32 value); int32 Lm_G(unsigned int which, int32 value); int32 Lm_H(int32 value); void MAC_to_RGB_FIFO(void); void MAC_to_IR(int lm); void MultiplyMatrixByVector(const gtematrix *matrix, const int16 *v, const int32 *crv, uint32 sf, int lm); static uint32 CR[32]; static uint32 FLAGS; // Temporary for instruction execution, copied into CR[31] at end of instruction execution. typedef union { gtematrix All[4]; int32 Raw[4][5]; // Don't read from this(Raw[][]), only write(and when writing, if running on a big-endian platform, swap the upper 16-bits with the lower 16-bits) int16 Raw16[4][10]; struct { gtematrix Rot; gtematrix Light; gtematrix Color; gtematrix AbbyNormal; }; } Matrices_t; static Matrices_t Matrices; static union { int32 All[4][4]; // Really only [4][3], but [4] to ease address calculation. struct { int32 T[4]; int32 B[4]; int32 FC[4]; int32 Null[4]; }; } CRVectors; static int32 OFX; static int32 OFY; static uint16 H; static int16 DQA; static int32 DQB; static int16 ZSF3; static int16 ZSF4; // Begin DR static int16 Vectors[3][4]; static gtergb RGB; static uint16 OTZ; static int16 IR[4]; #define IR0 IR[0] #define IR1 IR[1] #define IR2 IR[2] #define IR3 IR[3] static gtexy XY_FIFO[4]; static uint16 Z_FIFO[4]; static gtergb RGB_FIFO[3]; static int32 MAC[4]; static uint32 LZCS; static uint32 LZCR; static uint32 Reg23; // end DR int32 RTPS(uint32 instr); int32 RTPT(uint32 instr); int32 NCLIP(uint32 instr); void NormColor(uint32 sf, int lm, uint32 v); int32 NCS(uint32 instr); int32 NCT(uint32 instr); void NormColorColor(uint32 v, uint32 sf, int lm); int32 NCCS(uint32 instr); int32 NCCT(uint32 instr); void NormColorDepthCue(uint32 v, uint32 sf, int lm); int32 NCDS(uint32 instr); int32 NCDT(uint32 instr); int32 AVSZ3(uint32 instr); int32 AVSZ4(uint32 instr); int32 OP(uint32 instr); int32 GPF(uint32 instr); int32 GPL(uint32 instr); void DepthCue(int mult_IR123, int RGB_from_FIFO, uint32 sf, int lm); int32 DCPL(uint32 instr); int32 DPCS(uint32 instr); int32 DPCT(uint32 instr); int32 INTPL(uint32 instr); int32 SQR(uint32 instr); int32 MVMVA(uint32 instr); static INLINE uint8 Sat5(int16 cc) { if(cc < 0) cc = 0; if(cc > 0x1F) cc = 0x1F; return(cc); } void GTE_Power(void) { memset(CR, 0, sizeof(CR)); //memset(DR, 0, sizeof(DR)); memset(Matrices.All, 0, sizeof(Matrices.All)); memset(CRVectors.All, 0, sizeof(CRVectors.All)); OFX = 0; OFY = 0; H = 0; DQA = 0; DQB = 0; ZSF3 = 0; ZSF4 = 0; memset(Vectors, 0, sizeof(Vectors)); memset(&RGB, 0, sizeof(RGB)); OTZ = 0; IR0 = 0; IR1 = 0; IR2 = 0; IR3 = 0; memset(XY_FIFO, 0, sizeof(XY_FIFO)); memset(Z_FIFO, 0, sizeof(Z_FIFO)); memset(RGB_FIFO, 0, sizeof(RGB_FIFO)); memset(MAC, 0, sizeof(MAC)); LZCS = 0; LZCR = 0; Reg23 = 0; } // TODO: Don't save redundant state, regarding CR cache variables int GTE_StateAction(StateMem *sm, int load, int data_only) { SFORMAT StateRegs[] = { SFARRAY32(CR, 32), SFVAR(FLAGS), SFARRAY16(&Matrices.Raw16[0][0], 4 * 10), SFARRAY32(&CRVectors.All[0][0], 4 * 4), SFVAR(OFX), SFVAR(OFY), SFVAR(H), SFVAR(DQA), SFVAR(DQB), SFVAR(ZSF3), SFVAR(ZSF4), SFARRAY16(&Vectors[0][0], 3 * 4), SFARRAY(RGB.Raw8, 4), SFVAR(OTZ), SFARRAY16(IR, 4), SFVAR(XY_FIFO[0].X), SFVAR(XY_FIFO[0].Y), SFVAR(XY_FIFO[1].X), SFVAR(XY_FIFO[1].Y), SFVAR(XY_FIFO[2].X), SFVAR(XY_FIFO[2].Y), SFVAR(XY_FIFO[3].X), SFVAR(XY_FIFO[3].Y), SFARRAY16(Z_FIFO, 4), SFARRAY(RGB_FIFO[0].Raw8, 4), SFARRAY(RGB_FIFO[1].Raw8, 4), SFARRAY(RGB_FIFO[2].Raw8, 4), SFARRAY(RGB_FIFO[3].Raw8, 4), SFARRAY32(MAC, 4), SFVAR(LZCS), SFVAR(LZCR), SFVAR(Reg23), SFEND }; int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "GTE"); if(load) { } return(ret); } void GTE_WriteCR(unsigned int which, uint32 value) { static const uint32 mask_table[32] = { /* 0x00 */ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, /* 0x08 */ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, /* 0x10 */ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, /* 0x18 */ 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0x0000FFFF, 0xFFFFFFFF, 0x0000FFFF, 0x0000FFFF, 0xFFFFFFFF }; //PSX_WARNING("[GTE] Write CR %d, 0x%08x", which, value); value &= mask_table[which]; CR[which] = value | (CR[which] & ~mask_table[which]); if(which < 24) { int we = which >> 3; which &= 0x7; if(which >= 5) CRVectors.All[we][which - 5] = value; else { #ifdef MSB_FIRST Matrices.Raw[we][which] = (value << 16) | (value >> 16); #else Matrices.Raw[we][which] = value; #endif } return; } switch(which) { case 24: OFX = value; break; case 25: OFY = value; break; case 26: H = value; break; case 27: DQA = value; break; case 28: DQB = value; break; case 29: ZSF3 = value; break; case 30: ZSF4 = value; break; case 31: CR[31] = (value & 0x7ffff000) | ((value & 0x7f87e000) ? (1 << 31) : 0); break; } } uint32 GTE_ReadCR(unsigned int which) { uint32 ret = 0; switch(which) { default: ret = CR[which]; if(which == 4 || which == 12 || which == 20) ret = (int16)ret; break; case 24: ret = OFX; break; case 25: ret = OFY; break; case 26: ret = (int16)H; break; case 27: ret = (int16)DQA; break; case 28: ret = DQB; break; case 29: ret = (int16)ZSF3; break; case 30: ret = (int16)ZSF4; break; case 31: ret = CR[31]; break; } return(ret); } void GTE_WriteDR(unsigned int which, uint32 value) { switch(which & 0x1F) { case 0: Vectors[0][0] = value; Vectors[0][1] = value >> 16; break; case 1: Vectors[0][2] = value; break; case 2: Vectors[1][0] = value; Vectors[1][1] = value >> 16; break; case 3: Vectors[1][2] = value; break; case 4: Vectors[2][0] = value; Vectors[2][1] = value >> 16; break; case 5: Vectors[2][2] = value; break; case 6: RGB.R = value >> 0; RGB.G = value >> 8; RGB.B = value >> 16; RGB.CD = value >> 24; break; case 7: OTZ = value; break; case 8: IR0 = value; break; case 9: IR1 = value; break; case 10: IR2 = value; break; case 11: IR3 = value; break; case 12: XY_FIFO[0].X = value; XY_FIFO[0].Y = value >> 16; break; case 13: XY_FIFO[1].X = value; XY_FIFO[1].Y = value >> 16; break; case 14: XY_FIFO[2].X = value; XY_FIFO[2].Y = value >> 16; XY_FIFO[3].X = value; XY_FIFO[3].Y = value >> 16; break; case 15: XY_FIFO[3].X = value; XY_FIFO[3].Y = value >> 16; XY_FIFO[0] = XY_FIFO[1]; XY_FIFO[1] = XY_FIFO[2]; XY_FIFO[2] = XY_FIFO[3]; break; case 16: Z_FIFO[0] = value; break; case 17: Z_FIFO[1] = value; break; case 18: Z_FIFO[2] = value; break; case 19: Z_FIFO[3] = value; break; case 20: RGB_FIFO[0].R = value; RGB_FIFO[0].G = value >> 8; RGB_FIFO[0].B = value >> 16; RGB_FIFO[0].CD = value >> 24; break; case 21: RGB_FIFO[1].R = value; RGB_FIFO[1].G = value >> 8; RGB_FIFO[1].B = value >> 16; RGB_FIFO[1].CD = value >> 24; break; case 22: RGB_FIFO[2].R = value; RGB_FIFO[2].G = value >> 8; RGB_FIFO[2].B = value >> 16; RGB_FIFO[2].CD = value >> 24; break; case 23: Reg23 = value; break; case 24: MAC[0] = value; break; case 25: MAC[1] = value; break; case 26: MAC[2] = value; break; case 27: MAC[3] = value; break; case 28: IR1 = ((value >> 0) & 0x1F) << 7; IR2 = ((value >> 5) & 0x1F) << 7; IR3 = ((value >> 10) & 0x1F) << 7; break; case 29: // Read-only break; case 30: LZCS = value; { uint32 test = value & 0x80000000; LZCR = 0; while((value & 0x80000000) == test && LZCR < 32) { LZCR++; value <<= 1; } } break; case 31: // Read-only break; } } uint32 GTE_ReadDR(unsigned int which) { uint32 ret = 0; switch(which & 0x1F) { case 0: ret = (uint16)Vectors[0][0] | ((uint16)Vectors[0][1] << 16); break; case 1: ret = (int16)Vectors[0][2]; break; case 2: ret = (uint16)Vectors[1][0] | ((uint16)Vectors[1][1] << 16); break; case 3: ret = (int16)Vectors[1][2]; break; case 4: ret = (uint16)Vectors[2][0] | ((uint16)Vectors[2][1] << 16); break; case 5: ret = (int16)Vectors[2][2]; break; case 6: ret = RGB.R | (RGB.G << 8) | (RGB.B << 16) | (RGB.CD << 24); break; case 7: ret = (uint16)OTZ; break; case 8: ret = (int16)IR0; break; case 9: ret = (int16)IR1; break; case 10: ret = (int16)IR2; break; case 11: ret = (int16)IR3; break; case 12: ret = (uint16)XY_FIFO[0].X | ((uint16)XY_FIFO[0].Y << 16); break; case 13: ret = (uint16)XY_FIFO[1].X | ((uint16)XY_FIFO[1].Y << 16); break; case 14: ret = (uint16)XY_FIFO[2].X | ((uint16)XY_FIFO[2].Y << 16); break; case 15: ret = (uint16)XY_FIFO[3].X | ((uint16)XY_FIFO[3].Y << 16); break; case 16: ret = (uint16)Z_FIFO[0]; break; case 17: ret = (uint16)Z_FIFO[1]; break; case 18: ret = (uint16)Z_FIFO[2]; break; case 19: ret = (uint16)Z_FIFO[3]; break; case 20: ret = RGB_FIFO[0].R | (RGB_FIFO[0].G << 8) | (RGB_FIFO[0].B << 16) | (RGB_FIFO[0].CD << 24); break; case 21: ret = RGB_FIFO[1].R | (RGB_FIFO[1].G << 8) | (RGB_FIFO[1].B << 16) | (RGB_FIFO[1].CD << 24); break; case 22: ret = RGB_FIFO[2].R | (RGB_FIFO[2].G << 8) | (RGB_FIFO[2].B << 16) | (RGB_FIFO[2].CD << 24); break; case 23: ret = Reg23; break; case 24: ret = MAC[0]; break; case 25: ret = MAC[1]; break; case 26: ret = MAC[2]; break; case 27: ret = MAC[3]; break; case 28: case 29: ret = Sat5(IR1 >> 7) | (Sat5(IR2 >> 7) << 5) | (Sat5(IR3 >> 7) << 10); break; case 30: ret = LZCS; break; case 31: ret = LZCR; break; } return(ret); } #define sign_x_to_s64(_bits, _value) (((int64)((uint64)(_value) << (64 - _bits))) >> (64 - _bits)) INLINE int64 A_MV(unsigned which, int64 value) { if(value >= (1LL << 43)) FLAGS |= 1 << (30 - which); if(value < -(1LL << 43)) FLAGS |= 1 << (27 - which); return sign_x_to_s64(44, value); } INLINE int64 F(int64 value) { if(value < -2147483648LL) { // flag set here FLAGS |= 1 << 15; } if(value > 2147483647LL) { // flag set here FLAGS |= 1 << 16; } return(value); } INLINE int16 Lm_B(unsigned int which, int32 value, int lm) { int32 tmp = lm << 15; if(value < (-32768 + tmp)) { // set flag here FLAGS |= 1 << (24 - which); value = -32768 + tmp; } if(value > 32767) { // Set flag here FLAGS |= 1 << (24 - which); value = 32767; } return(value); } INLINE int16 Lm_B_PTZ(unsigned int which, int32 value, int32 ftv_value, int lm) { int32 tmp = lm << 15; if(ftv_value < -32768) { FLAGS |= 1 << (24 - which); } if(ftv_value > 32767) { FLAGS |= 1 << (24 - which); } if(value < (-32768 + tmp)) { value = -32768 + tmp; } if(value > 32767) { value = 32767; } return(value); } INLINE uint8 Lm_C(unsigned int which, int32 value) { if(value & ~0xFF) { // Set flag here FLAGS |= 1 << (21 - which); // Tested with GPF if(value < 0) value = 0; if(value > 255) value = 255; } return(value); } INLINE int32 Lm_D(int32 value, int unchained) { // Not sure if we should have it as int64, or just chain on to and special case when the F flags are set. if(!unchained) { if(FLAGS & (1 << 15)) { FLAGS |= 1 << 18; return(0); } if(FLAGS & (1 << 16)) { FLAGS |= 1 << 18; return(0xFFFF); } } if(value < 0) { // Set flag here value = 0; FLAGS |= 1 << 18; // Tested with AVSZ3 } else if(value > 65535) { // Set flag here. value = 65535; FLAGS |= 1 << 18; // Tested with AVSZ3 } return(value); } INLINE int32 Lm_G(unsigned int which, int32 value) { if(value < -1024) { // Set flag here value = -1024; FLAGS |= 1 << (14 - which); } if(value > 1023) { // Set flag here. value = 1023; FLAGS |= 1 << (14 - which); } return(value); } // limit to 4096, not 4095 INLINE int32 Lm_H(int32 value) { #if 0 if(FLAGS & (1 << 15)) { value = 0; FLAGS |= 1 << 12; return value; } if(FLAGS & (1 << 16)) { value = 4096; FLAGS |= 1 << 12; return value; } #endif if(value < 0) { value = 0; FLAGS |= 1 << 12; } if(value > 4096) { value = 4096; FLAGS |= 1 << 12; } return(value); } INLINE void MAC_to_RGB_FIFO(void) { RGB_FIFO[0] = RGB_FIFO[1]; RGB_FIFO[1] = RGB_FIFO[2]; RGB_FIFO[2].R = Lm_C(0, MAC[1] >> 4); RGB_FIFO[2].G = Lm_C(1, MAC[2] >> 4); RGB_FIFO[2].B = Lm_C(2, MAC[3] >> 4); RGB_FIFO[2].CD = RGB.CD; } INLINE void MAC_to_IR(int lm) { IR1 = Lm_B(0, MAC[1], lm); IR2 = Lm_B(1, MAC[2], lm); IR3 = Lm_B(2, MAC[3], lm); } INLINE void MultiplyMatrixByVector(const gtematrix *matrix, const int16 *v, const int32 *crv, uint32 sf, int lm) { unsigned i; for(i = 0; i < 3; i++) { int64 tmp; int32 mulr[3]; tmp = (int64)crv[i] << 12; if(matrix == &Matrices.AbbyNormal) { if(i == 0) { mulr[0] = -((RGB.R << 4) * v[0]); mulr[1] = (RGB.R << 4) * v[1]; mulr[2] = IR0 * v[2]; } else { mulr[0] = (int16)CR[i] * v[0]; mulr[1] = (int16)CR[i] * v[1]; mulr[2] = (int16)CR[i] * v[2]; } } else { mulr[0] = matrix->MX[i][0] * v[0]; mulr[1] = matrix->MX[i][1] * v[1]; mulr[2] = matrix->MX[i][2] * v[2]; } tmp = A_MV(i, tmp + mulr[0]); if(crv == CRVectors.FC) { Lm_B(i, tmp >> sf, FALSE); tmp = 0; } tmp = A_MV(i, tmp + mulr[1]); tmp = A_MV(i, tmp + mulr[2]); MAC[1 + i] = tmp >> sf; } MAC_to_IR(lm); } INLINE void MultiplyMatrixByVector_PT(const gtematrix *matrix, const int16 *v, const int32 *crv, uint32 sf, int lm) { int64 tmp[3]; unsigned i; for(i = 0; i < 3; i++) { int32 mulr[3]; tmp[i] = (int64)crv[i] << 12; mulr[0] = matrix->MX[i][0] * v[0]; mulr[1] = matrix->MX[i][1] * v[1]; mulr[2] = matrix->MX[i][2] * v[2]; tmp[i] = A_MV(i, tmp[i] + mulr[0]); tmp[i] = A_MV(i, tmp[i] + mulr[1]); tmp[i] = A_MV(i, tmp[i] + mulr[2]); MAC[1 + i] = tmp[i] >> sf; } IR1 = Lm_B(0, MAC[1], lm); IR2 = Lm_B(1, MAC[2], lm); //printf("FTV: %08x %08x\n", crv[2], (uint32)(tmp[2] >> 12)); IR3 = Lm_B_PTZ(2, MAC[3], tmp[2] >> 12, lm); Z_FIFO[0] = Z_FIFO[1]; Z_FIFO[1] = Z_FIFO[2]; Z_FIFO[2] = Z_FIFO[3]; Z_FIFO[3] = Lm_D(tmp[2] >> 12, TRUE); } #define VAR_UNUSED __attribute__((unused)) #define DECODE_FIELDS \ const uint32 sf VAR_UNUSED = (instr & (1 << 19)) ? 12 : 0; \ const uint32 mx VAR_UNUSED = (instr >> 17) & 0x3; \ const uint32 v_i = (instr >> 15) & 0x3; \ const int32* cv VAR_UNUSED = CRVectors.All[(instr >> 13) & 0x3]; \ const int lm VAR_UNUSED = (instr >> 10) & 1; \ int16 v[3]; \ if(v_i == 3) \ { \ v[0] = IR1; \ v[1] = IR2; \ v[2] = IR3; \ } \ else \ { \ v[0] = Vectors[v_i][0]; \ v[1] = Vectors[v_i][1]; \ v[2] = Vectors[v_i][2]; \ } int32 SQR(uint32 instr) { DECODE_FIELDS; MAC[1] = ((IR1 * IR1) >> sf); MAC[2] = ((IR2 * IR2) >> sf); MAC[3] = ((IR3 * IR3) >> sf); MAC_to_IR(lm); return(5); } int32 MVMVA(uint32 instr) { DECODE_FIELDS; MultiplyMatrixByVector(&Matrices.All[mx], v, cv, sf, lm); return(8); } static INLINE unsigned CountLeadingZeroU16(uint16 val) { unsigned ret = 0; while(!(val & 0x8000) && ret < 16) { val <<= 1; ret++; } return ret; } static INLINE uint32 Divide(uint32 dividend, uint32 divisor) { //if((Z_FIFO[3] * 2) > H) if((divisor * 2) > dividend) { unsigned shift_bias = CountLeadingZeroU16(divisor); dividend <<= shift_bias; divisor <<= shift_bias; return ((int64)dividend * ReciprocalTable[divisor & 0x7FFF] + 32768) >> 16; } else { FLAGS |= 1 << 17; return 0x1FFFF; } } static INLINE void TransformXY(int64 h_div_sz) { MAC[0] = F((int64)OFX + IR1 * h_div_sz) >> 16; XY_FIFO[3].X = Lm_G(0, MAC[0]); MAC[0] = F((int64)OFY + IR2 * h_div_sz) >> 16; XY_FIFO[3].Y = Lm_G(1, MAC[0]); XY_FIFO[0] = XY_FIFO[1]; XY_FIFO[1] = XY_FIFO[2]; XY_FIFO[2] = XY_FIFO[3]; } static INLINE void TransformDQ(int64 h_div_sz) { MAC[0] = F((int64)DQB + DQA * h_div_sz); IR0 = Lm_H(((int64)DQB + DQA * h_div_sz) >> 12); } int32 RTPS(uint32 instr) { DECODE_FIELDS; int64 h_div_sz; MultiplyMatrixByVector_PT(&Matrices.Rot, Vectors[0], CRVectors.T, sf, lm); h_div_sz = Divide(H, Z_FIFO[3]); TransformXY(h_div_sz); TransformDQ(h_div_sz); return(15); } int32 RTPT(uint32 instr) { DECODE_FIELDS; int i; for(i = 0; i < 3; i++) { int64 h_div_sz; MultiplyMatrixByVector_PT(&Matrices.Rot, Vectors[i], CRVectors.T, sf, lm); h_div_sz = Divide(H, Z_FIFO[3]); TransformXY(h_div_sz); if(i == 2) TransformDQ(h_div_sz); } return(23); } INLINE void NormColor(uint32 sf, int lm, uint32 v) { int16 tmp_vector[3]; MultiplyMatrixByVector(&Matrices.Light, Vectors[v], CRVectors.Null, sf, lm); tmp_vector[0] = IR1; tmp_vector[1] = IR2; tmp_vector[2] = IR3; MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm); MAC_to_RGB_FIFO(); } int32 NCS(uint32 instr) { DECODE_FIELDS; NormColor(sf, lm, 0); return(14); } int32 NCT(uint32 instr) { DECODE_FIELDS; int i; for(i = 0; i < 3; i++) NormColor(sf, lm, i); return(30); } INLINE void NormColorColor(uint32 v, uint32 sf, int lm) { int16 tmp_vector[3]; MultiplyMatrixByVector(&Matrices.Light, Vectors[v], CRVectors.Null, sf, lm); tmp_vector[0] = IR1; tmp_vector[1] = IR2; tmp_vector[2] = IR3; MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm); MAC[1] = ((RGB.R << 4) * IR1) >> sf; MAC[2] = ((RGB.G << 4) * IR2) >> sf; MAC[3] = ((RGB.B << 4) * IR3) >> sf; MAC_to_IR(lm); MAC_to_RGB_FIFO(); } int32 NCCS(uint32 instr) { DECODE_FIELDS; NormColorColor(0, sf, lm); return(17); } int32 NCCT(uint32 instr) { int i; DECODE_FIELDS; for(i = 0; i < 3; i++) NormColorColor(i, sf, lm); return(39); } INLINE void DepthCue(int mult_IR123, int RGB_from_FIFO, uint32 sf, int lm) { int32 RGB_temp[3]; int32 IR_temp[3] = { IR1, IR2, IR3 }; int i; //assert(sf); if(RGB_from_FIFO) { RGB_temp[0] = RGB_FIFO[0].R << 4; RGB_temp[1] = RGB_FIFO[0].G << 4; RGB_temp[2] = RGB_FIFO[0].B << 4; } else { RGB_temp[0] = RGB.R << 4; RGB_temp[1] = RGB.G << 4; RGB_temp[2] = RGB.B << 4; } if(mult_IR123) { for(i = 0; i < 3; i++) { MAC[1 + i] = A_MV(i, (((int64)CRVectors.FC[i] << 12) - RGB_temp[i] * IR_temp[i])) >> sf; MAC[1 + i] = A_MV(i, (RGB_temp[i] * IR_temp[i] + IR0 * Lm_B(i, MAC[1 + i], FALSE))) >> sf; } } else { for(i = 0; i < 3; i++) { MAC[1 + i] = A_MV(i, (((int64)CRVectors.FC[i] << 12) - (RGB_temp[i] << 12))) >> sf; MAC[1 + i] = A_MV(i, (((int64)RGB_temp[i] << 12) + IR0 * Lm_B(i, MAC[1 + i], FALSE))) >> sf; } } MAC_to_IR(lm); MAC_to_RGB_FIFO(); } int32 DCPL(uint32 instr) { DECODE_FIELDS; DepthCue(TRUE, FALSE, sf, lm); return(8); } int32 DPCS(uint32 instr) { DECODE_FIELDS; DepthCue(FALSE, FALSE, sf, lm); return(8); } int32 DPCT(uint32 instr) { int i; DECODE_FIELDS; for(i = 0; i < 3; i++) { DepthCue(FALSE, TRUE, sf, lm); } return(17); } int32 INTPL(uint32 instr) { DECODE_FIELDS; MAC[1] = A_MV(0, (((int64)CRVectors.FC[0] << 12) - (IR1 << 12))) >> sf; MAC[2] = A_MV(1, (((int64)CRVectors.FC[1] << 12) - (IR2 << 12))) >> sf; MAC[3] = A_MV(2, (((int64)CRVectors.FC[2] << 12) - (IR3 << 12))) >> sf; MAC[1] = A_MV(0, (((int64)IR1 << 12) + IR0 * Lm_B(0, MAC[1], FALSE)) >> sf); MAC[2] = A_MV(1, (((int64)IR2 << 12) + IR0 * Lm_B(1, MAC[2], FALSE)) >> sf); MAC[3] = A_MV(2, (((int64)IR3 << 12) + IR0 * Lm_B(2, MAC[3], FALSE)) >> sf); MAC_to_IR(lm); MAC_to_RGB_FIFO(); return(8); } INLINE void NormColorDepthCue(uint32 v, uint32 sf, int lm) { int16 tmp_vector[3]; MultiplyMatrixByVector(&Matrices.Light, Vectors[v], CRVectors.Null, sf, lm); tmp_vector[0] = IR1; tmp_vector[1] = IR2; tmp_vector[2] = IR3; MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm); DepthCue(TRUE, FALSE, sf, lm); } int32 NCDS(uint32 instr) { DECODE_FIELDS; NormColorDepthCue(0, sf, lm); return(19); } int32 NCDT(uint32 instr) { int i; DECODE_FIELDS; for(i = 0; i < 3; i++) { NormColorDepthCue(i, sf, lm); } return(44); } int32 CC(uint32 instr) { DECODE_FIELDS; int16 tmp_vector[3]; tmp_vector[0] = IR1; tmp_vector[1] = IR2; tmp_vector[2] = IR3; MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm); MAC[1] = ((RGB.R << 4) * IR1) >> sf; MAC[2] = ((RGB.G << 4) * IR2) >> sf; MAC[3] = ((RGB.B << 4) * IR3) >> sf; MAC_to_IR(lm); MAC_to_RGB_FIFO(); return(11); } int32 CDP(uint32 instr) { DECODE_FIELDS; int16 tmp_vector[3]; tmp_vector[0] = IR1; tmp_vector[1] = IR2; tmp_vector[2] = IR3; MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm); DepthCue(TRUE, FALSE, sf, lm); return(13); } int32 NCLIP(uint32 instr) { DECODE_FIELDS; MAC[0] = F( (int64)(XY_FIFO[0].X * (XY_FIFO[1].Y - XY_FIFO[2].Y)) + (XY_FIFO[1].X * (XY_FIFO[2].Y - XY_FIFO[0].Y)) + (XY_FIFO[2].X * (XY_FIFO[0].Y - XY_FIFO[1].Y)) ); return(8); } int32 AVSZ3(uint32 instr) { DECODE_FIELDS; MAC[0] = F(((int64)ZSF3 * (Z_FIFO[1] + Z_FIFO[2] + Z_FIFO[3]))); OTZ = Lm_D(MAC[0] >> 12, FALSE); return(5); } int32 AVSZ4(uint32 instr) { DECODE_FIELDS; MAC[0] = F(((int64)ZSF4 * (Z_FIFO[0] + Z_FIFO[1] + Z_FIFO[2] + Z_FIFO[3]))); OTZ = Lm_D(MAC[0] >> 12, FALSE); return(5); } // -32768 * -32768 - 32767 * -32768 = 2147450880 // (2 ^ 31) - 1 = 2147483647 int32 OP(uint32 instr) { DECODE_FIELDS; MAC[1] = ((Matrices.Rot.MX[1][1] * IR3) - (Matrices.Rot.MX[2][2] * IR2)) >> sf; MAC[2] = ((Matrices.Rot.MX[2][2] * IR1) - (Matrices.Rot.MX[0][0] * IR3)) >> sf; MAC[3] = ((Matrices.Rot.MX[0][0] * IR2) - (Matrices.Rot.MX[1][1] * IR1)) >> sf; MAC_to_IR(lm); return(6); } int32 GPF(uint32 instr) { DECODE_FIELDS; MAC[1] = (IR0 * IR1) >> sf; MAC[2] = (IR0 * IR2) >> sf; MAC[3] = (IR0 * IR3) >> sf; MAC_to_IR(lm); MAC_to_RGB_FIFO(); return(5); } int32 GPL(uint32 instr) { DECODE_FIELDS; MAC[1] = A_MV(0, ((int64)MAC[1] << sf) + (IR0 * IR1)) >> sf; MAC[2] = A_MV(1, ((int64)MAC[2] << sf) + (IR0 * IR2)) >> sf; MAC[3] = A_MV(2, ((int64)MAC[3] << sf) + (IR0 * IR3)) >> sf; MAC_to_IR(lm); MAC_to_RGB_FIFO(); return(5); } /* --------------------------------------------------------------------------------------------- | 24 23 22 21 20 | 19 | 18 17 | 16 15 | 14 13 | 12 11 | 10 | 9 8 7 6 | 5 4 3 2 1 0 | |-------------------------------------------------------------------------------------------| | (unused) | sf | mx | v | cv |(unused)| lm | (unused) | opcode | --------------------------------------------------------------------------------------------- (unused) = unused, ignored sf = shift 12 mx = matrix selection v = source vector cv = add vector(translation/back/far color(bugged)/none) (unused) = unused, ignored lm = limit negative results to 0 (unused) = unused, ignored opcode = operation code */ int32 GTE_Instruction(uint32 instr) { const unsigned code = instr & 0x3F; int32 ret = 1; FLAGS = 0; switch(code) { default: #ifndef PSXDEV_GTE_TESTING PSX_WARNING("[GTE] Unknown instruction code: 0x%02x", code); #endif break; case 0x00: // alternate? case 0x01: ret = RTPS(instr); break; /* case 0x02: // UNSTABLE? break; case 0x03: // UNSTABLE? break; case 0x04: // Probably simple with v,cv,sf,mx,lm ignored. Same calculation as 0x3B? break; case 0x05: // UNSTABLE? break; */ case 0x06: ret = NCLIP(instr); break; /* case 0x07: // UNSTABLE? break; case 0x08: // UNSTABLE? break; case 0x09: // UNSTABLE? break; case 0x0A: // UNSTABLE? break; case 0x0B: // UNSTABLE? break; */ case 0x0C: ret = OP(instr); break; /* case 0x0D: // UNSTABLE? break; case 0x0E: // UNSTABLE? break; case 0x0F: // UNSTABLE? break; */ case 0x10: ret = DPCS(instr); break; case 0x11: ret = INTPL(instr); break; case 0x12: ret = MVMVA(instr); break; case 0x13: ret = NCDS(instr); break; case 0x14: ret = CDP(instr); break; /* case 0x15: // does one push on RGB FIFO, what else... break; */ case 0x16: ret = NCDT(instr); break; /* case 0x17: // PARTIALLY UNSTABLE(depending on sf or v or cv or mx or lm???), similar behavior under some conditions to 0x16? break; case 0x18: break; case 0x19: break; */ case 0x1A: // Alternate for 0x29? ret = DCPL(instr); break; case 0x1B: ret = NCCS(instr); break; case 0x1C: ret = CC(instr); break; /* case 0x1D: break; */ case 0x1E: ret = NCS(instr); break; /* case 0x1F: break; */ case 0x20: ret = NCT(instr); break; /* case 0x21: break; case 0x22: // UNSTABLE? break; case 0x23: break; case 0x24: break; case 0x25: break; case 0x26: break; case 0x27: break; */ case 0x28: ret = SQR(instr); break; case 0x29: ret = DCPL(instr); break; case 0x2A: ret = DPCT(instr); break; /* case 0x2B: break; case 0x2C: break; */ case 0x2D: ret = AVSZ3(instr); break; case 0x2E: ret = AVSZ4(instr); break; /* case 0x2F: // UNSTABLE? break; */ case 0x30: ret = RTPT(instr); break; /* case 0x31: // UNSTABLE? break; case 0x32: // UNSTABLE? break; case 0x33: // UNSTABLE? break; case 0x34: // UNSTABLE? break; case 0x35: // UNSTABLE? break; case 0x36: // UNSTABLE? break; case 0x37: // UNSTABLE? break; case 0x38: break; case 0x39: // Probably simple with v,cv,sf,mx,lm ignored. break; case 0x3A: // Probably simple with v,cv,sf,mx,lm ignored. break; case 0x3B: // Probably simple with v,cv,sf,mx,lm ignored. Same calculation as 0x04? break; case 0x3C: // UNSTABLE? break; */ case 0x3D: ret = GPF(instr); break; case 0x3E: ret = GPL(instr); break; case 0x3F: ret = NCCT(instr); break; } if(FLAGS & 0x7f87e000) FLAGS |= 1 << 31; CR[31] = FLAGS; return(ret - 1); } #ifndef PSXDEV_GTE_TESTING } #endif