/[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 273 - (show annotations) (download)
Fri Nov 12 01:10:22 2010 UTC (9 years, 2 months ago) by william
File size: 8173 byte(s)
Auto Commited Import of: pcsx2-0.9.7-DEBUG (upstream: v0.9.7.4013 local: v0.9.7.197-latest) 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 setVifRow(vifStruct& vif, u32 reg, u32 data) {
29 vif.MaskRow._u32[reg] = data;
30 return data;
31 }
32
33 // cycle derives from vif.cl
34 // mode derives from vifRegs.mode
35 template< uint idx, uint mode, bool doMask >
36 static __ri void writeXYZW(u32 offnum, u32 &dest, u32 data) {
37 int n = 0;
38
39 vifStruct& vif = GetVifX;
40
41 if (doMask) {
42 const VIFregisters& regs = vifXRegs;
43 switch (vif.cl) {
44 case 0: n = (regs.mask >> (offnum * 2)) & 0x3; break;
45 case 1: n = (regs.mask >> ( 8 + (offnum * 2))) & 0x3; break;
46 case 2: n = (regs.mask >> (16 + (offnum * 2))) & 0x3; break;
47 default: n = (regs.mask >> (24 + (offnum * 2))) & 0x3; break;
48 }
49 }
50
51 // Four possible types of masking are handled below:
52 // 0 - Data
53 // 1 - MaskRow
54 // 2 - MaskCol
55 // 3 - Write protect
56
57 switch (n) {
58 case 0:
59 switch (mode) {
60 case 1: dest = data + vif.MaskRow._u32[offnum]; break;
61 case 2: dest = setVifRow(vif, offnum, vif.MaskRow._u32[offnum] + data); break;
62 default: dest = data; break;
63 }
64 break;
65 case 1: dest = vif.MaskRow._u32[offnum]; break;
66 case 2: dest = vif.MaskCol._u32[min(vif.cl,3)]; break;
67 case 3: break;
68 }
69 }
70 #define tParam idx,mode,doMask
71
72 template < uint idx, uint mode, bool doMask, class T >
73 static void __fastcall UNPACK_S(u32* dest, const T* src)
74 {
75 u32 data = *src;
76
77 //S-# will always be a complete packet, no matter what. So we can skip the offset bits
78 writeXYZW<tParam>(OFFSET_X, *(dest+0), data);
79 writeXYZW<tParam>(OFFSET_Y, *(dest+1), data);
80 writeXYZW<tParam>(OFFSET_Z, *(dest+2), data);
81 writeXYZW<tParam>(OFFSET_W, *(dest+3), data);
82 }
83
84 // The PS2 console actually writes v1v0v1v0 for all V2 unpacks -- the second v1v0 pair
85 // being officially "indeterminate" but some games very much depend on it.
86 template < uint idx, uint mode, bool doMask, class T >
87 static void __fastcall UNPACK_V2(u32* dest, const T* src)
88 {
89 writeXYZW<tParam>(OFFSET_X, *(dest+0), *(src+0));
90 writeXYZW<tParam>(OFFSET_Y, *(dest+1), *(src+1));
91 writeXYZW<tParam>(OFFSET_Z, *(dest+2), *(src+0));
92 writeXYZW<tParam>(OFFSET_W, *(dest+3), *(src+1));
93 }
94
95 // V3 and V4 unpacks both use the V4 unpack logic, even though most of the OFFSET_W fields
96 // during V3 unpacking end up being overwritten by the next unpack. This is confirmed real
97 // hardware behavior that games such as Ape Escape 3 depend on.
98 template < uint idx, uint mode, bool doMask, class T >
99 static void __fastcall UNPACK_V4(u32* dest, const T* src)
100 {
101 writeXYZW<tParam>(OFFSET_X, *(dest+0), *(src+0));
102 writeXYZW<tParam>(OFFSET_Y, *(dest+1), *(src+1));
103 writeXYZW<tParam>(OFFSET_Z, *(dest+2), *(src+2));
104 writeXYZW<tParam>(OFFSET_W, *(dest+3), *(src+3));
105 }
106
107 // V4_5 unpacks do not support the MODE register, and act as mode==0 always.
108 template< uint idx, bool doMask >
109 static void __fastcall UNPACK_V4_5(u32 *dest, const u32* src)
110 {
111 u32 data = *src;
112
113 writeXYZW<idx,0,doMask>(OFFSET_X, *(dest+0), ((data & 0x001f) << 3));
114 writeXYZW<idx,0,doMask>(OFFSET_Y, *(dest+1), ((data & 0x03e0) >> 2));
115 writeXYZW<idx,0,doMask>(OFFSET_Z, *(dest+2), ((data & 0x7c00) >> 7));
116 writeXYZW<idx,0,doMask>(OFFSET_W, *(dest+3), ((data & 0x8000) >> 8));
117 }
118
119 // =====================================================================================================
120
121 // --------------------------------------------------------------------------------------
122 // Main table for function unpacking.
123 // --------------------------------------------------------------------------------------
124 // The extra data bsize/dsize/etc are all duplicated between the doMask enabled and
125 // disabled versions. This is probably simpler and more efficient than bothering
126 // to generate separate tables.
127 //
128 // The double-cast function pointer nonsense is to appease GCC, which gives some rather
129 // cryptic error about being unable to deduce the type parameters (I think it's a bug
130 // relating to __fastcall, which I recall having some other places as well). It's fixed
131 // by explicitly casting the function to itself prior to casting it to what we need it
132 // to be cast as. --air
133 //
134
135 #define _upk (UNPACKFUNCTYPE)
136 #define _unpk(usn, bits) (UNPACKFUNCTYPE_##usn##bits)
137
138 #define UnpackFuncSet( vt, idx, mode, usn, doMask ) \
139 (UNPACKFUNCTYPE)_unpk(u,32) UNPACK_##vt<idx, mode, doMask, u32>, \
140 (UNPACKFUNCTYPE)_unpk(usn,16) UNPACK_##vt<idx, mode, doMask, usn##16>, \
141 (UNPACKFUNCTYPE)_unpk(usn,8) UNPACK_##vt<idx, mode, doMask, usn##8> \
142
143 #define UnpackV4_5set(idx, doMask) \
144 (UNPACKFUNCTYPE)_unpk(u,32) UNPACK_V4_5<idx, doMask> \
145
146 #define UnpackModeSet(idx, mode) \
147 UnpackFuncSet( S, idx, mode, s, 0 ), NULL, \
148 UnpackFuncSet( V2, idx, mode, s, 0 ), NULL, \
149 UnpackFuncSet( V4, idx, mode, s, 0 ), NULL, \
150 UnpackFuncSet( V4, idx, mode, s, 0 ), UnpackV4_5set(idx, 0), \
151 \
152 UnpackFuncSet( S, idx, mode, s, 1 ), NULL, \
153 UnpackFuncSet( V2, idx, mode, s, 1 ), NULL, \
154 UnpackFuncSet( V4, idx, mode, s, 1 ), NULL, \
155 UnpackFuncSet( V4, idx, mode, s, 1 ), UnpackV4_5set(idx, 1), \
156 \
157 UnpackFuncSet( S, idx, mode, u, 0 ), NULL, \
158 UnpackFuncSet( V2, idx, mode, u, 0 ), NULL, \
159 UnpackFuncSet( V4, idx, mode, u, 0 ), NULL, \
160 UnpackFuncSet( V4, idx, mode, u, 0 ), UnpackV4_5set(idx, 0), \
161 \
162 UnpackFuncSet( S, idx, mode, u, 1 ), NULL, \
163 UnpackFuncSet( V2, idx, mode, u, 1 ), NULL, \
164 UnpackFuncSet( V4, idx, mode, u, 1 ), NULL, \
165 UnpackFuncSet( V4, idx, mode, u, 1 ), UnpackV4_5set(idx, 1)
166
167 __aligned16 const UNPACKFUNCTYPE VIFfuncTable[2][3][4 * 4 * 2 * 2] =
168 {
169 {
170 { UnpackModeSet(0,0) },
171 { UnpackModeSet(0,1) },
172 { UnpackModeSet(0,2) }
173 },
174
175 {
176 { UnpackModeSet(1,0) },
177 { UnpackModeSet(1,1) },
178 { UnpackModeSet(1,2) }
179 }
180 };
181
182 //----------------------------------------------------------------------------
183 // Unpack Setup Code
184 //----------------------------------------------------------------------------
185
186 _vifT void vifUnpackSetup(const u32 *data) {
187
188 vifStruct& vifX = GetVifX;
189
190 if ((vifXRegs.cycle.wl == 0) && (vifXRegs.cycle.wl < vifXRegs.cycle.cl)) {
191 DevCon.WriteLn("Vif%d CL %d, WL %d", idx, vifXRegs.cycle.cl, vifXRegs.cycle.wl);
192 vifX.cmd = 0;
193 return; // Skipping write and 0 write-cycles, so do nothing!
194 }
195
196
197 //if (!idx) vif0FLUSH(); // Only VU0?
198
199 vifX.usn = (vifXRegs.code >> 14) & 0x01;
200 int vifNum = (vifXRegs.code >> 16) & 0xff;
201
202 if (vifNum == 0) vifNum = 256;
203 vifXRegs.num = vifNum;
204
205 // Traditional-style way of calculating the gsize, based on VN/VL parameters.
206 // Useful when VN/VL are known template params, but currently they are not so we use
207 // the LUT instead (for now).
208 //uint vl = vifX.cmd & 0x03;
209 //uint vn = (vifX.cmd >> 2) & 0x3;
210 //uint gsize = ((32 >> vl) * (vn+1)) / 8;
211
212 const u8& gsize = nVifT[vifX.cmd & 0x0f];
213
214 if (vifXRegs.cycle.wl <= vifXRegs.cycle.cl) {
215 vifX.tag.size = ((vifNum * gsize) + 3) / 4;
216 }
217 else {
218 int n = vifXRegs.cycle.cl * (vifNum / vifXRegs.cycle.wl) +
219 _limit(vifNum % vifXRegs.cycle.wl, vifXRegs.cycle.cl);
220
221 vifX.tag.size = ((n * gsize) + 3) >> 2;
222 }
223
224 u32 addr = vifXRegs.code;
225 if (idx && ((addr>>15)&1)) addr += vif1Regs.tops;
226 vifX.tag.addr = (addr<<4) & (idx ? 0x3ff0 : 0xff0);
227
228 VIF_LOG("Unpack VIF%x, QWC %x tagsize %x", idx, vifNum, vif0.tag.size);
229
230 vifX.cl = 0;
231 vifX.tag.cmd = vifX.cmd;
232 }
233
234 template void vifUnpackSetup<0>(const u32 *data);
235 template void vifUnpackSetup<1>(const u32 *data);

  ViewVC Help
Powered by ViewVC 1.1.22