Core commit. Compile and run on the OpenPandora
[mupen64plus-pandora.git] / source / mupen64plus-core / tools / savestate_convert.c
CommitLineData
451ab91e 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 */
28const char *savestate_magic = "M64+SAVE";
29const 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
52char rom_md5[32];
53
54char rdram_register[SIZE_REG_RDRAM];
55char mips_register[SIZE_REG_MIPS];
56char pi_register[SIZE_REG_PI];
57char sp_register[SIZE_REG_SP];
58char rsp_register[SIZE_REG_RSP];
59char si_register[SIZE_REG_SI];
60char vi_register[SIZE_REG_VI];
61char ri_register[SIZE_REG_RI];
62char ai_register[SIZE_REG_AI];
63char dpc_register[SIZE_REG_DPC];
64char dps_register[SIZE_REG_DPS];
65
66char *rdram; /* 0x800000 bytes */
67char SP_DMEM[0x1000];
68char SP_IMEM[0x1000];
69char PIF_RAM[0x40];
70
71char flashram[SIZE_FLASHRAM_INFO];
72
73char *tlb_LUT_r; /* 0x400000 bytes */
74char *tlb_LUT_w; /* 0x400000 bytes */
75
76char llbit[4];
77char reg[32][8];
78char reg_cop0[32][4];
79char lo[8];
80char hi[8];
81char reg_cop1_fgr_64[32][8];
82char FCR0[4];
83char FCR31[4];
84char tlb_e[32][SIZE_TLB_ENTRY];
85char PCaddr[4];
86
87char next_interupt[4];
88char next_vi[4];
89char vi_field[4];
90
91char eventqueue[SIZE_MAX_EVENTQUEUE];
92
93/* savestate data parameters calculated from file contents */
94int queuelength = 0;
95
96/* Forward declarations for functions */
97void printhelp(const char *progname);
98
99int allocate_memory(void);
100void free_memory(void);
101
102int load_original_mupen64(const char *filename);
103int save_newest(const char *filename);
104
105/* Main Function - parse arguments, check version, load state file, overwrite state file with new one */
106int 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
194void 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
202int 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
225void 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 */
247int 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
335int 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