ALL: Huge upstream synch + PerRom DelaySI & CountPerOp parameters
[mupen64plus-pandora.git] / source / mupen64plus-core / src / memory / dma.c
CommitLineData
451ab91e 1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Mupen64plus - dma.c *
3 * Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
4 * Copyright (C) 2002 Hacktarux *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
20 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21
22#include <stdlib.h>
23#include <string.h>
24#include <stdio.h>
25
26#include "api/m64p_types.h"
27
28#include "dma.h"
29#include "memory.h"
30#include "pif.h"
31#include "flashram.h"
32
33#include "r4300/r4300.h"
34#include "r4300/interupt.h"
35#include "r4300/macros.h"
36#include "r4300/ops.h"
37#include "../r4300/new_dynarec/new_dynarec.h"
38
39#define M64P_CORE_PROTOTYPES 1
40#include "api/m64p_config.h"
41#include "api/config.h"
42#include "api/callbacks.h"
43#include "main/main.h"
44#include "main/rom.h"
45#include "main/util.h"
46
47static unsigned char sram[0x8000];
2d262872 48int delay_si = 0;
451ab91e 49
50static char *get_sram_path(void)
51{
52 return formatstr("%s%s.sra", get_savesrampath(), ROM_SETTINGS.goodname);
53}
54
55static void sram_format(void)
56{
57 memset(sram, 0, sizeof(sram));
58}
59
60static void sram_read_file(void)
61{
62 char *filename = get_sram_path();
63
64 sram_format();
65 switch (read_from_file(filename, sram, sizeof(sram)))
66 {
67 case file_open_error:
68 DebugMessage(M64MSG_VERBOSE, "couldn't open sram file '%s' for reading", filename);
69 sram_format();
70 break;
71 case file_read_error:
72 DebugMessage(M64MSG_WARNING, "fread() failed on 32kb read from sram file '%s'", filename);
73 sram_format();
74 break;
75 default: break;
76 }
77
78 free(filename);
79}
80
81static void sram_write_file(void)
82{
83 char *filename = get_sram_path();
84
85 switch (write_to_file(filename, sram, sizeof(sram)))
86 {
87 case file_open_error:
88 DebugMessage(M64MSG_WARNING, "couldn't open sram file '%s' for writing.", filename);
89 break;
90 case file_write_error:
91 DebugMessage(M64MSG_WARNING, "fwrite() failed on 32kb write to sram file '%s'", filename);
92 break;
93 default: break;
94 }
95
96 free(filename);
97}
98
99void dma_pi_read(void)
100{
101 unsigned int i;
102
103 if (pi_register.pi_cart_addr_reg >= 0x08000000
104 && pi_register.pi_cart_addr_reg < 0x08010000)
105 {
106 if (flashram_info.use_flashram != 1)
107 {
108 sram_read_file();
109
110 for (i=0; i < (pi_register.pi_rd_len_reg & 0xFFFFFF)+1; i++)
111 {
112 sram[((pi_register.pi_cart_addr_reg-0x08000000)+i)^S8] =
113 ((unsigned char*)rdram)[(pi_register.pi_dram_addr_reg+i)^S8];
114 }
115
116 sram_write_file();
117
118 flashram_info.use_flashram = -1;
119 }
120 else
121 {
122 dma_write_flashram();
123 }
124 }
125 else
126 {
127 DebugMessage(M64MSG_WARNING, "Unknown dma read in dma_pi_read()");
128 }
129
130 pi_register.read_pi_status_reg |= 1;
131 update_count();
132 add_interupt_event(PI_INT, 0x1000/*pi_register.pi_rd_len_reg*/);
133}
134
135void dma_pi_write(void)
136{
137 unsigned int longueur;
138 int i;
139
140 if (pi_register.pi_cart_addr_reg < 0x10000000)
141 {
142 if (pi_register.pi_cart_addr_reg >= 0x08000000
143 && pi_register.pi_cart_addr_reg < 0x08010000)
144 {
145 if (flashram_info.use_flashram != 1)
146 {
147 int i;
148
149 sram_read_file();
150
151 for (i=0; i<(int)(pi_register.pi_wr_len_reg & 0xFFFFFF)+1; i++)
152 {
153 ((unsigned char*)rdram)[(pi_register.pi_dram_addr_reg+i)^S8]=
154 sram[(((pi_register.pi_cart_addr_reg-0x08000000)&0xFFFF)+i)^S8];
155 }
156
157 flashram_info.use_flashram = -1;
158 }
159 else
160 {
161 dma_read_flashram();
162 }
163 }
164 else if (pi_register.pi_cart_addr_reg >= 0x06000000
165 && pi_register.pi_cart_addr_reg < 0x08000000)
166 {
167 }
168 else
169 {
170 DebugMessage(M64MSG_WARNING, "Unknown dma write 0x%x in dma_pi_write()", (int)pi_register.pi_cart_addr_reg);
171 }
172
173 pi_register.read_pi_status_reg |= 1;
174 update_count();
175 add_interupt_event(PI_INT, /*pi_register.pi_wr_len_reg*/0x1000);
176
177 return;
178 }
179
180 if (pi_register.pi_cart_addr_reg >= 0x1fc00000) // for paper mario
181 {
182 pi_register.read_pi_status_reg |= 1;
183 update_count();
184 add_interupt_event(PI_INT, 0x1000);
185
186 return;
187 }
188
189 longueur = (pi_register.pi_wr_len_reg & 0xFFFFFF)+1;
190 i = (pi_register.pi_cart_addr_reg-0x10000000)&0x3FFFFFF;
191 longueur = (i + (int) longueur) > rom_size ?
192 (rom_size - i) : longueur;
193 longueur = (pi_register.pi_dram_addr_reg + longueur) > 0x7FFFFF ?
194 (0x7FFFFF - pi_register.pi_dram_addr_reg) : longueur;
195
196 if (i>rom_size || pi_register.pi_dram_addr_reg > 0x7FFFFF)
197 {
198 pi_register.read_pi_status_reg |= 3;
199 update_count();
200 add_interupt_event(PI_INT, longueur/8);
201
202 return;
203 }
204
205 if (r4300emu != CORE_PURE_INTERPRETER)
206 {
207 for (i=0; i<(int)longueur; i++)
208 {
209 unsigned long rdram_address1 = pi_register.pi_dram_addr_reg+i+0x80000000;
210 unsigned long rdram_address2 = pi_register.pi_dram_addr_reg+i+0xa0000000;
211 ((unsigned char*)rdram)[(pi_register.pi_dram_addr_reg+i)^S8]=
212 rom[(((pi_register.pi_cart_addr_reg-0x10000000)&0x3FFFFFF)+i)^S8];
213
214 if (!invalid_code[rdram_address1>>12])
215 {
216 if (!blocks[rdram_address1>>12] ||
217 blocks[rdram_address1>>12]->block[(rdram_address1&0xFFF)/4].ops !=
218 current_instruction_table.NOTCOMPILED)
219 {
220 invalid_code[rdram_address1>>12] = 1;
221 }
222#ifdef NEW_DYNAREC
223 invalidate_block(rdram_address1>>12);
224#endif
225 }
226 if (!invalid_code[rdram_address2>>12])
227 {
228 if (!blocks[rdram_address1>>12] ||
229 blocks[rdram_address2>>12]->block[(rdram_address2&0xFFF)/4].ops !=
230 current_instruction_table.NOTCOMPILED)
231 {
232 invalid_code[rdram_address2>>12] = 1;
233 }
234 }
235 }
236 }
237 else
238 {
239 for (i=0; i<(int)longueur; i++)
240 {
241 ((unsigned char*)rdram)[(pi_register.pi_dram_addr_reg+i)^S8]=
242 rom[(((pi_register.pi_cart_addr_reg-0x10000000)&0x3FFFFFF)+i)^S8];
243 }
244 }
245
246 // Set the RDRAM memory size when copying main ROM code
247 // (This is just a convenient way to run this code once at the beginning)
248 if (pi_register.pi_cart_addr_reg == 0x10001000)
249 {
250 switch (CIC_Chip)
251 {
252 case 1:
253 case 2:
254 case 3:
255 case 6:
256 {
257 if (ConfigGetParamInt(g_CoreConfig, "DisableExtraMem"))
258 {
259 rdram[0x318/4] = 0x400000;
260 }
261 else
262 {
263 rdram[0x318/4] = 0x800000;
264 }
265 break;
266 }
267 case 5:
268 {
269 if (ConfigGetParamInt(g_CoreConfig, "DisableExtraMem"))
270 {
271 rdram[0x3F0/4] = 0x400000;
272 }
273 else
274 {
275 rdram[0x3F0/4] = 0x800000;
276 }
277 break;
278 }
279 }
280 }
281
282 pi_register.read_pi_status_reg |= 3;
283 update_count();
284 add_interupt_event(PI_INT, longueur/8);
285
286 return;
287}
288
289void dma_sp_write(void)
290{
291 unsigned int i,j;
292
293 unsigned int l = sp_register.sp_rd_len_reg;
294
295 unsigned int length = ((l & 0xfff) | 7) + 1;
296 unsigned int count = ((l >> 12) & 0xff) + 1;
297 unsigned int skip = ((l >> 20) & 0xfff);
298
299 unsigned int memaddr = sp_register.sp_mem_addr_reg & 0xfff;
300 unsigned int dramaddr = sp_register.sp_dram_addr_reg & 0xffffff;
301
302 unsigned char *spmem = ((sp_register.sp_mem_addr_reg & 0x1000) != 0) ? (unsigned char*)SP_IMEM : (unsigned char*)SP_DMEM;
303 unsigned char *dram = (unsigned char*)rdram;
304
305 for(j=0; j<count; j++) {
306 for(i=0; i<length; i++) {
307 spmem[memaddr^S8] = dram[dramaddr^S8];
308 memaddr++;
309 dramaddr++;
310 }
311 dramaddr+=skip;
312 }
313}
314
315void dma_sp_read(void)
316{
317 unsigned int i,j;
318
319 unsigned int l = sp_register.sp_wr_len_reg;
320
321 unsigned int length = ((l & 0xfff) | 7) + 1;
322 unsigned int count = ((l >> 12) & 0xff) + 1;
323 unsigned int skip = ((l >> 20) & 0xfff);
324
325 unsigned int memaddr = sp_register.sp_mem_addr_reg & 0xfff;
326 unsigned int dramaddr = sp_register.sp_dram_addr_reg & 0xffffff;
327
328 unsigned char *spmem = ((sp_register.sp_mem_addr_reg & 0x1000) != 0) ? (unsigned char*)SP_IMEM : (unsigned char*)SP_DMEM;
329 unsigned char *dram = (unsigned char*)rdram;
330
331 for(j=0; j<count; j++) {
332 for(i=0; i<length; i++) {
333 dram[dramaddr^S8] = spmem[memaddr^S8];
334 memaddr++;
335 dramaddr++;
336 }
337 dramaddr+=skip;
338 }
339}
340
341void dma_si_write(void)
342{
343 int i;
344
345 if (si_register.si_pif_addr_wr64b != 0x1FC007C0)
346 {
347 DebugMessage(M64MSG_ERROR, "dma_si_write(): unknown SI use");
348 stop=1;
349 }
350
351 for (i=0; i<(64/4); i++)
352 {
353 PIF_RAM[i] = sl(rdram[si_register.si_dram_addr/4+i]);
354 }
355
356 update_pif_write();
357 update_count();
2d262872 358
359 if (delay_si) {
360 add_interupt_event(SI_INT, /*0x100*/0x900);
361 } else {
362 MI_register.mi_intr_reg |= 0x02; // SI
363 si_register.si_stat |= 0x1000; // INTERRUPT
364 check_interupt();
365 }
451ab91e 366}
367
368void dma_si_read(void)
369{
370 int i;
371
372 if (si_register.si_pif_addr_rd64b != 0x1FC007C0)
373 {
374 DebugMessage(M64MSG_ERROR, "dma_si_read(): unknown SI use");
375 stop=1;
376 }
377
378 update_pif_read();
379
380 for (i=0; i<(64/4); i++)
381 {
382 rdram[si_register.si_dram_addr/4+i] = sl(PIF_RAM[i]);
383 }
384
385 update_count();
2d262872 386
387 if (delay_si) {
388 add_interupt_event(SI_INT, /*0x100*/0x900);
389 } else {
390 MI_register.mi_intr_reg |= 0x02; // SI
391 si_register.si_stat |= 0x1000; // INTERRUPT
392 check_interupt();
393 }
451ab91e 394}
395