ALL: Huge upstream synch + PerRom DelaySI & CountPerOp parameters
[mupen64plus-pandora.git] / source / mupen64plus-core / src / memory / dma.c
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
47 static unsigned char sram[0x8000];
48 int delay_si = 0;
49
50 static char *get_sram_path(void)
51 {
52     return formatstr("%s%s.sra", get_savesrampath(), ROM_SETTINGS.goodname);
53 }
54
55 static void sram_format(void)
56 {
57     memset(sram, 0, sizeof(sram));
58 }
59
60 static 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
81 static 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
99 void 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
135 void 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
289 void 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
315 void 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
341 void 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();
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     }
366 }
367
368 void 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();
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     }
394 }
395