/[pcsx2_0.9.7]/trunk/pcsx2/Dmac.h
ViewVC logotype

Annotation of /trunk/pcsx2/Dmac.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10 - (hide annotations) (download)
Mon Sep 6 11:40:06 2010 UTC (9 years, 9 months ago) by william
File MIME type: text/plain
File size: 15783 byte(s)
exported r3113 from ./upstream/trunk
1 william 10 /* 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     #ifndef __DMAC_H__
18     #define __DMAC_H__
19    
20     extern u8 *psH; // hw mem
21    
22     // Useful enums for some of the fields.
23     enum pce_values
24     {
25     PCE_NOTHING = 0,
26     PCE_RESERVED,
27     PCE_DISABLED,
28     PCE_ENABLED
29     };
30    
31    
32     enum tag_id
33     {
34     TAG_CNTS = 0,
35     TAG_REFE = 0, // Transfer Packet According to ADDR field, clear STR, and end
36     TAG_CNT, // Transfer QWC following the tag.
37     TAG_NEXT, // Transfer QWC following tag. TADR = ADDR
38     TAG_REF, // Transfer QWC from ADDR field
39     TAG_REFS, // Transfer QWC from ADDR field (Stall Control)
40     TAG_CALL, // Transfer QWC following the tag, save succeeding tag
41     TAG_RET, // Transfer QWC following the tag, load next tag
42     TAG_END // Transfer QWC following the tag
43     };
44    
45     enum mfd_type
46     {
47     NO_MFD = 0,
48     MFD_RESERVED,
49     MFD_VIF1,
50     MFD_GIF
51     };
52    
53     enum sts_type
54     {
55     NO_STS = 0,
56     STS_SIF0,
57     STS_fromSPR,
58     STS_fromIPU
59     };
60    
61     enum std_type
62     {
63     NO_STD = 0,
64     STD_VIF1,
65     STD_GIF,
66     STD_SIF1
67     };
68    
69     enum TransferMode
70     {
71     NORMAL_MODE = 0,
72     CHAIN_MODE,
73     INTERLEAVE_MODE,
74     UNDEFINED_MODE
75     };
76    
77     //
78     // --- DMA ---
79     //
80    
81     // Doing double duty as both the top 32 bits *and* the lower 32 bits of a chain tag.
82     // Theoretically should probably both be in a u64 together, but with the way the
83     // code is layed out, this is easier for the moment.
84    
85     union tDMA_TAG {
86     struct {
87     u32 QWC : 16;
88     u32 reserved2 : 10;
89     u32 PCE : 2;
90     u32 ID : 3;
91     u32 IRQ : 1;
92     };
93     struct {
94     u32 ADDR : 31;
95     u32 SPR : 1;
96     };
97     u32 _u32;
98    
99     tDMA_TAG(u32 val) { _u32 = val; }
100     u16 upper() const { return (_u32 >> 16); }
101     u16 lower() const { return (u16)_u32; }
102     wxString tag_to_str() const
103     {
104     switch(ID)
105     {
106     case TAG_REFE: return wxsFormat(L"REFE %08X", _u32); break;
107     case TAG_CNT: return L"CNT"; break;
108     case TAG_NEXT: return wxsFormat(L"NEXT %08X", _u32); break;
109     case TAG_REF: return wxsFormat(L"REF %08X", _u32); break;
110     case TAG_REFS: return wxsFormat(L"REFS %08X", _u32); break;
111     case TAG_CALL: return L"CALL"; break;
112     case TAG_RET: return L"RET"; break;
113     case TAG_END: return L"END"; break;
114     default: return L"????"; break;
115     }
116     }
117     void reset() { _u32 = 0; }
118     };
119     #define DMA_TAG(value) ((tDMA_TAG)(value))
120    
121     union tDMA_CHCR {
122     struct {
123     u32 DIR : 1; // Direction: 0 - to memory, 1 - from memory. VIF1 & SIF2 only.
124     u32 reserved1 : 1;
125     u32 MOD : 2;
126     u32 ASP : 2; // ASP1 & ASP2; Address stack pointer. 0, 1, or 2 addresses.
127     u32 TTE : 1; // Tag Transfer Enable. 0 - Disable / 1 - Enable.
128     u32 TIE : 1; // Tag Interrupt Enable. 0 - Disable / 1 - Enable.
129     u32 STR : 1; // Start. 0 while stopping DMA, 1 while it's running.
130     u32 reserved2 : 7;
131     u32 TAG : 16;
132     };
133     u32 _u32;
134    
135     tDMA_CHCR( u32 val) { _u32 = val; }
136    
137     bool test(u32 flags) const { return !!(_u32 & flags); }
138     void set(u32 value) { _u32 = value; }
139     void set_flags(u32 flags) { _u32 |= flags; }
140     void clear_flags(u32 flags) { _u32 &= ~flags; }
141     void reset() { _u32 = 0; }
142     u16 upper() const { return (_u32 >> 16); }
143     u16 lower() const { return (u16)_u32; }
144     wxString desc() const { return wxsFormat(L"Chcr: 0x%x", _u32); }
145     };
146    
147     #define CHCR(value) ((tDMA_CHCR)(value))
148    
149     union tDMA_SADR {
150     struct {
151     u32 ADDR : 14;
152     u32 reserved2 : 18;
153     };
154     u32 _u32;
155    
156     tDMA_SADR(u32 val) { _u32 = val; }
157    
158     void reset() { _u32 = 0; }
159     wxString desc() const { return wxsFormat(L"Sadr: 0x%x", _u32); }
160     };
161    
162     union tDMA_MADR {
163     struct {
164     u32 ADDR : 31; // Transfer memory address
165     u32 SPR : 1; // Memory/SPR Address
166     };
167     u32 _u32;
168    
169     tDMA_MADR(u32 val) { _u32 = val; }
170    
171     void reset() { _u32 = 0; }
172     wxString desc() const { return wxsFormat(L"Madr: 0x%x", _u32); }
173     };
174    
175     union tDMA_TADR {
176     struct {
177     u32 ADDR : 31; // Next Tag address
178     u32 SPR : 1; // Memory/SPR Address
179     };
180     u32 _u32;
181    
182     tDMA_TADR(u32 val) { _u32 = val; }
183    
184     void reset() { _u32 = 0; }
185     wxString desc() const { return wxsFormat(L"Tadr: 0x%x", _u32); }
186     };
187    
188     union tDMA_ASR { // The Address Stack Register
189     struct {
190     u32 ADDR : 31; // Tag memory address
191     u32 SPR : 1; // Memory/SPR Address
192     };
193     u32 _u32;
194    
195     tDMA_ASR(u32 val) { _u32 = val; }
196    
197     void reset() { _u32 = 0; }
198     wxString desc() const { return wxsFormat(L"Asr: 0x%x", _u32); }
199     };
200    
201     union tDMA_QWC {
202     struct {
203     u32 QWC : 16;
204     u32 reserved2 : 16;
205     };
206     u32 _u32;
207    
208     tDMA_QWC(u32 val) { _u32 = val; }
209    
210     void reset() { _u32 = 0; }
211     wxString desc() const { return wxsFormat(L"QWC: 0x%x", _u32); }
212     };
213     static __forceinline void setDmacStat(u32 num);
214     static __forceinline tDMA_TAG *dmaGetAddr(u32 addr, bool write);
215     static __forceinline void throwBusError(const char *s);
216    
217     struct DMACh {
218     tDMA_CHCR chcr;
219     u32 null0[3];
220     u32 madr;
221     u32 null1[3];
222     u16 qwc; u16 pad;
223     u32 null2[3];
224     u32 tadr;
225     u32 null3[3];
226     u32 asr0;
227     u32 null4[3];
228     u32 asr1;
229     u32 null5[11];
230     u32 sadr;
231    
232     void chcrTransfer(tDMA_TAG* ptag)
233     {
234     chcr.TAG = ptag[0].upper();
235     }
236    
237     void qwcTransfer(tDMA_TAG* ptag)
238     {
239     qwc = ptag[0].QWC;
240     }
241    
242     bool transfer(const char *s, tDMA_TAG* ptag)
243     {
244     if (ptag == NULL) // Is ptag empty?
245     {
246     throwBusError(s);
247     return false;
248     }
249     chcrTransfer(ptag);
250    
251     qwcTransfer(ptag);
252     return true;
253     }
254    
255     void unsafeTransfer(tDMA_TAG* ptag)
256     {
257     chcrTransfer(ptag);
258     qwcTransfer(ptag);
259     }
260    
261     tDMA_TAG *getAddr(u32 addr, u32 num, bool write)
262     {
263     tDMA_TAG *ptr = dmaGetAddr(addr, write);
264     if (ptr == NULL)
265     {
266     throwBusError("dmaGetAddr");
267     setDmacStat(num);
268     chcr.STR = false;
269     }
270    
271     return ptr;
272     }
273    
274     tDMA_TAG *DMAtransfer(u32 addr, u32 num)
275     {
276     tDMA_TAG *tag = getAddr(addr, num, false);
277    
278     if (tag == NULL) return NULL;
279    
280     chcrTransfer(tag);
281     qwcTransfer(tag);
282     return tag;
283     }
284    
285     tDMA_TAG dma_tag() const
286     {
287     return DMA_TAG(chcr._u32);
288     }
289    
290     wxString cmq_to_str() const
291     {
292     return wxsFormat(L"chcr = %lx, madr = %lx, qwc = %lx", chcr._u32, madr, qwc);
293     }
294    
295     wxString cmqt_to_str() const
296     {
297     return wxsFormat(L"chcr = %lx, madr = %lx, qwc = %lx, tadr = %1x", chcr._u32, madr, qwc, tadr);
298     }
299     };
300    
301     enum INTCIrqs
302     {
303     INTC_GS = 0,
304     INTC_SBUS,
305     INTC_VBLANK_S,
306     INTC_VBLANK_E,
307     INTC_VIF0,
308     INTC_VIF1,
309     INTC_VU0,
310     INTC_VU1,
311     INTC_IPU,
312     INTC_TIM0,
313     INTC_TIM1,
314     INTC_TIM2,
315     INTC_TIM3,
316     INTC_SFIFO,
317     INTVU0_WD
318     };
319    
320     enum dmac_conditions
321     {
322     DMAC_STAT_SIS = (1<<13), // stall condition
323     DMAC_STAT_MEIS = (1<<14), // mfifo empty
324     DMAC_STAT_BEIS = (1<<15), // bus error
325     DMAC_STAT_SIM = (1<<29), // stall mask
326     DMAC_STAT_MEIM = (1<<30) // mfifo mask
327     };
328    
329     enum DMACIrqs
330     {
331     DMAC_VIF0 = 0,
332     DMAC_VIF1,
333     DMAC_GIF,
334     DMAC_FROM_IPU,
335     DMAC_TO_IPU,
336     DMAC_SIF0,
337     DMAC_SIF1,
338     DMAC_SIF2,
339     DMAC_FROM_SPR,
340     DMAC_TO_SPR,
341    
342     // We're setting error conditions through hwDmacIrq, so these correspond to the conditions above.
343     DMAC_STALL_SIS = 13, // SIS
344     DMAC_MFIFO_EMPTY = 14, // MEIS
345     DMAC_BUS_ERROR = 15 // BEIS
346     };
347    
348     //DMA interrupts & masks
349     enum DMAInter
350     {
351     BEISintr = 0x00008000,
352     VIF0intr = 0x00010001,
353     VIF1intr = 0x00020002,
354     GIFintr = 0x00040004,
355     IPU0intr = 0x00080008,
356     IPU1intr = 0x00100010,
357     SIF0intr = 0x00200020,
358     SIF1intr = 0x00400040,
359     SIF2intr = 0x00800080,
360     SPR0intr = 0x01000100,
361     SPR1intr = 0x02000200,
362     SISintr = 0x20002000,
363     MEISintr = 0x40004000
364     };
365    
366     union tDMAC_QUEUE
367     {
368     struct
369     {
370     u16 VIF0 : 1;
371     u16 VIF1 : 1;
372     u16 GIF : 1;
373     u16 IPU0 : 1;
374     u16 IPU1 : 1;
375     u16 SIF0 : 1;
376     u16 SIF1 : 1;
377     u16 SIF2 : 1;
378     u16 SPR0 : 1;
379     u16 SPR1 : 1;
380     u16 SIS : 1;
381     u16 MEIS : 1;
382     u16 BEIS : 1;
383     };
384     u16 _u16;
385    
386     tDMAC_QUEUE(u16 val) { _u16 = val; }
387     void reset() { _u16 = 0; }
388     bool empty() const { return (_u16 == 0); }
389     };
390    
391     static __forceinline const wxChar* ChcrName(u32 addr)
392     {
393     switch (addr)
394     {
395     case D0_CHCR: return L"Vif 0";
396     case D1_CHCR: return L"Vif 1";
397     case D2_CHCR: return L"GIF";
398     case D3_CHCR: return L"Ipu 0";
399     case D4_CHCR: return L"Ipu 1";
400     case D5_CHCR: return L"Sif 0";
401     case D6_CHCR: return L"Sif 1";
402     case D7_CHCR: return L"Sif 2";
403     case D8_CHCR: return L"SPR 0";
404     case D9_CHCR: return L"SPR 1";
405     default: return L"???";
406     }
407     }
408    
409     // Believe it or not, making this const can generate compiler warnings in gcc.
410     static __forceinline int ChannelNumber(u32 addr)
411     {
412     switch (addr)
413     {
414     case D0_CHCR: return 0;
415     case D1_CHCR: return 1;
416     case D2_CHCR: return 2;
417     case D3_CHCR: return 3;
418     case D4_CHCR: return 4;
419     case D5_CHCR: return 5;
420     case D6_CHCR: return 6;
421     case D7_CHCR: return 7;
422     case D8_CHCR: return 8;
423     case D9_CHCR: return 9;
424     default:
425     {
426     DevCon.Warning("Invalid DMA channel number");
427     return 51; // some value
428     }
429     }
430     }
431    
432     union tDMAC_CTRL {
433     struct {
434     u32 DMAE : 1; // 0/1 - disables/enables all DMAs
435     u32 RELE : 1; // 0/1 - cycle stealing off/on
436     u32 MFD : 2; // Memory FIFO drain channel (mfd_type)
437     u32 STS : 2; // Stall Control source channel (sts type)
438     u32 STD : 2; // Stall Control drain channel (std_type)
439     u32 RCYC : 3; // Release cycle (8/16/32/64/128/256)
440     u32 reserved1 : 21;
441     };
442     u32 _u32;
443    
444     tDMAC_CTRL(u32 val) { _u32 = val; }
445    
446     bool test(u32 flags) const { return !!(_u32 & flags); }
447     void set_flags(u32 flags) { _u32 |= flags; }
448     void clear_flags(u32 flags) { _u32 &= ~flags; }
449     void reset() { _u32 = 0; }
450     wxString desc() const { return wxsFormat(L"Ctrl: 0x%x", _u32); }
451     };
452    
453     union tDMAC_STAT {
454     struct {
455     u32 CIS : 10;
456     u32 reserved1 : 3;
457     u32 SIS : 1;
458     u32 MEIS : 1;
459     u32 BEIS : 1;
460     u32 CIM : 10;
461     u32 reserved2 : 3;
462     u32 SIM : 1;
463     u32 MEIM : 1;
464     u32 reserved3 : 1;
465     };
466     u32 _u32;
467    
468     tDMAC_STAT(u32 val) { _u32 = val; }
469    
470     bool test(u32 flags) const { return !!(_u32 & flags); }
471     void set_flags(u32 flags) { _u32 |= flags; }
472     void clear_flags(u32 flags) { _u32 &= ~flags; }
473     void reset() { _u32 = 0; }
474     wxString desc() const { return wxsFormat(L"Stat: 0x%x", _u32); }
475     };
476    
477     union tDMAC_PCR {
478     struct {
479     u32 CPC : 10;
480     u32 reserved1 : 6;
481     u32 CDE : 10;
482     u32 reserved2 : 5;
483     u32 PCE : 1;
484     };
485     u32 _u32;
486    
487     tDMAC_PCR(u32 val) { _u32 = val; }
488    
489     bool test(u32 flags) const { return !!(_u32 & flags); }
490     void set_flags(u32 flags) { _u32 |= flags; }
491     void clear_flags(u32 flags) { _u32 &= ~flags; }
492     void reset() { _u32 = 0; }
493     wxString desc() const { return wxsFormat(L"Pcr: 0x%x", _u32); }
494     };
495    
496     union tDMAC_SQWC {
497     struct {
498     u32 SQWC : 8;
499     u32 reserved1 : 8;
500     u32 TQWC : 8;
501     u32 reserved2 : 8;
502     };
503     u32 _u32;
504    
505     tDMAC_SQWC(u32 val) { _u32 = val; }
506    
507     bool test(u32 flags) const { return !!(_u32 & flags); }
508     void set_flags(u32 flags) { _u32 |= flags; }
509     void clear_flags(u32 flags) { _u32 &= ~flags; }
510     void reset() { _u32 = 0; }
511     wxString desc() const { return wxsFormat(L"Sqwc: 0x%x", _u32); }
512     };
513    
514     union tDMAC_RBSR {
515     struct {
516     u32 RMSK : 31;
517     u32 reserved1 : 1;
518     };
519     u32 _u32;
520    
521     tDMAC_RBSR(u32 val) { _u32 = val; }
522    
523     void reset() { _u32 = 0; }
524     wxString desc() const { return wxsFormat(L"Rbsr: 0x%x", _u32); }
525     };
526    
527     union tDMAC_RBOR {
528     struct {
529     u32 ADDR : 31;
530     u32 reserved1 : 1;
531     };
532     u32 _u32;
533    
534     tDMAC_RBOR(u32 val) { _u32 = val; }
535    
536     void reset() { _u32 = 0; }
537     wxString desc() const { return wxsFormat(L"Rbor: 0x%x", _u32); }
538     };
539    
540     union tDMAC_STADR {
541     struct {
542     u32 ADDR : 31;
543     u32 reserved1 : 1;
544     };
545     u32 _u32;
546    
547     tDMAC_STADR(u32 val) { _u32 = val; }
548    
549     void reset() { _u32 = 0; }
550     wxString desc() const { return wxsFormat(L"Stadr: 0x%x", _u32); }
551     };
552    
553    
554     struct DMACregisters
555     {
556     tDMAC_CTRL ctrl;
557     u32 padding[3];
558     tDMAC_STAT stat;
559     u32 padding1[3];
560     tDMAC_PCR pcr;
561     u32 padding2[3];
562    
563     tDMAC_SQWC sqwc;
564     u32 padding3[3];
565     tDMAC_RBSR rbsr;
566     u32 padding4[3];
567     tDMAC_RBOR rbor;
568     u32 padding5[3];
569     tDMAC_STADR stadr;
570     };
571    
572     // Currently guesswork.
573     union tINTC_STAT {
574     struct {
575     u32 interrupts : 10;
576     u32 placeholder : 22;
577     };
578     u32 _u32;
579    
580     tINTC_STAT(u32 val) { _u32 = val; }
581    
582     bool test(u32 flags) const { return !!(_u32 & flags); }
583     void set_flags(u32 flags) { _u32 |= flags; }
584     void clear_flags(u32 flags) { _u32 &= ~flags; }
585     void reset() { _u32 = 0; }
586     wxString desc() const { return wxsFormat(L"Stat: 0x%x", _u32); }
587     };
588    
589     union tINTC_MASK {
590     struct {
591     u32 int_mask : 10;
592     u32 placeholder:22;
593     };
594     u32 _u32;
595    
596     tINTC_MASK(u32 val) { _u32 = val; }
597    
598     bool test(u32 flags) const { return !!(_u32 & flags); }
599     void set_flags(u32 flags) { _u32 |= flags; }
600     void clear_flags(u32 flags) { _u32 &= ~flags; }
601     void reset() { _u32 = 0; }
602     wxString desc() const { return wxsFormat(L"Mask: 0x%x", _u32); }
603     };
604    
605     struct INTCregisters
606     {
607     tINTC_STAT stat;
608     u32 padding[3];
609     tINTC_MASK mask;
610     };
611    
612     #define dmacRegs ((DMACregisters*)(PS2MEM_HW+0xE000))
613     #define intcRegs ((INTCregisters*)(PS2MEM_HW+0xF000))
614    
615     static __forceinline void throwBusError(const char *s)
616     {
617     Console.Error("%s BUSERR", s);
618     dmacRegs->stat.BEIS = true;
619     }
620    
621     static __forceinline void setDmacStat(u32 num)
622     {
623     dmacRegs->stat.set_flags(1 << num);
624     }
625    
626     // Note: Dma addresses are guaranteed to be aligned to 16 bytes (128 bits)
627     static __forceinline tDMA_TAG *SPRdmaGetAddr(u32 addr, bool write)
628     {
629     // if (addr & 0xf) { DMA_LOG("*PCSX2*: DMA address not 128bit aligned: %8.8x", addr); }
630    
631     // FIXME: Why??? DMA uses physical addresses
632     addr &= 0x1ffffff0;
633    
634     if (addr < Ps2MemSize::Base)
635     {
636     return (tDMA_TAG*)&psM[addr];
637     }
638    
639     if (addr >= 0x11004000 && addr < 0x11010000)
640     {
641     //Access for VU Memory
642     return (tDMA_TAG*)vtlb_GetPhyPtr(addr & 0x1FFFFFF0);
643     }
644    
645     if (addr >= Ps2MemSize::Base && addr < 0x10000000)
646     {
647     return (tDMA_TAG*)(write ? psMHW : psMHR);
648     }
649    
650     Console.Error( "*PCSX2*: DMA error: %8.8x", addr);
651     return NULL;
652     }
653    
654     // Note: Dma addresses are guaranteed to be aligned to 16 bytes (128 bits)
655     static __forceinline tDMA_TAG *dmaGetAddr(u32 addr, bool write)
656     {
657     // if (addr & 0xf) { DMA_LOG("*PCSX2*: DMA address not 128bit aligned: %8.8x", addr); }
658    
659     if (DMA_TAG(addr).SPR) return (tDMA_TAG*)&psS[addr & 0x3ff0];
660    
661     // FIXME: Why??? DMA uses physical addresses
662     addr &= 0x1ffffff0;
663    
664     if (addr < Ps2MemSize::Base)
665     {
666     return (tDMA_TAG*)&psM[addr];
667     }
668    
669     // Secret scratchpad address for DMA = end of maximum main memory?
670     if (addr >= 0x10000000 && addr < 0x10004000)
671     {
672     //Console.Warning("Writing to the scratchpad without the SPR flag set!");
673     return (tDMA_TAG*)&psS[addr & 0x3ff0];
674     }
675    
676     if (addr >= Ps2MemSize::Base && addr < 0x10000000)
677     {
678     return (tDMA_TAG*)(write ? psMHW : psMHR);
679     }
680    
681     Console.Error( "*PCSX2*: DMA error: %8.8x", addr);
682     return NULL;
683     }
684    
685     void hwIntcIrq(int n);
686     void hwDmacIrq(int n);
687    
688     bool hwDmacSrcChainWithStack(DMACh *dma, int id);
689     bool hwDmacSrcChain(DMACh *dma, int id);
690    
691     extern void intcInterrupt();
692     extern void dmacInterrupt();
693    
694     #endif

  ViewVC Help
Powered by ViewVC 1.1.22