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

Contents of /trunk/pcsx2/Hw.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 280 - (show annotations) (download)
Thu Dec 23 12:02:12 2010 UTC (9 years, 1 month ago) by william
File size: 10706 byte(s)
re-commit (had local access denied errors when committing)
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
19 #include "Hardware.h"
20 #include "newVif.h"
21 #include "IPU/IPUdma.h"
22
23 using namespace R5900;
24
25 const int rdram_devices = 2; // put 8 for TOOL and 2 for PS2 and PSX
26 int rdram_sdevid = 0;
27
28 static bool hwInitialized = false;
29
30 void hwInit()
31 {
32 // [TODO] / FIXME: PCSX2 no longer works on an Init system. It assumes that the
33 // static global vars for the process will be initialized when the process is created, and
34 // then issues *resets only* from then on. (reset code for various S2 components should do
35 // NULL checks and allocate memory and such if the pointers are NULL only).
36
37 if( hwInitialized ) return;
38
39 VifUnpackSSE_Init();
40
41 gsInit();
42 sifInit();
43 sprInit();
44 ipuInit();
45
46 hwInitialized = true;
47 }
48
49 void hwReset()
50 {
51 hwInit();
52
53 memzero( eeHw );
54
55 psHu32(SBUS_F260) = 0x1D000060;
56
57 // i guess this is kinda a version, it's used by some bioses
58 psHu32(DMAC_ENABLEW) = 0x1201;
59 psHu32(DMAC_ENABLER) = 0x1201;
60
61 SPU2reset();
62
63 sifInit();
64 sprInit();
65
66 gsReset();
67 ipuReset();
68 vif0Reset();
69 vif1Reset();
70
71 // needed for legacy DMAC
72 ipuDmaReset();
73 }
74
75 __fi uint intcInterrupt()
76 {
77 if ((psHu32(INTC_STAT)) == 0) {
78 //DevCon.Warning("*PCSX2*: intcInterrupt already cleared");
79 return 0;
80 }
81 if ((psHu32(INTC_STAT) & psHu32(INTC_MASK)) == 0)
82 {
83 //DevCon.Warning("*PCSX2*: No valid interrupt INTC_MASK: %x INTC_STAT: %x", psHu32(INTC_MASK), psHu32(INTC_STAT));
84 return 0;
85 }
86
87 HW_LOG("intcInterrupt %x", psHu32(INTC_STAT) & psHu32(INTC_MASK));
88 if(psHu32(INTC_STAT) & 0x2){
89 counters[0].hold = rcntRcount(0);
90 counters[1].hold = rcntRcount(1);
91 }
92
93 //cpuException(0x400, cpuRegs.branch);
94 return 0x400;
95 }
96
97 __fi uint dmacInterrupt()
98 {
99 if( ((psHu16(DMAC_STAT + 2) & psHu16(DMAC_STAT)) == 0 ) &&
100 ( psHu16(DMAC_STAT) & 0x8000) == 0 )
101 {
102 //DevCon.Warning("No valid DMAC interrupt MASK %x STAT %x", psHu16(DMAC_STAT+2), psHu16(DMAC_STAT));
103 return 0;
104 }
105
106 if (!dmacRegs.ctrl.DMAE || psHu8(DMAC_ENABLER+2) == 1)
107 {
108 //DevCon.Warning("DMAC Suspended or Disabled on interrupt");
109 return 0;
110 }
111
112 DMA_LOG("dmacInterrupt %x",
113 ((psHu16(DMAC_STAT + 2) & psHu16(DMAC_STAT)) |
114 (psHu16(DMAC_STAT) & 0x8000))
115 );
116
117 //cpuException(0x800, cpuRegs.branch);
118 return 0x800;
119 }
120
121 void hwIntcIrq(int n)
122 {
123 psHu32(INTC_STAT) |= 1<<n;
124 if(psHu32(INTC_MASK) & (1<<n))cpuTestINTCInts();
125 }
126
127 void hwDmacIrq(int n)
128 {
129 psHu32(DMAC_STAT) |= 1<<n;
130 if(psHu16(DMAC_STAT+2) & (1<<n))cpuTestDMACInts();
131 }
132
133 void FireMFIFOEmpty()
134 {
135 SPR_LOG("VIF MFIFO Data Empty");
136 hwDmacIrq(DMAC_MFIFO_EMPTY);
137
138 if (dmacRegs.ctrl.MFD == MFD_VIF1) vif1Regs.stat.FQC = 0;
139 else if (dmacRegs.ctrl.MFD == MFD_GIF) gifRegs.stat.FQC = 0;
140 }
141 // Write 'size' bytes to memory address 'addr' from 'data'.
142 __ri bool hwMFIFOWrite(u32 addr, const u128* data, uint qwc)
143 {
144 // all FIFO addresses should always be QWC-aligned.
145 pxAssume((dmacRegs.rbor.ADDR & 15) == 0);
146 pxAssume((addr & 15) == 0);
147
148 if(qwc > ((dmacRegs.rbsr.RMSK + 16) >> 4)) DevCon.Warning("MFIFO Write bigger than MFIFO! QWC=%x FifoSize=%x", qwc, ((dmacRegs.rbsr.RMSK + 16) >> 4));
149 // DMAC Address resolution: FIFO can be placed anywhere in the *physical* memory map
150 // for the PS2. Its probably a serious error for a PS2 app to have the buffer cross
151 // valid/invalid page areas of ram, so realistically we only need to test the base address
152 // of the FIFO for address validity.
153
154 if (u128* dst = (u128*)PSM(dmacRegs.rbor.ADDR))
155 {
156 const u32 ringsize = (dmacRegs.rbsr.RMSK / 16) + 1;
157 pxAssertMsg( PSM(dmacRegs.rbor.ADDR+ringsize-1) != NULL, "Scratchpad/MFIFO ringbuffer spans into invalid (unmapped) physical memory!" );
158 uint startpos = (addr & dmacRegs.rbsr.RMSK)/16;
159 MemCopy_WrappedDest( data, dst, startpos, ringsize, qwc );
160 }
161 else
162 {
163 SPR_LOG( "Scratchpad/MFIFO: invalid base physical address: 0x%08x", dmacRegs.rbor.ADDR );
164 pxFailDev( wxsFormat( L"Scratchpad/MFIFO: Invalid base physical address: 0x%08x", dmacRegs.rbor.ADDR) );
165 return false;
166 }
167
168 return true;
169 }
170
171 __ri bool hwDmacSrcChainWithStack(DMACh& dma, int id) {
172 switch (id) {
173 case TAG_REFE: // Refe - Transfer Packet According to ADDR field
174 dma.tadr += 16;
175 //End Transfer
176 return true;
177
178 case TAG_CNT: // CNT - Transfer QWC following the tag.
179 // Set MADR to QW afer tag, and set TADR to QW following the data.
180 dma.tadr += 16;
181 dma.madr = dma.tadr;
182 //dma.tadr = dma.madr + (dma.qwc << 4);
183 return false;
184
185 case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR
186 {
187 // Set MADR to QW following the tag, and set TADR to the address formerly in MADR.
188 u32 temp = dma.madr;
189 dma.madr = dma.tadr + 16;
190 dma.tadr = temp;
191 return false;
192 }
193 case TAG_REF: // Ref - Transfer QWC from ADDR field
194 case TAG_REFS: // Refs - Transfer QWC from ADDR field (Stall Control)
195 //Set TADR to next tag
196 dma.tadr += 16;
197 return false;
198
199 case TAG_CALL: // Call - Transfer QWC following the tag, save succeeding tag
200 {
201 // Store the address in MADR in temp, and set MADR to the data following the tag.
202 u32 temp = dma.madr;
203 dma.madr = dma.tadr + 16;
204
205 if(temp == 0)
206 {
207 DevCon.Warning("DMA Chain CALL next tag error. Tag Addr = 0");
208 dma.tadr = dma.madr + (dma.qwc << 4);
209 return false;
210 }
211 // Stash an address on the address stack pointer.
212 switch(dma.chcr.ASP)
213 {
214 case 0: //Check if ASR0 is empty
215 // Store the succeeding tag in asr0, and mark chcr as having 1 address.
216 dma.asr0 = dma.madr + (dma.qwc << 4);
217 dma.chcr.ASP++;
218 break;
219
220 case 1:
221 // Store the succeeding tag in asr1, and mark chcr as having 2 addresses.
222 dma.asr1 = dma.madr + (dma.qwc << 4);
223 dma.chcr.ASP++;
224 break;
225
226 default:
227 Console.Warning("Call Stack Overflow (report if it fixes/breaks anything)");
228 return true;
229 }
230
231 // Set TADR to the address from MADR we stored in temp.
232 dma.tadr = temp;
233
234 return false;
235 }
236
237 case TAG_RET: // Ret - Transfer QWC following the tag, load next tag
238 //Set MADR to data following the tag.
239 dma.madr = dma.tadr + 16;
240
241 // Snag an address from the address stack pointer.
242 switch(dma.chcr.ASP)
243 {
244 case 2:
245 // Pull asr1 from the stack, give it to TADR, and decrease the # of addresses.
246 dma.tadr = dma.asr1;
247 dma.asr1 = 0;
248 dma.chcr.ASP--;
249 break;
250
251 case 1:
252 // Pull asr0 from the stack, give it to TADR, and decrease the # of addresses.
253 dma.tadr = dma.asr0;
254 dma.asr0 = 0;
255 dma.chcr.ASP--;
256 break;
257
258 case 0:
259 // There aren't any addresses to pull, so end the transfer.
260 //dma.tadr += 16; //Clear tag address - Kills Klonoa 2
261 return true;
262
263 default:
264 // If ASR1 and ASR0 are messed up, end the transfer.
265 //Console.Error("TAG_RET: ASR 1 & 0 == 1. This shouldn't happen!");
266 //dma.tadr += 16; //Clear tag address - Kills Klonoa 2
267 return true;
268 }
269 return false;
270
271 case TAG_END: // End - Transfer QWC following the tag
272 //Set MADR to data following the tag, and end the transfer.
273 dma.madr = dma.tadr + 16;
274 //Don't Increment tadr; breaks Soul Calibur II and III
275 return true;
276 }
277
278 return false;
279 }
280
281
282 /********TADR NOTES***********
283 From what i've gathered from testing tadr increment stuff (with CNT) is that we might not be 100% accurate in what
284 increments it and what doesnt. Previously we presumed REFE and END didn't increment the tag, but SIF and IPU never
285 liked this.
286
287 From what i've deduced, REFE does in fact increment, but END doesn't, after much testing, i've concluded this is how
288 we can standardize DMA chains, so i've modified the code to work like this. The below function controls the increment
289 of the TADR along with the MADR on VIF, GIF and SPR1 when using the CNT tag, the others don't use it yet, but they
290 can probably be modified to do so now.
291
292 Reason for this:- Many games (such as clock tower 3 and FFX Videos) watched the TADR to see when a transfer has finished,
293 so we need to simulate this wherever we can! Even the FFX video gets corruption and tries to fire multiple DMA Kicks
294 if this doesnt happen, which was the reasoning for the hacked up SPR timing we had, that is no longer required.
295
296 -Refraction
297 ******************************/
298
299 void hwDmacSrcTadrInc(DMACh& dma)
300 {
301 u16 tagid = (dma.chcr.TAG >> 12) & 0x7;
302
303 if(tagid == TAG_CNT)
304 {
305 dma.tadr = dma.madr;
306 }
307 }
308 bool hwDmacSrcChain(DMACh& dma, int id)
309 {
310 u32 temp;
311
312 switch (id)
313 {
314 case TAG_REFE: // Refe - Transfer Packet According to ADDR field
315 dma.tadr += 16;
316 // End the transfer.
317 return true;
318
319 case TAG_CNT: // CNT - Transfer QWC following the tag.
320 // Set MADR to QW after the tag, and TADR to QW following the data.
321 dma.madr = dma.tadr + 16;
322 dma.tadr = dma.madr;
323 return false;
324
325 case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR
326 // Set MADR to QW following the tag, and set TADR to the address formerly in MADR.
327 temp = dma.madr;
328 dma.madr = dma.tadr + 16;
329 dma.tadr = temp;
330 return false;
331
332 case TAG_REF: // Ref - Transfer QWC from ADDR field
333 case TAG_REFS: // Refs - Transfer QWC from ADDR field (Stall Control)
334 //Set TADR to next tag
335 dma.tadr += 16;
336 return false;
337
338 case TAG_END: // End - Transfer QWC following the tag
339 //Set MADR to data following the tag, and end the transfer.
340 dma.madr = dma.tadr + 16;
341 //Don't Increment tadr; breaks Soul Calibur II and III
342 return true;
343 }
344
345 return false;
346 }
347

  ViewVC Help
Powered by ViewVC 1.1.22