Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmupen64plus/mupen64plus-core/tools/savestate_convert.c
2 views
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
397
398