# HG changeset patch # User Mike Pavone # Date 1378070837 25200 # Node ID 608815ab4ff26816d4cabefa777da60f97ae9949 # Parent b7c3b2d228582aa22f092ac8a298c6adb5ea0452# Parent 3758bcdae5de73abe72dcec1ac37fd2b2f7b217b Merge diff -r 3758bcdae5de -r 608815ab4ff2 Makefile --- a/Makefile Sun Sep 01 12:11:28 2013 -0700 +++ b/Makefile Sun Sep 01 14:27:17 2013 -0700 @@ -18,18 +18,18 @@ all : dis trans stateview blastem -blastem : blastem.o vdp.o render_sdl.o io.o config.o tern.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS) - $(CC) -ggdb -o blastem blastem.o vdp.o render_sdl.o io.o config.o tern.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS) $(LDFLAGS) +blastem : blastem.o vdp.o render_sdl.o io.o config.o tern.o gst.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS) + $(CC) -ggdb -o blastem blastem.o vdp.o render_sdl.o io.o config.o tern.o gst.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS) $(LDFLAGS) dis : dis.o 68kinst.o $(CC) -o dis dis.o 68kinst.o zdis : zdis.o z80inst.o $(CC) -o zdis zdis.o z80inst.o - + libemu68k.a : $(M68KOBJS) $(TRANSOBJS) ar rcs libemu68k.a $(M68KOBJS) $(TRANSOBJS) - + trans : trans.o $(M68KOBJS) $(TRANSOBJS) $(CC) -o trans trans.o $(M68KOBJS) $(TRANSOBJS) @@ -48,6 +48,9 @@ vgmplay : vgmplay.o render_sdl.o $(AUDIOOBJS) $(CC) -o vgmplay vgmplay.o render_sdl.o $(AUDIOOBJS) `pkg-config --libs $(LIBS)` +testgst : testgst.o gst.o + $(CC) -o testgst testgst.o gst.o + test_x86 : test_x86.o gen_x86.o $(CC) -o test_x86 test_x86.o gen_x86.o @@ -56,7 +59,7 @@ offsets : offsets.c z80_to_x86.h m68k_to_x86.h $(CC) -o offsets offsets.c - + %.o : %.S $(CC) -c -o $@ $< diff -r 3758bcdae5de -r 608815ab4ff2 blastem.c --- a/blastem.c Sun Sep 01 12:11:28 2013 -0700 +++ b/blastem.c Sun Sep 01 14:27:17 2013 -0700 @@ -5,6 +5,7 @@ #include "vdp.h" #include "render.h" #include "blastem.h" +#include "gst.h" #include #include #include @@ -152,6 +153,7 @@ } int break_on_sync = 0; +int save_state = 0; uint8_t reset = 1; uint8_t need_reset = 0; @@ -258,9 +260,19 @@ context->int_ack = 0; } adjust_int_cycle(context, v_context); - if (break_on_sync && address) { - break_on_sync = 0; - debugger(context, address); + if (address) { + if (break_on_sync) { + break_on_sync = 0; + debugger(context, address); + } + if (save_state) { + save_state = 0; + while (!z_context->pc) + { + sync_z80(z_context, z_context->current_cycle * MCLKS_PER_Z80 + MCLKS_PER_Z80); + } + save_gst(gen, "savestate.gst", address); + } } return context; } @@ -1467,190 +1479,6 @@ return context; } -#define GST_68K_REGS 0x80 -#define GST_68K_REG_SIZE (0xDA-GST_68K_REGS) -#define GST_68K_PC_OFFSET (0xC8-GST_68K_REGS) -#define GST_68K_SR_OFFSET (0xD0-GST_68K_REGS) -#define GST_68K_USP_OFFSET (0xD2-GST_68K_REGS) -#define GST_68K_SSP_OFFSET (0xD6-GST_68K_REGS) -#define GST_68K_RAM 0x2478 -#define GST_Z80_REGS 0x404 -#define GST_Z80_REG_SIZE (0x440-GST_Z80_REGS) -#define GST_Z80_RAM 0x474 - -uint32_t read_le_32(uint8_t * data) -{ - return data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0]; -} - -uint16_t read_le_16(uint8_t * data) -{ - return data[1] << 8 | data[0]; -} - -uint16_t read_be_16(uint8_t * data) -{ - return data[0] << 8 | data[1]; -} - -uint32_t m68k_load_gst(m68k_context * context, FILE * gstfile) -{ - uint8_t buffer[4096]; - fseek(gstfile, GST_68K_REGS, SEEK_SET); - if (fread(buffer, 1, GST_68K_REG_SIZE, gstfile) != GST_68K_REG_SIZE) { - fputs("Failed to read 68K registers from savestate\n", stderr); - return 0; - } - uint8_t * curpos = buffer; - for (int i = 0; i < 8; i++) { - context->dregs[i] = read_le_32(curpos); - curpos += sizeof(uint32_t); - } - for (int i = 0; i < 8; i++) { - context->aregs[i] = read_le_32(curpos); - curpos += sizeof(uint32_t); - } - uint32_t pc = read_le_32(buffer + GST_68K_PC_OFFSET); - uint16_t sr = read_le_16(buffer + GST_68K_SR_OFFSET); - context->status = sr >> 8; - for (int flag = 4; flag >= 0; flag--) { - context->flags[flag] = sr & 1; - sr >>= 1; - } - if (context->status & (1 << 5)) { - context->aregs[8] = read_le_32(buffer + GST_68K_USP_OFFSET); - } else { - context->aregs[8] = read_le_32(buffer + GST_68K_SSP_OFFSET); - } - fseek(gstfile, GST_68K_RAM, SEEK_SET); - for (int i = 0; i < (32*1024);) { - if (fread(buffer, 1, sizeof(buffer), gstfile) != sizeof(buffer)) { - fputs("Failed to read 68K RAM from savestate\n", stderr); - return 0; - } - for(curpos = buffer; curpos < (buffer + sizeof(buffer)); curpos += sizeof(uint16_t)) { - context->mem_pointers[1][i++] = read_be_16(curpos); - } - } - return pc; -} - -uint8_t z80_load_gst(z80_context * context, FILE * gstfile) -{ - uint8_t regdata[GST_Z80_REG_SIZE]; - fseek(gstfile, GST_Z80_REGS, SEEK_SET); - if (fread(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) { - fputs("Failed to read Z80 registers from savestate\n", stderr); - return 0; - } - uint8_t * curpos = regdata; - uint8_t f = *(curpos++); - context->flags[ZF_C] = f & 1; - f >>= 1; - context->flags[ZF_N] = f & 1; - f >>= 1; - context->flags[ZF_PV] = f & 1; - f >>= 2; - context->flags[ZF_H] = f & 1; - f >>= 2; - context->flags[ZF_Z] = f & 1; - f >>= 1; - context->flags[ZF_S] = f; - - context->regs[Z80_A] = *curpos; - curpos += 3; - for (int reg = Z80_C; reg <= Z80_IYH; reg++) { - context->regs[reg++] = *(curpos++); - context->regs[reg] = *curpos; - curpos += 3; - } - uint16_t pc = read_le_16(curpos); - curpos += 4; - context->sp = read_le_16(curpos); - curpos += 4; - f = *(curpos++); - context->alt_flags[ZF_C] = f & 1; - f >>= 1; - context->alt_flags[ZF_N] = f & 1; - f >>= 1; - context->alt_flags[ZF_PV] = f & 1; - f >>= 2; - context->alt_flags[ZF_H] = f & 1; - f >>= 2; - context->alt_flags[ZF_Z] = f & 1; - f >>= 1; - context->alt_flags[ZF_S] = f; - context->alt_regs[Z80_A] = *curpos; - curpos += 3; - for (int reg = Z80_C; reg <= Z80_H; reg++) { - context->alt_regs[reg++] = *(curpos++); - context->alt_regs[reg] = *curpos; - curpos += 3; - } - context->regs[Z80_I] = *curpos; - curpos += 2; - context->iff1 = context->iff2 = *curpos; - curpos += 2; - reset = !*(curpos++); - busreq = *curpos; - curpos += 3; - uint32_t bank = read_le_32(curpos); - if (bank < 0x400000) { - context->mem_pointers[1] = context->mem_pointers[2] + bank; - } else { - context->mem_pointers[1] = NULL; - } - context->bank_reg = bank >> 15; - fseek(gstfile, GST_Z80_RAM, SEEK_SET); - if(fread(context->mem_pointers[0], 1, 8*1024, gstfile) != (8*1024)) { - fputs("Failed to read Z80 RAM from savestate\n", stderr); - return 0; - } - context->native_pc = z80_get_native_address_trans(context, pc); - return 1; -} - -uint32_t load_gst(genesis_context * gen, char * fname) -{ - FILE * gstfile = fopen(fname, "rb"); - if (!gstfile) { - fprintf(stderr, "Could not open file %s for reading\n", fname); - goto error; - } - char ident[5]; - if (fread(ident, 1, sizeof(ident), gstfile) != sizeof(ident)) { - fprintf(stderr, "Could not read ident code from %s\n", fname); - goto error_close; - } - if (memcmp(ident, "GST\xE0\x40", 3) != 0) { - 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\\xE0\\x40.\n", fname, ident[0], ident[1], ident[2], ident[3], ident[4]); - goto error_close; - } - uint32_t pc = m68k_load_gst(gen->m68k, gstfile); - if (!pc) { - goto error_close; - } - if (!vdp_load_gst(gen->vdp, gstfile)) { - goto error_close; - } - if (!ym_load_gst(gen->ym, gstfile)) { - goto error_close; - } - if (!z80_load_gst(gen->z80, gstfile)) { - goto error_close; - } - gen->ports[0].control = 0x40; - gen->ports[1].control = 0x40; - adjust_int_cycle(gen->m68k, gen->vdp); - fclose(gstfile); - return pc; - -error_close: - fclose(gstfile); -error: - return 0; -} - #define ROM_END 0x1A4 #define RAM_ID 0x1B0 #define RAM_FLAGS 0x1B2 @@ -1807,11 +1635,15 @@ if (statefile) { uint32_t pc = load_gst(gen, statefile); if (!pc) { + fprintf(stderr, "Failed to load save state %s\n", statefile); exit(1); } + printf("Loaded %s\n", statefile); if (debug) { insert_breakpoint(&context, pc, (uint8_t *)debugger); } + adjust_int_cycle(gen->m68k, gen->vdp); + gen->z80->native_pc = z80_get_native_address_trans(gen->z80, gen->z80->pc); start_68k_context(&context, pc); } else { if (debug) { diff -r 3758bcdae5de -r 608815ab4ff2 blastem.h --- a/blastem.h Sun Sep 01 12:11:28 2013 -0700 +++ b/blastem.h Sun Sep 01 14:27:17 2013 -0700 @@ -31,7 +31,10 @@ extern genesis_context * genesis; extern int break_on_sync; +extern int save_state; extern tern_node * config; +extern uint8_t busreq; +extern uint8_t reset; uint16_t read_dma_value(uint32_t address); m68k_context * debugger(m68k_context * context, uint32_t address); diff -r 3758bcdae5de -r 608815ab4ff2 default.cfg --- a/default.cfg Sun Sep 01 12:11:28 2013 -0700 +++ b/default.cfg Sun Sep 01 14:27:17 2013 -0700 @@ -13,11 +13,12 @@ e gamepads.1.z f gamepads.1.mode enter gamepads.1.start - + [ ui.vdp_debug_mode ] ui.vdp_debug_pal u ui.enter_debugger esc ui.exit + ` ui.save_state } pads { 0 { diff -r 3758bcdae5de -r 608815ab4ff2 gst.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst.c Sun Sep 01 14:27:17 2013 -0700 @@ -0,0 +1,478 @@ +#include "gst.h" +#include + +#define GST_68K_REGS 0x80 +#define GST_68K_REG_SIZE (0xDA-GST_68K_REGS) +#define GST_68K_PC_OFFSET (0xC8-GST_68K_REGS) +#define GST_68K_SR_OFFSET (0xD0-GST_68K_REGS) +#define GST_68K_USP_OFFSET (0xD2-GST_68K_REGS) +#define GST_68K_SSP_OFFSET (0xD6-GST_68K_REGS) +#define GST_68K_RAM 0x2478 +#define GST_Z80_REGS 0x404 +#define GST_Z80_REG_SIZE (0x440-GST_Z80_REGS) +#define GST_Z80_RAM 0x474 +#define GST_VDP_REGS 0xFA +#define GST_VDP_MEM 0x12478 +#define GST_YM_OFFSET 0x1E4 +#define GST_YM_SIZE (0x3E4-GST_YM_OFFSET) + +uint32_t read_le_32(uint8_t * data) +{ + return data[3] << 24 | data[2] << 16 | data[1] << 8 | data[0]; +} + +uint16_t read_le_16(uint8_t * data) +{ + return data[1] << 8 | data[0]; +} + +uint16_t read_be_16(uint8_t * data) +{ + return data[0] << 8 | data[1]; +} + +void write_le_32(uint8_t * dst, uint32_t val) +{ + dst[0] = val; + dst[1] = val >> 8; + dst[2] = val >> 16; + dst[3] = val >> 24; +} + +void write_le_16(uint8_t * dst, uint16_t val) +{ + dst[0] = val; + dst[1] = val >> 8; +} + +void write_be_32(uint8_t * dst, uint32_t val) +{ + dst[0] = val >> 24; + dst[1] = val >> 16; + dst[2] = val >> 8; + dst[3] = val; +} + +void write_be_16(uint8_t * dst, uint16_t val) +{ + dst[0] = val >> 8; + dst[1] = val; +} + +uint32_t m68k_load_gst(m68k_context * context, FILE * gstfile) +{ + uint8_t buffer[4096]; + fseek(gstfile, GST_68K_REGS, SEEK_SET); + if (fread(buffer, 1, GST_68K_REG_SIZE, gstfile) != GST_68K_REG_SIZE) { + fputs("Failed to read 68K registers from savestate\n", stderr); + return 0; + } + uint8_t * curpos = buffer; + for (int i = 0; i < 8; i++) { + context->dregs[i] = read_le_32(curpos); + curpos += sizeof(uint32_t); + } + for (int i = 0; i < 8; i++) { + context->aregs[i] = read_le_32(curpos); + curpos += sizeof(uint32_t); + } + uint32_t pc = read_le_32(buffer + GST_68K_PC_OFFSET); + uint16_t sr = read_le_16(buffer + GST_68K_SR_OFFSET); + context->status = sr >> 8; + for (int flag = 4; flag >= 0; flag--) { + context->flags[flag] = sr & 1; + sr >>= 1; + } + if (context->status & (1 << 5)) { + context->aregs[8] = read_le_32(buffer + GST_68K_USP_OFFSET); + } else { + context->aregs[8] = read_le_32(buffer + GST_68K_SSP_OFFSET); + } + fseek(gstfile, GST_68K_RAM, SEEK_SET); + for (int i = 0; i < (32*1024);) { + if (fread(buffer, 1, sizeof(buffer), gstfile) != sizeof(buffer)) { + fputs("Failed to read 68K RAM from savestate\n", stderr); + return 0; + } + for(curpos = buffer; curpos < (buffer + sizeof(buffer)); curpos += sizeof(uint16_t)) { + context->mem_pointers[1][i++] = read_be_16(curpos); + } + } + return pc; +} + +uint8_t m68k_save_gst(m68k_context * context, uint32_t pc, FILE * gstfile) +{ + uint8_t buffer[4096]; + uint8_t * curpos = buffer; + for (int i = 0; i < 8; i++) { + write_le_32(curpos, context->dregs[i]); + curpos += sizeof(uint32_t); + } + for (int i = 0; i < 8; i++) { + write_le_32(curpos, context->aregs[i]); + curpos += sizeof(uint32_t); + } + write_le_32(buffer + GST_68K_PC_OFFSET, pc); + uint16_t sr = context->status << 3; + for (int flag = 4; flag >= 0; flag--) { + sr <<= 1; + sr |= context->flags[flag]; + } + write_le_16(buffer + GST_68K_SR_OFFSET, sr); + if (context->status & (1 << 5)) { + write_le_32(buffer + GST_68K_USP_OFFSET, context->aregs[8]); + write_le_32(buffer + GST_68K_SSP_OFFSET, context->aregs[7]); + } else { + write_le_32(buffer + GST_68K_USP_OFFSET, context->aregs[7]); + write_le_32(buffer + GST_68K_SSP_OFFSET, context->aregs[8]); + } + fseek(gstfile, GST_68K_REGS, SEEK_SET); + if (fwrite(buffer, 1, GST_68K_REG_SIZE, gstfile) != GST_68K_REG_SIZE) { + fputs("Failed to write 68K registers to savestate\n", stderr); + return 0; + } + + fseek(gstfile, GST_68K_RAM, SEEK_SET); + for (int i = 0; i < (32*1024);) { + for(curpos = buffer; curpos < (buffer + sizeof(buffer)); curpos += sizeof(uint16_t)) { + write_be_16(curpos, context->mem_pointers[1][i++]); + } + if (fwrite(buffer, 1, sizeof(buffer), gstfile) != sizeof(buffer)) { + fputs("Failed to write 68K RAM to savestate\n", stderr); + return 0; + } + } + return 1; +} + +uint8_t z80_load_gst(z80_context * context, FILE * gstfile) +{ + uint8_t regdata[GST_Z80_REG_SIZE]; + fseek(gstfile, GST_Z80_REGS, SEEK_SET); + if (fread(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) { + fputs("Failed to read Z80 registers from savestate\n", stderr); + return 0; + } + uint8_t * curpos = regdata; + uint8_t f = *(curpos++); + context->flags[ZF_C] = f & 1; + f >>= 1; + context->flags[ZF_N] = f & 1; + f >>= 1; + context->flags[ZF_PV] = f & 1; + f >>= 2; + context->flags[ZF_H] = f & 1; + f >>= 2; + context->flags[ZF_Z] = f & 1; + f >>= 1; + context->flags[ZF_S] = f; + + context->regs[Z80_A] = *curpos; + curpos += 3; + for (int reg = Z80_C; reg <= Z80_IYH; reg++) { + context->regs[reg++] = *(curpos++); + context->regs[reg] = *curpos; + curpos += 3; + } + context->pc = read_le_16(curpos); + curpos += 4; + context->sp = read_le_16(curpos); + curpos += 4; + f = *(curpos++); + context->alt_flags[ZF_C] = f & 1; + f >>= 1; + context->alt_flags[ZF_N] = f & 1; + f >>= 1; + context->alt_flags[ZF_PV] = f & 1; + f >>= 2; + context->alt_flags[ZF_H] = f & 1; + f >>= 2; + context->alt_flags[ZF_Z] = f & 1; + f >>= 1; + context->alt_flags[ZF_S] = f; + context->alt_regs[Z80_A] = *curpos; + curpos += 3; + for (int reg = Z80_C; reg <= Z80_H; reg++) { + context->alt_regs[reg++] = *(curpos++); + context->alt_regs[reg] = *curpos; + curpos += 3; + } + context->regs[Z80_I] = *curpos; + curpos += 2; + context->iff1 = context->iff2 = *curpos; + curpos += 2; + reset = !*(curpos++); + busreq = *curpos; + curpos += 3; + uint32_t bank = read_le_32(curpos); + if (bank < 0x400000) { + context->mem_pointers[1] = context->mem_pointers[2] + bank; + } else { + context->mem_pointers[1] = NULL; + } + context->bank_reg = bank >> 15; + fseek(gstfile, GST_Z80_RAM, SEEK_SET); + if(fread(context->mem_pointers[0], 1, 8*1024, gstfile) != (8*1024)) { + fputs("Failed to read Z80 RAM from savestate\n", stderr); + return 0; + } + return 1; +} + +uint8_t vdp_load_gst(vdp_context * context, FILE * state_file) +{ + uint8_t tmp_buf[CRAM_SIZE*2]; + fseek(state_file, GST_VDP_REGS, SEEK_SET); + if (fread(context->regs, 1, VDP_REGS, state_file) != VDP_REGS) { + fputs("Failed to read VDP registers from savestate\n", stderr); + return 0; + } + context->double_res = (context->regs[REG_MODE_4] & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); + if (!context->double_res) { + context->framebuf = context->oddbuf; + } + latch_mode(context); + if (fread(tmp_buf, 1, sizeof(tmp_buf), state_file) != sizeof(tmp_buf)) { + fputs("Failed to read CRAM from savestate\n", stderr); + return 0; + } + for (int i = 0; i < CRAM_SIZE; i++) { + uint16_t value; + context->cram[i] = value = (tmp_buf[i*2+1] << 8) | tmp_buf[i*2]; + context->colors[i] = color_map[value & 0xEEE]; + context->colors[i + CRAM_SIZE] = color_map[(value & 0xEEE) | FBUF_SHADOW]; + context->colors[i + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT]; + } + if (fread(tmp_buf, 2, VSRAM_SIZE, state_file) != VSRAM_SIZE) { + fputs("Failed to read VSRAM from savestate\n", stderr); + return 0; + } + for (int i = 0; i < VSRAM_SIZE; i++) { + context->vsram[i] = (tmp_buf[i*2+1] << 8) | tmp_buf[i*2]; + } + fseek(state_file, GST_VDP_MEM, SEEK_SET); + if (fread(context->vdpmem, 1, VRAM_SIZE, state_file) != VRAM_SIZE) { + fputs("Failed to read VRAM from savestate\n", stderr); + return 0; + } + return 1; +} + +uint8_t vdp_save_gst(vdp_context * context, FILE * outfile) +{ + uint8_t tmp_buf[CRAM_SIZE*2]; + fseek(outfile, GST_VDP_REGS, SEEK_SET); + if(fwrite(context->regs, 1, VDP_REGS, outfile) != VDP_REGS) { + fputs("Error writing VDP regs to savestate\n", stderr); + return 0; + } + for (int i = 0; i < CRAM_SIZE; i++) + { + tmp_buf[i*2] = context->cram[i]; + tmp_buf[i*2+1] = context->cram[i] >> 8; + } + if (fwrite(tmp_buf, 1, sizeof(tmp_buf), outfile) != sizeof(tmp_buf)) { + fputs("Error writing CRAM to savestate\n", stderr); + return 0; + } + for (int i = 0; i < VSRAM_SIZE; i++) + { + tmp_buf[i*2] = context->vsram[i]; + tmp_buf[i*2+1] = context->vsram[i] >> 8; + } + if (fwrite(tmp_buf, 2, VSRAM_SIZE, outfile) != VSRAM_SIZE) { + fputs("Error writing VSRAM to savestate\n", stderr); + return 0; + } + fseek(outfile, GST_VDP_MEM, SEEK_SET); + if (fwrite(context->vdpmem, 1, VRAM_SIZE, outfile) != VRAM_SIZE) { + fputs("Error writing VRAM to savestate\n", stderr); + return 0; + } + return 1; +} + +uint8_t z80_save_gst(z80_context * context, FILE * gstfile) +{ + uint8_t regdata[GST_Z80_REG_SIZE]; + uint8_t * curpos = regdata; + memset(regdata, 0, sizeof(regdata)); + uint8_t f = context->flags[ZF_S]; + f <<= 1; + f |= context->flags[ZF_Z] ; + f <<= 2; + f |= context->flags[ZF_H]; + f <<= 2; + f |= context->flags[ZF_PV]; + f <<= 1; + f |= context->flags[ZF_N]; + f <<= 1; + f |= context->flags[ZF_C]; + *(curpos++) = f; + *curpos = context->regs[Z80_A]; + + curpos += 3; + for (int reg = Z80_C; reg <= Z80_IYH; reg++) { + *(curpos++) = context->regs[reg++]; + *curpos = context->regs[reg]; + curpos += 3; + } + write_le_16(curpos, context->pc); + curpos += 4; + write_le_16(curpos, context->sp); + curpos += 4; + f = context->alt_flags[ZF_S]; + f <<= 1; + f |= context->alt_flags[ZF_Z] ; + f <<= 2; + f |= context->alt_flags[ZF_H]; + f <<= 2; + f |= context->alt_flags[ZF_PV]; + f <<= 1; + f |= context->alt_flags[ZF_N]; + f <<= 1; + f |= context->alt_flags[ZF_C]; + *(curpos++) = f; + *curpos = context->alt_regs[Z80_A]; + curpos += 3; + for (int reg = Z80_C; reg <= Z80_H; reg++) { + *(curpos++) = context->alt_regs[reg++]; + *curpos = context->alt_regs[reg]; + curpos += 3; + } + *curpos = context->regs[Z80_I]; + curpos += 2; + *curpos = context->iff1; + curpos += 2; + *(curpos++) = !reset; + *curpos = busreq; + curpos += 3; + uint32_t bank = context->bank_reg << 15; + write_le_32(curpos, bank); + fseek(gstfile, GST_Z80_REGS, SEEK_SET); + if (fwrite(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) { + return 0; + } + fseek(gstfile, GST_Z80_RAM, SEEK_SET); + if(fwrite(context->mem_pointers[0], 1, 8*1024, gstfile) != (8*1024)) { + fputs("Failed to write Z80 RAM to savestate\n", stderr); + return 0; + } + return 1; +} + +uint8_t ym_load_gst(ym2612_context * context, FILE * gstfile) +{ + uint8_t regdata[GST_YM_SIZE]; + fseek(gstfile, GST_YM_OFFSET, SEEK_SET); + if (fread(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) { + return 0; + } + for (int i = 0; i < sizeof(regdata); i++) { + if (i & 0x100) { + ym_address_write_part2(context, i & 0xFF); + } else { + ym_address_write_part1(context, i); + } + ym_data_write(context, regdata[i]); + } + return 1; +} + +uint8_t ym_save_gst(ym2612_context * context, FILE * gstfile) +{ + uint8_t regdata[GST_YM_SIZE]; + for (int i = 0; i < sizeof(regdata); i++) { + if (i & 0x100) { + int reg = (i & 0xFF); + if (reg >= YM_PART2_START && reg < YM_REG_END) { + regdata[i] = context->part2_regs[reg-YM_PART2_START]; + } else { + regdata[i] = 0xFF; + } + } else { + if (i >= YM_PART1_START && i < YM_REG_END) { + regdata[i] = context->part1_regs[i-YM_PART1_START]; + } else { + regdata[i] = 0xFF; + } + } + } + fseek(gstfile, GST_YM_OFFSET, SEEK_SET); + if (fwrite(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) { + return 0; + } + return 1; +} + +uint32_t load_gst(genesis_context * gen, char * fname) +{ + FILE * gstfile = fopen(fname, "rb"); + if (!gstfile) { + fprintf(stderr, "Could not open file %s for reading\n", fname); + goto error; + } + char ident[5]; + if (fread(ident, 1, sizeof(ident), gstfile) != sizeof(ident)) { + fprintf(stderr, "Could not read ident code from %s\n", fname); + goto error_close; + } + if (memcmp(ident, "GST\x40\xE0", 5) != 0) { + 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]); + goto error_close; + } + uint32_t pc = m68k_load_gst(gen->m68k, gstfile); + if (!pc) { + goto error_close; + } + if (!vdp_load_gst(gen->vdp, gstfile)) { + goto error_close; + } + if (!ym_load_gst(gen->ym, gstfile)) { + goto error_close; + } + if (!z80_load_gst(gen->z80, gstfile)) { + goto error_close; + } + gen->ports[0].control = 0x40; + gen->ports[1].control = 0x40; + fclose(gstfile); + return pc; + +error_close: + fclose(gstfile); +error: + return 0; +} + +uint8_t save_gst(genesis_context * gen, char *fname, uint32_t m68k_pc) +{ + FILE * gstfile = fopen(fname, "wb"); + if (!gstfile) { + fprintf(stderr, "Could not open %s for writing\n", fname); + goto error; + } + if (fwrite("GST\x40\xE0", 1, 5, gstfile) != 5) { + fputs("Error writing signature to savestate\n", stderr); + goto error_close; + } + if (!m68k_save_gst(gen->m68k, m68k_pc, gstfile)) { + goto error_close; + } + if (!z80_save_gst(gen->z80, gstfile)) { + goto error_close; + } + if (!vdp_save_gst(gen->vdp, gstfile)) { + goto error_close; + } + if (!ym_save_gst(gen->ym, gstfile)) { + goto error_close; + } + return 1; + +error_close: + fclose(gstfile); +error: + return 0; +} diff -r 3758bcdae5de -r 608815ab4ff2 gst.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gst.h Sun Sep 01 14:27:17 2013 -0700 @@ -0,0 +1,8 @@ +#ifndef GST_H_ +#define GST_H_ +#include "blastem.h" + +uint8_t save_gst(genesis_context * gen, char *fname, uint32_t m68k_pc); +uint32_t load_gst(genesis_context * gen, char * fname); + +#endif //GST_H_ diff -r 3758bcdae5de -r 608815ab4ff2 io.c --- a/io.c Sun Sep 01 12:11:28 2013 -0700 +++ b/io.c Sun Sep 01 14:27:17 2013 -0700 @@ -13,6 +13,7 @@ UI_DEBUG_MODE_INC, UI_DEBUG_PAL_INC, UI_ENTER_DEBUGGER, + UI_SAVE_STATE, UI_EXIT } ui_action; @@ -107,7 +108,7 @@ void bind_gamepad(int keycode, int gamepadnum, int button) { - + if (gamepadnum < 1 || gamepadnum > 2) { return; } @@ -210,6 +211,9 @@ case UI_ENTER_DEBUGGER: break_on_sync = 1; break; + case UI_SAVE_STATE: + save_state = 1; + break; case UI_EXIT: exit(0); } @@ -283,6 +287,8 @@ *ui_out = UI_DEBUG_PAL_INC; } else if(!strcmp(target + 3, "enter_debugger")) { *ui_out = UI_ENTER_DEBUGGER; + } else if(!strcmp(target + 3, "save_state")) { + *ui_out = UI_SAVE_STATE; } else if(!strcmp(target + 3, "exit")) { *ui_out = UI_EXIT; } else { @@ -345,7 +351,7 @@ special = tern_insert_int(special, "right", RENDERKEY_RIGHT); special = tern_insert_int(special, "enter", '\r'); special = tern_insert_int(special, "esc", RENDERKEY_ESC); - + tern_node * padbuttons = tern_insert_int(NULL, ".up", DPAD_UP); padbuttons = tern_insert_int(padbuttons, ".down", DPAD_DOWN); padbuttons = tern_insert_int(padbuttons, ".left", DPAD_LEFT); @@ -358,7 +364,7 @@ padbuttons = tern_insert_int(padbuttons, ".z", BUTTON_Z); padbuttons = tern_insert_int(padbuttons, ".start", BUTTON_START); padbuttons = tern_insert_int(padbuttons, ".mode", BUTTON_MODE); - + tern_node * keys = tern_find_prefix(config, "bindingskeys"); process_keys(keys, special, padbuttons, NULL); char prefix[] = "bindingspads00"; diff -r 3758bcdae5de -r 608815ab4ff2 testgst.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/testgst.c Sun Sep 01 14:27:17 2013 -0700 @@ -0,0 +1,78 @@ +#include "gst.h" +#include +#include + +uint8_t busreq; +uint8_t reset; + +int32_t color_map[1 << 12]; + +void latch_mode(vdp_context * context) +{ +} +void ym_data_write(ym2612_context * context, uint8_t value) +{ + if (context->selected_reg >= YM_REG_END) { + return; + } + if (context->selected_part) { + if (context->selected_reg < YM_PART2_START) { + return; + } + context->part2_regs[context->selected_reg - YM_PART2_START] = value; + } else { + if (context->selected_reg < YM_PART1_START) { + return; + } + context->part1_regs[context->selected_reg - YM_PART1_START] = value; + } +} + +void ym_address_write_part1(ym2612_context * context, uint8_t address) +{ + //printf("address_write_part1: %X\n", address); + context->selected_reg = address; + context->selected_part = 0; +} + +void ym_address_write_part2(ym2612_context * context, uint8_t address) +{ + //printf("address_write_part2: %X\n", address); + context->selected_reg = address; + context->selected_part = 1; +} + +uint16_t ram[64*1024]; +uint8_t zram[8*1024]; + + +int main(int argc, char ** argv) +{ + vdp_context vdp; + ym2612_context ym; + psg_context psg; + m68k_context m68k; + z80_context z80; + genesis_context gen; + if (argc < 3) { + fputs("Usage: testgst infile outfile\n", stderr); + return 1; + } + memset(&gen, 0, sizeof(gen)); + memset(&m68k, 0, sizeof(m68k)); + memset(&z80, 0, sizeof(z80)); + memset(&ym, 0, sizeof(ym)); + memset(&vdp, 0, sizeof(vdp)); + memset(&psg, 0, sizeof(psg)); + m68k.mem_pointers[1] = ram; + z80.mem_pointers[0] = zram; + vdp.vdpmem = malloc(VRAM_SIZE); + gen.vdp = &vdp; + gen.ym = &ym; + gen.psg = &psg; + gen.m68k = &m68k; + gen.z80 = &z80; + uint32_t pc = load_gst(&gen, argv[1]); + save_gst(&gen, argv[2], pc); + return 0; +} diff -r 3758bcdae5de -r 608815ab4ff2 vdp.c --- a/vdp.c Sun Sep 01 12:11:28 2013 -0700 +++ b/vdp.c Sun Sep 01 14:27:17 2013 -0700 @@ -1792,64 +1792,3 @@ } } -#define GST_VDP_REGS 0xFA -#define GST_VDP_MEM 0x12478 - -uint8_t vdp_load_gst(vdp_context * context, FILE * state_file) -{ - uint8_t tmp_buf[CRAM_SIZE*2]; - fseek(state_file, GST_VDP_REGS, SEEK_SET); - if (fread(context->regs, 1, VDP_REGS, state_file) != VDP_REGS) { - fputs("Failed to read VDP registers from savestate\n", stderr); - return 0; - } - context->double_res = (context->regs[REG_MODE_4] & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); - if (!context->double_res) { - context->framebuf = context->oddbuf; - } - latch_mode(context); - if (fread(tmp_buf, 1, sizeof(tmp_buf), state_file) != sizeof(tmp_buf)) { - fputs("Failed to read CRAM from savestate\n", stderr); - return 0; - } - for (int i = 0; i < CRAM_SIZE; i++) { - uint16_t value; - context->cram[i] = value = (tmp_buf[i*2+1] << 8) | tmp_buf[i*2]; - context->colors[i] = color_map[value & 0xEEE]; - context->colors[i + CRAM_SIZE] = color_map[(value & 0xEEE) | FBUF_SHADOW]; - context->colors[i + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT]; - } - if (fread(tmp_buf, 2, VSRAM_SIZE, state_file) != VSRAM_SIZE) { - fputs("Failed to read VSRAM from savestate\n", stderr); - return 0; - } - for (int i = 0; i < VSRAM_SIZE; i++) { - context->vsram[i] = (tmp_buf[i*2+1] << 8) | tmp_buf[i*2]; - } - fseek(state_file, GST_VDP_MEM, SEEK_SET); - if (fread(context->vdpmem, 1, VRAM_SIZE, state_file) != VRAM_SIZE) { - fputs("Failed to read VRAM from savestate\n", stderr); - return 0; - } - return 1; -} - -void vdp_save_state(vdp_context * context, FILE * outfile) -{ - uint8_t tmp_buf[CRAM_SIZE*2]; - fseek(outfile, GST_VDP_REGS, SEEK_SET); - fwrite(context->regs, 1, VDP_REGS, outfile); - for (int i = 0; i < CRAM_SIZE; i++) { - tmp_buf[i*2] = context->cram[i]; - tmp_buf[i*2+1] = context->cram[i] >> 8; - } - fwrite(tmp_buf, 1, sizeof(tmp_buf), outfile); - for (int i = 0; i < VSRAM_SIZE; i++) { - tmp_buf[i*2] = context->vsram[i]; - tmp_buf[i*2+1] = context->vsram[i] >> 8; - } - fwrite(tmp_buf, 2, VSRAM_SIZE, outfile); - fseek(outfile, GST_VDP_MEM, SEEK_SET); - fwrite(context->vdpmem, 1, VRAM_SIZE, outfile); -} - diff -r 3758bcdae5de -r 608815ab4ff2 vdp.h --- a/vdp.h Sun Sep 01 12:11:28 2013 -0700 +++ b/vdp.h Sun Sep 01 14:27:17 2013 -0700 @@ -164,7 +164,7 @@ //runs until the target cycle is reached or the current DMA operation has completed, whicever comes first void vdp_run_dma_done(vdp_context * context, uint32_t target_cycles); uint8_t vdp_load_gst(vdp_context * context, FILE * state_file); -void vdp_save_state(vdp_context * context, FILE * outfile); +uint8_t vdp_save_gst(vdp_context * context, FILE * outfile); int vdp_control_port_write(vdp_context * context, uint16_t value); int vdp_data_port_write(vdp_context * context, uint16_t value); uint16_t vdp_control_port_read(vdp_context * context); @@ -177,5 +177,8 @@ void vdp_int_ack(vdp_context * context, uint16_t int_num); void vdp_print_sprite_table(vdp_context * context); void vdp_print_reg_explain(vdp_context * context); +void latch_mode(vdp_context * context); + +extern int32_t color_map[1 << 12]; #endif //VDP_H_ diff -r 3758bcdae5de -r 608815ab4ff2 ym2612.c --- a/ym2612.c Sun Sep 01 12:11:28 2013 -0700 +++ b/ym2612.c Sun Sep 01 14:27:17 2013 -0700 @@ -582,9 +582,20 @@ void ym_data_write(ym2612_context * context, uint8_t value) { - if (context->selected_reg < 0x21 || context->selected_reg > 0xB6 || (context->selected_reg < 0x30 && context->selected_part)) { + if (context->selected_reg >= YM_REG_END) { return; } + if (context->selected_part) { + if (context->selected_reg < YM_PART2_START) { + return; + } + context->part2_regs[context->selected_reg - YM_PART2_START] = value; + } else { + if (context->selected_reg < YM_PART1_START) { + return; + } + context->part1_regs[context->selected_reg - YM_PART1_START] = value; + } dfprintf(debug_file, "write of %X to reg %X in part %d\n", value, context->selected_reg, context->selected_part+1); if (context->selected_reg < 0x30) { //Shared regs @@ -765,24 +776,3 @@ return context->status; } -#define GST_YM_OFFSET 0x1E4 -#define GST_YM_SIZE (0x3E4-GST_YM_OFFSET) - -uint8_t ym_load_gst(ym2612_context * context, FILE * gstfile) -{ - uint8_t regdata[GST_YM_SIZE]; - fseek(gstfile, GST_YM_OFFSET, SEEK_SET); - if (fread(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) { - return 0; - } - for (int i = 0; i < sizeof(regdata); i++) { - if (i & 0x100) { - ym_address_write_part2(context, i & 0xFF); - } else { - ym_address_write_part1(context, i); - } - ym_data_write(context, regdata[i]); - } - return 1; -} - diff -r 3758bcdae5de -r 608815ab4ff2 ym2612.h --- a/ym2612.h Sun Sep 01 12:11:28 2013 -0700 +++ b/ym2612.h Sun Sep 01 14:27:17 2013 -0700 @@ -45,6 +45,12 @@ uint8_t keycode; } ym_supp; +#define YM_PART1_START 0x21 +#define YM_PART2_START 0x30 +#define YM_REG_END 0xB8 +#define YM_PART1_REGS (YM_REG_END-YM_PART1_START) +#define YM_PART2_REGS (YM_REG_END-YM_PART2_START) + typedef struct { int16_t *audio_buffer; int16_t *back_buffer; @@ -66,7 +72,7 @@ uint8_t ch3_mode; uint8_t current_op; uint8_t current_env_op; - + uint8_t timer_control; uint8_t dac_enable; uint8_t lfo_enable; @@ -77,6 +83,8 @@ uint8_t status; uint8_t selected_reg; uint8_t selected_part; + uint8_t part1_regs[YM_PART1_REGS]; + uint8_t part2_regs[YM_PART2_REGS]; } ym2612_context; void ym_init(ym2612_context * context, uint32_t sample_rate, uint32_t master_clock, uint32_t clock_div, uint32_t sample_limit, uint32_t options); @@ -86,6 +94,7 @@ void ym_data_write(ym2612_context * context, uint8_t value); uint8_t ym_read_status(ym2612_context * context); uint8_t ym_load_gst(ym2612_context * context, FILE * gstfile); +uint8_t ym_save_gst(ym2612_context * context, FILE * gstfile); #endif //YM2612_H_ diff -r 3758bcdae5de -r 608815ab4ff2 z80_to_x86.h --- a/z80_to_x86.h Sun Sep 01 12:11:28 2013 -0700 +++ b/z80_to_x86.h Sun Sep 01 14:27:17 2013 -0700 @@ -50,6 +50,7 @@ void * system; uint8_t ram_code_flags[(8 * 1024)/128/8]; uint32_t int_enable_cycle; + uint16_t pc; } z80_context; void translate_z80_stream(z80_context * context, uint32_t address); diff -r 3758bcdae5de -r 608815ab4ff2 zruntime.S --- a/zruntime.S Sun Sep 01 12:11:28 2013 -0700 +++ b/zruntime.S Sun Sep 01 14:27:17 2013 -0700 @@ -19,12 +19,13 @@ cmp 112(%rsi), %ebp jb no_sync sync_io: + movw $0, 164(%rsi) call z80_save_context_scratch pop %rax /*return address in read/write func*/ pop 104(%rsi) /*return address in native code*/ sub $5, %rax /* adjust return addres to point to the call instruction that got us here */ mov %rax, (%rsi) - + pop %r15 /* restore callee saved regsiters */ pop %r14 pop %r13 @@ -32,7 +33,7 @@ pop %rbp pop %rbx ret /* return to caller of z80_run */ - + .global z80_handle_cycle_limit_int z80_handle_cycle_limit_int: cmp 116(%rsi), %ebp @@ -63,6 +64,7 @@ zskip_int: cmp 112(%rsi), %ebp jb zskip_sync +mov %r13w, 164(%rsi) .global z80_do_sync z80_do_sync: call z80_save_context @@ -244,7 +246,7 @@ call z_inccycles_io /* genesis Z80 has no IO port hardware and writes have no effect */ ret - + .global z80_retrans_stub z80_retrans_stub: pop %r14 @@ -264,7 +266,7 @@ z80_native_addr: call z80_save_context push %rsi - mov %rsi, %rdi + mov %rsi, %rdi movzx %r13w, %esi call z80_get_native_address_trans mov %rax, %r13 @@ -275,7 +277,7 @@ z80_save_context_scratch: mov %r13w, 98(%rsi) /* scratch1 */ mov %r14w, 100(%rsi) /* scratch2 */ - + .global z80_save_context z80_save_context: mov %r9w, 8(%rsi) /* SP */ @@ -295,7 +297,7 @@ z80_load_context_scratch: mov 98(%rsi), %r13w /* scratch1 */ mov 100(%rsi), %r14w /* scratch2 */ - + .global z80_load_context z80_load_context: mov 8(%rsi), %r9w /* SP */ @@ -328,4 +330,4 @@ movq $0, 104(%rsi) no_extra: jmp *(%rsi) - +