main gst.c
  1/*
  2 Copyright 2013 Michael Pavone
  3 This file is part of BlastEm.
  4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
  5*/
  6#include "genesis.h"
  7#include "gst.h"
  8#include <string.h>
  9#include <stdio.h>
 10
 11#define GST_68K_REGS 0x80
 12#define GST_68K_REG_SIZE (0xDA-GST_68K_REGS)
 13#define GST_68K_PC_OFFSET (0xC8-GST_68K_REGS)
 14#define GST_68K_SR_OFFSET (0xD0-GST_68K_REGS)
 15#define GST_68K_USP_OFFSET (0xD2-GST_68K_REGS)
 16#define GST_68K_SSP_OFFSET (0xD6-GST_68K_REGS)
 17#define GST_68K_RAM  0x2478
 18#define GST_Z80_REGS 0x404
 19#define GST_Z80_REG_SIZE (0x440-GST_Z80_REGS)
 20#define GST_Z80_RAM 0x474
 21#define GST_VDP_REGS 0xFA
 22#define GST_VDP_MEM 0x12478
 23#define GST_YM_OFFSET 0x1E4
 24#define GST_YM_SIZE (0x3E4-GST_YM_OFFSET)
 25
 26uint32_t read_le_32(uint8_t * data)
 27{
 28	return data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0];
 29}
 30
 31uint16_t read_le_16(uint8_t * data)
 32{
 33	return data[1] << 8 | data[0];
 34}
 35
 36uint16_t read_be_16(uint8_t * data)
 37{
 38	return data[0] << 8 | data[1];
 39}
 40
 41void write_le_32(uint8_t * dst, uint32_t val)
 42{
 43	dst[0] = val;
 44	dst[1] = val >> 8;
 45	dst[2] = val >> 16;
 46	dst[3] = val >> 24;
 47}
 48
 49void write_le_16(uint8_t * dst, uint16_t val)
 50{
 51	dst[0] = val;
 52	dst[1] = val >> 8;
 53}
 54
 55void write_be_32(uint8_t * dst, uint32_t val)
 56{
 57	dst[0] = val >> 24;
 58	dst[1] = val >> 16;
 59	dst[2] = val >> 8;
 60	dst[3] = val;
 61}
 62
 63void write_be_16(uint8_t * dst, uint16_t val)
 64{
 65	dst[0] = val >> 8;
 66	dst[1] = val;
 67}
 68
 69uint32_t m68k_load_gst(m68k_context * context, FILE * gstfile)
 70{
 71	uint8_t buffer[GST_68K_REG_SIZE];
 72	fseek(gstfile, GST_68K_REGS, SEEK_SET);
 73	if (fread(buffer, 1, GST_68K_REG_SIZE, gstfile) != GST_68K_REG_SIZE) {
 74		fputs("Failed to read 68K registers from savestate\n", stderr);
 75		return 0;
 76	}
 77	uint8_t * curpos = buffer;
 78	for (int i = 0; i < 8; i++) {
 79		context->dregs[i] = read_le_32(curpos);
 80		curpos += sizeof(uint32_t);
 81	}
 82	for (int i = 0; i < 8; i++) {
 83		context->aregs[i] = read_le_32(curpos);
 84		curpos += sizeof(uint32_t);
 85	}
 86	uint32_t pc = read_le_32(buffer + GST_68K_PC_OFFSET);
 87	uint16_t sr = read_le_16(buffer + GST_68K_SR_OFFSET);
 88	context->status = sr >> 8;
 89	for (int flag = 4; flag >= 0; flag--) {
 90		context->flags[flag] = sr & 1;
 91		sr >>= 1;
 92	}
 93	if (context->status & (1 << 5)) {
 94		context->aregs[8] = read_le_32(buffer + GST_68K_USP_OFFSET);
 95	} else {
 96		context->aregs[8] = read_le_32(buffer + GST_68K_SSP_OFFSET);
 97	}
 98	
 99	return pc;
100}
101
102uint8_t m68k_save_gst(m68k_context * context, uint32_t pc, FILE * gstfile)
103{
104	uint8_t buffer[GST_68K_REG_SIZE];
105	uint8_t * curpos = buffer;
106	for (int i = 0; i < 8; i++) {
107		write_le_32(curpos, context->dregs[i]);
108		curpos += sizeof(uint32_t);
109	}
110	for (int i = 0; i < 8; i++) {
111		write_le_32(curpos, context->aregs[i]);
112		curpos += sizeof(uint32_t);
113	}
114	write_le_32(buffer + GST_68K_PC_OFFSET, pc);
115	uint16_t sr = context->status << 3;
116	for (int flag = 4; flag >= 0; flag--) {
117		sr <<= 1;
118		sr |= context->flags[flag];
119	}
120	write_le_16(buffer + GST_68K_SR_OFFSET, sr);
121	if (context->status & (1 << 5)) {
122		write_le_32(buffer + GST_68K_USP_OFFSET, context->aregs[8]);
123		write_le_32(buffer + GST_68K_SSP_OFFSET, context->aregs[7]);
124	} else {
125		write_le_32(buffer + GST_68K_USP_OFFSET, context->aregs[7]);
126		write_le_32(buffer + GST_68K_SSP_OFFSET, context->aregs[8]);
127	}
128	fseek(gstfile, GST_68K_REGS, SEEK_SET);
129	if (fwrite(buffer, 1, GST_68K_REG_SIZE, gstfile) != GST_68K_REG_SIZE) {
130		fputs("Failed to write 68K registers to savestate\n", stderr);
131		return 0;
132	}
133
134	return 1;
135}
136
137uint8_t z80_load_gst(z80_context * context, FILE * gstfile)
138{
139	uint8_t regdata[GST_Z80_REG_SIZE];
140	fseek(gstfile, GST_Z80_REGS, SEEK_SET);
141	if (fread(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) {
142		fputs("Failed to read Z80 registers from savestate\n", stderr);
143		return 0;
144	}
145	uint8_t * curpos = regdata;
146	uint8_t f = *(curpos++);
147	context->flags[ZF_C] = f & 1;
148	f >>= 1;
149	context->flags[ZF_N] = f & 1;
150	f >>= 1;
151	context->flags[ZF_PV] = f & 1;
152	f >>= 2;
153	context->flags[ZF_H] = f & 1;
154	f >>= 2;
155	context->flags[ZF_Z] = f & 1;
156	f >>= 1;
157	context->flags[ZF_S] = f;
158
159	context->regs[Z80_A] = *curpos;
160	curpos += 3;
161	for (int reg = Z80_C; reg <= Z80_IYH; reg++) {
162		context->regs[reg++] = *(curpos++);
163		context->regs[reg] = *curpos;
164		curpos += 3;
165	}
166	context->pc = read_le_16(curpos);
167	curpos += 4;
168	context->sp = read_le_16(curpos);
169	curpos += 4;
170	f = *(curpos++);
171	context->alt_flags[ZF_C] = f & 1;
172	f >>= 1;
173	context->alt_flags[ZF_N] = f & 1;
174	f >>= 1;
175	context->alt_flags[ZF_PV] = f & 1;
176	f >>= 2;
177	context->alt_flags[ZF_H] = f & 1;
178	f >>= 2;
179	context->alt_flags[ZF_Z] = f & 1;
180	f >>= 1;
181	context->alt_flags[ZF_S] = f;
182	context->alt_regs[Z80_A] = *curpos;
183	curpos += 3;
184	for (int reg = Z80_C; reg <= Z80_H; reg++) {
185		context->alt_regs[reg++] = *(curpos++);
186		context->alt_regs[reg] = *curpos;
187		curpos += 3;
188	}
189	context->regs[Z80_I] = *curpos;
190	curpos += 2;
191	context->iff1 = context->iff2 = *curpos;
192	curpos += 2;
193	context->reset = !*(curpos++);
194	context->busreq = *curpos;
195	curpos += 3;
196	uint32_t bank = read_le_32(curpos);
197	if (bank < 0x400000) {
198		context->mem_pointers[1] = context->mem_pointers[2] + bank;
199	} else {
200		context->mem_pointers[1] = NULL;
201	}
202	context->bank_reg = bank >> 15;
203	uint8_t buffer[Z80_RAM_BYTES];
204	fseek(gstfile, GST_Z80_RAM, SEEK_SET);
205	if(fread(buffer, 1, sizeof(buffer), gstfile) != (8*1024)) {
206		fputs("Failed to read Z80 RAM from savestate\n", stderr);
207		return 0;
208	}
209	for (int i = 0; i < Z80_RAM_BYTES; i++)
210	{
211		if (context->mem_pointers[0][i] != buffer[i]) {
212			context->mem_pointers[0][i] = buffer[i];
213			z80_handle_code_write(i, context);
214		}
215	}
216	context->native_pc = NULL;
217	context->extra_pc = NULL;
218	return 1;
219}
220
221uint8_t vdp_load_gst(vdp_context * context, FILE * state_file)
222{
223	uint8_t tmp_buf[VRAM_SIZE];
224	fseek(state_file, GST_VDP_REGS, SEEK_SET);
225	if (fread(tmp_buf, 1, VDP_REGS, state_file) != VDP_REGS) {
226		fputs("Failed to read VDP registers from savestate\n", stderr);
227		return 0;
228	}
229	for (uint16_t i = 0; i < VDP_REGS; i++)
230	{
231		vdp_control_port_write(context, 0x8000 | (i << 8) | tmp_buf[i]);
232	}
233	if (fread(tmp_buf, 1, CRAM_SIZE*2, state_file) != CRAM_SIZE*2) {
234		fputs("Failed to read CRAM from savestate\n", stderr);
235		return 0;
236	}
237	for (int i = 0; i < CRAM_SIZE; i++) {
238		uint16_t value;
239		write_cram_internal(context, i, (tmp_buf[i*2+1] << 8) | tmp_buf[i*2]);
240	}
241	if (fread(tmp_buf, 2, VSRAM_SIZE, state_file) != VSRAM_SIZE) {
242		fputs("Failed to read VSRAM from savestate\n", stderr);
243		return 0;
244	}
245	for (int i = 0; i < VSRAM_SIZE; i++) {
246		context->vsram[i] = (tmp_buf[i*2+1] << 8) | tmp_buf[i*2];
247	}
248	fseek(state_file, GST_VDP_MEM, SEEK_SET);
249	if (fread(tmp_buf, 1, VRAM_SIZE, state_file) != VRAM_SIZE) {
250		fputs("Failed to read VRAM from savestate\n", stderr);
251		return 0;
252	}
253	for (int i = 0; i < VRAM_SIZE; i++) {
254		context->vdpmem[i] = tmp_buf[i];
255		vdp_check_update_sat_byte(context, i, tmp_buf[i]);
256	}
257	return 1;
258}
259
260uint8_t vdp_save_gst(vdp_context * context, FILE * outfile)
261{
262	uint8_t tmp_buf[CRAM_SIZE*2];
263	fseek(outfile, GST_VDP_REGS, SEEK_SET);
264	if(fwrite(context->regs, 1, VDP_REGS, outfile) != VDP_REGS) {
265		fputs("Error writing VDP regs to savestate\n", stderr);
266		return 0;
267	}
268	for (int i = 0; i < CRAM_SIZE; i++)
269	{
270		tmp_buf[i*2] = context->cram[i];
271		tmp_buf[i*2+1] = context->cram[i] >> 8;
272	}
273	if (fwrite(tmp_buf, 1, sizeof(tmp_buf), outfile) != sizeof(tmp_buf)) {
274		fputs("Error writing CRAM to savestate\n", stderr);
275		return 0;
276	}
277	for (int i = 0; i < VSRAM_SIZE; i++)
278	{
279		tmp_buf[i*2] = context->vsram[i];
280		tmp_buf[i*2+1] = context->vsram[i] >> 8;
281	}
282	if (fwrite(tmp_buf, 2, VSRAM_SIZE, outfile) != VSRAM_SIZE) {
283		fputs("Error writing VSRAM to savestate\n", stderr);
284		return 0;
285	}
286	fseek(outfile, GST_VDP_MEM, SEEK_SET);
287	if (fwrite(context->vdpmem, 1, VRAM_SIZE, outfile) != VRAM_SIZE) {
288		fputs("Error writing VRAM to savestate\n", stderr);
289		return 0;
290	}
291	return 1;
292}
293
294uint8_t z80_save_gst(z80_context * context, FILE * gstfile)
295{
296	uint8_t regdata[GST_Z80_REG_SIZE];
297	uint8_t * curpos = regdata;
298	memset(regdata, 0, sizeof(regdata));
299	uint8_t f = context->flags[ZF_S];
300	f <<= 1;
301	f |= context->flags[ZF_Z] ;
302	f <<= 2;
303	f |= context->flags[ZF_H];
304	f <<= 2;
305	f |= context->flags[ZF_PV];
306	f <<= 1;
307	f |= context->flags[ZF_N];
308	f <<= 1;
309	f |= context->flags[ZF_C];
310	*(curpos++) = f;
311	*curpos = context->regs[Z80_A];
312
313	curpos += 3;
314	for (int reg = Z80_C; reg <= Z80_IYH; reg++) {
315		*(curpos++) = context->regs[reg++];
316		*curpos = context->regs[reg];
317		curpos += 3;
318	}
319	write_le_16(curpos, context->pc);
320	curpos += 4;
321	write_le_16(curpos, context->sp);
322	curpos += 4;
323	f = context->alt_flags[ZF_S];
324	f <<= 1;
325	f |= context->alt_flags[ZF_Z] ;
326	f <<= 2;
327	f |= context->alt_flags[ZF_H];
328	f <<= 2;
329	f |= context->alt_flags[ZF_PV];
330	f <<= 1;
331	f |= context->alt_flags[ZF_N];
332	f <<= 1;
333	f |= context->alt_flags[ZF_C];
334	*(curpos++) = f;
335	*curpos = context->alt_regs[Z80_A];
336	curpos += 3;
337	for (int reg = Z80_C; reg <= Z80_H; reg++) {
338		*(curpos++) = context->alt_regs[reg++];
339		*curpos = context->alt_regs[reg];
340		curpos += 3;
341	}
342	*curpos = context->regs[Z80_I];
343	curpos += 2;
344	*curpos = context->iff1;
345	curpos += 2;
346	*(curpos++) = !context->reset;
347	*curpos = context->busreq;
348	curpos += 3;
349	uint32_t bank = context->bank_reg << 15;
350	write_le_32(curpos, bank);
351	fseek(gstfile, GST_Z80_REGS, SEEK_SET);
352	if (fwrite(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) {
353		return 0;
354	}
355	fseek(gstfile, GST_Z80_RAM, SEEK_SET);
356	if(fwrite(context->mem_pointers[0], 1, 8*1024, gstfile) != (8*1024)) {
357		fputs("Failed to write Z80 RAM to savestate\n", stderr);
358		return 0;
359	}
360	return 1;
361}
362
363uint8_t ym_load_gst(ym2612_context * context, FILE * gstfile)
364{
365	uint8_t regdata[GST_YM_SIZE];
366	fseek(gstfile, GST_YM_OFFSET, SEEK_SET);
367	if (fread(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) {
368		return 0;
369	}
370	for (int i = 0; i < sizeof(regdata); i++) {
371		if (i & 0x100) {
372			ym_address_write_part2(context, i & 0xFF);
373		} else {
374			ym_address_write_part1(context, i);
375		}
376		ym_data_write(context, regdata[i]);
377	}
378	return 1;
379}
380
381uint8_t ym_save_gst(ym2612_context * context, FILE * gstfile)
382{
383	uint8_t regdata[GST_YM_SIZE];
384	for (int i = 0; i < sizeof(regdata); i++) {
385		if (i & 0x100) {
386			int reg = (i & 0xFF);
387			if (reg >= YM_PART2_START && reg < YM_REG_END) {
388				regdata[i] = context->part2_regs[reg-YM_PART2_START];
389			} else {
390				regdata[i] = 0xFF;
391			}
392		} else {
393			if (i >= YM_PART1_START && i < YM_REG_END) {
394				regdata[i] = context->part1_regs[i-YM_PART1_START];
395			} else {
396				regdata[i] = 0xFF;
397			}
398		}
399	}
400	fseek(gstfile, GST_YM_OFFSET, SEEK_SET);
401	if (fwrite(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) {
402		return 0;
403	}
404	return 1;
405}
406
407uint32_t load_gst(genesis_context * gen, char * fname)
408{
409	char buffer[4096];
410	FILE * gstfile = fopen(fname, "rb");
411	if (!gstfile) {
412		fprintf(stderr, "Could not open file %s for reading\n", fname);
413		goto error;
414	}
415	char ident[5];
416	if (fread(ident, 1, sizeof(ident), gstfile) != sizeof(ident)) {
417		fprintf(stderr, "Could not read ident code from %s\n", fname);
418		goto error_close;
419	}
420	if (memcmp(ident, "GST\x40\xE0", 3) != 0) {
421		fprintf(stderr, "%s doesn't appear to be a GST savestate. The ident code is %c%c%c\\x%X\\x%X instead of GST\\x40\\xE0.\n", fname, ident[0], ident[1], ident[2], ident[3], ident[4]);
422		goto error_close;
423	}
424	uint32_t pc = m68k_load_gst(gen->m68k, gstfile);
425	if (!pc) {
426		goto error_close;
427	}
428	
429	if (!vdp_load_gst(gen->vdp, gstfile)) {
430		goto error_close;
431	}
432	if (!ym_load_gst(gen->ym, gstfile)) {
433		goto error_close;
434	}
435	if (!z80_load_gst(gen->z80, gstfile)) {
436		goto error_close;
437	}
438	gen->io.ports[0].control = 0x40;
439	gen->io.ports[1].control = 0x40;
440	
441	fseek(gstfile, GST_68K_RAM, SEEK_SET);
442	for (int i = 0; i < (32*1024);) {
443		if (fread(buffer, 1, sizeof(buffer), gstfile) != sizeof(buffer)) {
444			fputs("Failed to read 68K RAM from savestate\n", stderr);
445			return 0;
446		}
447		for(char *curpos = buffer; curpos < (buffer + sizeof(buffer)); curpos += sizeof(uint16_t)) {
448			uint16_t word = read_be_16(curpos);
449			if (word != gen->work_ram[i]) {
450				gen->work_ram[i] = word;
451				m68k_handle_code_write(0xFF0000 | (i << 1), gen->m68k);
452			}
453			i++;
454		}
455	}
456	fclose(gstfile);
457	return pc;
458
459error_close:
460	fclose(gstfile);
461error:
462	return 0;
463}
464
465uint8_t save_gst(genesis_context * gen, char *fname, uint32_t m68k_pc)
466{
467	char buffer[4096];
468	FILE * gstfile = fopen(fname, "wb");
469	if (!gstfile) {
470		fprintf(stderr, "Could not open %s for writing\n", fname);
471		goto error;
472	}
473	if (fwrite("GST\x40\xE0", 1, 5, gstfile) != 5) {
474		fputs("Error writing signature to savestate\n", stderr);
475		goto error_close;
476	}
477	if (!m68k_save_gst(gen->m68k, m68k_pc, gstfile)) {
478		goto error_close;
479	}
480	if (!z80_save_gst(gen->z80, gstfile)) {
481		goto error_close;
482	}
483	if (!vdp_save_gst(gen->vdp, gstfile)) {
484		goto error_close;
485	}
486	if (!ym_save_gst(gen->ym, gstfile)) {
487		goto error_close;
488	}
489	fseek(gstfile, GST_68K_RAM, SEEK_SET);
490	for (int i = 0; i < (32*1024);) {
491		for(char *curpos = buffer; curpos < (buffer + sizeof(buffer)); curpos += sizeof(uint16_t)) {
492			write_be_16(curpos, gen->work_ram[i++]);
493		}
494		if (fwrite(buffer, 1, sizeof(buffer), gstfile) != sizeof(buffer)) {
495			fputs("Failed to write 68K RAM to savestate\n", stderr);
496			return 0;
497		}
498	}
499	return 1;
500
501error_close:
502	fclose(gstfile);
503error:
504	return 0;
505}