/[pcsx2_0.9.7]/trunk/pcsx2/Vif_Unpack.cpp
ViewVC logotype

Contents of /trunk/pcsx2/Vif_Unpack.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 148 - (show annotations) (download)
Fri Sep 10 17:22:32 2010 UTC (9 years, 4 months ago) by william
File size: 8519 byte(s)
Auto Commited Import of: pcsx2-0.9.7-DEBUG (upstream: v0.9.7.3746 local: v0.9.7.138) in ./trunk
1 /* PCSX2 - PS2 Emulator for PCs
2 * Copyright (C) 2002-2010 PCSX2 Dev Team
3 *
4 * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU Lesser General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with PCSX2.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #include "PrecompiledHeader.h"
17 #include "Common.h"
18 #include "Vif.h"
19 #include "Vif_Dma.h"
20
21 enum UnpackOffset {
22 OFFSET_X = 0,
23 OFFSET_Y = 1,
24 OFFSET_Z = 2,
25 OFFSET_W = 3
26 };
27
28 static __fi u32 setVifRowRegs(u32 reg, u32 data) {
29 switch (reg) {
30 case 0: vifRegs->r0 = data; break;
31 case 1: vifRegs->r1 = data; break;
32 case 2: vifRegs->r2 = data; break;
33 case 3: vifRegs->r3 = data; break;
34 jNO_DEFAULT;
35 }
36 return data;
37 }
38
39 static __fi u32 getVifRowRegs(u32 reg) {
40 switch (reg) {
41 case 0: return vifRegs->r0; break;
42 case 1: return vifRegs->r1; break;
43 case 2: return vifRegs->r2; break;
44 case 3: return vifRegs->r3; break;
45 jNO_DEFAULT;
46 }
47 return 0; // unreachable...
48 }
49
50 static __fi u32 getVifColRegs(u32 reg) {
51 switch (reg) {
52 case 0: return vifRegs->c0; break;
53 case 1: return vifRegs->c1; break;
54 case 2: return vifRegs->c2; break;
55 default: return vifRegs->c3; break;
56 }
57 return 0; // unreachable...
58 }
59
60 template< bool doMask >
61 static __ri void writeXYZW(u32 offnum, u32 &dest, u32 data) {
62 u32 vifRowReg = getVifRowRegs(offnum);
63 int n = 0;
64
65 if (doMask) {
66 switch (vif->cl) {
67 case 0: n = (vifRegs->mask >> (offnum * 2)) & 0x3; break;
68 case 1: n = (vifRegs->mask >> ( 8 + (offnum * 2))) & 0x3; break;
69 case 2: n = (vifRegs->mask >> (16 + (offnum * 2))) & 0x3; break;
70 default: n = (vifRegs->mask >> (24 + (offnum * 2))) & 0x3; break;
71 }
72 }
73
74 switch (n) {
75 case 0:
76 if ((vif->cmd & 0x6F) != 0x6f) {
77 switch (vifRegs->mode) {
78 case 1: dest = data + vifRowReg; break;
79 case 2: dest = setVifRowRegs(offnum, vifRowReg + data); break;
80 default: dest = data; break;
81 }
82 }
83 else dest = data; // v4-5 Unpack Mode
84 break;
85 case 1: dest = vifRowReg; break;
86 case 2: dest = getVifColRegs(vif->cl); break;
87 case 3: break;
88 }
89 }
90
91 template < bool doMask, class T >
92 static void __fastcall UNPACK_S(u32 *dest, const T *data)
93 {
94 //S-# will always be a complete packet, no matter what. So we can skip the offset bits
95 writeXYZW<doMask>(OFFSET_X, *dest++, *data);
96 writeXYZW<doMask>(OFFSET_Y, *dest++, *data);
97 writeXYZW<doMask>(OFFSET_Z, *dest++, *data);
98 writeXYZW<doMask>(OFFSET_W, *dest , *data);
99 }
100
101 // The PS2 console actually writes v1v0v1v0 for all V2 unpacks -- the second v1v0 pair
102 // being officially "indeterminate" but some games very much depend on it.
103 template <bool doMask, class T>
104 static void __fastcall UNPACK_V2(u32 *dest, const T *data)
105 {
106 writeXYZW<doMask>(0, *dest++, *data);
107 writeXYZW<doMask>(1, *dest++, *(data+1));
108 writeXYZW<doMask>(2, *dest++, *data);
109 writeXYZW<doMask>(3, *dest++, *(data+1));
110 }
111
112 // V3 and V4 unpacks both use the V4 unpack logic, even though most of the OFFSET_W fields
113 // during V3 unpacking end up being overwritten by the next unpack. This is confirmed real
114 // hardware behavior that games such as Ape Escape 3 depend on.
115 template <bool doMask, class T>
116 static void __fastcall UNPACK_V4(u32 *dest, const T *data)
117 {
118 writeXYZW<doMask>(OFFSET_X, *dest++, *data++);
119 writeXYZW<doMask>(OFFSET_Y, *dest++, *data++);
120 writeXYZW<doMask>(OFFSET_Z, *dest++, *data++);
121 writeXYZW<doMask>(OFFSET_W, *dest , *data);
122 }
123
124 template< bool doMask >
125 static void __fastcall UNPACK_V4_5(u32 *dest, const u32 *data)
126 {
127 //As with S-#, this will always be a complete packet
128 writeXYZW<doMask>(OFFSET_X, *dest++, ((*data & 0x001f) << 3));
129 writeXYZW<doMask>(OFFSET_Y, *dest++, ((*data & 0x03e0) >> 2));
130 writeXYZW<doMask>(OFFSET_Z, *dest++, ((*data & 0x7c00) >> 7));
131 writeXYZW<doMask>(OFFSET_W, *dest, ((*data & 0x8000) >> 8));
132 }
133
134 // =====================================================================================================
135
136 // --------------------------------------------------------------------------------------
137 // Main table for function unpacking.
138 // --------------------------------------------------------------------------------------
139 // The extra data bsize/dsize/etc are all duplicated between the doMask enabled and
140 // disabled versions. This is probably simpler and more efficient than bothering
141 // to generate separate tables.
142 //
143 // The double-cast function pointer nonsense is to appease GCC, which gives some rather
144 // cryptic error about being unable to deduce the type parameters (I think it's a bug
145 // relating to __fastcall, which I recall having some other places as well). It's fixed
146 // by explicitly casting the function to itself prior to casting it to what we need it
147 // to be cast as. --air
148 //
149
150 #define _upk (UNPACKFUNCTYPE)
151 #define _odd (UNPACKFUNCTYPE_ODD)
152 #define _unpk_s(bits) (UNPACKFUNCTYPE_S##bits)
153 #define _unpk_u(bits) (UNPACKFUNCTYPE_U##bits)
154
155 // 32-bits versions are unsigned-only!!
156 #define UnpackFuncPair32( vt, doMask ) \
157 (UNPACKFUNCTYPE)_unpk_u(32) UNPACK_##vt<doMask, u32>, \
158 (UNPACKFUNCTYPE)_unpk_u(32) UNPACK_##vt<doMask, u32>
159
160 #define UnpackFuncPair( vt, bits, doMask ) \
161 (UNPACKFUNCTYPE)_unpk_u(bits) UNPACK_##vt<doMask, u##bits>, \
162 (UNPACKFUNCTYPE)_unpk_s(bits) UNPACK_##vt<doMask, s##bits>
163
164 #define UnpackFuncSet( doMask ) \
165 { UnpackFuncPair32( S, doMask ), 4, 4 }, /* 0x0 - S-32 */ \
166 { UnpackFuncPair ( S, 16, doMask ), 2, 4 }, /* 0x1 - S-16 */ \
167 { UnpackFuncPair ( S, 8, doMask ), 1, 4 }, /* 0x2 - S-8 */ \
168 { NULL, NULL, 0, 0 }, /* 0x3 (NULL) */ \
169 { UnpackFuncPair32( V2, doMask ), 8, 2 }, /* 0x4 - V2-32 */ \
170 { UnpackFuncPair ( V2, 16, doMask ), 4, 2 }, /* 0x5 - V2-16 */ \
171 { UnpackFuncPair ( V2, 8, doMask ), 2, 2 }, /* 0x6 - V2-8 */ \
172 { NULL, NULL, 0, 0 }, /* 0x7 (NULL) */ \
173 { UnpackFuncPair32( V4, doMask ), 12, 3 }, /* 0x8 - V3-32 */ \
174 { UnpackFuncPair ( V4, 16, doMask ), 6, 3 }, /* 0x9 - V3-16 */ \
175 { UnpackFuncPair ( V4, 8, doMask ), 3, 3 }, /* 0xA - V3-8 */ \
176 { NULL, NULL, 0, 0 }, /* 0xB (NULL) */ \
177 { UnpackFuncPair32( V4, doMask ), 16, 4 }, /* 0xC - V4-32 */ \
178 { UnpackFuncPair ( V4, 16, doMask ), 8, 4 }, /* 0xD - V4-16 */ \
179 { UnpackFuncPair ( V4, 8, doMask ), 4, 4 }, /* 0xE - V4-8 */ \
180 { /* 0xF - V4-5 */ \
181 (UNPACKFUNCTYPE)_unpk_u(32)UNPACK_V4_5<doMask>, \
182 (UNPACKFUNCTYPE)_unpk_u(32)UNPACK_V4_5<doMask>, \
183 2, 4 \
184 },
185
186 const __aligned16 VIFUnpackFuncTable VIFfuncTable[32] =
187 {
188 UnpackFuncSet( false )
189 UnpackFuncSet( true )
190 };
191
192 //----------------------------------------------------------------------------
193 // Unpack Setup Code
194 //----------------------------------------------------------------------------
195
196 _vifT void vifUnpackSetup(const u32 *data) {
197
198 vifStruct& vifX = GetVifX;
199
200 if ((vifXRegs.cycle.wl == 0) && (vifXRegs.cycle.wl < vifXRegs.cycle.cl)) {
201 Console.WriteLn("Vif%d CL %d, WL %d", idx, vifXRegs.cycle.cl, vifXRegs.cycle.wl);
202 vifX.cmd = 0;
203 return; // Skipping write and 0 write-cycles, so do nothing!
204 }
205
206
207 //if (!idx) vif0FLUSH(); // Only VU0?
208
209 vifX.usn = (vifXRegs.code >> 14) & 0x01;
210 int vifNum = (vifXRegs.code >> 16) & 0xff;
211
212 if (vifNum == 0) vifNum = 256;
213 vifXRegs.num = vifNum;
214
215 if (vifXRegs.cycle.wl <= vifXRegs.cycle.cl) {
216 if (!idx) vif0.tag.size = ((vifNum * VIFfuncTable[ vif0.cmd & 0xf ].gsize) + 3) >> 2;
217 else vif1.tag.size = ((vifNum * VIFfuncTable[ vif1.cmd & 0xf ].gsize) + 3) >> 2;
218 }
219 else {
220 int n = vifXRegs.cycle.cl * (vifNum / vifXRegs.cycle.wl) +
221 _limit(vifNum % vifXRegs.cycle.wl, vifXRegs.cycle.cl);
222
223 if (!idx) vif0.tag.size = ((n * VIFfuncTable[ vif0.cmd & 0xf ].gsize) + 3) >> 2;
224 else vif1.tag.size = ((n * VIFfuncTable[ vif1.cmd & 0xf ].gsize) + 3) >> 2;
225 }
226
227 u32 addr = vifXRegs.code;
228 if (idx && ((addr>>15)&1)) addr += vif1Regs.tops;
229 vifX.tag.addr = (addr<<4) & (idx ? 0x3ff0 : 0xff0);
230
231 VIF_LOG("Unpack VIF%x, QWC %x tagsize %x", idx, vifNum, vif0.tag.size);
232
233 vifX.cl = 0;
234 vifX.tag.cmd = vifX.cmd;
235 }
236
237 template void vifUnpackSetup<0>(const u32 *data);
238 template void vifUnpackSetup<1>(const u32 *data);

  ViewVC Help
Powered by ViewVC 1.1.22