Commit | Line | Data |
---|---|---|
ef79bbde P |
1 | /*************************************************************************** |
2 | * Copyright (C) 2007 Ryan Schultz, PCSX-df Team, PCSX team * | |
3 | * * | |
4 | * This program is free software; you can redistribute it and/or modify * | |
5 | * it under the terms of the GNU General Public License as published by * | |
6 | * the Free Software Foundation; either version 2 of the License, or * | |
7 | * (at your option) any later version. * | |
8 | * * | |
9 | * This program is distributed in the hope that it will be useful, * | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of * | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * | |
12 | * GNU General Public License for more details. * | |
13 | * * | |
14 | * You should have received a copy of the GNU General Public License * | |
15 | * along with this program; if not, write to the * | |
16 | * Free Software Foundation, Inc., * | |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA. * | |
18 | ***************************************************************************/ | |
19 | ||
20 | /* | |
21 | * Handles PSX DMA functions. | |
22 | */ | |
23 | ||
24 | #include "psxdma.h" | |
25 | ||
26 | // Dma0/1 in Mdec.c | |
27 | // Dma3 in CdRom.c | |
28 | ||
29 | void spuInterrupt() { | |
ad418c19 | 30 | if (HW_DMA4_CHCR & SWAP32(0x01000000)) |
31 | { | |
32 | HW_DMA4_CHCR &= SWAP32(~0x01000000); | |
33 | DMA_INTERRUPT(4); | |
34 | } | |
ef79bbde P |
35 | } |
36 | ||
37 | void psxDma4(u32 madr, u32 bcr, u32 chcr) { // SPU | |
38 | u16 *ptr; | |
39 | u32 size; | |
40 | ||
41 | switch (chcr) { | |
42 | case 0x01000201: //cpu to spu transfer | |
43 | #ifdef PSXDMA_LOG | |
44 | PSXDMA_LOG("*** DMA4 SPU - mem2spu *** %x addr = %x size = %x\n", chcr, madr, bcr); | |
45 | #endif | |
46 | ptr = (u16 *)PSXM(madr); | |
47 | if (ptr == NULL) { | |
48 | #ifdef CPU_LOG | |
49 | CPU_LOG("*** DMA4 SPU - mem2spu *** NULL Pointer!!!\n"); | |
50 | #endif | |
51 | break; | |
52 | } | |
53 | SPU_writeDMAMem(ptr, (bcr >> 16) * (bcr & 0xffff) * 2); | |
54 | SPUDMA_INT((bcr >> 16) * (bcr & 0xffff) / 2); | |
55 | return; | |
56 | ||
57 | case 0x01000200: //spu to cpu transfer | |
58 | #ifdef PSXDMA_LOG | |
59 | PSXDMA_LOG("*** DMA4 SPU - spu2mem *** %x addr = %x size = %x\n", chcr, madr, bcr); | |
60 | #endif | |
61 | ptr = (u16 *)PSXM(madr); | |
62 | if (ptr == NULL) { | |
63 | #ifdef CPU_LOG | |
64 | CPU_LOG("*** DMA4 SPU - spu2mem *** NULL Pointer!!!\n"); | |
65 | #endif | |
66 | break; | |
67 | } | |
68 | size = (bcr >> 16) * (bcr & 0xffff) * 2; | |
69 | SPU_readDMAMem(ptr, size); | |
70 | psxCpu->Clear(madr, size); | |
71 | break; | |
72 | ||
73 | #ifdef PSXDMA_LOG | |
74 | default: | |
75 | PSXDMA_LOG("*** DMA4 SPU - unknown *** %x addr = %x size = %x\n", chcr, madr, bcr); | |
76 | break; | |
77 | #endif | |
78 | } | |
79 | ||
80 | HW_DMA4_CHCR &= SWAP32(~0x01000000); | |
81 | DMA_INTERRUPT(4); | |
82 | } | |
83 | ||
57a757ce | 84 | // Taken from PEOPS SOFTGPU |
85 | static inline boolean CheckForEndlessLoop(u32 laddr, u32 *lUsedAddr) { | |
86 | if (laddr == lUsedAddr[1]) return TRUE; | |
87 | if (laddr == lUsedAddr[2]) return TRUE; | |
88 | ||
89 | if (laddr < lUsedAddr[0]) lUsedAddr[1] = laddr; | |
90 | else lUsedAddr[2] = laddr; | |
91 | ||
92 | lUsedAddr[0] = laddr; | |
93 | ||
94 | return FALSE; | |
95 | } | |
96 | ||
97 | static u32 gpuDmaChainSize(u32 addr) { | |
98 | u32 size; | |
99 | u32 DMACommandCounter = 0; | |
100 | u32 lUsedAddr[3]; | |
101 | ||
102 | lUsedAddr[0] = lUsedAddr[1] = lUsedAddr[2] = 0xffffff; | |
103 | ||
104 | // initial linked list ptr (word) | |
105 | size = 1; | |
106 | ||
107 | do { | |
108 | addr &= 0x1ffffc; | |
109 | ||
110 | if (DMACommandCounter++ > 2000000) break; | |
111 | if (CheckForEndlessLoop(addr, lUsedAddr)) break; | |
112 | ||
113 | // # 32-bit blocks to transfer | |
114 | size += psxMu8( addr + 3 ); | |
115 | ||
116 | // next 32-bit pointer | |
117 | addr = psxMu32( addr & ~0x3 ) & 0xffffff; | |
118 | size += 1; | |
119 | } while (addr != 0xffffff); | |
120 | ||
121 | return size; | |
122 | } | |
123 | ||
ef79bbde P |
124 | void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU |
125 | u32 *ptr; | |
126 | u32 size; | |
127 | ||
57a757ce | 128 | switch (chcr) { |
ef79bbde P |
129 | case 0x01000200: // vram2mem |
130 | #ifdef PSXDMA_LOG | |
57a757ce | 131 | PSXDMA_LOG("*** DMA2 GPU - vram2mem *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); |
ef79bbde P |
132 | #endif |
133 | ptr = (u32 *)PSXM(madr); | |
134 | if (ptr == NULL) { | |
135 | #ifdef CPU_LOG | |
136 | CPU_LOG("*** DMA2 GPU - vram2mem *** NULL Pointer!!!\n"); | |
137 | #endif | |
138 | break; | |
139 | } | |
57a757ce | 140 | // BA blocks * BS words (word = 32-bits) |
ef79bbde P |
141 | size = (bcr >> 16) * (bcr & 0xffff); |
142 | GPU_readDataMem(ptr, size); | |
143 | psxCpu->Clear(madr, size); | |
57a757ce | 144 | |
145 | // already 32-bit word size ((size * 4) / 4) | |
916a765b | 146 | GPUDMA_INT(size / 4); |
57a757ce | 147 | return; |
ef79bbde P |
148 | |
149 | case 0x01000201: // mem2vram | |
150 | #ifdef PSXDMA_LOG | |
57a757ce | 151 | PSXDMA_LOG("*** DMA 2 - GPU mem2vram *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); |
ef79bbde P |
152 | #endif |
153 | ptr = (u32 *)PSXM(madr); | |
154 | if (ptr == NULL) { | |
155 | #ifdef CPU_LOG | |
156 | CPU_LOG("*** DMA2 GPU - mem2vram *** NULL Pointer!!!\n"); | |
157 | #endif | |
158 | break; | |
159 | } | |
57a757ce | 160 | // BA blocks * BS words (word = 32-bits) |
ef79bbde P |
161 | size = (bcr >> 16) * (bcr & 0xffff); |
162 | GPU_writeDataMem(ptr, size); | |
57a757ce | 163 | |
164 | // already 32-bit word size ((size * 4) / 4) | |
916a765b | 165 | GPUDMA_INT(size / 4); |
ef79bbde P |
166 | return; |
167 | ||
168 | case 0x01000401: // dma chain | |
169 | #ifdef PSXDMA_LOG | |
57a757ce | 170 | PSXDMA_LOG("*** DMA 2 - GPU dma chain *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); |
ef79bbde | 171 | #endif |
57a757ce | 172 | |
b03e0caf | 173 | size = GPU_dmaChain((u32 *)psxM, madr & 0x1fffff); |
174 | if ((int)size <= 0) | |
175 | size = gpuDmaChainSize(madr); | |
57a757ce | 176 | |
177 | // Tekken 3 = use 1.0 only (not 1.5x) | |
178 | ||
179 | // Einhander = parse linked list in pieces (todo) | |
180 | // Final Fantasy 4 = internal vram time (todo) | |
181 | // Rebel Assault 2 = parse linked list in pieces (todo) | |
182 | // Vampire Hunter D = allow edits to linked list (todo) | |
183 | GPUDMA_INT(size); | |
184 | return; | |
ef79bbde P |
185 | |
186 | #ifdef PSXDMA_LOG | |
187 | default: | |
57a757ce | 188 | PSXDMA_LOG("*** DMA 2 - GPU unknown *** %lx addr = %lx size = %lx\n", chcr, madr, bcr); |
ef79bbde P |
189 | break; |
190 | #endif | |
191 | } | |
192 | ||
193 | HW_DMA2_CHCR &= SWAP32(~0x01000000); | |
194 | DMA_INTERRUPT(2); | |
195 | } | |
196 | ||
197 | void gpuInterrupt() { | |
ad418c19 | 198 | if (HW_DMA2_CHCR & SWAP32(0x01000000)) |
199 | { | |
200 | HW_DMA2_CHCR &= SWAP32(~0x01000000); | |
201 | DMA_INTERRUPT(2); | |
202 | } | |
ef79bbde P |
203 | } |
204 | ||
205 | void psxDma6(u32 madr, u32 bcr, u32 chcr) { | |
57a757ce | 206 | u32 size; |
ef79bbde P |
207 | u32 *mem = (u32 *)PSXM(madr); |
208 | ||
209 | #ifdef PSXDMA_LOG | |
210 | PSXDMA_LOG("*** DMA6 OT *** %x addr = %x size = %x\n", chcr, madr, bcr); | |
211 | #endif | |
212 | ||
213 | if (chcr == 0x11000002) { | |
214 | if (mem == NULL) { | |
215 | #ifdef CPU_LOG | |
216 | CPU_LOG("*** DMA6 OT *** NULL Pointer!!!\n"); | |
217 | #endif | |
218 | HW_DMA6_CHCR &= SWAP32(~0x01000000); | |
219 | DMA_INTERRUPT(6); | |
220 | return; | |
221 | } | |
222 | ||
57a757ce | 223 | // already 32-bit size |
224 | size = bcr; | |
225 | ||
ef79bbde P |
226 | while (bcr--) { |
227 | *mem-- = SWAP32((madr - 4) & 0xffffff); | |
228 | madr -= 4; | |
229 | } | |
230 | mem++; *mem = 0xffffff; | |
57a757ce | 231 | |
232 | GPUOTCDMA_INT(size); | |
233 | return; | |
ef79bbde P |
234 | } |
235 | #ifdef PSXDMA_LOG | |
236 | else { | |
237 | // Unknown option | |
238 | PSXDMA_LOG("*** DMA6 OT - unknown *** %x addr = %x size = %x\n", chcr, madr, bcr); | |
239 | } | |
240 | #endif | |
241 | ||
242 | HW_DMA6_CHCR &= SWAP32(~0x01000000); | |
243 | DMA_INTERRUPT(6); | |
244 | } | |
245 | ||
57a757ce | 246 | void gpuotcInterrupt() |
247 | { | |
ad418c19 | 248 | if (HW_DMA6_CHCR & SWAP32(0x01000000)) |
249 | { | |
250 | HW_DMA6_CHCR &= SWAP32(~0x01000000); | |
251 | DMA_INTERRUPT(6); | |
252 | } | |
57a757ce | 253 | } |