workaround a problem with the harmattan gcc
[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
50 static int S9xCompareSDD1IndexEntries (const void *p1, const void *p2)
51 {
52     return (*(uint32 *) p1 - *(uint32 *) p2);
53 }
54
55 static int S9xGetSDD1Dir(char * packdir)
56 {
57         char dir[_MAX_DIR + 1];
58         char drive[_MAX_DRIVE + 1];
59         char name[_MAX_FNAME + 1];
60         char ext[_MAX_EXT + 1];
61
62         PathSplit(S9xGetFilename(FILE_ROM), drive, dir, name, ext);
63
64         if (strncmp(Memory.ROMName, "Star Ocean", 10) == 0) {
65         PathMake(packdir, drive, dir, "socnsdd1", 0);
66         return 1;
67         } else if(strncmp(Memory.ROMName, "STREET FIGHTER ALPHA2", 21) == 0) {
68                 PathMake(packdir, drive, dir, "sfa2sdd1", 0);
69                 return 1;
70         } else {
71                 S9xMessage(S9X_WARNING, S9X_ROM_INFO,
72                         "WARNING: No default SDD1 pack for this ROM");
73                 return 0;
74         }
75 }
76
77 void S9xLoadSDD1Data ()
78 {
79         char packdir[_MAX_PATH + 1];
80
81         // Unload any previous pack
82         Settings.SDD1Pack = FALSE;
83         Memory.FreeSDD1Data();
84
85         if (!S9xGetSDD1Dir(packdir)) {
86                 printf("SDD1: Didn't found pack for this ROM\n");
87                 return;
88         }
89
90         printf("SDD1: Searching for pack in %s\n", packdir);
91         Settings.SDD1Pack=TRUE;
92
93         char index[_MAX_PATH + 1];
94         char data[_MAX_PATH + 1];
95         char patch[_MAX_PATH + 1];
96         DIR *dir = opendir(packdir);
97
98         index[0] = 0;
99         data[0] = 0;
100         patch[0] = 0;
101
102         if (dir) {
103                 struct dirent *d;
104
105                 while ((d = readdir (dir))) {
106                         if (strcasecmp (d->d_name, "SDD1GFX.IDX") == 0) {
107                                 strcpy(index, packdir);
108                                 strcat(index, "/");
109                                 strcat(index, d->d_name);
110                         } else if (strcasecmp (d->d_name, "SDD1GFX.DAT") == 0) {
111                                 strcpy(data, packdir);
112                                 strcat(data, "/");
113                                 strcat(data, d->d_name);
114                         } else if (strcasecmp (d->d_name, "SDD1GFX.PAT") == 0) {
115                                 strcpy(patch, packdir);
116                                 strcat(patch, "/");
117                                 strcat(patch, d->d_name);
118                         }
119                 }
120                 closedir (dir);
121         }
122
123         if (strlen (index) && strlen (data)) {
124                 FILE *fs = fopen (index, "rb");
125                 size_t len = 0;
126
127                 if (fs) {
128                         // Index is stored as a sequence of entries, each entry being
129                         // 12 bytes consisting of:
130                         // 4 byte key: (24bit address & 0xfffff * 16) | translated block
131                         // 4 byte ROM offset
132                         // 4 byte length
133
134                         fseek (fs, 0, SEEK_END);
135                         len = ftell (fs);
136                         rewind (fs);
137                         Memory.SDD1Index = (uint8 *) malloc (len);
138                         if (fread (Memory.SDD1Index, 1, len, fs) < len) {
139                                 fprintf(stderr, "Failed to fully read SDD1 index file %s\n",
140                                         data);
141                         }
142                         fclose (fs);
143                         Memory.SDD1Entries = len / 12;
144                 } else {
145                         fprintf(stderr, "Failed to read SDD1 index file %s\n", index);
146                         return;
147                 }
148                 printf("SDD1: index: %s\n", PathBasename(index));
149
150                 if (!(fs = fopen (data, "rb"))) {
151                         fprintf(stderr, "Failed to read SDD1 data file %s\n", data);
152                         free ((char *) Memory.SDD1Index);
153                         Memory.SDD1Index = NULL;
154                         Memory.SDD1Entries = 0;
155                         return;
156                 } else {
157                         fseek (fs, 0, SEEK_END);
158                         len = ftell (fs);
159                         rewind (fs);
160                         Memory.SDD1Data = (uint8 *) malloc (len);
161                         if (fread (Memory.SDD1Data, 1, len, fs) < len) {
162                                 fprintf(stderr, "Failed to fully read SDD1 data file %s\n",
163                                         data);
164                         }
165                         fclose (fs);
166                 }
167                 printf("SDD1: data pack: %s\n", PathBasename(data));
168
169                 if (strlen (patch) > 0 && (fs = fopen (patch, "rb"))) {
170                         fclose (fs);
171                 }
172
173 #ifdef MSB_FIRST
174                 // Swap the byte order of the 32-bit value triplets on
175                 // MSBFirst machines.
176                 uint8 *ptr = Memory.SDD1Index;
177                 for (int i = 0; i < Memory.SDD1Entries; i++, ptr += 12)         {
178                         SWAP_DWORD ((*(uint32 *) (ptr + 0)));
179                         SWAP_DWORD ((*(uint32 *) (ptr + 4)));
180                         SWAP_DWORD ((*(uint32 *) (ptr + 8)));
181                 }
182 #endif
183
184                 qsort(Memory.SDD1Index, Memory.SDD1Entries, 12,
185                         S9xCompareSDD1IndexEntries);
186                 printf("SDD1: Pack loaded succesfully\n");
187         } else {
188                 fprintf(stderr, "SDD1: SDD1 data pack not found in '%s'\n",
189                         packdir);
190                 fprintf(stderr, "SDD1: Check if sdd1gfx files exist\n");
191                 printf("SDD1: Failed to load pack\n");
192         }
193 }
194
195 void S9xSetSDD1MemoryMap (uint32 bank, uint32 value)
196 {
197     bank = 0xc00 + bank * 0x100;
198     value = value * 1024 * 1024;
199
200     int c;
201
202     for (c = 0; c < 0x100; c += 16)
203     {
204         uint8 *block = &Memory.ROM [value + (c << 12)];
205         int i;
206
207         for (i = c; i < c + 16; i++)
208             Memory.Map [i + bank] = block;
209     }
210 }
211
212 void S9xResetSDD1 ()
213 {
214     memset (&Memory.FillRAM [0x4800], 0, 4);
215     for (int i = 0; i < 4; i++)
216     {
217         Memory.FillRAM [0x4804 + i] = i;
218         S9xSetSDD1MemoryMap (i, i);
219     }
220 }
221
222 void S9xSDD1PostLoadState ()
223 {
224     for (int i = 0; i < 4; i++)
225         S9xSetSDD1MemoryMap (i, Memory.FillRAM [0x4804 + i]);
226 }
227
228 #ifndef _SNESPPC
229 static int S9xCompareSDD1LoggedDataEntries (const void *p1, const void *p2)
230 #else
231 static int _cdecl S9xCompareSDD1LoggedDataEntries (const void *p1, const void *p2)
232 #endif
233 {
234     uint8 *b1 = (uint8 *) p1;
235     uint8 *b2 = (uint8 *) p2;
236     uint32 a1 = (*b1 << 16) + (*(b1 + 1) << 8) + *(b1 + 2);
237     uint32 a2 = (*b2 << 16) + (*(b2 + 1) << 8) + *(b2 + 2);
238
239     return (a1 - a2);
240 }
241
242 void S9xSDD1SaveLoggedData ()
243 {
244     if (Memory.SDD1LoggedDataCount != Memory.SDD1LoggedDataCountPrev)
245     {
246         qsort (Memory.SDD1LoggedData, Memory.SDD1LoggedDataCount, 8,
247                S9xCompareSDD1LoggedDataEntries);
248
249         const char * sdd1_dat_file = S9xGetFilename(FILE_SDD1_DAT);
250         FILE *fs = fopen(sdd1_dat_file, "wb");
251
252         if (fs)
253         {
254             size_t c = fwrite(Memory.SDD1LoggedData, 8,
255                                 Memory.SDD1LoggedDataCount, fs);
256                 if (c < Memory.SDD1LoggedDataCount) {
257                         fprintf(stderr, "Failed to write sdd1 log data\n");
258                 }
259             fclose(fs);
260         }
261         Memory.SDD1LoggedDataCountPrev = Memory.SDD1LoggedDataCount;
262     }
263 }
264
265 void S9xSDD1LoadLoggedData ()
266 {
267     FILE *fs = fopen (S9xGetFilename(FILE_SDD1_DAT), "rb");
268
269     Memory.SDD1LoggedDataCount = Memory.SDD1LoggedDataCountPrev = 0;
270
271     if (fs)
272     {
273         size_t c = fread (Memory.SDD1LoggedData, 8,
274                             MEMMAP_MAX_SDD1_LOGGED_ENTRIES, fs);
275
276         if (c > 0)
277             Memory.SDD1LoggedDataCount = Memory.SDD1LoggedDataCountPrev = c;
278         fclose (fs);
279     }
280 }