/[pcsx2_0.9.7]/trunk/pcsx2/ps2/LegacyDmac.cpp
ViewVC logotype

Contents of /trunk/pcsx2/ps2/LegacyDmac.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: 13623 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
17 #include "PrecompiledHeader.h"
18 #include "Common.h"
19 #include "Hardware.h"
20
21 #include "IPU/IPUdma.h"
22 #include "ps2/HwInternal.h"
23
24 bool DMACh::transfer(const char *s, tDMA_TAG* ptag)
25 {
26 if (ptag == NULL) // Is ptag empty?
27 {
28 throwBusError(s);
29 return false;
30 }
31 chcrTransfer(ptag);
32
33 qwcTransfer(ptag);
34 return true;
35 }
36
37 void DMACh::unsafeTransfer(tDMA_TAG* ptag)
38 {
39 chcrTransfer(ptag);
40 qwcTransfer(ptag);
41 }
42
43 tDMA_TAG *DMACh::getAddr(u32 addr, u32 num, bool write)
44 {
45 tDMA_TAG *ptr = dmaGetAddr(addr, write);
46 if (ptr == NULL)
47 {
48 throwBusError("dmaGetAddr");
49 setDmacStat(num);
50 chcr.STR = false;
51 }
52
53 return ptr;
54 }
55
56 tDMA_TAG *DMACh::DMAtransfer(u32 addr, u32 num)
57 {
58 tDMA_TAG *tag = getAddr(addr, num, false);
59
60 if (tag == NULL) return NULL;
61
62 chcrTransfer(tag);
63 qwcTransfer(tag);
64 return tag;
65 }
66
67 tDMA_TAG DMACh::dma_tag()
68 {
69 return chcr.tag();
70 }
71
72 wxString DMACh::cmq_to_str() const
73 {
74 return wxsFormat(L"chcr = %lx, madr = %lx, qwc = %lx", chcr._u32, madr, qwc);
75 }
76
77 wxString DMACh::cmqt_to_str() const
78 {
79 return wxsFormat(L"chcr = %lx, madr = %lx, qwc = %lx, tadr = %1x", chcr._u32, madr, qwc, tadr);
80 }
81
82 __fi void throwBusError(const char *s)
83 {
84 Console.Error("%s BUSERR", s);
85 dmacRegs.stat.BEIS = true;
86 }
87
88 __fi void setDmacStat(u32 num)
89 {
90 dmacRegs.stat.set_flags(1 << num);
91 }
92
93 // Note: Dma addresses are guaranteed to be aligned to 16 bytes (128 bits)
94 __fi tDMA_TAG *SPRdmaGetAddr(u32 addr, bool write)
95 {
96 // if (addr & 0xf) { DMA_LOG("*PCSX2*: DMA address not 128bit aligned: %8.8x", addr); }
97
98 //For some reason Getaway references SPR Memory from itself using SPR0, oh well, let it i guess...
99 if((addr & 0x70000000) == 0x70000000)
100 {
101 return (tDMA_TAG*)&eeMem->Scratch[addr & 0x3ff0];
102 }
103
104 // FIXME: Why??? DMA uses physical addresses
105 addr &= 0x1ffffff0;
106
107 if (addr < Ps2MemSize::MainRam)
108 {
109 return (tDMA_TAG*)&eeMem->Main[addr];
110 }
111 else if (addr < 0x10000000)
112 {
113 return (tDMA_TAG*)(write ? eeMem->ZeroWrite : eeMem->ZeroRead);
114 }
115 else if ((addr >= 0x11004000) && (addr < 0x11010000))
116 {
117 //Access for VU Memory
118 return (tDMA_TAG*)vtlb_GetPhyPtr(addr & 0x1FFFFFF0);
119 }
120 else
121 {
122 Console.Error( "*PCSX2*: DMA error: %8.8x", addr);
123 return NULL;
124 }
125 }
126
127 // Note: Dma addresses are guaranteed to be aligned to 16 bytes (128 bits)
128 __ri tDMA_TAG *dmaGetAddr(u32 addr, bool write)
129 {
130 // if (addr & 0xf) { DMA_LOG("*PCSX2*: DMA address not 128bit aligned: %8.8x", addr); }
131 if (DMA_TAG(addr).SPR) return (tDMA_TAG*)&eeMem->Scratch[addr & 0x3ff0];
132
133 // FIXME: Why??? DMA uses physical addresses
134 addr &= 0x1ffffff0;
135
136 if (addr < Ps2MemSize::MainRam)
137 {
138 return (tDMA_TAG*)&eeMem->Main[addr];
139 }
140 else if (addr < 0x10000000)
141 {
142 return (tDMA_TAG*)(write ? eeMem->ZeroWrite : eeMem->ZeroRead);
143 }
144 else if (addr < 0x10004000)
145 {
146 // Secret scratchpad address for DMA = end of maximum main memory?
147 //Console.Warning("Writing to the scratchpad without the SPR flag set!");
148 return (tDMA_TAG*)&eeMem->Scratch[addr & 0x3ff0];
149 }
150 else
151 {
152 Console.Error( "*PCSX2*: DMA error: %8.8x", addr);
153 return NULL;
154 }
155 }
156
157
158 // Returns true if the DMA is enabled and executed successfully. Returns false if execution
159 // was blocked (DMAE or master DMA enabler).
160 static bool QuickDmaExec( void (*func)(), u32 mem)
161 {
162 bool ret = false;
163 DMACh& reg = (DMACh&)psHu32(mem);
164
165 if (reg.chcr.STR && dmacRegs.ctrl.DMAE && !psHu8(DMAC_ENABLER+2))
166 {
167 func();
168 ret = true;
169 }
170
171 return ret;
172 }
173
174
175 static tDMAC_QUEUE QueuedDMA(0);
176 static u32 oldvalue = 0;
177
178 static void StartQueuedDMA()
179 {
180 if (QueuedDMA.VIF0) { DMA_LOG("Resuming DMA for VIF0"); QueuedDMA.VIF0 = !QuickDmaExec(dmaVIF0, D0_CHCR); }
181 if (QueuedDMA.VIF1) { DMA_LOG("Resuming DMA for VIF1"); QueuedDMA.VIF1 = !QuickDmaExec(dmaVIF1, D1_CHCR); }
182 if (QueuedDMA.GIF ) { DMA_LOG("Resuming DMA for GIF" ); QueuedDMA.GIF = !QuickDmaExec(dmaGIF , D2_CHCR); }
183 if (QueuedDMA.IPU0) { DMA_LOG("Resuming DMA for IPU0"); QueuedDMA.IPU0 = !QuickDmaExec(dmaIPU0, D3_CHCR); }
184 if (QueuedDMA.IPU1) { DMA_LOG("Resuming DMA for IPU1"); QueuedDMA.IPU1 = !QuickDmaExec(dmaIPU1, D4_CHCR); }
185 if (QueuedDMA.SIF0) { DMA_LOG("Resuming DMA for SIF0"); QueuedDMA.SIF0 = !QuickDmaExec(dmaSIF0, D5_CHCR); }
186 if (QueuedDMA.SIF1) { DMA_LOG("Resuming DMA for SIF1"); QueuedDMA.SIF1 = !QuickDmaExec(dmaSIF1, D6_CHCR); }
187 if (QueuedDMA.SIF2) { DMA_LOG("Resuming DMA for SIF2"); QueuedDMA.SIF2 = !QuickDmaExec(dmaSIF2, D7_CHCR); }
188 if (QueuedDMA.SPR0) { DMA_LOG("Resuming DMA for SPR0"); QueuedDMA.SPR0 = !QuickDmaExec(dmaSPR0, D8_CHCR); }
189 if (QueuedDMA.SPR1) { DMA_LOG("Resuming DMA for SPR1"); QueuedDMA.SPR1 = !QuickDmaExec(dmaSPR1, D9_CHCR); }
190 }
191
192 static __ri void DmaExec( void (*func)(), u32 mem, u32 value )
193 {
194 DMACh& reg = (DMACh&)psHu32(mem);
195 tDMA_CHCR chcr(value);
196
197 //It's invalid for the hardware to write a DMA while it is active, not without Suspending the DMAC
198 if (reg.chcr.STR)
199 {
200 const uint channel = ChannelNumber(mem);
201
202 if(psHu8(DMAC_ENABLER+2) == 1) //DMA is suspended so we can allow writes to anything
203 {
204 //If it stops the DMA, we need to clear any pending interrupts so the DMA doesnt continue.
205 if(chcr.STR == 0)
206 {
207 //DevCon.Warning(L"32bit %s DMA Stopped on Suspend", ChcrName(mem));
208 if(channel == 1)
209 {
210 cpuClearInt( 10 );
211 QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel
212 }
213 else if(channel == 2)
214 {
215 cpuClearInt( 11 );
216 QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel
217 }
218
219 cpuClearInt( channel );
220 QueuedDMA._u16 &= ~(1 << channel); //Clear any queued DMA requests for this channel
221 }
222 //Sanity Check for possible future bug fix0rs ;p
223 //Spams on Persona 4 opening.
224 //if(reg.chcr.TAG != chcr.TAG) DevCon.Warning(L"32bit CHCR Tag on %s changed to %x from %x QWC = %x Channel Active", ChcrName(mem), chcr.TAG, reg.chcr.TAG, reg.qwc);
225 //Here we update the LOWER CHCR, if a chain is stopped half way through, it can be manipulated in to a different mode
226 //But we need to preserve the existing tag for now
227 reg.chcr.set((reg.chcr.TAG << 16) | chcr.lower());
228 return;
229 }
230 else //Else the DMA is running (Not Suspended), so we cant touch it!
231 {
232 //As the manual states "Fields other than STR can only be written to when the DMA is stopped"
233 //Also "The DMA may not stop properly just by writing 0 to STR"
234 //So the presumption is that STR can be written to (ala force stop the DMA) but nothing else
235
236 if(chcr.STR == 0)
237 {
238 //DevCon.Warning(L"32bit Force Stopping %s (Current CHCR %x) while DMA active", ChcrName(mem), reg.chcr._u32, chcr._u32);
239 reg.chcr.STR = 0;
240 //We need to clear any existing DMA loops that are in progress else they will continue!
241
242 if(channel == 1)
243 {
244 cpuClearInt( 10 );
245 QueuedDMA._u16 &= ~(1 << 10); //Clear any queued DMA requests for this channel
246 }
247 else if(channel == 2)
248 {
249 cpuClearInt( 11 );
250 QueuedDMA._u16 &= ~(1 << 11); //Clear any queued DMA requests for this channel
251 }
252
253 cpuClearInt( channel );
254 QueuedDMA._u16 &= ~(1 << channel); //Clear any queued DMA requests for this channel
255 }
256 //else DevCon.Warning(L"32bit Attempted to change %s CHCR (Currently %x) with %x while DMA active, ignoring QWC = %x", ChcrName(mem), reg.chcr._u32, chcr._u32, reg.qwc);
257 return;
258 }
259
260 }
261
262 //if(reg.chcr.TAG != chcr.TAG && chcr.MOD == CHAIN_MODE) DevCon.Warning(L"32bit CHCR Tag on %s changed to %x from %x QWC = %x Channel Not Active", ChcrName(mem), chcr.TAG, reg.chcr.TAG, reg.qwc);
263
264 reg.chcr.set(value);
265
266 if (reg.chcr.STR && dmacRegs.ctrl.DMAE && !psHu8(DMAC_ENABLER+2))
267 {
268 func();
269 }
270 else if(reg.chcr.STR)
271 {
272 //DevCon.Warning(L"32bit %s DMA Start while DMAC Disabled\n", ChcrName(mem));
273 QueuedDMA._u16 |= (1 << ChannelNumber(mem)); //Queue the DMA up to be started then the DMA's are Enabled and or the Suspend is lifted
274 } //else QueuedDMA._u16 &~= (1 << ChannelNumber(mem)); //
275 }
276
277 template< uint page >
278 __fi u32 dmacRead32( u32 mem )
279 {
280 // Fixme: OPH hack. Toggle the flag on each GIF_STAT access. (rama)
281 if (IsPageFor(mem) && (mem == GIF_STAT) && CHECK_OPHFLAGHACK)
282 {
283 gifRegs.stat.OPH = !gifRegs.stat.OPH;
284 }
285
286 return psHu32(mem);
287 }
288
289 // Returns TRUE if the caller should do writeback of the register to eeHw; false if the
290 // register has no writeback, or if the writeback is handled internally.
291 template< uint page >
292 __fi bool dmacWrite32( u32 mem, mem32_t& value )
293 {
294 iswitch(mem) {
295 icase(D0_CHCR) // dma0 - vif0
296 {
297 DMA_LOG("VIF0dma EXECUTE, value=0x%x", value);
298 DmaExec(dmaVIF0, mem, value);
299 return false;
300 }
301
302 icase(D1_CHCR) // dma1 - vif1 - chcr
303 {
304 DMA_LOG("VIF1dma EXECUTE, value=0x%x", value);
305 DmaExec(dmaVIF1, mem, value);
306 return false;
307 }
308
309 icase(D2_CHCR) // dma2 - gif
310 {
311 DMA_LOG("GIFdma EXECUTE, value=0x%x", value);
312 DmaExec(dmaGIF, mem, value);
313 return false;
314 }
315
316 icase(D3_CHCR) // dma3 - fromIPU
317 {
318 DMA_LOG("IPU0dma EXECUTE, value=0x%x\n", value);
319 DmaExec(dmaIPU0, mem, value);
320 return false;
321 }
322
323 icase(D4_CHCR) // dma4 - toIPU
324 {
325 DMA_LOG("IPU1dma EXECUTE, value=0x%x\n", value);
326 DmaExec(dmaIPU1, mem, value);
327 return false;
328 }
329
330 icase(D5_CHCR) // dma5 - sif0
331 {
332 DMA_LOG("SIF0dma EXECUTE, value=0x%x", value);
333 DmaExec(dmaSIF0, mem, value);
334 return false;
335 }
336
337 icase(D6_CHCR) // dma6 - sif1
338 {
339 DMA_LOG("SIF1dma EXECUTE, value=0x%x", value);
340 DmaExec(dmaSIF1, mem, value);
341 return false;
342 }
343
344 icase(D7_CHCR) // dma7 - sif2
345 {
346 DMA_LOG("SIF2dma EXECUTE, value=0x%x", value);
347 DmaExec(dmaSIF2, mem, value);
348 return false;
349 }
350
351 icase(D8_CHCR) // dma8 - fromSPR
352 {
353 DMA_LOG("SPR0dma EXECUTE (fromSPR), value=0x%x", value);
354 DmaExec(dmaSPR0, mem, value);
355 return false;
356 }
357
358 icase(D9_CHCR) // dma9 - toSPR
359 {
360 DMA_LOG("SPR1dma EXECUTE (toSPR), value=0x%x", value);
361 DmaExec(dmaSPR1, mem, value);
362 return false;
363 }
364
365 icase(DMAC_CTRL)
366 {
367 u32 oldvalue = psHu32(mem);
368
369 HW_LOG("DMAC_CTRL Write 32bit %x", value);
370
371 psHu32(mem) = value;
372 //Check for DMAS that were started while the DMAC was disabled
373 if (((oldvalue & 0x1) == 0) && ((value & 0x1) == 1))
374 {
375 if (!QueuedDMA.empty()) StartQueuedDMA();
376 }
377 if ((oldvalue & 0x30) != (value & 0x30))
378 {
379 DevCon.Warning("32bit Stall Source Changed to %x", (value & 0x30) >> 4);
380 }
381 if ((oldvalue & 0xC0) != (value & 0xC0))
382 {
383 DevCon.Warning("32bit Stall Destination Changed to %x", (value & 0xC0) >> 4);
384 }
385 return false;
386 }
387
388 //Midway are a bunch of idiots, writing to E100 (reserved) instead of E010
389 //Which causes a CPCOND0 to fail.
390 icase(DMAC_FAKESTAT)
391 {
392 DevCon.Warning("Midway fixup addr=%x writing %x for DMA_STAT", mem, value);
393 HW_LOG("Midways own DMAC_STAT Write 32bit %x", value);
394
395 // lower 16 bits: clear on 1
396 // upper 16 bits: reverse on 1
397
398 psHu16(0xe010) &= ~(value & 0xffff);
399 psHu16(0xe012) ^= (u16)(value >> 16);
400
401 cpuTestDMACInts();
402 return false;
403 }
404 icase(DMAC_STAT)
405 {
406 HW_LOG("DMAC_STAT Write 32bit %x", value);
407
408 // lower 16 bits: clear on 1
409 // upper 16 bits: reverse on 1
410
411 psHu16(0xe010) &= ~(value & 0xffff);
412 psHu16(0xe012) ^= (u16)(value >> 16);
413
414 cpuTestDMACInts();
415 return false;
416 }
417
418 icase(DMAC_ENABLEW)
419 {
420 HW_LOG("DMAC_ENABLEW Write 32bit %lx", value);
421 oldvalue = psHu8(DMAC_ENABLEW + 2);
422 psHu32(DMAC_ENABLEW) = value;
423 psHu32(DMAC_ENABLER) = value;
424 if (((oldvalue & 0x1) == 1) && (((value >> 16) & 0x1) == 0))
425 {
426 if (!QueuedDMA.empty()) StartQueuedDMA();
427 }
428 return false;
429 }
430 }
431
432 //DMA Writes are invalid to everything except the STR on CHCR when it is busy
433 if((mem & 0xf0))
434 {
435 if((psHu32(mem & ~0xff) & 0x100) && dmacRegs.ctrl.DMAE && !psHu8(DMAC_ENABLER+2))
436 {
437 DevCon.Warning("Write to DMA addr %x while STR is busy! Ignoring", mem);
438 return false;
439 }
440 }
441
442 // fall-through: use the default writeback provided by caller.
443 return true;
444 }
445
446 template u32 dmacRead32<0x03>( u32 mem );
447
448 template bool dmacWrite32<0x00>( u32 mem, mem32_t& value );
449 template bool dmacWrite32<0x01>( u32 mem, mem32_t& value );
450 template bool dmacWrite32<0x02>( u32 mem, mem32_t& value );
451 template bool dmacWrite32<0x03>( u32 mem, mem32_t& value );
452 template bool dmacWrite32<0x04>( u32 mem, mem32_t& value );
453 template bool dmacWrite32<0x05>( u32 mem, mem32_t& value );
454 template bool dmacWrite32<0x06>( u32 mem, mem32_t& value );
455 template bool dmacWrite32<0x07>( u32 mem, mem32_t& value );
456 template bool dmacWrite32<0x08>( u32 mem, mem32_t& value );
457 template bool dmacWrite32<0x09>( u32 mem, mem32_t& value );
458 template bool dmacWrite32<0x0a>( u32 mem, mem32_t& value );
459 template bool dmacWrite32<0x0b>( u32 mem, mem32_t& value );
460 template bool dmacWrite32<0x0c>( u32 mem, mem32_t& value );
461 template bool dmacWrite32<0x0d>( u32 mem, mem32_t& value );
462 template bool dmacWrite32<0x0e>( u32 mem, mem32_t& value );
463 template bool dmacWrite32<0x0f>( u32 mem, mem32_t& value );

  ViewVC Help
Powered by ViewVC 1.1.22