Core commit. Compile and run on the OpenPandora
[mupen64plus-pandora.git] / source / mupen64plus-core / tools / savestate_convert.c
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  *   Mupen64plus - savestate_convert.c                                     *
3  *   Mupen64Plus homepage: http://code.google.com/p/mupen64plus/           *
4  *   Copyright (C) 2008 Richard Goedeken                                   *
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 <zlib.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 /* savestate file header: magic number and version number */
28 const char *savestate_magic = "M64+SAVE";
29 const int savestate_newest_version = 0x00010000;  // 1.0
30
31 /* Data field lengths */
32
33 #define SIZE_REG_RDRAM       40
34 #define SIZE_REG_MIPS        36
35 #define SIZE_REG_PI          52
36 #define SIZE_REG_SP          52
37 #define SIZE_REG_RSP         8
38 #define SIZE_REG_SI          16
39 #define SIZE_REG_VI          60
40 #define SIZE_REG_RI          32
41 #define SIZE_REG_AI          40
42 #define SIZE_REG_DPC         48
43 #define SIZE_REG_DPS         16
44
45 #define SIZE_FLASHRAM_INFO   24
46 #define SIZE_TLB_ENTRY       52
47
48 #define SIZE_MAX_EVENTQUEUE  1024
49
50 /* Arrays and pointers for savestate data */
51
52 char rom_md5[32];
53
54 char rdram_register[SIZE_REG_RDRAM];
55 char mips_register[SIZE_REG_MIPS];
56 char pi_register[SIZE_REG_PI];
57 char sp_register[SIZE_REG_SP];
58 char rsp_register[SIZE_REG_RSP];
59 char si_register[SIZE_REG_SI];
60 char vi_register[SIZE_REG_VI];
61 char ri_register[SIZE_REG_RI];
62 char ai_register[SIZE_REG_AI];
63 char dpc_register[SIZE_REG_DPC];
64 char dps_register[SIZE_REG_DPS];
65
66 char *rdram;       /* 0x800000 bytes */
67 char SP_DMEM[0x1000];
68 char SP_IMEM[0x1000];
69 char PIF_RAM[0x40];
70
71 char flashram[SIZE_FLASHRAM_INFO];
72
73 char *tlb_LUT_r;   /* 0x400000 bytes */
74 char *tlb_LUT_w;   /* 0x400000 bytes */
75
76 char llbit[4];
77 char reg[32][8];
78 char reg_cop0[32][4];
79 char lo[8];
80 char hi[8];
81 char reg_cop1_fgr_64[32][8];
82 char FCR0[4];
83 char FCR31[4];
84 char tlb_e[32][SIZE_TLB_ENTRY];
85 char PCaddr[4];
86
87 char next_interupt[4];
88 char next_vi[4];
89 char vi_field[4];
90
91 char eventqueue[SIZE_MAX_EVENTQUEUE];
92
93 /* savestate data parameters calculated from file contents */
94 int queuelength = 0;
95
96 /* Forward declarations for functions */
97 void printhelp(const char *progname);
98
99 int allocate_memory(void);
100 void free_memory(void);
101
102 int load_original_mupen64(const char *filename);
103 int save_newest(const char *filename);
104
105 /* Main Function - parse arguments, check version, load state file, overwrite state file with new one */
106 int main(int argc, char *argv[])
107 {
108     FILE *pfTest;
109     gzFile f;
110     char *filename;
111     char magictag[8];
112     unsigned char inbuf[4];
113     int (*load_function)(const char *) = NULL;
114     int iVersion;
115
116     /* start by parsing the command-line arguments */
117     if (argc != 2 || strncmp(argv[1], "-h", 2) == 0 || strncmp(argv[1], "--help", 6) == 0)
118     {
119         printhelp(argv[0]);
120         return 1;
121     }
122     filename = argv[1];
123     pfTest = fopen(filename, "rb");
124     if (pfTest == NULL)
125     {
126         printf("Error: cannot open savestate file '%s' for reading.\n", filename);
127         return 2;
128     }
129     fclose(pfTest);
130
131     /* try to determine the version of this savestate file */
132     f = gzopen(filename, "rb");
133     if (f == NULL)
134     {
135         printf("Error: state file '%s' is corrupt\n", filename);
136         return 3;
137     }
138     if (gzread(f, magictag, 8) != 8 || gzread(f, inbuf, 4) != 4)
139     {
140         printf("Error: state file '%s' is corrupt: end of savestate file while reading header.\n", filename);
141         gzclose(f);
142         return 4;
143     }
144     gzclose(f);
145     iVersion =                   inbuf[0];
146     iVersion = (iVersion << 8) | inbuf[1];
147     iVersion = (iVersion << 8) | inbuf[2];
148     iVersion = (iVersion << 8) | inbuf[3];
149
150     /* determine which type of savestate file to load, based on savestate version */
151     if (strncmp(magictag, savestate_magic, 8) != 0)
152     {
153         printf("Warning: old savestate file format.  This is presumed to be from the original Mupen64 or Mupen64Plus version 1.4 or earlier.\n");
154         load_function = load_original_mupen64;
155     }
156     else if (iVersion == savestate_newest_version)
157     {
158         printf("This savestate file is already up to date (version %08x)\n", savestate_newest_version);
159         return 0;
160     }
161     else
162     {
163         printf("This savestate file uses an unknown version (%08x)\n", iVersion);
164         return 5;
165     }
166
167     /* allocate memory for savestate data */
168     if (allocate_memory() != 0)
169     {
170         printf("Error: couldn't allocate memory for savestate data storage.\n");
171         return 6;
172     }
173
174     /* load the savestate file */
175     if (load_function(filename) != 0)
176     {
177         free_memory();
178         return 7;
179     }
180
181     /* write new updated savestate file */
182     if (save_newest(filename) != 0)
183     {
184         free_memory();
185         return 8;
186     }
187
188     /* free the memory and return */
189     printf("Savestate file '%s' successfully converted to latest version (%08x).\n", filename, savestate_newest_version);
190     free_memory();
191     return 0;
192 }
193
194 void printhelp(const char *progname)
195 {
196     printf("%s - convert older Mupen64Plus savestate files to most recent version.\n\n", progname);
197     printf("Usage: %s [-h] [--help] <savestatepath>\n\n", progname);
198     printf("       -h, --help: display this message\n");
199     printf("       <savestatepath>: full path to savestate file which will be overwritten with latest version.\n");
200 }
201
202 int allocate_memory(void)
203 {
204     rdram = malloc(0x800000);
205     if (rdram == NULL)
206         return 1;
207
208     tlb_LUT_r = malloc(0x400000);
209     if (tlb_LUT_r == NULL)
210     {
211         free_memory();
212         return 2;
213     }
214
215     tlb_LUT_w = malloc(0x400000);
216     if (tlb_LUT_w == NULL)
217     {
218         free_memory();
219         return 3;
220     }
221
222     return 0;
223 }
224
225 void free_memory(void)
226 {
227     if (rdram != NULL)
228     {
229         free(rdram);
230         rdram = NULL;
231     }
232
233     if (tlb_LUT_r != NULL)
234     {
235         free(tlb_LUT_r);
236         tlb_LUT_r = NULL;
237     }
238
239     if (tlb_LUT_w != NULL)
240     {
241         free(tlb_LUT_w);
242         tlb_LUT_w = NULL;
243     }
244 }
245
246 /* State Loading Functions */
247 int load_original_mupen64(const char *filename)
248 {
249     char buffer[4];
250     int i;
251     gzFile f;
252
253     f = gzopen(filename, "rb");
254
255     if (f == NULL)
256     {
257         printf("Error: savestate file '%s' is corrupt.\n", filename);
258         return 1;
259     }
260
261     gzread(f, rom_md5, 32);
262
263     gzread(f, rdram_register, SIZE_REG_RDRAM);
264     gzread(f, mips_register, SIZE_REG_MIPS);
265     gzread(f, pi_register, SIZE_REG_PI);
266     gzread(f, sp_register, SIZE_REG_SP);
267     gzread(f, rsp_register, SIZE_REG_RSP);
268     gzread(f, si_register, SIZE_REG_SI);
269     gzread(f, vi_register, SIZE_REG_VI);
270     gzread(f, ri_register, SIZE_REG_RI);
271     gzread(f, ai_register, SIZE_REG_AI);
272     gzread(f, dpc_register, SIZE_REG_DPC);
273     gzread(f, dps_register, SIZE_REG_DPS);
274
275     gzread(f, rdram, 0x800000);
276     gzread(f, SP_DMEM, 0x1000);
277     gzread(f, SP_IMEM, 0x1000);
278     gzread(f, PIF_RAM, 0x40);
279
280     gzread(f, flashram, SIZE_FLASHRAM_INFO);
281
282     memset(tlb_LUT_r, 0, 0x400000);
283     memset(tlb_LUT_w, 0, 0x400000);
284     gzread(f, tlb_LUT_r, 0x100000);
285     gzread(f, tlb_LUT_w, 0x100000);
286
287     gzread(f, llbit, 4);
288     gzread(f, reg, 32*8);
289     for (i = 0; i < 32; i++)
290     {
291         gzread(f, reg_cop0[i], 4);
292         gzread(f, buffer, 4); /* for compatibility with older versions. */
293     }
294     gzread(f, lo, 8);
295     gzread(f, hi, 8);
296     gzread(f, reg_cop1_fgr_64[0], 32 * 8);
297     gzread(f, FCR0, 4);
298     gzread(f, FCR31, 4);
299     gzread(f, tlb_e[0], 32 * SIZE_TLB_ENTRY);
300     gzread(f, PCaddr, 4);
301
302     gzread(f, next_interupt, 4);
303     gzread(f, next_vi, 4);
304     gzread(f, vi_field, 4);
305
306     queuelength = 0;
307     while(queuelength < SIZE_MAX_EVENTQUEUE)
308     {
309         if (gzread(f, eventqueue + queuelength, 4) != 4)
310         {
311             printf("Error: savestate file '%s' is corrupt.\n", filename);
312             return 2;
313         }
314         if (*((unsigned int*) &eventqueue[queuelength]) == 0xFFFFFFFF)
315         {
316             queuelength += 4;
317             break;
318         }
319         gzread(f, eventqueue + queuelength + 4, 4);
320         queuelength += 8;
321     }
322
323     if (queuelength >= SIZE_MAX_EVENTQUEUE)
324     {
325         printf("Error: savestate file '%s' has event queue larger than %i bytes.\n", filename, SIZE_MAX_EVENTQUEUE);
326         return 3;
327     }
328
329     gzclose(f);
330     return 0;
331 }
332
333 /* State Saving Functions */
334
335 int save_newest(const char *filename)
336 {
337     unsigned char outbuf[4];
338     gzFile f;
339
340     f = gzopen(filename, "wb");
341
342     /* write magic number */
343     gzwrite(f, savestate_magic, 8);
344
345     /* write savestate file version in big-endian */
346     outbuf[0] = (savestate_newest_version >> 24) & 0xff;
347     outbuf[1] = (savestate_newest_version >> 16) & 0xff;
348     outbuf[2] = (savestate_newest_version >>  8) & 0xff;
349     outbuf[3] = (savestate_newest_version >>  0) & 0xff;
350     gzwrite(f, outbuf, 4);
351
352     gzwrite(f, rom_md5, 32);
353
354     gzwrite(f, rdram_register, SIZE_REG_RDRAM);
355     gzwrite(f, mips_register, SIZE_REG_MIPS);
356     gzwrite(f, pi_register, SIZE_REG_PI);
357     gzwrite(f, sp_register, SIZE_REG_SP);
358     gzwrite(f, rsp_register, SIZE_REG_RSP);
359     gzwrite(f, si_register, SIZE_REG_SI);
360     gzwrite(f, vi_register, SIZE_REG_VI);
361     gzwrite(f, ri_register, SIZE_REG_RI);
362     gzwrite(f, ai_register, SIZE_REG_AI);
363     gzwrite(f, dpc_register, SIZE_REG_DPC);
364     gzwrite(f, dps_register, SIZE_REG_DPS);
365
366     gzwrite(f, rdram, 0x800000);
367     gzwrite(f, SP_DMEM, 0x1000);
368     gzwrite(f, SP_IMEM, 0x1000);
369     gzwrite(f, PIF_RAM, 0x40);
370
371     gzwrite(f, flashram, SIZE_FLASHRAM_INFO);
372
373     gzwrite(f, tlb_LUT_r, 0x400000);
374     gzwrite(f, tlb_LUT_w, 0x400000);
375
376     gzwrite(f, llbit, 4);
377     gzwrite(f, reg[0], 32*8);
378     gzwrite(f, reg_cop0[0], 32*4);
379     gzwrite(f, lo, 8);
380     gzwrite(f, hi, 8);
381     gzwrite(f, reg_cop1_fgr_64[0], 32*8);
382     gzwrite(f, FCR0, 4);
383     gzwrite(f, FCR31, 4);
384     gzwrite(f, tlb_e[0], 32 * SIZE_TLB_ENTRY);
385     gzwrite(f, PCaddr, 4);
386
387     gzwrite(f, next_interupt, 4);
388     gzwrite(f, next_vi, 4);
389     gzwrite(f, vi_field, 4);
390
391     gzwrite(f, eventqueue, queuelength);
392
393     gzclose(f);
394     return 0;
395 }
396