summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile13
-rw-r--r--blastem.c206
-rw-r--r--blastem.h3
-rw-r--r--default.cfg3
-rw-r--r--gst.c478
-rw-r--r--gst.h8
-rw-r--r--io.c12
-rw-r--r--testgst.c78
-rw-r--r--vdp.c91
-rw-r--r--vdp.h5
-rw-r--r--ym2612.c34
-rw-r--r--ym2612.h11
-rw-r--r--z80_to_x86.h1
-rw-r--r--zruntime.S16
14 files changed, 656 insertions, 303 deletions
diff --git a/Makefile b/Makefile
index 7c38e95..81f33d3 100644
--- a/Makefile
+++ b/Makefile
@@ -18,18 +18,18 @@ AUDIOOBJS=ym2612.o psg.o wave.o
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 @@ stateview : stateview.o vdp.o render_sdl.o
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 @@ gen_fib : gen_fib.o gen_x86.o mem.o
offsets : offsets.c z80_to_x86.h m68k_to_x86.h
$(CC) -o offsets offsets.c
-
+
%.o : %.S
$(CC) -c -o $@ $<
diff --git a/blastem.c b/blastem.c
index a4afa0b..4e76afc 100644
--- a/blastem.c
+++ b/blastem.c
@@ -5,6 +5,7 @@
#include "vdp.h"
#include "render.h"
#include "blastem.h"
+#include "gst.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -152,6 +153,7 @@ void adjust_int_cycle(m68k_context * context, vdp_context * v_context)
}
int break_on_sync = 0;
+int save_state = 0;
uint8_t reset = 1;
uint8_t need_reset = 0;
@@ -258,9 +260,19 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
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;
}
@@ -1465,190 +1477,6 @@ m68k_context * debugger(m68k_context * context, uint32_t address)
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
@@ -1805,11 +1633,15 @@ void init_run_cpu(genesis_context * gen, int debug, FILE * address_log, char * s
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 --git a/blastem.h b/blastem.h
index 635794d..da7953a 100644
--- a/blastem.h
+++ b/blastem.h
@@ -31,7 +31,10 @@ typedef struct {
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 --git a/default.cfg b/default.cfg
index ba4559e..6d6fd14 100644
--- a/default.cfg
+++ b/default.cfg
@@ -13,11 +13,12 @@ bindings {
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 --git a/gst.c b/gst.c
new file mode 100644
index 0000000..ac651dd
--- /dev/null
+++ b/gst.c
@@ -0,0 +1,478 @@
+#include "gst.h"
+#include <string.h>
+
+#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 --git a/gst.h b/gst.h
new file mode 100644
index 0000000..ff5d98c
--- /dev/null
+++ b/gst.h
@@ -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 --git a/io.c b/io.c
index b277c3c..03875c5 100644
--- a/io.c
+++ b/io.c
@@ -13,6 +13,7 @@ typedef enum {
UI_DEBUG_MODE_INC,
UI_DEBUG_PAL_INC,
UI_ENTER_DEBUGGER,
+ UI_SAVE_STATE,
UI_EXIT
} ui_action;
@@ -107,7 +108,7 @@ void bind_dpad(int joystick, int dpad, int direction, uint8_t bind_type, uint8_t
void bind_gamepad(int keycode, int gamepadnum, int button)
{
-
+
if (gamepadnum < 1 || gamepadnum > 2) {
return;
}
@@ -210,6 +211,9 @@ void handle_binding_up(keybinding * binding)
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 @@ int parse_binding_target(char * target, tern_node * padbuttons, int * ui_out, in
*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 @@ void set_keybindings()
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 @@ void set_keybindings()
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 --git a/testgst.c b/testgst.c
new file mode 100644
index 0000000..9b0a88b
--- /dev/null
+++ b/testgst.c
@@ -0,0 +1,78 @@
+#include "gst.h"
+#include <string.h>
+#include <stdlib.h>
+
+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 --git a/vdp.c b/vdp.c
index 7154548..6e20009 100644
--- a/vdp.c
+++ b/vdp.c
@@ -125,7 +125,7 @@ void render_sprite_cells(vdp_context * context)
{
if (context->cur_slot >= context->sprite_draws) {
sprite_draw * d = context->sprite_draw_list + context->cur_slot;
-
+
uint16_t dir;
int16_t x;
if (d->h_flip) {
@@ -164,7 +164,7 @@ void vdp_print_sprite_table(vdp_context * context)
uint16_t link = context->vdpmem[address+3] & 0x7F;
uint8_t pal = context->vdpmem[address + 4] >> 5 & 0x3;
uint8_t pri = context->vdpmem[address + 4] >> 7;
- uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5;
+ uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5;
//printf("Sprite %d: X=%d(%d), Y=%d(%d), Width=%u, Height=%u, Link=%u, Pal=%u, Pri=%u, Pat=%X\n", current_index, x, x-128, y, y-128, width, height, link, pal, pri, pattern);
current_index = link;
count++;
@@ -179,9 +179,9 @@ void vdp_print_reg_explain(vdp_context * context)
"01: %.2X | Display %s, V-ints %s, Height: %d, Mode %d\n"
"0B: %.2X | E-ints %s, V-Scroll: %s, H-Scroll: %s\n"
"0C: %.2X | Width: %d, Shadow/Highlight: %s\n",
- context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_PAL_SEL != 0,
+ context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_PAL_SEL != 0,
context->regs[REG_MODE_1] & BIT_HVC_LATCH ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_DISP_DIS ? "disabled" : "enabled",
- context->regs[REG_MODE_2], context->regs[REG_MODE_2] & BIT_DISP_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_VINT_EN ? "enabled" : "disabled",
+ context->regs[REG_MODE_2], context->regs[REG_MODE_2] & BIT_DISP_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_VINT_EN ? "enabled" : "disabled",
context->regs[REG_MODE_2] & BIT_PAL ? 30 : 28, context->regs[REG_MODE_2] & BIT_MODE_5 ? 5 : 4,
context->regs[REG_MODE_3], context->regs[REG_MODE_3] & BIT_EINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_3] & BIT_VSCROLL ? "2 cell" : "full",
hscroll[context->regs[REG_MODE_3] & 0x3],
@@ -203,8 +203,8 @@ void vdp_print_reg_explain(vdp_context * context)
"0A: %.2X | H-Int Counter: %u\n"
"0F: %.2X | Auto-increment: $%X\n"
"10: %.2X | Scroll A/B Size: %sx%s\n",
- context->regs[REG_BG_COLOR], context->regs[REG_BG_COLOR] & 0x3F,
- context->regs[REG_HINT], context->regs[REG_HINT],
+ context->regs[REG_BG_COLOR], context->regs[REG_BG_COLOR] & 0x3F,
+ context->regs[REG_HINT], context->regs[REG_HINT],
context->regs[REG_AUTOINC], context->regs[REG_AUTOINC],
context->regs[REG_SCROLL], sizes[context->regs[REG_SCROLL] & 0x3], sizes[context->regs[REG_SCROLL] >> 4 & 0x3]);
printf("\n**Internal Group**\n"
@@ -212,8 +212,8 @@ void vdp_print_reg_explain(vdp_context * context)
"CD: %X\n"
"Pending: %s\n",
context->address, context->cd, (context->flags & FLAG_PENDING) ? "true" : "false");
-
- //TODO: Window Group, DMA Group
+
+ //TODO: Window Group, DMA Group
}
void scan_sprite_table(uint32_t line, vdp_context * context)
@@ -295,7 +295,7 @@ void read_sprite_x(uint32_t line, vdp_context * context)
height *= 2;
}
uint16_t att_addr = ((context->regs[REG_SAT] & 0x7F) << 9) + context->sprite_info_list[context->cur_slot].index * 8 + 4;
- uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1];
+ uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1];
uint8_t pal_priority = (tileinfo >> 9) & 0x70;
uint8_t row;
if (tileinfo & MAP_BIT_V_FLIP) {
@@ -315,7 +315,7 @@ void read_sprite_x(uint32_t line, vdp_context * context)
} else if(context->flags & (FLAG_CAN_MASK | FLAG_DOT_OFLOW)) {
context->flags |= FLAG_MASKED;
}
-
+
context->flags &= ~FLAG_DOT_OFLOW;
int16_t i;
if (context->flags & FLAG_MASKED) {
@@ -415,7 +415,7 @@ void external_slot(vdp_context * context)
context->dma_val = (context->dma_val << 8) | ((context->dma_val >> 8) & 0xFF);
break;
case CRAM_WRITE:
- write_cram(context, context->address, context->dma_val);
+ write_cram(context, context->address, context->dma_val);
//printf("CRAM DMA Fill | %X set to %X at %d\n", (context->address/2) & (CRAM_SIZE-1), context->cram[(context->address/2) & (CRAM_SIZE-1)], context->cycles);
break;
case VSRAM_WRITE:
@@ -575,7 +575,7 @@ void read_map_scroll(uint16_t column, uint16_t vsram_off, uint32_t line, uint16_
address &= 0xF000;
line_offset = (((line) >> vscroll_shift) * 64 * 2) & 0xFFF;
mask = 0x7F;
-
+
} else {
address &= 0xF800;
line_offset = (((line) >> vscroll_shift) * 32 * 2) & 0xFFF;
@@ -751,7 +751,7 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context)
}
plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF);
//printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7));
-
+
if (context->regs[REG_MODE_4] & BIT_HILIGHT) {
for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) {
uint8_t pixel;
@@ -1402,9 +1402,9 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles)
}
if ((line < active_lines || (line == active_lines && linecyc < (context->latched_mode & BIT_H40 ? 64 : 80))) && context->regs[REG_MODE_2] & DISPLAY_ENABLE) {
//first sort-of active line is treated as 255 internally
- //it's used for gathering sprite info for line
+ //it's used for gathering sprite info for line
line = (line - 1) & 0xFF;
-
+
//Convert to slot number
if (context->latched_mode & BIT_H40){
vdp_h40(line, slot, context);
@@ -1789,64 +1789,3 @@ void vdp_int_ack(vdp_context * context, uint16_t int_num)
}
}
-#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 --git a/vdp.h b/vdp.h
index 97be57b..15f86b1 100644
--- a/vdp.h
+++ b/vdp.h
@@ -164,7 +164,7 @@ uint32_t vdp_run_to_vblank(vdp_context * context);
//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 @@ uint32_t vdp_next_vint_z80(vdp_context * context);
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 --git a/ym2612.c b/ym2612.c
index 811cf48..fda0249 100644
--- a/ym2612.c
+++ b/ym2612.c
@@ -582,9 +582,20 @@ void ym_update_phase_inc(ym2612_context * context, ym_operator * operator, uint3
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 @@ uint8_t ym_read_status(ym2612_context * context)
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 --git a/ym2612.h b/ym2612.h
index b0e3526..b693507 100644
--- a/ym2612.h
+++ b/ym2612.h
@@ -45,6 +45,12 @@ typedef struct {
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 @@ typedef struct {
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 @@ typedef struct {
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_address_write_part2(ym2612_context * context, uint8_t address);
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 --git a/z80_to_x86.h b/z80_to_x86.h
index 9f70803..e45a823 100644
--- a/z80_to_x86.h
+++ b/z80_to_x86.h
@@ -50,6 +50,7 @@ typedef struct {
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 --git a/zruntime.S b/zruntime.S
index 8ef8745..a4a53ef 100644
--- a/zruntime.S
+++ b/zruntime.S
@@ -19,12 +19,13 @@ do_limit:
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 @@ sync_io:
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 @@ z80_handle_cycle_limit_int:
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 @@ z80_io_write:
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_retrans_stub:
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_native_addr:
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_save_context:
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 @@ z80_run:
movq $0, 104(%rsi)
no_extra:
jmp *(%rsi)
-
+