summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--blastem.c4
-rwxr-xr-xcpu_dsl.py21
-rw-r--r--debug.c29
-rw-r--r--debug.h4
-rw-r--r--gdb_remote.c10
-rw-r--r--genesis.c68
-rw-r--r--genesis.h5
-rw-r--r--gst.c8
-rw-r--r--sms.c75
-rw-r--r--sms.h4
-rw-r--r--z80.cpu73
-rw-r--r--z80_util.c151
13 files changed, 380 insertions, 76 deletions
diff --git a/Makefile b/Makefile
index 1a8e68b..0c8b55f 100644
--- a/Makefile
+++ b/Makefile
@@ -161,7 +161,7 @@ endif
endif
ifdef NEW_CORE
-Z80OBJS=z80.o
+Z80OBJS=z80.o z80inst.o
CFLAGS+= -DNEW_CORE
else
Z80OBJS=z80inst.o z80_to_x86.o
@@ -302,7 +302,7 @@ offsets : offsets.c z80_to_x86.h m68k_core.h
vos_prog_info : vos_prog_info.o vos_program_module.o
$(CC) -o vos_prog_info vos_prog_info.o vos_program_module.o
-%.c : %.cpu
+%.c : %.cpu cpu_dsl.py
./cpu_dsl.py -d goto $< > $@
%.o : %.S
diff --git a/blastem.c b/blastem.c
index 557ad57..d5dcf7c 100644
--- a/blastem.c
+++ b/blastem.c
@@ -11,7 +11,11 @@
#include "system.h"
#include "68kinst.h"
#include "m68k_core.h"
+#ifdef NEW_CORE
+#include "z80.h"
+#else
#include "z80_to_x86.h"
+#endif
#include "mem.h"
#include "vdp.h"
#include "render.h"
diff --git a/cpu_dsl.py b/cpu_dsl.py
index 7bce683..605ce7a 100755
--- a/cpu_dsl.py
+++ b/cpu_dsl.py
@@ -666,6 +666,9 @@ def _rrcCImpl(prog, params, rawParams, flagUpdates):
return decl + '\n\t{dst} = {a} >> {b} | {a} << ({size} + 1 - {b}) | ({check} ? 1 : 0) << ({size}-{b});'.format(dst = dst,
a = params[0], b = params[1], size=size, check=carryCheck
)
+
+def _updateSyncCImpl(prog, params):
+ return '\n\tsync_cycle = {sync}(context, target_cycle);'.format(sync=prog.sync_cycle)
_opMap = {
'mov': Op(lambda val: val).cUnaryOperator(''),
@@ -711,7 +714,8 @@ _opMap = {
)),
'xchg': Op().addImplementation('c', (0,1), _xchgCImpl),
'dispatch': Op().addImplementation('c', None, _dispatchCImpl),
- 'update_flags': Op().addImplementation('c', None, _updateFlagsCImpl)
+ 'update_flags': Op().addImplementation('c', None, _updateFlagsCImpl),
+ 'update_sync': Op().addImplementation('c', None, _updateSyncCImpl)
}
#represents a simple DSL instruction
@@ -1028,6 +1032,7 @@ class Registers:
self.pointers = {}
self.regArrays = {}
self.regToArray = {}
+ self.addReg('cycles', 32)
def addReg(self, name, size):
self.regs[name] = size
@@ -1290,6 +1295,8 @@ class Program:
self.extra_tables = info.get('extra_tables', [])
self.context_type = self.prefix + 'context'
self.body = info.get('body', [None])[0]
+ self.interrupt = info.get('interrupt', [None])[0]
+ self.sync_cycle = info.get('sync_cycle', [None])[0]
self.includes = info.get('include', [])
self.flags = flags
self.lastDst = None
@@ -1324,7 +1331,6 @@ class Program:
hFile.write('\n}} {0}options;'.format(self.prefix))
hFile.write('\n\ntypedef struct {')
hFile.write('\n\t{0}options *opts;'.format(self.prefix))
- hFile.write('\n\tuint32_t cycles;')
self.regs.writeHeader(otype, hFile)
hFile.write('\n}} {0}context;'.format(self.prefix))
hFile.write('\n')
@@ -1380,7 +1386,15 @@ class Program:
def nextInstruction(self, otype):
output = []
if self.dispatch == 'goto':
+ if self.interrupt in self.subroutines:
+ output.append('\n\tif (context->cycles >= sync_cycle) {')
output.append('\n\tif (context->cycles >= target_cycle) { return; }')
+ if self.interrupt in self.subroutines:
+ self.meta = {}
+ self.temp = {}
+ self.subroutines[self.interrupt].inline(self, [], output, otype, None)
+ output.append('\n\t}')
+
self.meta = {}
self.temp = {}
self.subroutines[self.body].inline(self, [], output, otype, None)
@@ -1410,14 +1424,17 @@ class Program:
if self.dispatch == 'call' and self.body in self.subroutines:
pieces.append('\nvoid {pre}execute({type} *context, uint32_t target_cycle)'.format(pre = self.prefix, type = self.context_type))
pieces.append('\n{')
+ pieces.append('\n\tuint32_t sync_cycle = {sync}(context, target_cycle);'.format(sync=self.sync_cycle))
pieces.append('\n\twhile (context->cycles < target_cycle)')
pieces.append('\n\t{')
+ #TODO: Handle interrupts in call dispatch mode
self.meta = {}
self.temp = {}
self.subroutines[self.body].inline(self, [], pieces, otype, None)
pieces.append('\n\t}')
pieces.append('\n}')
elif self.dispatch == 'goto':
+ body.append('\n\tuint32_t sync_cycle = {sync}(context, target_cycle);'.format(sync=self.sync_cycle))
body += self.nextInstruction(otype)
pieces.append('\nunimplemented:')
pieces.append('\n\tfatal_error("Unimplemented instruction\\n");')
diff --git a/debug.c b/debug.c
index cb93ac3..92579f9 100644
--- a/debug.c
+++ b/debug.c
@@ -9,6 +9,13 @@
#include "render.h"
#include "util.h"
#include "terminal.h"
+#include "z80inst.h"
+
+#ifdef NEW_CORE
+#define Z80_OPTS opts
+#else
+#define Z80_OPTS options
+#endif
static bp_def * breakpoints = NULL;
static bp_def * zbreakpoints = NULL;
@@ -190,6 +197,7 @@ void zdebugger_print(z80_context * context, char format_char, char * param)
}
switch (param[0])
{
+#ifndef NEW_CORE
case 'a':
if (param[1] == 'f') {
if(param[2] == '\'') {
@@ -331,6 +339,7 @@ void zdebugger_print(z80_context * context, char format_char, char * param)
value = context->im;
}
break;
+#endif
case 's':
if (param[1] == 'p') {
value = context->sp;
@@ -342,7 +351,7 @@ void zdebugger_print(z80_context * context, char format_char, char * param)
if (p_addr < 0x4000) {
value = system->zram[p_addr & 0x1FFF];
} else if(p_addr >= 0x8000) {
- uint32_t v_addr = context->bank_reg << 15;
+ uint32_t v_addr = system->z80_bank_reg << 15;
v_addr += p_addr & 0x7FFF;
if (v_addr < 0x400000) {
value = system->cart[v_addr/2];
@@ -377,7 +386,7 @@ z80_context * zdebugger(z80_context * context, uint16_t address)
} else {
zremove_breakpoint(context, address);
}
- uint8_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->options->gen);
+ uint8_t * pc = get_native_pointer(address, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
if (!pc) {
fatal_error("Failed to get native pointer on entering Z80 debugger at address %X\n", address);
}
@@ -487,19 +496,21 @@ z80_context * zdebugger(z80_context * context, uint16_t address)
if (inst.addr_mode == Z80_IMMED) {
after = inst.immed;
} else if (inst.ea_reg == Z80_HL) {
+#ifndef NEW_CORE
after = context->regs[Z80_H] << 8 | context->regs[Z80_L];
} else if (inst.ea_reg == Z80_IX) {
after = context->regs[Z80_IXH] << 8 | context->regs[Z80_IXL];
} else if (inst.ea_reg == Z80_IY) {
after = context->regs[Z80_IYH] << 8 | context->regs[Z80_IYL];
+#endif
}
} else if(inst.op == Z80_JR) {
after += inst.immed;
} else if(inst.op == Z80_RET) {
- uint8_t *sp = get_native_pointer(context->sp, (void **)context->mem_pointers, &context->options->gen);
+ uint8_t *sp = get_native_pointer(context->sp, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
if (sp) {
after = *sp;
- sp = get_native_pointer((context->sp + 1) & 0xFFFF, (void **)context->mem_pointers, &context->options->gen);
+ sp = get_native_pointer((context->sp + 1) & 0xFFFF, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
if (sp) {
after |= *sp << 8;
}
@@ -527,9 +538,9 @@ z80_context * zdebugger(z80_context * context, uint16_t address)
break;
}
memmap_chunk const *ram_chunk = NULL;
- for (int i = 0; i < context->options->gen.memmap_chunks; i++)
+ for (int i = 0; i < context->Z80_OPTS->gen.memmap_chunks; i++)
{
- memmap_chunk const *cur = context->options->gen.memmap + i;
+ memmap_chunk const *cur = context->Z80_OPTS->gen.memmap + i;
if (cur->flags & MMAP_WRITE) {
ram_chunk = cur;
break;
@@ -540,7 +551,7 @@ z80_context * zdebugger(z80_context * context, uint16_t address)
if (size > ram_chunk->mask) {
size = ram_chunk->mask+1;
}
- uint8_t *buf = get_native_pointer(ram_chunk->start, (void **)context->mem_pointers, &context->options->gen);
+ uint8_t *buf = get_native_pointer(ram_chunk->start, (void **)context->mem_pointers, &context->Z80_OPTS->gen);
FILE * f = fopen(param, "wb");
if (f) {
if(fwrite(buf, 1, size, f) != size) {
@@ -558,8 +569,8 @@ z80_context * zdebugger(z80_context * context, uint16_t address)
}
default:
if (
- !context->options->gen.debug_cmd_handler
- || !context->options->gen.debug_cmd_handler(&system->header, input_buf)
+ !context->Z80_OPTS->gen.debug_cmd_handler
+ || !context->Z80_OPTS->gen.debug_cmd_handler(&system->header, input_buf)
) {
fprintf(stderr, "Unrecognized debugger command %s\n", input_buf);
}
diff --git a/debug.h b/debug.h
index 3ae71df..031671a 100644
--- a/debug.h
+++ b/debug.h
@@ -3,7 +3,11 @@
#include <stdint.h>
#include "m68k_core.h"
+#ifdef NEW_CORE
+#include "z80.h"
+#else
#include "z80_to_x86.h"
+#endif
typedef struct disp_def {
struct disp_def * next;
diff --git a/gdb_remote.c b/gdb_remote.c
index 17929f8..173e2bc 100644
--- a/gdb_remote.c
+++ b/gdb_remote.c
@@ -132,7 +132,7 @@ void update_status(m68k_context * context, uint16_t value)
}
}
-uint8_t read_byte(m68k_context * context, uint32_t address)
+uint8_t m68k_read_byte(m68k_context * context, uint32_t address)
{
genesis_context *gen = context->system;
@@ -150,7 +150,7 @@ uint8_t read_byte(m68k_context * context, uint32_t address)
return 0;
}
-void write_byte(m68k_context * context, uint32_t address, uint8_t value)
+void m68k_write_byte(m68k_context * context, uint32_t address, uint8_t value)
{
genesis_context *gen = context->system;
//TODO: Use generated read/write functions so that memory map is properly respected
@@ -170,7 +170,7 @@ void write_byte(m68k_context * context, uint32_t address, uint8_t value)
if (address >= 0xA00000 && address < 0xA04000) {
gen->zram[address & 0x1FFF] = value;
genesis_context * gen = context->system;
-#ifndef NO_Z80
+#if !defined(NO_Z80) && !defined(NEW_CORE)
z80_handle_code_write(address & 0x1FFF, gen->z80);
#endif
return;
@@ -305,7 +305,7 @@ void gdb_run_command(m68k_context * context, uint32_t pc, char * command)
char *cur = send_buf;
while (size)
{
- hex_8(read_byte(context, address), cur);
+ hex_8(m68k_read_byte(context, address), cur);
cur += 2;
address++;
size--;
@@ -326,7 +326,7 @@ void gdb_run_command(m68k_context * context, uint32_t pc, char * command)
tmp[0] = *(cur++);
tmp[1] = *(cur++);
tmp[2] = 0;
- write_byte(context, address, strtoul(tmp, NULL, 16));
+ m68k_write_byte(context, address, strtoul(tmp, NULL, 16));
address++;
size--;
}
diff --git a/genesis.c b/genesis.c
index 8e680e0..b599497 100644
--- a/genesis.c
+++ b/genesis.c
@@ -39,6 +39,15 @@ uint32_t MCLKS_PER_68K;
#define MAX_SOUND_CYCLES 100000
#endif
+#ifdef NEW_CORE
+#define Z80_CYCLE cycles
+#define Z80_OPTS opts
+#define z80_handle_code_write(...)
+#else
+#define Z80_CYCLE current_cycle
+#define Z80_OPTS options
+#endif
+
void genesis_serialize(genesis_context *gen, serialize_buffer *buf, uint32_t m68k_pc)
{
start_section(buf, SECTION_68000);
@@ -64,7 +73,7 @@ void genesis_serialize(genesis_context *gen, serialize_buffer *buf, uint32_t m68
start_section(buf, SECTION_GEN_BUS_ARBITER);
save_int8(buf, gen->z80->reset);
save_int8(buf, gen->z80->busreq);
- save_int16(buf, gen->z80->bank_reg);
+ save_int16(buf, gen->z80_bank_reg);
end_section(buf);
start_section(buf, SECTION_SEGA_IO_1);
@@ -141,8 +150,8 @@ static void zram_deserialize(deserialize_buffer *buf, void *vgen)
static void update_z80_bank_pointer(genesis_context *gen)
{
- if (gen->z80->bank_reg < 0x140) {
- gen->z80->mem_pointers[1] = get_native_pointer(gen->z80->bank_reg << 15, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen);
+ if (gen->z80_bank_reg < 0x140) {
+ gen->z80->mem_pointers[1] = get_native_pointer(gen->z80_bank_reg << 15, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen);
} else {
gen->z80->mem_pointers[1] = NULL;
}
@@ -153,7 +162,7 @@ static void bus_arbiter_deserialize(deserialize_buffer *buf, void *vgen)
genesis_context *gen = vgen;
gen->z80->reset = load_int8(buf);
gen->z80->busreq = load_int8(buf);
- gen->z80->bank_reg = load_int16(buf) & 0x1FF;
+ gen->z80_bank_reg = load_int16(buf) & 0x1FF;
}
static void adjust_int_cycle(m68k_context * context, vdp_context * v_context);
@@ -284,6 +293,7 @@ static void adjust_int_cycle(m68k_context * context, vdp_context * v_context)
#define dputs
#endif
+#ifndef NEW_CORE
static void z80_next_int_pulse(z80_context * z_context)
{
genesis_context * gen = z_context->system;
@@ -291,6 +301,7 @@ static void z80_next_int_pulse(z80_context * z_context)
z_context->int_pulse_end = z_context->int_pulse_start + Z80_INT_PULSE_MCLKS;
z_context->im2_vector = 0xFF;
}
+#endif
static void sync_z80(z80_context * z_context, uint32_t mclks)
{
@@ -300,7 +311,7 @@ static void sync_z80(z80_context * z_context, uint32_t mclks)
} else
#endif
{
- z_context->current_cycle = mclks;
+ z_context->Z80_CYCLE = mclks;
}
}
@@ -410,9 +421,14 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
gen->header.enter_debugger = 0;
debugger(context, address);
}
+#ifdef NEW_CORE
+ if (gen->header.save_state) {
+#else
if (gen->header.save_state && (z_context->pc || !z_context->native_pc || z_context->reset || !z_context->busreq)) {
+#endif
uint8_t slot = gen->header.save_state - 1;
gen->header.save_state = 0;
+#ifndef NEW_CORE
if (z_context->native_pc && !z_context->reset) {
//advance Z80 core to the start of an instruction
while (!z_context->pc)
@@ -420,6 +436,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address)
sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80);
}
}
+#endif
char *save_path = slot == SERIALIZE_SLOT ? NULL : get_slot_name(&gen->header, slot, use_native_states ? "state" : "gst");
if (use_native_states || slot == SERIALIZE_SLOT) {
serialize_buffer state;
@@ -571,16 +588,16 @@ static void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t val
if (vdp_port < 0x10) {
//These probably won't currently interact well with the 68K accessing the VDP
if (vdp_port < 4) {
- vdp_run_context(gen->vdp, context->current_cycle);
+ vdp_run_context(gen->vdp, context->Z80_CYCLE);
vdp_data_port_write(gen->vdp, value << 8 | value);
} else if (vdp_port < 8) {
- vdp_run_context_full(gen->vdp, context->current_cycle);
+ vdp_run_context_full(gen->vdp, context->Z80_CYCLE);
vdp_control_port_write(gen->vdp, value << 8 | value);
} else {
fatal_error("Illegal write to HV Counter port %X\n", vdp_port);
}
} else if (vdp_port < 0x18) {
- sync_sound(gen, context->current_cycle);
+ sync_sound(gen, context->Z80_CYCLE);
psg_write(gen->psg, value);
} else {
vdp_test_port_write(gen->vdp, value);
@@ -659,7 +676,7 @@ static uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext)
genesis_context * gen = context->system;
//VDP access goes over the 68K bus like a bank area access
//typical delay from bus arbitration
- context->current_cycle += 3 * MCLKS_PER_Z80;
+ context->Z80_CYCLE += 3 * MCLKS_PER_Z80;
//TODO: add cycle for an access right after a previous one
//TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
// Needs a new logic analyzer capture to get the actual delay on the 68K side
@@ -670,7 +687,7 @@ static uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext)
uint16_t ret;
if (vdp_port < 0x10) {
//These probably won't currently interact well with the 68K accessing the VDP
- vdp_run_context(gen->vdp, context->current_cycle);
+ vdp_run_context(gen->vdp, context->Z80_CYCLE);
if (vdp_port < 4) {
ret = vdp_data_port_read(gen->vdp);
} else if (vdp_port < 8) {
@@ -711,9 +728,9 @@ static m68k_context * io_write(uint32_t location, m68k_context * context, uint8_
ym_address_write_part1(gen->ym, value);
}
} else if (location == 0x6000) {
- gen->z80->bank_reg = (gen->z80->bank_reg >> 1 | value << 8) & 0x1FF;
- if (gen->z80->bank_reg < 0x80) {
- gen->z80->mem_pointers[1] = (gen->z80->bank_reg << 15) + ((char *)gen->z80->mem_pointers[2]);
+ gen->z80_bank_reg = (gen->z80_bank_reg >> 1 | value << 8) & 0x1FF;
+ if (gen->z80_bank_reg < 0x80) {
+ gen->z80->mem_pointers[1] = (gen->z80_bank_reg << 15) + ((char *)gen->z80->mem_pointers[2]);
} else {
gen->z80->mem_pointers[1] = NULL;
}
@@ -942,7 +959,7 @@ static void * z80_write_ym(uint32_t location, void * vcontext, uint8_t value)
{
z80_context * context = vcontext;
genesis_context * gen = context->system;
- sync_sound(gen, context->current_cycle);
+ sync_sound(gen, context->Z80_CYCLE);
if (location & 1) {
ym_data_write(gen->ym, value);
} else if (location & 2) {
@@ -957,7 +974,7 @@ static uint8_t z80_read_ym(uint32_t location, void * vcontext)
{
z80_context * context = vcontext;
genesis_context * gen = context->system;
- sync_sound(gen, context->current_cycle);
+ sync_sound(gen, context->Z80_CYCLE);
return ym_read_status(gen->ym);
}
@@ -966,10 +983,10 @@ static uint8_t z80_read_bank(uint32_t location, void * vcontext)
z80_context * context = vcontext;
genesis_context *gen = context->system;
if (gen->bus_busy) {
- context->current_cycle = context->sync_cycle;
+ context->Z80_CYCLE = gen->m68k->current_cycle;
}
//typical delay from bus arbitration
- context->current_cycle += 3 * MCLKS_PER_Z80;
+ context->Z80_CYCLE += 3 * MCLKS_PER_Z80;
//TODO: add cycle for an access right after a previous one
//TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
// Needs a new logic analyzer capture to get the actual delay on the 68K side
@@ -979,11 +996,11 @@ static uint8_t z80_read_bank(uint32_t location, void * vcontext)
if (context->mem_pointers[1]) {
return context->mem_pointers[1][location ^ 1];
}
- uint32_t address = context->bank_reg << 15 | location;
+ uint32_t address = gen->z80_bank_reg << 15 | location;
if (address >= 0xC00000 && address < 0xE00000) {
return z80_vdp_port_read(location & 0xFF, context);
} else {
- fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area (%X)\n", address, context->bank_reg << 15);
+ fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area (%X)\n", address, gen->z80_bank_reg << 15);
}
return 0;
}
@@ -993,17 +1010,17 @@ static void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value)
z80_context * context = vcontext;
genesis_context *gen = context->system;
if (gen->bus_busy) {
- context->current_cycle = context->sync_cycle;
+ context->Z80_CYCLE = gen->m68k->current_cycle;
}
//typical delay from bus arbitration
- context->current_cycle += 3 * MCLKS_PER_Z80;
+ context->Z80_CYCLE += 3 * MCLKS_PER_Z80;
//TODO: add cycle for an access right after a previous one
//TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high
// Needs a new logic analyzer capture to get the actual delay on the 68K side
gen->m68k->current_cycle += 8 * MCLKS_PER_68K;
location &= 0x7FFF;
- uint32_t address = context->bank_reg << 15 | location;
+ uint32_t address = gen->z80_bank_reg << 15 | location;
if (address >= 0xE00000) {
address &= 0xFFFF;
((uint8_t *)gen->work_ram)[address ^ 1] = value;
@@ -1018,8 +1035,9 @@ static void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value)
static void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value)
{
z80_context * context = vcontext;
+ genesis_context *gen = context->system;
- context->bank_reg = (context->bank_reg >> 1 | value << 8) & 0x1FF;
+ gen->z80_bank_reg = (gen->z80_bank_reg >> 1 | value << 8) & 0x1FF;
update_z80_bank_pointer(context->system);
return context;
@@ -1240,7 +1258,7 @@ static void free_genesis(system_header *system)
free(gen->cart);
free(gen->m68k);
free(gen->work_ram);
- z80_options_free(gen->z80->options);
+ z80_options_free(gen->z80->Z80_OPTS);
free(gen->z80);
free(gen->zram);
ym_free(gen->ym);
@@ -1368,7 +1386,9 @@ genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on
z80_options *z_opts = malloc(sizeof(z80_options));
init_z80_opts(z_opts, z80_map, 5, NULL, 0, MCLKS_PER_Z80, 0xFFFF);
gen->z80 = init_z80_context(z_opts);
+#ifndef NEW_CORE
gen->z80->next_int_pulse = z80_next_int_pulse;
+#endif
z80_assert_reset(gen->z80, 0);
#else
gen->z80 = calloc(1, sizeof(z80_context));
diff --git a/genesis.h b/genesis.h
index d39e800..8e84a90 100644
--- a/genesis.h
+++ b/genesis.h
@@ -9,7 +9,11 @@
#include <stdint.h>
#include "system.h"
#include "m68k_core.h"
+#ifdef NEW_CORE
+#include "z80.h"
+#else
#include "z80_to_x86.h"
+#endif
#include "ym2612.h"
#include "vdp.h"
#include "psg.h"
@@ -55,6 +59,7 @@ struct genesis_context {
uint8_t version_reg;
uint8_t bus_busy;
uint8_t reset_requested;
+ uint8_t z80_bank_reg;
eeprom_state eeprom;
nor_state nor;
};
diff --git a/gst.c b/gst.c
index 4a9b348..5a5afcf 100644
--- a/gst.c
+++ b/gst.c
@@ -144,6 +144,7 @@ uint8_t z80_load_gst(z80_context * context, FILE * gstfile)
}
uint8_t * curpos = regdata;
uint8_t f = *(curpos++);
+#ifndef NEW_CORE
context->flags[ZF_C] = f & 1;
f >>= 1;
context->flags[ZF_N] = f & 1;
@@ -200,6 +201,7 @@ uint8_t z80_load_gst(z80_context * context, FILE * gstfile)
context->mem_pointers[1] = NULL;
}
context->bank_reg = bank >> 15;
+#endif
uint8_t buffer[Z80_RAM_BYTES];
fseek(gstfile, GST_Z80_RAM, SEEK_SET);
if(fread(buffer, 1, sizeof(buffer), gstfile) != (8*1024)) {
@@ -210,11 +212,15 @@ uint8_t z80_load_gst(z80_context * context, FILE * gstfile)
{
if (context->mem_pointers[0][i] != buffer[i]) {
context->mem_pointers[0][i] = buffer[i];
+#ifndef NEW_CORE
z80_handle_code_write(i, context);
+#endif
}
}
+#ifndef NEW_CORE
context->native_pc = NULL;
context->extra_pc = NULL;
+#endif
return 1;
}
@@ -296,6 +302,7 @@ 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));
+#ifndef NEW_CORE
uint8_t f = context->flags[ZF_S];
f <<= 1;
f |= context->flags[ZF_Z] ;
@@ -348,6 +355,7 @@ uint8_t z80_save_gst(z80_context * context, FILE * gstfile)
curpos += 3;
uint32_t bank = context->bank_reg << 15;
write_le_32(curpos, bank);
+#endif
fseek(gstfile, GST_Z80_REGS, SEEK_SET);
if (fwrite(regdata, 1, sizeof(regdata), gstfile) != sizeof(regdata)) {
return 0;
diff --git a/sms.c b/sms.c
index 0ca499c..7ceb7a4 100644
--- a/sms.c
+++ b/sms.c
@@ -9,26 +9,35 @@
#include "saves.h"
#include "bindings.h"
+#ifdef NEW_CORE
+#define Z80_CYCLE cycles
+#define Z80_OPTS opts
+#define z80_handle_code_write(...)
+#else
+#define Z80_CYCLE current_cycle
+#define Z80_OPTS options
+#endif
+
static void *memory_io_write(uint32_t location, void *vcontext, uint8_t value)
{
z80_context *z80 = vcontext;
sms_context *sms = z80->system;
if (location & 1) {
uint8_t fuzzy_ctrl_0 = sms->io.ports[0].control, fuzzy_ctrl_1 = sms->io.ports[1].control;
- io_control_write(sms->io.ports, (~value) << 5 & 0x60, z80->current_cycle);
+ io_control_write(sms->io.ports, (~value) << 5 & 0x60, z80->Z80_CYCLE);
fuzzy_ctrl_0 |= sms->io.ports[0].control;
- io_control_write(sms->io.ports+1, (~value) << 3 & 0x60, z80->current_cycle);
+ io_control_write(sms->io.ports+1, (~value) << 3 & 0x60, z80->Z80_CYCLE);
fuzzy_ctrl_1 |= sms->io.ports[1].control;
if (
(fuzzy_ctrl_0 & 0x40 & (sms->io.ports[0].output ^ (value << 1)) & (value << 1))
|| (fuzzy_ctrl_0 & 0x40 & (sms->io.ports[1].output ^ (value >> 1)) & (value >> 1))
) {
//TH is an output and it went from 0 -> 1
- vdp_run_context(sms->vdp, z80->current_cycle);
+ vdp_run_context(sms->vdp, z80->Z80_CYCLE);
vdp_latch_hv(sms->vdp);
}
- io_data_write(sms->io.ports, value << 1, z80->current_cycle);
- io_data_write(sms->io.ports + 1, value >> 1, z80->current_cycle);
+ io_data_write(sms->io.ports, value << 1, z80->Z80_CYCLE);
+ io_data_write(sms->io.ports + 1, value >> 1, z80->Z80_CYCLE);
} else {
//TODO: memory control write
}
@@ -39,7 +48,7 @@ static uint8_t hv_read(uint32_t location, void *vcontext)
{
z80_context *z80 = vcontext;
sms_context *sms = z80->system;
- vdp_run_context(sms->vdp, z80->current_cycle);
+ vdp_run_context(sms->vdp, z80->Z80_CYCLE);
uint16_t hv = vdp_hv_counter_read(sms->vdp);
if (location & 1) {
return hv;
@@ -52,7 +61,7 @@ static void *sms_psg_write(uint32_t location, void *vcontext, uint8_t value)
{
z80_context *z80 = vcontext;
sms_context *sms = z80->system;
- psg_run(sms->psg, z80->current_cycle);
+ psg_run(sms->psg, z80->Z80_CYCLE);
psg_write(sms->psg, value);
return vcontext;
}
@@ -61,14 +70,18 @@ static void update_interrupts(sms_context *sms)
{
uint32_t vint = vdp_next_vint(sms->vdp);
uint32_t hint = vdp_next_hint(sms->vdp);
+#ifdef NEW_CORE
+ sms->z80->int_cycle = vint < hint ? vint : hint;
+#else
sms->z80->int_pulse_start = vint < hint ? vint : hint;
+#endif
}
static uint8_t vdp_read(uint32_t location, void *vcontext)
{
z80_context *z80 = vcontext;
sms_context *sms = z80->system;
- vdp_run_context(sms->vdp, z80->current_cycle);
+ vdp_run_context(sms->vdp, z80->Z80_CYCLE);
if (location & 1) {
uint8_t ret = vdp_control_port_read(sms->vdp);
sms->vdp->flags2 &= ~(FLAG2_VINT_PENDING|FLAG2_HINT_PENDING);
@@ -84,11 +97,11 @@ static void *vdp_write(uint32_t location, void *vcontext, uint8_t value)
z80_context *z80 = vcontext;
sms_context *sms = z80->system;
if (location & 1) {
- vdp_run_context_full(sms->vdp, z80->current_cycle);
+ vdp_run_context_full(sms->vdp, z80->Z80_CYCLE);
vdp_control_port_write_pbc(sms->vdp, value);
update_interrupts(sms);
} else {
- vdp_run_context(sms->vdp, z80->current_cycle);
+ vdp_run_context(sms->vdp, z80->Z80_CYCLE);
vdp_data_port_write_pbc(sms->vdp, value);
}
return vcontext;
@@ -99,13 +112,13 @@ static uint8_t io_read(uint32_t location, void *vcontext)
z80_context *z80 = vcontext;
sms_context *sms = z80->system;
if (location == 0xC0 || location == 0xDC) {
- uint8_t port_a = io_data_read(sms->io.ports, z80->current_cycle);
- uint8_t port_b = io_data_read(sms->io.ports+1, z80->current_cycle);
+ uint8_t port_a = io_data_read(sms->io.ports, z80->Z80_CYCLE);
+ uint8_t port_b = io_data_read(sms->io.ports+1, z80->Z80_CYCLE);
return (port_a & 0x3F) | (port_b << 6);
}
if (location == 0xC1 || location == 0xDD) {
- uint8_t port_a = io_data_read(sms->io.ports, z80->current_cycle);
- uint8_t port_b = io_data_read(sms->io.ports+1, z80->current_cycle);
+ uint8_t port_a = io_data_read(sms->io.ports, z80->Z80_CYCLE);
+ uint8_t port_b = io_data_read(sms->io.ports+1, z80->Z80_CYCLE);
return (port_a & 0x40) | (port_b >> 2 & 0xF) | (port_b << 1 & 0x80) | 0x10;
}
return 0xFF;
@@ -343,6 +356,7 @@ static uint8_t load_state(system_header *system, uint8_t slot)
sms_context *sms = (sms_context *)system;
char *statepath = get_slot_name(system, slot, "state");
uint8_t ret;
+#ifndef NEW_CORE
if (!sms->z80->native_pc) {
ret = get_modification_time(statepath) != 0;
if (ret) {
@@ -351,6 +365,7 @@ static uint8_t load_state(system_header *system, uint8_t slot)
goto done;
}
+#endif
ret = load_state_path(sms, statepath);
done:
free(statepath);
@@ -360,7 +375,7 @@ done:
static void run_sms(system_header *system)
{
sms_context *sms = (sms_context *)system;
- uint32_t target_cycle = sms->z80->current_cycle + 3420*16;
+ uint32_t target_cycle = sms->z80->Z80_CYCLE + 3420*16;
//TODO: PAL support
render_set_video_standard(VID_NTSC);
while (!sms->should_return)
@@ -374,7 +389,11 @@ static void run_sms(system_header *system)
system->enter_debugger = 0;
zdebugger(sms->z80, sms->z80->pc);
}
+#ifdef NEW_CORE
+ if (sms->z80->nmi_cycle == CYCLE_NEVER) {
+#else
if (sms->z80->nmi_start == CYCLE_NEVER) {
+#endif
uint32_t nmi = vdp_next_nmi(sms->vdp);
if (nmi != CYCLE_NEVER) {
z80_assert_nmi(sms->z80, nmi);
@@ -382,16 +401,16 @@ static void run_sms(system_header *system)
}
z80_run(sms->z80, target_cycle);
if (sms->z80->reset) {
- z80_clear_reset(sms->z80, sms->z80->current_cycle + 128*15);
+ z80_clear_reset(sms->z80, sms->z80->Z80_CYCLE + 128*15);
}
- target_cycle = sms->z80->current_cycle;
+ target_cycle = sms->z80->Z80_CYCLE;
vdp_run_context(sms->vdp, target_cycle);
psg_run(sms->psg, target_cycle);
if (system->save_state) {
while (!sms->z80->pc) {
//advance Z80 to an instruction boundary
- z80_run(sms->z80, sms->z80->current_cycle + 1);
+ z80_run(sms->z80, sms->z80->Z80_CYCLE + 1);
}
save_state(sms, system->save_state - 1);
system->save_state = 0;
@@ -399,9 +418,9 @@ static void run_sms(system_header *system)
target_cycle += 3420*16;
if (target_cycle > 0x10000000) {
- uint32_t adjust = sms->z80->current_cycle - 3420*262*2;
- io_adjust_cycles(sms->io.ports, sms->z80->current_cycle, adjust);
- io_adjust_cycles(sms->io.ports+1, sms->z80->current_cycle, adjust);
+ uint32_t adjust = sms->z80->Z80_CYCLE - 3420*262*2;
+ io_adjust_cycles(sms->io.ports, sms->z80->Z80_CYCLE, adjust);
+ io_adjust_cycles(sms->io.ports+1, sms->z80->Z80_CYCLE, adjust);
z80_adjust_cycles(sms->z80, adjust);
vdp_adjust_cycles(sms->vdp, adjust);
sms->psg->cycles -= adjust;
@@ -449,15 +468,17 @@ static void start_sms(system_header *system, char *statefile)
static void soft_reset(system_header *system)
{
sms_context *sms = (sms_context *)system;
- z80_assert_reset(sms->z80, sms->z80->current_cycle);
- sms->z80->target_cycle = sms->z80->sync_cycle = sms->z80->current_cycle;
+ z80_assert_reset(sms->z80, sms->z80->Z80_CYCLE);
+#ifndef NEW_CORE
+ sms->z80->target_cycle = sms->z80->sync_cycle = sms->z80->Z80_CYCLE;
+#endif
}
static void free_sms(system_header *system)
{
sms_context *sms = (sms_context *)system;
vdp_free(sms->vdp);
- z80_options_free(sms->z80->options);
+ z80_options_free(sms->z80->Z80_OPTS);
free(sms->z80);
psg_free(sms->psg);
free(sms);
@@ -472,7 +493,9 @@ static void request_exit(system_header *system)
{
sms_context *sms = (sms_context *)system;
sms->should_return = 1;
- sms->z80->target_cycle = sms->z80->sync_cycle = sms->z80->current_cycle;
+#ifndef NEW_CORE
+ sms->z80->target_cycle = sms->z80->sync_cycle = sms->z80->Z80_CYCLE;
+#endif
}
static void inc_debug_mode(system_header *system)
@@ -577,7 +600,7 @@ sms_context *alloc_configure_sms(system_media *media, uint32_t opts, uint8_t for
init_z80_opts(zopts, sms->header.info.map, sms->header.info.map_chunks, io_map, 4, 15, 0xFF);
sms->z80 = init_z80_context(zopts);
sms->z80->system = sms;
- sms->z80->options->gen.debug_cmd_handler = debug_commands;
+ sms->z80->Z80_OPTS->gen.debug_cmd_handler = debug_commands;
sms->rom = media->buffer;
sms->rom_size = rom_size;
diff --git a/sms.h b/sms.h
index 9f17c0f..0923611 100644
--- a/sms.h
+++ b/sms.h
@@ -4,7 +4,11 @@
#include "system.h"
#include "vdp.h"
#include "psg.h"
+#ifdef NEW_CORE
+#include "z80.h"
+#else
#include "z80_to_x86.h"
+#endif
#include "io.h"
#define SMS_RAM_SIZE (8*1024)
diff --git a/z80.cpu b/z80.cpu
index c126258..68ed2ce 100644
--- a/z80.cpu
+++ b/z80.cpu
@@ -3,13 +3,29 @@ info
opcode_size 8
extra_tables cb ed dded fded ddcb fdcb dd fd
body z80_run_op
+ sync_cycle z80_sync_cycle
+ interrupt z80_interrupt
include z80_util.c
header z80.h
declare
void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks, memmap_chunk const * io_chunks, uint32_t num_io_chunks, uint32_t clock_divider, uint32_t io_address_mask);
z80_context * init_z80_context(z80_options *options);
-
+ void z80_run(z80_context *context, uint32_t target_cycle);
+ void z80_assert_reset(z80_context * context, uint32_t cycle);
+ void z80_clear_reset(z80_context * context, uint32_t cycle);
+ void z80_assert_busreq(z80_context * context, uint32_t cycle);
+ void z80_clear_busreq(z80_context * context, uint32_t cycle);
+ void z80_assert_nmi(z80_context *context, uint32_t cycle);
+ uint8_t z80_get_busack(z80_context * context, uint32_t cycle);
+ void z80_invalidate_code_range(z80_context *context, uint32_t start, uint32_t end);
+ void z80_adjust_cycles(z80_context * context, uint32_t deduction);
+ void z80_serialize(z80_context *context, serialize_buffer *buf);
+ void z80_deserialize(deserialize_buffer *buf, void *vcontext);
+ void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler);
+ void zremove_breakpoint(z80_context * context, uint16_t address);
+ void z80_options_free(z80_options *opts);
+
regs
main 8 b c d e h l f a
alt 8 b' c' d' e' h' l' f' a'
@@ -31,10 +47,18 @@ regs
zflag 8
scratch1 16
scratch2 16
+ busreq 8
+ busack 8
+ reset 8
io_map ptrmemmap_chunk
io_chunks 32
io_mask 32
+ int_cycle 32
+ int_value 8
+ nmi_cycle 32
+ system ptrvoid
fastmem ptr8 64
+ mem_pointers ptr8 4
flags
register f
@@ -59,6 +83,49 @@ z80_op_fetch
z80_run_op
z80_op_fetch
dispatch scratch1
+
+z80_interrupt
+ cmp int_cycle cycles
+ if >=U
+
+ mov 0xFFFFFFFF int_cycle
+ mov 0 iff1
+ mov 0 iff2
+ cycles 6
+ update_sync
+
+ switch imode
+ case 0
+ dispatch int_value
+
+ case 1
+ dispatch 0xFF
+
+ case 2
+ lsl i 8 pc
+ or int_value pc pc
+ #CD is call
+ dispatch 0xCD
+ end
+
+ else
+
+ cmp nmi_cycle cycles
+ if >=U
+
+ mov 0xFFFFFFFF nmi_cycle
+ mov 0 iff1
+ local pch 8
+ lsr pc 8 pch
+ meta high pch
+ meta low pc
+ z80_push
+ mov 0x66 pc
+ update_sync
+
+ end
+ end
+
11001011 cb_prefix
z80_op_fetch
@@ -1485,7 +1552,9 @@ ed 01D11110 im2
mov 2 imode
ed 01D01110 im3
- mov 3 imode
+ #some sources call this mode 0/1, but unclear
+ #if the behavior is really different from im 0
+ mov 0 imode
11000011 jp
z80_fetch_immed16
diff --git a/z80_util.c b/z80_util.c
index 1ccc40c..7d97bea 100644
--- a/z80_util.c
+++ b/z80_util.c
@@ -7,7 +7,7 @@ void z80_read_8(z80_context *context)
if (fast) {
context->scratch1 = fast[context->scratch1 & 0x3FF];
} else {
- context->scratch1 = read_byte(context->scratch1, NULL, &context->opts->gen, context);
+ context->scratch1 = read_byte(context->scratch1, (void **)context->mem_pointers, &context->opts->gen, context);
}
}
@@ -18,7 +18,7 @@ void z80_write_8(z80_context *context)
if (fast) {
fast[context->scratch2 & 0x3FF] = context->scratch1;
} else {
- write_byte(context->scratch2, context->scratch1, NULL, &context->opts->gen, context);
+ write_byte(context->scratch2, context->scratch1, (void **)context->mem_pointers, &context->opts->gen, context);
}
}
@@ -32,7 +32,7 @@ void z80_io_read8(z80_context *context)
context->opts->gen.memmap = context->io_map;
context->opts->gen.memmap_chunks = context->io_chunks;
- context->scratch1 = read_byte(context->scratch1, NULL, &context->opts->gen, context);
+ context->scratch1 = read_byte(context->scratch1, (void **)context->mem_pointers, &context->opts->gen, context);
context->opts->gen.address_mask = tmp_mask;
context->opts->gen.memmap = tmp_map;
@@ -49,7 +49,7 @@ void z80_io_write8(z80_context *context)
context->opts->gen.memmap = context->io_map;
context->opts->gen.memmap_chunks = context->io_chunks;
- write_byte(context->scratch2, context->scratch1, NULL, &context->opts->gen, context);
+ write_byte(context->scratch2, context->scratch1, (void **)context->mem_pointers, &context->opts->gen, context);
context->opts->gen.address_mask = tmp_mask;
context->opts->gen.memmap = tmp_map;
@@ -72,6 +72,11 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t
tmp_io_mask = io_address_mask;
}
+void z80_options_free(z80_options *opts)
+{
+ free(opts);
+}
+
z80_context * init_z80_context(z80_options *options)
{
z80_context *context = calloc(1, sizeof(z80_context));
@@ -79,11 +84,12 @@ z80_context * init_z80_context(z80_options *options)
context->io_map = (memmap_chunk *)tmp_io_chunks;
context->io_chunks = tmp_num_io_chunks;
context->io_mask = tmp_io_mask;
+ context->int_cycle = context->nmi_cycle = 0xFFFFFFFFU;
for(uint32_t address = 0; address < 0x10000; address+=1024)
{
- uint8_t *start = get_native_pointer(address, NULL, &options->gen);
+ uint8_t *start = get_native_pointer(address, (void**)context->mem_pointers, &options->gen);
if (start) {
- uint8_t *end = get_native_pointer(address + 1023, NULL, &options->gen);
+ uint8_t *end = get_native_pointer(address + 1023, (void**)context->mem_pointers, &options->gen);
if (end && end - start == 1023) {
context->fastmem[address >> 10] = start;
}
@@ -92,3 +98,136 @@ z80_context * init_z80_context(z80_options *options)
return context;
}
+uint32_t z80_sync_cycle(z80_context *context, uint32_t target_cycle)
+{
+ if (context->iff1 && context->int_cycle < target_cycle) {
+ target_cycle = context->int_cycle;
+ };
+ if (context->nmi_cycle < target_cycle) {
+ target_cycle = context->nmi_cycle;
+ }
+ return target_cycle;
+}
+
+void z80_run(z80_context *context, uint32_t target_cycle)
+{
+ if (context->reset || context->busack) {
+ context->cycles = target_cycle;
+ } else if (target_cycle > context->cycles) {
+ if (context->busreq) {
+ //busreq is sampled at the end of an m-cycle
+ //we can approximate that by running for a single m-cycle after a bus request
+ target_cycle = context->cycles + 4 * context->opts->gen.clock_divider;
+ }
+ z80_execute(context, target_cycle);
+ if (context->busreq) {
+ context->busack = 1;
+ }
+ }
+}
+
+void z80_assert_reset(z80_context * context, uint32_t cycle)
+{
+ z80_run(context, cycle);
+ context->reset = 1;
+}
+
+void z80_clear_reset(z80_context * context, uint32_t cycle)
+{
+ z80_run(context, cycle);
+ if (context->reset) {
+ context->imode = 0;
+ context->iff1 = context->iff2 = 0;
+ context->pc = 0;
+ context->reset = 0;
+ if (context->busreq) {
+ //TODO: Figure out appropriate delay
+ context->busack = 1;
+ }
+ }
+}
+
+#define MAX_MCYCLE_LENGTH 6
+void z80_assert_busreq(z80_context * context, uint32_t cycle)
+{
+ z80_run(context, cycle);
+ context->busreq = 1;
+ //this is an imperfect aproximation since most M-cycles take less tstates than the max
+ //and a short 3-tstate m-cycle can take an unbounded number due to wait states
+ if (context->cycles - cycle > MAX_MCYCLE_LENGTH * context->opts->gen.clock_divider) {
+ context->busack = 1;
+ }
+}
+
+void z80_clear_busreq(z80_context * context, uint32_t cycle)
+{
+ z80_run(context, cycle);
+ context->busreq = 0;
+ context->busack = 0;
+ //there appears to be at least a 1 Z80 cycle delay between busreq
+ //being released and resumption of execution
+ context->cycles += context->opts->gen.clock_divider;
+}
+
+void z80_assert_nmi(z80_context *context, uint32_t cycle)
+{
+ context->nmi_cycle = cycle;
+}
+
+uint8_t z80_get_busack(z80_context * context, uint32_t cycle)
+{
+ z80_run(context, cycle);
+ return context->busack;
+}
+
+void z80_invalidate_code_range(z80_context *context, uint32_t startA, uint32_t endA)
+{
+ for(startA &= ~0x3FF; startA += 1024; startA < endA)
+ {
+ uint8_t *start = get_native_pointer(startA, (void**)context->mem_pointers, &context->opts->gen);
+ if (start) {
+ uint8_t *end = get_native_pointer(startA + 1023, (void**)context->mem_pointers, &context->opts->gen);
+ if (!end || end - start != 1023) {
+ start = NULL;
+ }
+ }
+ context->fastmem[startA >> 10] = start;
+ }
+}
+
+void z80_adjust_cycles(z80_context * context, uint32_t deduction)
+{
+ context->cycles -= deduction;
+ if (context->int_cycle != 0xFFFFFFFFU) {
+ if (context->int_cycle > deduction) {
+ context->int_cycle -= deduction;
+ } else {
+ context->int_cycle = 0;
+ }
+ }
+ if (context->nmi_cycle != 0xFFFFFFFFU) {
+ if (context->nmi_cycle > deduction) {
+ context->nmi_cycle -= deduction;
+ } else {
+ context->nmi_cycle = 0;
+ }
+ }
+}
+
+void z80_serialize(z80_context *context, serialize_buffer *buf)
+{
+ //TODO: Implement me
+}
+
+void z80_deserialize(deserialize_buffer *buf, void *vcontext)
+{
+ //TODO: Implement me
+}
+
+void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler)
+{
+}
+
+void zremove_breakpoint(z80_context * context, uint16_t address)
+{
+}