8d606d40e4d430f704ea99055ea42adabab1ee54
[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
49 static char *get_sram_path(void)
50 {
51     return formatstr("%s%s.sra", get_savesrampath(), ROM_SETTINGS.goodname);
52 }
53
54 static void sram_format(void)
55 {
56     memset(sram, 0, sizeof(sram));
57 }
58
59 static void sram_read_file(void)
60 {
61     char *filename = get_sram_path();
62
63     sram_format();
64     switch (read_from_file(filename, sram, sizeof(sram)))
65     {
66         case file_open_error:
67             DebugMessage(M64MSG_VERBOSE, "couldn't open sram file '%s' for reading", filename);
68             sram_format();
69             break;
70         case file_read_error:
71             DebugMessage(M64MSG_WARNING, "fread() failed on 32kb read from sram file '%s'", filename);
72             sram_format();
73             break;
74         default: break;
75     }
76
77     free(filename);
78 }
79
80 static void sram_write_file(void)
81 {
82     char *filename = get_sram_path();
83
84     switch (write_to_file(filename, sram, sizeof(sram)))
85     {
86         case file_open_error:
87             DebugMessage(M64MSG_WARNING, "couldn't open sram file '%s' for writing.", filename);
88             break;
89         case file_write_error:
90             DebugMessage(M64MSG_WARNING, "fwrite() failed on 32kb write to sram file '%s'", filename);
91             break;
92         default: break;
93     }
94
95     free(filename);
96 }
97
98 void dma_pi_read(void)
99 {
100     unsigned int i;
101
102     if (pi_register.pi_cart_addr_reg >= 0x08000000
103             && pi_register.pi_cart_addr_reg < 0x08010000)
104     {
105         if (flashram_info.use_flashram != 1)
106         {
107             sram_read_file();
108
109             for (i=0; i < (pi_register.pi_rd_len_reg & 0xFFFFFF)+1; i++)
110             {
111                 sram[((pi_register.pi_cart_addr_reg-0x08000000)+i)^S8] =
112                     ((unsigned char*)rdram)[(pi_register.pi_dram_addr_reg+i)^S8];
113             }
114
115             sram_write_file();
116
117             flashram_info.use_flashram = -1;
118         }
119         else
120         {
121             dma_write_flashram();
122         }
123     }
124     else
125     {
126         DebugMessage(M64MSG_WARNING, "Unknown dma read in dma_pi_read()");
127     }
128
129     pi_register.read_pi_status_reg |= 1;
130     update_count();
131     add_interupt_event(PI_INT, 0x1000/*pi_register.pi_rd_len_reg*/);
132 }
133
134 void dma_pi_write(void)
135 {
136     unsigned int longueur;
137     int i;
138
139     if (pi_register.pi_cart_addr_reg < 0x10000000)
140     {
141         if (pi_register.pi_cart_addr_reg >= 0x08000000
142                 && pi_register.pi_cart_addr_reg < 0x08010000)
143         {
144             if (flashram_info.use_flashram != 1)
145             {
146                 int i;
147
148                 sram_read_file();
149
150                 for (i=0; i<(int)(pi_register.pi_wr_len_reg & 0xFFFFFF)+1; i++)
151                 {
152                     ((unsigned char*)rdram)[(pi_register.pi_dram_addr_reg+i)^S8]=
153                         sram[(((pi_register.pi_cart_addr_reg-0x08000000)&0xFFFF)+i)^S8];
154                 }
155
156                 flashram_info.use_flashram = -1;
157             }
158             else
159             {
160                 dma_read_flashram();
161             }
162         }
163         else if (pi_register.pi_cart_addr_reg >= 0x06000000
164                  && pi_register.pi_cart_addr_reg < 0x08000000)
165         {
166         }
167         else
168         {
169             DebugMessage(M64MSG_WARNING, "Unknown dma write 0x%x in dma_pi_write()", (int)pi_register.pi_cart_addr_reg);
170         }
171
172         pi_register.read_pi_status_reg |= 1;
173         update_count();
174         add_interupt_event(PI_INT, /*pi_register.pi_wr_len_reg*/0x1000);
175
176         return;
177     }
178
179     if (pi_register.pi_cart_addr_reg >= 0x1fc00000) // for paper mario
180     {
181         pi_register.read_pi_status_reg |= 1;
182         update_count();
183         add_interupt_event(PI_INT, 0x1000);
184
185         return;
186     }
187
188     longueur = (pi_register.pi_wr_len_reg & 0xFFFFFF)+1;
189     i = (pi_register.pi_cart_addr_reg-0x10000000)&0x3FFFFFF;
190     longueur = (i + (int) longueur) > rom_size ?
191                (rom_size - i) : longueur;
192     longueur = (pi_register.pi_dram_addr_reg + longueur) > 0x7FFFFF ?
193                (0x7FFFFF - pi_register.pi_dram_addr_reg) : longueur;
194
195     if (i>rom_size || pi_register.pi_dram_addr_reg > 0x7FFFFF)
196     {
197         pi_register.read_pi_status_reg |= 3;
198         update_count();
199         add_interupt_event(PI_INT, longueur/8);
200
201         return;
202     }
203
204     if (r4300emu != CORE_PURE_INTERPRETER)
205     {
206         for (i=0; i<(int)longueur; i++)
207         {
208             unsigned long rdram_address1 = pi_register.pi_dram_addr_reg+i+0x80000000;
209             unsigned long rdram_address2 = pi_register.pi_dram_addr_reg+i+0xa0000000;
210             ((unsigned char*)rdram)[(pi_register.pi_dram_addr_reg+i)^S8]=
211                 rom[(((pi_register.pi_cart_addr_reg-0x10000000)&0x3FFFFFF)+i)^S8];
212
213             if (!invalid_code[rdram_address1>>12])
214             {
215                 if (!blocks[rdram_address1>>12] ||
216                     blocks[rdram_address1>>12]->block[(rdram_address1&0xFFF)/4].ops !=
217                     current_instruction_table.NOTCOMPILED)
218                 {
219                     invalid_code[rdram_address1>>12] = 1;
220                 }
221 #ifdef NEW_DYNAREC
222                 invalidate_block(rdram_address1>>12);
223 #endif
224             }
225             if (!invalid_code[rdram_address2>>12])
226             {
227                 if (!blocks[rdram_address1>>12] ||
228                     blocks[rdram_address2>>12]->block[(rdram_address2&0xFFF)/4].ops !=
229                     current_instruction_table.NOTCOMPILED)
230                 {
231                     invalid_code[rdram_address2>>12] = 1;
232                 }
233             }
234         }
235     }
236     else
237     {
238         for (i=0; i<(int)longueur; i++)
239         {
240             ((unsigned char*)rdram)[(pi_register.pi_dram_addr_reg+i)^S8]=
241                 rom[(((pi_register.pi_cart_addr_reg-0x10000000)&0x3FFFFFF)+i)^S8];
242         }
243     }
244
245     // Set the RDRAM memory size when copying main ROM code
246     // (This is just a convenient way to run this code once at the beginning)
247     if (pi_register.pi_cart_addr_reg == 0x10001000)
248     {
249         switch (CIC_Chip)
250         {
251         case 1:
252         case 2:
253         case 3:
254         case 6:
255         {
256             if (ConfigGetParamInt(g_CoreConfig, "DisableExtraMem"))
257             {
258                 rdram[0x318/4] = 0x400000;
259             }
260             else
261             {
262                 rdram[0x318/4] = 0x800000;
263             }
264             break;
265         }
266         case 5:
267         {
268             if (ConfigGetParamInt(g_CoreConfig, "DisableExtraMem"))
269             {
270                 rdram[0x3F0/4] = 0x400000;
271             }
272             else
273             {
274                 rdram[0x3F0/4] = 0x800000;
275             }
276             break;
277         }
278         }
279     }
280
281     pi_register.read_pi_status_reg |= 3;
282     update_count();
283     add_interupt_event(PI_INT, longueur/8);
284
285     return;
286 }
287
288 void dma_sp_write(void)
289 {
290     unsigned int i,j;
291
292     unsigned int l = sp_register.sp_rd_len_reg;
293
294     unsigned int length = ((l & 0xfff) | 7) + 1;
295     unsigned int count = ((l >> 12) & 0xff) + 1;
296     unsigned int skip = ((l >> 20) & 0xfff);
297  
298     unsigned int memaddr = sp_register.sp_mem_addr_reg & 0xfff;
299     unsigned int dramaddr = sp_register.sp_dram_addr_reg & 0xffffff;
300
301     unsigned char *spmem = ((sp_register.sp_mem_addr_reg & 0x1000) != 0) ? (unsigned char*)SP_IMEM : (unsigned char*)SP_DMEM;
302     unsigned char *dram = (unsigned char*)rdram;
303
304     for(j=0; j<count; j++) {
305         for(i=0; i<length; i++) {
306             spmem[memaddr^S8] = dram[dramaddr^S8];
307             memaddr++;
308             dramaddr++;
309         }
310         dramaddr+=skip;
311     }
312 }
313
314 void dma_sp_read(void)
315 {
316     unsigned int i,j;
317
318     unsigned int l = sp_register.sp_wr_len_reg;
319
320     unsigned int length = ((l & 0xfff) | 7) + 1;
321     unsigned int count = ((l >> 12) & 0xff) + 1;
322     unsigned int skip = ((l >> 20) & 0xfff);
323
324     unsigned int memaddr = sp_register.sp_mem_addr_reg & 0xfff;
325     unsigned int dramaddr = sp_register.sp_dram_addr_reg & 0xffffff;
326
327     unsigned char *spmem = ((sp_register.sp_mem_addr_reg & 0x1000) != 0) ? (unsigned char*)SP_IMEM : (unsigned char*)SP_DMEM;
328     unsigned char *dram = (unsigned char*)rdram;
329
330     for(j=0; j<count; j++) {
331         for(i=0; i<length; i++) {
332             dram[dramaddr^S8] = spmem[memaddr^S8];
333             memaddr++;
334             dramaddr++;
335         }
336         dramaddr+=skip;
337     }
338 }
339
340 void dma_si_write(void)
341 {
342     int i;
343
344     if (si_register.si_pif_addr_wr64b != 0x1FC007C0)
345     {
346         DebugMessage(M64MSG_ERROR, "dma_si_write(): unknown SI use");
347         stop=1;
348     }
349
350     for (i=0; i<(64/4); i++)
351     {
352         PIF_RAM[i] = sl(rdram[si_register.si_dram_addr/4+i]);
353     }
354
355     update_pif_write();
356     update_count();
357     add_interupt_event(SI_INT, /*0x100*/0x900);
358 }
359
360 void dma_si_read(void)
361 {
362     int i;
363
364     if (si_register.si_pif_addr_rd64b != 0x1FC007C0)
365     {
366         DebugMessage(M64MSG_ERROR, "dma_si_read(): unknown SI use");
367         stop=1;
368     }
369
370     update_pif_read();
371
372     for (i=0; i<(64/4); i++)
373     {
374         rdram[si_register.si_dram_addr/4+i] = sl(PIF_RAM[i]);
375     }
376
377     update_count();
378     add_interupt_event(SI_INT, /*0x100*/0x900);
379 }
380