bumping to 1.3.2
[drnoksnes] / sdd1.cpp
1 /*
2  * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3  *
4  * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5  *                           Jerremy Koot (jkoot@snes9x.com)
6  *
7  * Super FX C emulator code 
8  * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
9  *                           Gary Henderson.
10  * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
11  *
12  * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
13  * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
14  * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
15  *
16  * DOS port code contains the works of other authors. See headers in
17  * individual files.
18  *
19  * Snes9x homepage: http://www.snes9x.com
20  *
21  * Permission to use, copy, modify and distribute Snes9x in both binary and
22  * source form, for non-commercial purposes, is hereby granted without fee,
23  * providing that this license information and copyright notice appear with
24  * all copies and any derived work.
25  *
26  * This software is provided 'as-is', without any express or implied
27  * warranty. In no event shall the authors be held liable for any damages
28  * arising from the use of this software.
29  *
30  * Snes9x is freeware for PERSONAL USE only. Commercial users should
31  * seek permission of the copyright holders first. Commercial use includes
32  * charging money for Snes9x or software derived from Snes9x.
33  *
34  * The copyright holders request that bug fixes and improvements to the code
35  * should be forwarded to them so everyone can benefit from the modifications
36  * in future versions.
37  *
38  * Super NES and Super Nintendo Entertainment System are trademarks of
39  * Nintendo Co., Limited and its subsidiary companies.
40  */
41
42 #include <stdio.h>
43 #include <dirent.h>
44
45 #include "snes9x.h"
46 #include "memmap.h"
47 #include "ppu.h"
48 #include "sdd1.h"
49 #include "display.h"
50
51 static int S9xCompareSDD1IndexEntries (const void *p1, const void *p2)
52 {
53     return (*(uint32 *) p1 - *(uint32 *) p2);
54 }
55
56 static int S9xGetSDD1Dir(char * packdir)
57 {
58         char dir[_MAX_DIR + 1];
59         char drive[_MAX_DRIVE + 1];
60         char name[_MAX_FNAME + 1];
61         char ext[_MAX_EXT + 1];
62
63         PathSplit(S9xGetFilename(FILE_ROM), drive, dir, name, ext);
64
65         if (strncmp(Memory.ROMName, "Star Ocean", 10) == 0) {
66         PathMake(packdir, drive, dir, "socnsdd1", 0);
67         return 1;
68         } else if(strncmp(Memory.ROMName, "STREET FIGHTER ALPHA2", 21) == 0) {
69                 PathMake(packdir, drive, dir, "sfa2sdd1", 0);
70                 return 1;
71         } else {
72                 S9xMessage(S9X_WARNING, S9X_ROM_INFO,
73                         "WARNING: No default SDD1 pack for this ROM");
74                 return 0;
75         }
76 }
77
78 void S9xLoadSDD1Data ()
79 {
80         char packdir[_MAX_PATH + 1];
81
82         // Unload any previous pack
83         Settings.SDD1Pack = FALSE;
84         Memory.FreeSDD1Data();
85
86         if (!S9xGetSDD1Dir(packdir)) {
87                 printf("SDD1: Didn't found pack for this ROM\n");
88                 return;
89         }
90
91         printf("SDD1: Searching for pack in %s\n", packdir);
92         Settings.SDD1Pack=TRUE;
93
94         char index[_MAX_PATH + 1];
95         char data[_MAX_PATH + 1];
96         char patch[_MAX_PATH + 1];
97         DIR *dir = opendir(packdir);
98
99         index[0] = 0;
100         data[0] = 0;
101         patch[0] = 0;
102
103         if (dir) {
104                 struct dirent *d;
105
106                 while ((d = readdir (dir))) {
107                         if (strcasecmp (d->d_name, "SDD1GFX.IDX") == 0) {
108                                 strcpy(index, packdir);
109                                 strcat(index, "/");
110                                 strcat(index, d->d_name);
111                         } else if (strcasecmp (d->d_name, "SDD1GFX.DAT") == 0) {
112                                 strcpy(data, packdir);
113                                 strcat(data, "/");
114                                 strcat(data, d->d_name);
115                         } else if (strcasecmp (d->d_name, "SDD1GFX.PAT") == 0) {
116                                 strcpy(patch, packdir);
117                                 strcat(patch, "/");
118                                 strcat(patch, d->d_name);
119                         }
120                 }
121                 closedir (dir);
122         }
123
124         if (strlen (index) && strlen (data)) {
125                 FILE *fs = fopen (index, "rb");
126                 int len = 0;
127
128                 if (fs) {
129                         // Index is stored as a sequence of entries, each entry being
130                         // 12 bytes consisting of:
131                         // 4 byte key: (24bit address & 0xfffff * 16) | translated block
132                         // 4 byte ROM offset
133                         // 4 byte length
134
135                         fseek (fs, 0, SEEK_END);
136                         len = ftell (fs);
137                         rewind (fs);
138                         Memory.SDD1Index = (uint8 *) malloc (len);
139                         fread (Memory.SDD1Index, 1, len, fs);
140                         fclose (fs);
141                         Memory.SDD1Entries = len / 12;
142                 } else {
143                         fprintf(stderr, "Failed to read SDD1 index file %s\n", index);
144                         return;
145                 }
146                 printf("SDD1: index: %s\n", PathBasename(index));
147
148                 if (!(fs = fopen (data, "rb"))) {
149                         fprintf(stderr, "Failed to read SDD1 data file %s\n", data);
150                         free ((char *) Memory.SDD1Index);
151                         Memory.SDD1Index = NULL;
152                         Memory.SDD1Entries = 0;
153                         return;
154                 } else {
155                         fseek (fs, 0, SEEK_END);
156                         len = ftell (fs);
157                         rewind (fs);
158                         Memory.SDD1Data = (uint8 *) malloc (len);
159                         fread (Memory.SDD1Data, 1, len, fs);
160                         fclose (fs);
161                 }
162                 printf("SDD1: data pack: %s\n", PathBasename(data));
163
164                 if (strlen (patch) > 0 && (fs = fopen (patch, "rb"))) {
165                         fclose (fs);
166                 }
167
168 #ifdef MSB_FIRST
169                 // Swap the byte order of the 32-bit value triplets on
170                 // MSBFirst machines.
171                 uint8 *ptr = Memory.SDD1Index;
172                 for (int i = 0; i < Memory.SDD1Entries; i++, ptr += 12)         {
173                         SWAP_DWORD ((*(uint32 *) (ptr + 0)));
174                         SWAP_DWORD ((*(uint32 *) (ptr + 4)));
175                         SWAP_DWORD ((*(uint32 *) (ptr + 8)));
176                 }
177 #endif
178
179                 qsort(Memory.SDD1Index, Memory.SDD1Entries, 12,
180                         S9xCompareSDD1IndexEntries);
181                 printf("SDD1: Pack loaded succesfully\n", data);
182         } else {
183                 fprintf(stderr, "SDD1: SDD1 data pack not found in '%s'\n",
184                         packdir);
185                 fprintf(stderr, "SDD1: Check if sdd1gfx files exist\n",
186                         packdir);
187                 printf("SDD1: Failed to load pack\n", data);
188         }
189 }
190
191 void S9xSetSDD1MemoryMap (uint32 bank, uint32 value)
192 {
193     bank = 0xc00 + bank * 0x100;
194     value = value * 1024 * 1024;
195
196     int c;
197
198     for (c = 0; c < 0x100; c += 16)
199     {
200         uint8 *block = &Memory.ROM [value + (c << 12)];
201         int i;
202
203         for (i = c; i < c + 16; i++)
204             Memory.Map [i + bank] = block;
205     }
206 }
207
208 void S9xResetSDD1 ()
209 {
210     memset (&Memory.FillRAM [0x4800], 0, 4);
211     for (int i = 0; i < 4; i++)
212     {
213         Memory.FillRAM [0x4804 + i] = i;
214         S9xSetSDD1MemoryMap (i, i);
215     }
216 }
217
218 void S9xSDD1PostLoadState ()
219 {
220     for (int i = 0; i < 4; i++)
221         S9xSetSDD1MemoryMap (i, Memory.FillRAM [0x4804 + i]);
222 }
223
224 #ifndef _SNESPPC
225 static int S9xCompareSDD1LoggedDataEntries (const void *p1, const void *p2)
226 #else
227 static int _cdecl S9xCompareSDD1LoggedDataEntries (const void *p1, const void *p2)
228 #endif
229 {
230     uint8 *b1 = (uint8 *) p1;
231     uint8 *b2 = (uint8 *) p2;
232     uint32 a1 = (*b1 << 16) + (*(b1 + 1) << 8) + *(b1 + 2);
233     uint32 a2 = (*b2 << 16) + (*(b2 + 1) << 8) + *(b2 + 2);
234
235     return (a1 - a2);
236 }
237
238 void S9xSDD1SaveLoggedData ()
239 {
240     if (Memory.SDD1LoggedDataCount != Memory.SDD1LoggedDataCountPrev)
241     {
242         qsort (Memory.SDD1LoggedData, Memory.SDD1LoggedDataCount, 8,
243                S9xCompareSDD1LoggedDataEntries);
244
245         const char * sdd1_dat_file = S9xGetFilename(FILE_SDD1_DAT);
246         FILE *fs = fopen (sdd1_dat_file, "wb");
247
248         if (fs)
249         {
250             fwrite (Memory.SDD1LoggedData, 8,
251                     Memory.SDD1LoggedDataCount, fs);
252             fclose (fs);
253 #if defined(__linux)
254             chown (sdd1_dat_file, getuid (), getgid ());
255 #endif
256         }
257         Memory.SDD1LoggedDataCountPrev = Memory.SDD1LoggedDataCount;
258     }
259 }
260
261 void S9xSDD1LoadLoggedData ()
262 {
263     FILE *fs = fopen (S9xGetFilename(FILE_SDD1_DAT), "rb");
264
265     Memory.SDD1LoggedDataCount = Memory.SDD1LoggedDataCountPrev = 0;
266
267     if (fs)
268     {
269         int c = fread (Memory.SDD1LoggedData, 8, 
270                        MEMMAP_MAX_SDD1_LOGGED_ENTRIES, fs);
271
272         if (c != EOF)
273             Memory.SDD1LoggedDataCount = Memory.SDD1LoggedDataCountPrev = c;
274         fclose (fs);
275     }
276 }