# HG changeset patch # User Michael Pavone # Date 1549828703 28800 # Node ID d6d4c006a7b3beab10d46947841ee6dbadcc2427 # Parent c5d4e1d14dac3ebd32331155f5c3e139e993365f Initial attempt at interrupts in new Z80 core and integrating it into main executable diff -r c5d4e1d14dac -r d6d4c006a7b3 Makefile --- a/Makefile Sat Feb 09 11:52:43 2019 -0800 +++ b/Makefile Sun Feb 10 11:58:23 2019 -0800 @@ -161,7 +161,7 @@ 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 @@ 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 -r c5d4e1d14dac -r d6d4c006a7b3 blastem.c --- a/blastem.c Sat Feb 09 11:52:43 2019 -0800 +++ b/blastem.c Sun Feb 10 11:58:23 2019 -0800 @@ -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 -r c5d4e1d14dac -r d6d4c006a7b3 cpu_dsl.py --- a/cpu_dsl.py Sat Feb 09 11:52:43 2019 -0800 +++ b/cpu_dsl.py Sun Feb 10 11:58:23 2019 -0800 @@ -666,6 +666,9 @@ 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 @@ )), '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 @@ self.pointers = {} self.regArrays = {} self.regToArray = {} + self.addReg('cycles', 32) def addReg(self, name, size): self.regs[name] = size @@ -1290,6 +1295,8 @@ 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 @@ 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 @@ 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 @@ 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 -r c5d4e1d14dac -r d6d4c006a7b3 debug.c --- a/debug.c Sat Feb 09 11:52:43 2019 -0800 +++ b/debug.c Sun Feb 10 11:58:23 2019 -0800 @@ -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 @@ } switch (param[0]) { +#ifndef NEW_CORE case 'a': if (param[1] == 'f') { if(param[2] == '\'') { @@ -331,6 +339,7 @@ value = context->im; } break; +#endif case 's': if (param[1] == 'p') { value = context->sp; @@ -342,7 +351,7 @@ 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 @@ } 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 @@ 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 @@ 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 @@ 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 @@ } 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 -r c5d4e1d14dac -r d6d4c006a7b3 debug.h --- a/debug.h Sat Feb 09 11:52:43 2019 -0800 +++ b/debug.h Sun Feb 10 11:58:23 2019 -0800 @@ -3,7 +3,11 @@ #include #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 -r c5d4e1d14dac -r d6d4c006a7b3 gdb_remote.c --- a/gdb_remote.c Sat Feb 09 11:52:43 2019 -0800 +++ b/gdb_remote.c Sun Feb 10 11:58:23 2019 -0800 @@ -132,7 +132,7 @@ } } -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 @@ 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 @@ 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 @@ 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 @@ 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 -r c5d4e1d14dac -r d6d4c006a7b3 genesis.c --- a/genesis.c Sat Feb 09 11:52:43 2019 -0800 +++ b/genesis.c Sun Feb 10 11:58:23 2019 -0800 @@ -39,6 +39,15 @@ #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 @@ 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 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 @@ 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 @@ #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 @@ 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 @@ } else #endif { - z_context->current_cycle = mclks; + z_context->Z80_CYCLE = mclks; } } @@ -410,9 +421,14 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ { 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 @@ { 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 @@ 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 @@ 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 @@ 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_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 @@ 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 @@ 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 -r c5d4e1d14dac -r d6d4c006a7b3 genesis.h --- a/genesis.h Sat Feb 09 11:52:43 2019 -0800 +++ b/genesis.h Sun Feb 10 11:58:23 2019 -0800 @@ -9,7 +9,11 @@ #include #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 @@ uint8_t version_reg; uint8_t bus_busy; uint8_t reset_requested; + uint8_t z80_bank_reg; eeprom_state eeprom; nor_state nor; }; diff -r c5d4e1d14dac -r d6d4c006a7b3 gst.c --- a/gst.c Sat Feb 09 11:52:43 2019 -0800 +++ b/gst.c Sun Feb 10 11:58:23 2019 -0800 @@ -144,6 +144,7 @@ } 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 @@ 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 @@ { 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 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 @@ 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 -r c5d4e1d14dac -r d6d4c006a7b3 sms.c --- a/sms.c Sat Feb 09 11:52:43 2019 -0800 +++ b/sms.c Sun Feb 10 11:58:23 2019 -0800 @@ -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 @@ { 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 @@ { 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ goto done; } +#endif ret = load_state_path(sms, statepath); done: free(statepath); @@ -360,7 +375,7 @@ 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 @@ 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 @@ } 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 @@ 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 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 @@ { 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 @@ 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 -r c5d4e1d14dac -r d6d4c006a7b3 sms.h --- a/sms.h Sat Feb 09 11:52:43 2019 -0800 +++ b/sms.h Sun Feb 10 11:58:23 2019 -0800 @@ -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 -r c5d4e1d14dac -r d6d4c006a7b3 z80.cpu --- a/z80.cpu Sat Feb 09 11:52:43 2019 -0800 +++ b/z80.cpu Sun Feb 10 11:58:23 2019 -0800 @@ -3,13 +3,29 @@ 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 @@ 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_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 @@ 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 -r c5d4e1d14dac -r d6d4c006a7b3 z80_util.c --- a/z80_util.c Sat Feb 09 11:52:43 2019 -0800 +++ b/z80_util.c Sun Feb 10 11:58:23 2019 -0800 @@ -7,7 +7,7 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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) +{ +}