From 8668ed398f50601c805f7e9fb629dec93e5a45f4 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 16 Jun 2014 19:13:28 -0700 Subject: Fix a few values reported by the vr debugger command. Add DMA registers to vr debugger command. Fix horizontal interrupt bug. Slightly more accurate (but still broken) handling of switches between H32 and H40 modes. --- vdp.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/vdp.c b/vdp.c index 5cf5797..1ae6480 100644 --- a/vdp.c +++ b/vdp.c @@ -227,8 +227,8 @@ void vdp_print_reg_explain(vdp_context * context) context->regs[REG_SCROLL_A], (context->regs[REG_SCROLL_A] & 0x38) << 10, context->regs[REG_WINDOW], (context->regs[REG_WINDOW] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x3C : 0x3E)) << 10, context->regs[REG_SCROLL_B], (context->regs[REG_SCROLL_B] & 0x7) << 13, - context->regs[REG_SAT], (context->regs[REG_SAT] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x3E : 0x3F)) << 9, - context->regs[REG_HSCROLL], (context->regs[REG_HSCROLL] & 0x1F) << 10); + context->regs[REG_SAT], (context->regs[REG_SAT] & (context->regs[REG_MODE_4] & BIT_H40 ? 0x7E : 0x7F)) << 9, + context->regs[REG_HSCROLL], (context->regs[REG_HSCROLL] & 0x3F) << 10); char * sizes[] = {"32", "64", "invalid", "128"}; printf("\n**Misc Group**\n" "07: %.2X | Backdrop Color: $%X\n" @@ -239,6 +239,20 @@ void vdp_print_reg_explain(vdp_context * context) 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]); + char * src_types[] = {"68K", "68K", "Copy", "Fill"}; + printf("\n**DMA Group**\n" + "13: %.2X |\n" + "14: %.2X | DMA Length: $%.4X words\n" + "15: %.2X |\n" + "16: %.2X |\n" + "17: %.2X | DMA Source Address: $%.6X, Type: %s\n", + context->regs[REG_DMALEN_L], + context->regs[REG_DMALEN_H], context->regs[REG_DMALEN_H] << 8 | context->regs[REG_DMALEN_L], + context->regs[REG_DMASRC_L], + context->regs[REG_DMASRC_M], + context->regs[REG_DMASRC_H], + context->regs[REG_DMASRC_H] << 17 | context->regs[REG_DMASRC_M] << 9 | context->regs[REG_DMASRC_L], + src_types[context->regs[REG_DMASRC_H] >> 6 & 3]); printf("\n**Internal Group**\n" "Address: %X\n" "CD: %X\n" @@ -1422,7 +1436,9 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) } uint32_t linecyc = context->cycles % MCLKS_LINE; if (linecyc == 0) { - if (line <= 1 || line >= active_lines) { + context->latched_mode &= ~0x81; + context->latched_mode |= context->regs[REG_MODE_4] & 0x81; + if (line < 1 || line >= active_lines) { context->hint_counter = context->regs[REG_HINT]; } else if (context->hint_counter) { context->hint_counter--; @@ -1925,9 +1941,6 @@ uint32_t vdp_next_hint(vdp_context * context) } uint32_t linecyc = context->cycles % MCLKS_LINE; uint32_t hcycle = context->cycles + context->hint_counter * MCLKS_LINE + MCLKS_LINE - linecyc; - if (!line) { - hcycle += MCLKS_LINE; - } return hcycle; } -- cgit v1.2.3 From a39a82cc9773c8336eaa48379f2d2fe3615f178c Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Tue, 17 Jun 2014 01:50:29 -0400 Subject: blastem builds and almost works on OS X now --- Makefile | 13 ++++++++++++- blastem.c | 3 +++ m68k_to_x86.c | 17 +++++++++++++---- runtime.S | 12 ------------ util.c | 2 +- z80_to_x86.c | 31 ++++++++++++++++--------------- z80_to_x86.h | 6 +++--- zruntime.S | 6 +++--- 8 files changed, 51 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index a20ae8f..0eb57cd 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,17 @@ +ifndef OS +OS:=$(shell uname -s) +endif + ifdef NOGL LIBS=sdl else +ifeq ($(OS),Darwin) +LIBS=sdl glew +else LIBS=sdl glew gl endif +endif + LDFLAGS:=-lm $(shell pkg-config --libs $(LIBS)) ifdef DEBUG CFLAGS:=-ggdb -std=gnu99 $(shell pkg-config --cflags-only-I $(LIBS)) -Wreturn-type -Werror=return-type @@ -22,7 +31,9 @@ ifndef CPU CPU:=$(shell uname -m) endif - +ifeq ($(OS),Darwin) +LDFLAGS+= -framework OpenGL +endif TRANSOBJS=gen_x86.o backend.o mem.o M68KOBJS=68kinst.o m68k_to_x86.o diff --git a/blastem.c b/blastem.c index 52de892..962ea9b 100644 --- a/blastem.c +++ b/blastem.c @@ -383,6 +383,7 @@ m68k_context * vdp_port_write_b(uint32_t vdp_port, m68k_context * context, uint8 return vdp_port_write(vdp_port, context, vdp_port < 0x10 ? value | value << 8 : ((vdp_port & 1) ? value : 0)); } +z80_context * z80_vdp_port_write(uint16_t vdp_port, z80_context * context, uint8_t value) asm("z80_vdp_port_write"); z80_context * z80_vdp_port_write(uint16_t vdp_port, z80_context * context, uint8_t value) { genesis_context * gen = context->system; @@ -674,6 +675,7 @@ uint16_t io_read_w(uint32_t location, m68k_context * context) return value; } +extern z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value) asm("z80_write_ym"); z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value) { genesis_context * gen = context->system; @@ -688,6 +690,7 @@ z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t val return context; } +extern uint8_t z80_read_ym(uint16_t location, z80_context * context) asm("z80_read_ym"); uint8_t z80_read_ym(uint16_t location, z80_context * context) { genesis_context * gen = context->system; diff --git a/m68k_to_x86.c b/m68k_to_x86.c index 34a631f..959d62b 100644 --- a/m68k_to_x86.c +++ b/m68k_to_x86.c @@ -39,9 +39,14 @@ char disasm_buf[1024]; m68k_context * sync_components(m68k_context * context, uint32_t address); -void m68k_invalid(); -void bcd_add(); -void bcd_sub(); +extern void bcd_add() asm("bcd_add"); +extern void bcd_sub() asm("bcd_sub"); + +void m68k_invalid(uint32_t address, m68k_context * context) +{ + printf("Invalid instruction at %X\n", address); + exit(1); +} code_ptr cycles(code_ptr dst, uint32_t num) { @@ -2864,7 +2869,11 @@ code_ptr translate_m68k(code_ptr dst, m68kinst * inst, x86_68k_options * opts) if (inst->src.params.immed == 0x7100) { return retn(dst); } - dst = mov_ir(dst, inst->address, SCRATCH1, SZ_D); + dst = mov_ir(dst, inst->address, SCRATCH2, SZ_D); +#ifdef X86_32 + dst = push_r(dst, CONTEXT); + dst = push_r(dst, SCRATCH2); +#endif return call(dst, (code_ptr)m68k_invalid); } else if(inst->op == M68K_CMP) { return translate_m68k_cmp(dst, inst, opts); diff --git a/runtime.S b/runtime.S index e66b158..caac541 100644 --- a/runtime.S +++ b/runtime.S @@ -1,17 +1,5 @@ -invalid_msg: - .asciz "Invalid instruction at %X\n" - - .global m68k_invalid -m68k_invalid: - lea invalid_msg(%rip), %rdi - mov %ecx, %esi - xor %rax, %rax - call printf - mov $1, %rdi - call exit - .global bcd_add bcd_add: xchg %rax, %rdi diff --git a/util.c b/util.c index 2bc3109..5367cd5 100644 --- a/util.c +++ b/util.c @@ -92,7 +92,7 @@ char * readlink_alloc(char * path) if (linksize == -1) { perror("readlink"); free(linktext); - linktext = NULL; + return NULL; } } while ((linksize+1) > cursize); linktext[linksize] = 0; diff --git a/z80_to_x86.c b/z80_to_x86.c index 2cab1c9..34263ad 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -28,21 +28,21 @@ #define dprintf #endif -void z80_read_byte(); -void z80_read_word(); -void z80_write_byte(); -void z80_write_word_highfirst(); -void z80_write_word_lowfirst(); -void z80_save_context(); -void z80_native_addr(); -void z80_do_sync(); -void z80_handle_cycle_limit_int(); -void z80_retrans_stub(); -void z80_io_read(); -void z80_io_write(); -void z80_halt(); -void z80_save_context(); -void z80_load_context(); +extern void z80_read_byte() asm("z80_read_byte"); +extern void z80_read_word() asm("z80_read_word"); +extern void z80_write_byte() asm("z80_write_byte"); +extern void z80_write_word_highfirst() asm("z80_write_word_highfirst"); +extern void z80_write_word_lowfirst() asm("z80_write_word_lowfirst"); +extern void z80_save_context() asm("z80_save_context"); +extern void z80_native_addr() asm("z80_native_addr"); +extern void z80_do_sync() asm("z80_do_sync"); +extern void z80_handle_cycle_limit_int() asm("z80_handle_cycle_limit_int"); +extern void z80_retrans_stub() asm("z80_retrans_stub"); +extern void z80_io_read() asm("z80_io_read"); +extern void z80_io_write() asm("z80_io_write"); +extern void z80_halt() asm("z80_halt"); +extern void z80_save_context() asm("z80_save_context"); +extern void z80_load_context() asm("z80_load_context"); uint8_t z80_size(z80inst * inst) { @@ -1780,6 +1780,7 @@ void z80_handle_deferred(z80_context * context) } } +extern void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * orig_start) asm("z80_retranslate_inst"); void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * orig_start) { char disbuf[80]; diff --git a/z80_to_x86.h b/z80_to_x86.h index ab2c846..48cc942 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -62,9 +62,9 @@ void translate_z80_stream(z80_context * context, uint32_t address); void init_x86_z80_opts(x86_z80_options * options); void init_z80_context(z80_context * context, x86_z80_options * options); uint8_t * z80_get_native_address(z80_context * context, uint32_t address); -uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address); -z80_context * z80_handle_code_write(uint32_t address, z80_context * context); -void z80_run(z80_context * context); +extern uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address) asm("z80_get_native_address_trans"); +z80_context * z80_handle_code_write(uint32_t address, z80_context * context) asm("z80_handle_code_write"); +extern void z80_run(z80_context * context) asm("z80_run"); void z80_reset(z80_context * context); void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler); void zremove_breakpoint(z80_context * context, uint16_t address); diff --git a/zruntime.S b/zruntime.S index 4445842..1883239 100644 --- a/zruntime.S +++ b/zruntime.S @@ -125,7 +125,7 @@ z80_read_bank: add $3, %ebp push %rsi mov 144(%rsi), %rsi /* get system context pointer */ - cmp $0, 120(%rsi) /* check bus busy flag */ + cmpb $0, 120(%rsi) /* check bus busy flag */ pop %rsi jne bus_busy z80_read_bank_cont: @@ -243,7 +243,7 @@ z80_read_bank_word: add $3, %ebp /* first read typically has 3 wait states */ push %rsi mov 144(%rsi), %rsi /* get system context pointer */ - cmp $0, 120(%rsi) /* check bus busy flag */ + cmpb $0, 120(%rsi) /* check bus busy flag */ pop %rsi jne bus_busy_word z80_read_bank_word_cont: @@ -256,7 +256,7 @@ z80_read_bank_word_cont: add $4, %ebp /* second read typically has 4 wait states */ push %rsi mov 144(%rsi), %rsi /* get system context pointer */ - cmp $0, 120(%rsi) /* check bus busy flag */ + cmpb $0, 120(%rsi) /* check bus busy flag */ pop %rsi jne bus_busy_word2 z80_read_bank_word_cont2: -- cgit v1.2.3 From 6cd595a305c71f0540a3ecf4c4038891a7eba762 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 17 Jun 2014 19:01:01 -0700 Subject: Partially working switch to having a vcounter and hslot counter in the context rather than trying to derive them from the cycle count. This should allow for more accurate handling of mid screen mode switches. Interrupt timing is broken currently though --- debug.c | 11 +- render_sdl.c | 2 +- vdp.c | 664 +++++++++++++++++++++++------------------------------------ vdp.h | 4 +- 4 files changed, 272 insertions(+), 409 deletions(-) diff --git a/debug.c b/debug.c index aa0cb7f..c9f9293 100644 --- a/debug.c +++ b/debug.c @@ -598,9 +598,14 @@ m68k_context * debugger(m68k_context * context, uint32_t address) } } else if(param[0] == 'c') { value = context->current_cycle; - } else if (param[0] == '0' && param[1] == 'x') { - uint32_t p_addr = strtol(param+2, NULL, 16); - value = read_dma_value(p_addr/2); + } else if ((param[0] == '0' && param[1] == 'x') || param[0] == '$') { + uint32_t p_addr = strtol(param+(param[0] == '0' ? 2 : 1), NULL, 16); + if ((p_addr & 0xFFFFFF) == 0xC00004) { + genesis_context * gen = context->system; + value = vdp_hv_counter_read(gen->vdp); + } else { + value = read_dma_value(p_addr/2); + } } else { fprintf(stderr, "Unrecognized parameter to p: %s\n", param); break; diff --git a/render_sdl.c b/render_sdl.c index e5f5c96..9f635a8 100644 --- a/render_sdl.c +++ b/render_sdl.c @@ -364,7 +364,7 @@ void render_context_gl(vdp_context * context) glBindTexture(GL_TEXTURE_2D, (context->regs[REG_MODE_4] & BIT_INTERLACE) ? textures[1] : textures[2]); glUniform1i(un_textures[1], 1); - glUniform1f(un_width, context->latched_mode & BIT_H40 ? 320.0f : 256.0f); + glUniform1f(un_width, context->regs[REG_MODE_4] & BIT_H40 ? 320.0f : 256.0f); glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); diff --git a/vdp.c b/vdp.c index 1ae6480..ad8ed00 100644 --- a/vdp.c +++ b/vdp.c @@ -9,8 +9,8 @@ #include #include "render.h" -#define NTSC_ACTIVE 225 -#define PAL_ACTIVE 241 +#define NTSC_INACTIVE_START 224 +#define PAL_INACTIVE_START 240 #define BUF_BIT_PRIORITY 0x40 #define MAP_BIT_PRIORITY 0x8000 #define MAP_BIT_H_FLIP 0x800 @@ -22,14 +22,15 @@ #define MCLKS_SLOT_H40 16 #define MCLKS_SLOT_H32 20 -#define VINT_CYCLE_H40 (21*MCLKS_SLOT_H40+332+9*MCLKS_SLOT_H40) //21 slots before HSYNC, 16 during, 10 after -#define VINT_CYCLE_H32 ((33+20+7)*MCLKS_SLOT_H32) //33 slots before HSYNC, 20 during, 7 after TODO: confirm final number -#define HSYNC_SLOT_H40 21 -#define MCLK_WEIRD_END (HSYNC_SLOT_H40*MCLKS_SLOT_H40 + 332) -#define SLOT_WEIRD_END (HSYNC_SLOT_H40+17) +#define VINT_SLOT_H40 4 //21 slots before HSYNC, 16 during, 10 after +#define VINT_SLOT_H32 23 //33 slots before HSYNC, 20 during, 7 after TODO: confirm final number +#define HSYNC_SLOT_H40 240 +#define HSYNC_END_H40 (240+17) #define HSYNC_END_H32 (33 * MCLKS_SLOT_H32) -#define HBLANK_CLEAR_H40 (MCLK_WEIRD_END+61*4) -#define HBLANK_CLEAR_H32 (HSYNC_END_H32 + 46*5) +#define HBLANK_START_H40 167 +#define HBLANK_END_H40 11 //should be 10.25 according to Nemesis IIRC +#define HBLANK_START_H32 134 +#define HBLANK_END_H32 8 //should be 7.5 according to Nemesis IIRC #define FIFO_LATENCY 3 int32_t color_map[1 << 12]; @@ -136,14 +137,14 @@ void init_vdp_context(vdp_context * context) int is_refresh(vdp_context * context, uint32_t slot) { - if (context->latched_mode & BIT_H40) { - return (slot == 37 || slot == 69 || slot == 102 || slot == 133 || slot == 165 || slot == 197 || slot >= 210); + if (context->regs[REG_MODE_4] & BIT_H40) { + return slot == 250 || slot == 26 || slot == 59 || slot == 90 || slot == 122 || slot == 154; } else { //TODO: Figure out which slots are refresh when display is off in 32-cell mode //These numbers are guesses based on H40 numbers - return (slot == 24 || slot == 56 || slot == 88 || slot == 120 || slot == 152); + return slot == 243 || slot == 19 || slot == 51 || slot == 83 || slot == 115; //The numbers below are the refresh slots during active display - //return (slot == 66 || slot == 98 || slot == 130 || slot == 162); + //return (slot == 29 || slot == 61 || slot == 93 || slot == 125); } } @@ -283,7 +284,7 @@ void scan_sprite_table(uint32_t line, vdp_context * context) height_mult = 8; } context->sprite_index &= 0x7F; - if (context->latched_mode & BIT_H40) { + if (context->regs[REG_MODE_4] & BIT_H40) { if (context->sprite_index >= MAX_SPRITES_FRAME) { context->sprite_index = 0; return; @@ -486,7 +487,7 @@ void run_dma_src(vdp_context * context, uint32_t slot) case 0x40: if (!slot || !is_refresh(context, slot-1)) { cur = context->fifo + context->fifo_write; - cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; + cur->cycle = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*FIFO_LATENCY; cur->address = context->address; cur->value = read_dma_value((context->regs[REG_DMASRC_H] << 16) | (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]); cur->cd = context->cd; @@ -581,7 +582,7 @@ void read_map_scroll(uint16_t column, uint16_t vsram_off, uint32_t line, uint16_ if ((column >= left_col && column < right_col) || (line >= top_line && line < bottom_line)) { uint16_t address = context->regs[REG_WINDOW] << 10; uint16_t line_offset, offset, mask; - if (context->latched_mode & BIT_H40) { + if (context->regs[REG_MODE_4] & BIT_H40) { address &= 0xF000; line_offset = (((line) >> vscroll_shift) * 64 * 2) & 0xFFF; mask = 0x7F; @@ -908,12 +909,12 @@ void vdp_h40(uint32_t line, uint32_t linecyc, vdp_context * context) switch(linecyc) { //sprite render to line buffer starts - case 0: + case 167: context->cur_slot = MAX_DRAWS-1; memset(context->linebuf, 0, LINEBUF_SIZE); - case 1: - case 2: - case 3: + case 168: + case 169: + case 170: if (line == 0xFF) { external_slot(context); } else { @@ -921,52 +922,52 @@ void vdp_h40(uint32_t line, uint32_t linecyc, vdp_context * context) } break; //sprite attribute table scan starts - case 4: + case 171: render_sprite_cells( context); context->sprite_index = 0x80; context->slot_counter = MAX_SPRITES_LINE; scan_sprite_table(line, context); break; - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - case 16: - case 17: - case 18: - case 19: - case 20: + case 172: + case 173: + case 174: + case 175: + case 176: + case 177: + case 178: + case 179: + case 180: + case 181: + case 182: + case 229: + case 230: + case 231: + case 232: + case 233: //!HSYNC asserted - case 21: - case 22: + case 234: + case 235: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 23: + case 236: external_slot(context); break; - case 24: - case 25: - case 26: - case 27: - case 28: - case 29: - case 30: - case 31: - case 32: - case 33: - case 34: + case 237: + case 238: + case 239: + case 240: + case 241: + case 242: + case 243: + case 244: + case 245: + case 246: + case 247: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 35: + case 248: address = (context->regs[REG_HSCROLL] & 0x3F) << 10; mask = 0; if (context->regs[REG_MODE_3] & 0x2) { @@ -981,41 +982,41 @@ void vdp_h40(uint32_t line, uint32_t linecyc, vdp_context * context) context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; //printf("%d: HScroll A: %d, HScroll B: %d\n", line, context->hscroll_a, context->hscroll_b); break; - case 36: + case 249: //!HSYNC high - case 37: - case 38: - case 39: + case 250: + case 251: + case 252: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 40: + case 253: read_map_scroll_a(0, line, context); break; - case 41: + case 254: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 42: + case 255: render_map_1(context); scan_sprite_table(line, context);//Just a guess break; - case 43: + case 0: render_map_2(context); scan_sprite_table(line, context);//Just a guess break; - case 44: + case 1: read_map_scroll_b(0, line, context); break; - case 45: + case 2: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 46: + case 3: render_map_3(context); scan_sprite_table(line, context);//Just a guess break; - case 47: + case 4: render_map_output(line, 0, context); scan_sprite_table(line, context);//Just a guess //reverse context slot counter so it counts the number of sprite slots @@ -1025,33 +1026,30 @@ void vdp_h40(uint32_t line, uint32_t linecyc, vdp_context * context) context->sprite_draws = MAX_DRAWS; context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED); break; - COLUMN_RENDER_BLOCK(2, 48) - COLUMN_RENDER_BLOCK(4, 56) - COLUMN_RENDER_BLOCK(6, 64) - COLUMN_RENDER_BLOCK_REFRESH(8, 72) - COLUMN_RENDER_BLOCK(10, 80) - COLUMN_RENDER_BLOCK(12, 88) - COLUMN_RENDER_BLOCK(14, 96) - COLUMN_RENDER_BLOCK_REFRESH(16, 104) - COLUMN_RENDER_BLOCK(18, 112) - COLUMN_RENDER_BLOCK(20, 120) - COLUMN_RENDER_BLOCK(22, 128) - COLUMN_RENDER_BLOCK_REFRESH(24, 136) - COLUMN_RENDER_BLOCK(26, 144) - COLUMN_RENDER_BLOCK(28, 152) - COLUMN_RENDER_BLOCK(30, 160) - COLUMN_RENDER_BLOCK_REFRESH(32, 168) - COLUMN_RENDER_BLOCK(34, 176) - COLUMN_RENDER_BLOCK(36, 184) - COLUMN_RENDER_BLOCK(38, 192) - COLUMN_RENDER_BLOCK_REFRESH(40, 200) - case 208: - case 209: + COLUMN_RENDER_BLOCK(2, 5) + COLUMN_RENDER_BLOCK(4, 13) + COLUMN_RENDER_BLOCK(6, 21) + COLUMN_RENDER_BLOCK_REFRESH(8, 29) + COLUMN_RENDER_BLOCK(10, 37) + COLUMN_RENDER_BLOCK(12, 45) + COLUMN_RENDER_BLOCK(14, 53) + COLUMN_RENDER_BLOCK_REFRESH(16, 61) + COLUMN_RENDER_BLOCK(18, 69) + COLUMN_RENDER_BLOCK(20, 77) + COLUMN_RENDER_BLOCK(22, 85) + COLUMN_RENDER_BLOCK_REFRESH(24, 93) + COLUMN_RENDER_BLOCK(26, 101) + COLUMN_RENDER_BLOCK(28, 109) + COLUMN_RENDER_BLOCK(30, 117) + COLUMN_RENDER_BLOCK_REFRESH(32, 125) + COLUMN_RENDER_BLOCK(34, 133) + COLUMN_RENDER_BLOCK(36, 141) + COLUMN_RENDER_BLOCK(38, 149) + COLUMN_RENDER_BLOCK_REFRESH(40, 157) + case 165: + case 166: external_slot(context); break; - default: - //leftovers from HSYNC clock change nonsense - break; } } @@ -1062,12 +1060,12 @@ void vdp_h32(uint32_t line, uint32_t linecyc, vdp_context * context) switch(linecyc) { //sprite render to line buffer starts - case 0: + case 134: context->cur_slot = MAX_DRAWS_H32-1; memset(context->linebuf, 0, LINEBUF_SIZE); - case 1: - case 2: - case 3: + case 135: + case 136: + case 137: if (line == 0xFF) { external_slot(context); } else { @@ -1075,46 +1073,46 @@ void vdp_h32(uint32_t line, uint32_t linecyc, vdp_context * context) } break; //sprite attribute table scan starts - case 4: + case 138: render_sprite_cells( context); context->sprite_index = 0x80; context->slot_counter = MAX_SPRITES_LINE_H32; scan_sprite_table(line, context); break; - case 5: - case 6: - case 7: - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: + case 139: + case 140: + case 141: + case 142: + case 143: + case 144: + case 145: + case 146: + case 147: render_sprite_cells(context); scan_sprite_table(line, context); - case 14: + case 233: external_slot(context); break; - case 15: - case 16: - case 17: - case 18: - case 19: + case 234: + case 235: + case 236: + case 237: + case 238: //HSYNC start - case 20: - case 21: - case 22: - case 23: - case 24: - case 25: - case 26: + case 239: + case 240: + case 241: + case 242: + case 243: + case 244: + case 245: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 27: + case 246: external_slot(context); break; - case 28: + case 247: address = (context->regs[REG_HSCROLL] & 0x3F) << 10; mask = 0; if (context->regs[REG_MODE_3] & 0x2) { @@ -1129,41 +1127,41 @@ void vdp_h32(uint32_t line, uint32_t linecyc, vdp_context * context) context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; //printf("%d: HScroll A: %d, HScroll B: %d\n", line, context->hscroll_a, context->hscroll_b); break; - case 29: - case 30: - case 31: - case 32: + case 248: + case 249: + case 250: + case 251: render_sprite_cells(context); scan_sprite_table(line, context); break; //!HSYNC high - case 33: + case 252: read_map_scroll_a(0, line, context); break; - case 34: + case 253: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 35: + case 254: render_map_1(context); scan_sprite_table(line, context);//Just a guess break; - case 36: + case 255: render_map_2(context); scan_sprite_table(line, context);//Just a guess break; - case 37: + case 0: read_map_scroll_b(0, line, context); break; - case 38: + case 1: render_sprite_cells(context); scan_sprite_table(line, context); break; - case 39: + case 2: render_map_3(context); scan_sprite_table(line, context);//Just a guess break; - case 40: + case 3: render_map_output(line, 0, context); scan_sprite_table(line, context);//Just a guess //reverse context slot counter so it counts the number of sprite slots @@ -1173,24 +1171,24 @@ void vdp_h32(uint32_t line, uint32_t linecyc, vdp_context * context) context->sprite_draws = MAX_DRAWS_H32; context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED); break; - COLUMN_RENDER_BLOCK(2, 41) - COLUMN_RENDER_BLOCK(4, 49) - COLUMN_RENDER_BLOCK(6, 57) - COLUMN_RENDER_BLOCK_REFRESH(8, 65) - COLUMN_RENDER_BLOCK(10, 73) - COLUMN_RENDER_BLOCK(12, 81) - COLUMN_RENDER_BLOCK(14, 89) - COLUMN_RENDER_BLOCK_REFRESH(16, 97) - COLUMN_RENDER_BLOCK(18, 105) - COLUMN_RENDER_BLOCK(20, 113) - COLUMN_RENDER_BLOCK(22, 121) - COLUMN_RENDER_BLOCK_REFRESH(24, 129) - COLUMN_RENDER_BLOCK(26, 137) - COLUMN_RENDER_BLOCK(28, 145) - COLUMN_RENDER_BLOCK(30, 153) - COLUMN_RENDER_BLOCK_REFRESH(32, 161) - case 169: - case 170: + COLUMN_RENDER_BLOCK(2, 4) + COLUMN_RENDER_BLOCK(4, 12) + COLUMN_RENDER_BLOCK(6, 20) + COLUMN_RENDER_BLOCK_REFRESH(8, 28) + COLUMN_RENDER_BLOCK(10, 36) + COLUMN_RENDER_BLOCK(12, 44) + COLUMN_RENDER_BLOCK(14, 52) + COLUMN_RENDER_BLOCK_REFRESH(16, 60) + COLUMN_RENDER_BLOCK(18, 68) + COLUMN_RENDER_BLOCK(20, 76) + COLUMN_RENDER_BLOCK(22, 84) + COLUMN_RENDER_BLOCK_REFRESH(24, 92) + COLUMN_RENDER_BLOCK(26, 100) + COLUMN_RENDER_BLOCK(28, 108) + COLUMN_RENDER_BLOCK(30, 116) + COLUMN_RENDER_BLOCK_REFRESH(32, 124) + case 132: + case 133: external_slot(context); break; } @@ -1379,66 +1377,59 @@ void vdp_h40_line(uint32_t line, vdp_context * context) void latch_mode(vdp_context * context) { - context->latched_mode = (context->regs[REG_MODE_4] & 0x81) | (context->regs[REG_MODE_2] & BIT_PAL); + context->latched_mode = context->regs[REG_MODE_2] & BIT_PAL; } void check_render_bg(vdp_context * context, int32_t line, uint32_t slot) { - if (line > 0) { - line -= 1; - int starti = -1; - if (context->latched_mode & BIT_H40) { - if (slot >= 55 && slot < 210) { - uint32_t x = (slot-55)*2; - starti = line * 320 + x; - } else if (slot < 5) { - uint32_t x = (slot + 155)*2; - starti = (line-1)*320 + x; + int starti = -1; + if (context->regs[REG_MODE_4] & BIT_H40) { + if (slot >= 12 && slot < 172) { + uint32_t x = (slot-12)*2; + starti = line * 320 + x; + } + } else { + if (slot >= 11 && slot < 139) { + uint32_t x = (slot-11)*2; + starti = line * 320 + x; + } + } + if (starti >= 0) { + if (context->b32) { + uint32_t color = context->colors[context->regs[REG_BG_COLOR]]; + uint32_t * start = context->framebuf; + start += starti; + for (int i = 0; i < 2; i++) { + *(start++) = color; } } else { - if (slot >= 48 && slot < 171) { - uint32_t x = (slot-48)*2; - starti = line * 320 + x; - } else if (slot < 5) { - uint32_t x = (slot + 123)*2; - starti = (line-1)*320 + x; - } - } - if (starti >= 0) { - if (context->b32) { - uint32_t color = context->colors[context->regs[REG_BG_COLOR]]; - uint32_t * start = context->framebuf; - start += starti; - for (int i = 0; i < 2; i++) { - *(start++) = color; - } - } else { - uint16_t color = context->colors[context->regs[REG_BG_COLOR]]; - uint16_t * start = context->framebuf; - start += starti; - for (int i = 0; i < 2; i++) { - *(start++) = color; - } + uint16_t color = context->colors[context->regs[REG_BG_COLOR]]; + uint16_t * start = context->framebuf; + start += starti; + for (int i = 0; i < 2; i++) { + *(start++) = color; } } } } +uint32_t h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19}; + void vdp_run_context(vdp_context * context, uint32_t target_cycles) { while(context->cycles < target_cycles) { context->flags &= ~FLAG_UNUSED_SLOT; - uint32_t line = context->cycles / MCLKS_LINE; - uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; - if (!context->cycles) { + uint32_t line = context->vcounter; + uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; + uint32_t slot = context->hslot; + //TODO: Figure out when this actually happens + if (!line && !slot) { latch_mode(context); } - uint32_t linecyc = context->cycles % MCLKS_LINE; - if (linecyc == 0) { - context->latched_mode &= ~0x81; - context->latched_mode |= context->regs[REG_MODE_4] & 0x81; - if (line < 1 || line >= active_lines) { + uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; + if (is_h40 && slot == 167 || !is_h40 && slot == 134) { + if (line >= inactive_start) { context->hint_counter = context->regs[REG_HINT]; } else if (context->hint_counter) { context->hint_counter--; @@ -1446,111 +1437,41 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) context->flags2 |= FLAG2_HINT_PENDING; context->hint_counter = context->regs[REG_HINT]; } - } else if(line == active_lines) { - uint32_t intcyc = context->latched_mode & BIT_H40 ? VINT_CYCLE_H40 : VINT_CYCLE_H32; - if (linecyc == intcyc) { + } else if(line == inactive_start) { + uint32_t intslot = context->regs[REG_MODE_4] & BIT_H40 ? VINT_SLOT_H40 : VINT_SLOT_H32; + if (slot == intslot) { context->flags2 |= FLAG2_VINT_PENDING; } } - uint32_t inccycles, slot; - if (context->latched_mode & BIT_H40){ - if (linecyc < MCLKS_SLOT_H40*HSYNC_SLOT_H40) { - slot = linecyc/MCLKS_SLOT_H40; + uint32_t inccycles; + //line 0x1FF is basically active even though it's not displayed + uint8_t active_slot = line < inactive_start || line == 0x1FF; + if (is_h40) { + if (slot < HSYNC_SLOT_H40 || slot >= HSYNC_END_H40) { inccycles = MCLKS_SLOT_H40; - } else if(linecyc < MCLK_WEIRD_END) { - switch(linecyc-(MCLKS_SLOT_H40*HSYNC_SLOT_H40)) - { - case 0: - inccycles = 19; - slot = 0; - break; - case 19: - slot = 1; - inccycles = 20; - break; - case 39: - slot = 2; - inccycles = 20; - break; - case 59: - slot = 3; - inccycles = 20; - break; - case 79: - slot = 4; - inccycles = 18; - break; - case 97: - slot = 5; - inccycles = 20; - break; - case 117: - slot = 6; - inccycles = 20; - break; - case 137: - slot = 7; - inccycles = 20; - break; - case 157: - slot = 8; - inccycles = 18; - break; - case 175: - slot = 9; - inccycles = 20; - break; - case 195: - slot = 10; - inccycles = 20; - break; - case 215: - slot = 11; - inccycles = 20; - break; - case 235: - slot = 12; - inccycles = 18; - break; - case 253: - slot = 13; - inccycles = 20; - break; - case 273: - slot = 14; - inccycles = 20; - break; - case 293: - slot = 15; - inccycles = 20; - break; - case 313: - slot = 16; - inccycles = 19; - break; - default: - fprintf(stderr, "cycles after weirdness %d\n", linecyc-(MCLKS_SLOT_H40*HSYNC_SLOT_H40)); - exit(1); - } - slot += HSYNC_SLOT_H40; } else { - slot = (linecyc-MCLK_WEIRD_END)/MCLKS_SLOT_H40 + SLOT_WEIRD_END; - inccycles = MCLKS_SLOT_H40; + inccycles = h40_hsync_cycles[slot-HSYNC_SLOT_H40]; + } + //the first inactive line behaves as an active one for the first 4 slots + if (line == inactive_start && slot > 166 && slot < 171) { + active_slot = 1; } } else { inccycles = MCLKS_SLOT_H32; - slot = linecyc/MCLKS_SLOT_H32; + //the first inactive line behaves as an active one for the first 4 slots + if (line == inactive_start && slot > 166 && slot < 171) { + active_slot = 1; + } } - 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 - line = (line - 1) & 0xFF; - - //Convert to slot number - if (context->latched_mode & BIT_H40){ - if (!slot && line != (active_lines-1) && (target_cycles - context->cycles) >= MCLKS_LINE) { + uint8_t inc_slot = 1; + if (context->regs[REG_MODE_2] & DISPLAY_ENABLE && active_slot) { + //run VDP rendering for a slot or a line + if (is_h40) { + if (slot == 167 && line < inactive_start && (target_cycles - context->cycles) >= MCLKS_LINE) { vdp_h40_line(line, context); inccycles = MCLKS_LINE; + context->vcounter++; + inc_slot = 0; } else { vdp_h40(line, slot, context); } @@ -1561,20 +1482,43 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) if (!is_refresh(context, slot)) { external_slot(context); } - if (line < active_lines) { + if (line < inactive_start) { check_render_bg(context, line, slot); } } if (context->flags & FLAG_DMA_RUN && !is_refresh(context, slot)) { run_dma_src(context, slot); } + if (inc_slot) { + context->hslot++; + context->hslot &= 0xFF; + if (is_h40) { + if (context->hslot == 167) { + context->vcounter++; + } else if (context->hslot == 183) { + context->hslot = 229; + } + } else { + if (context->hslot == 134) { + context->vcounter++; + } else if (context->hslot == 148) { + context->hslot = 233; + } + } + + } + if (context->vcounter == 0xEA) { + context->vcounter += 0xFA; + } else { + context->vcounter &= 0x1FF; + } context->cycles += inccycles; } } uint32_t vdp_run_to_vblank(vdp_context * context) { - uint32_t target_cycles = ((context->latched_mode & BIT_PAL) ? PAL_ACTIVE : NTSC_ACTIVE) * MCLKS_LINE; + uint32_t target_cycles = ((context->latched_mode & BIT_PAL) ? PAL_INACTIVE_START : NTSC_INACTIVE_START) * MCLKS_LINE; vdp_run_context(context, target_cycles); return context->cycles; } @@ -1586,7 +1530,7 @@ void vdp_run_dma_done(vdp_context * context, uint32_t target_cycles) if (!dmalen) { dmalen = 0x10000; } - uint32_t min_dma_complete = dmalen * (context->latched_mode & BIT_H40 ? 16 : 20); + uint32_t min_dma_complete = dmalen * (context->regs[REG_MODE_4] & BIT_H40 ? 16 : 20); if ((context->regs[REG_DMASRC_H] & 0xC0) == 0xC0 || (context->cd & 0xF) == VRAM_WRITE) { //DMA copies take twice as long to complete since they require a read and a write //DMA Fills and transfers to VRAM also take twice as long as it requires 2 writes for a single word @@ -1677,10 +1621,10 @@ int vdp_data_port_write(vdp_context * context, uint16_t value) context->flags &= ~FLAG_DMA_RUN; } while (context->fifo_write == context->fifo_read) { - vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); + vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); } fifo_entry * cur = context->fifo + context->fifo_write; - cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; + cur->cycle = context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)*FIFO_LATENCY; cur->address = context->address; cur->value = value; if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { @@ -1725,13 +1669,19 @@ uint16_t vdp_control_port_read(vdp_context * context) if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && context->framebuf == context->oddbuf) { value |= 0x10; } - uint32_t line= context->cycles / MCLKS_LINE; - uint32_t linecyc = context->cycles % MCLKS_LINE; - if (line >= (context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) { + uint32_t line= context->vcounter; + uint32_t slot = context->hslot; + if (line >= (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) { value |= 0x8; } - if (linecyc < (context->latched_mode & BIT_H40 ? HBLANK_CLEAR_H40 : HBLANK_CLEAR_H32)) { - value |= 0x4; + if (context->regs[REG_MODE_4] & BIT_H40) { + if (slot < HBLANK_END_H40 || slot > HBLANK_START_H40) { + value |= 0x4; + } + } else { + if (slot < HBLANK_END_H32 || slot > HBLANK_START_H32) { + value |= 0x4; + } } if (context->flags & FLAG_DMA_RUN) { value |= 0x2; @@ -1757,7 +1707,7 @@ uint16_t vdp_data_port_read(vdp_context * context) context->flags &= ~FLAG_UNUSED_SLOT; //context->flags2 |= FLAG2_READ_PENDING; while (!(context->flags & FLAG_UNUSED_SLOT)) { - vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); + vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); } uint16_t value = 0; switch (context->cd & 0xF) @@ -1767,7 +1717,7 @@ uint16_t vdp_data_port_read(vdp_context * context) context->flags &= ~FLAG_UNUSED_SLOT; context->flags2 |= FLAG2_READ_PENDING; while (!(context->flags & FLAG_UNUSED_SLOT)) { - vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); + vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); } value |= context->vdpmem[context->address | 1]; break; @@ -1798,102 +1748,8 @@ uint16_t vdp_hv_counter_read(vdp_context * context) if (context->regs[REG_MODE_1] & BIT_HVC_LATCH) { return context->hv_latch; } - uint32_t line= context->cycles / MCLKS_LINE; - if (!line) { - line = 0xFF; - } else { - line--; - if (line > 0xEA) { - line = (line + 0xFA) & 0xFF; - } - } - uint32_t linecyc = context->cycles % MCLKS_LINE; - if (context->latched_mode & BIT_H40) { - uint32_t slot; - if (linecyc < MCLKS_SLOT_H40*HSYNC_SLOT_H40) { - slot = linecyc/MCLKS_SLOT_H40; - } else if(linecyc < MCLK_WEIRD_END) { - switch(linecyc-(MCLKS_SLOT_H40*HSYNC_SLOT_H40)) - { - case 0: - slot = 0; - break; - case 19: - slot = 1; - break; - case 39: - slot = 2; - break; - case 59: - slot = 2; - break; - case 79: - slot = 3; - break; - case 97: - slot = 4; - break; - case 117: - slot = 5; - break; - case 137: - slot = 6; - break; - case 157: - slot = 7; - break; - case 175: - slot = 8; - break; - case 195: - slot = 9; - break; - case 215: - slot = 11; - break; - case 235: - slot = 12; - break; - case 253: - slot = 13; - break; - case 273: - slot = 14; - break; - case 293: - slot = 15; - break; - case 313: - slot = 16; - break; - default: - fprintf(stderr, "cycles after weirdness %d\n", linecyc-(MCLKS_SLOT_H40*HSYNC_SLOT_H40)); - exit(1); - } - slot += HSYNC_SLOT_H40; - } else { - slot = (linecyc-MCLK_WEIRD_END)/MCLKS_SLOT_H40 + SLOT_WEIRD_END; - } - linecyc = slot * 2; - if (linecyc >= 86) { - linecyc -= 86; - } else { - linecyc += 334; - } - if (linecyc > 0x16C) { - linecyc += 92; - } - } else { - linecyc /= 10; - if (linecyc >= 74) { - linecyc -= 74; - } else { - linecyc += 268; - } - if (linecyc > 0x127) { - linecyc += 170; - } - } + uint32_t line= context->vcounter & 0xFF; + uint32_t linecyc = (context->hslot * 2) & 0xFF; linecyc &= 0xFF; if (context->double_res) { line <<= 1; @@ -1934,9 +1790,9 @@ uint32_t vdp_next_hint(vdp_context * context) if (context->flags2 & FLAG2_HINT_PENDING) { return context->cycles; } - uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; + uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; uint32_t line = context->cycles / MCLKS_LINE; - if (line >= active_lines) { + if (line >= inactive_start) { return 0xFFFFFFFF; } uint32_t linecyc = context->cycles % MCLKS_LINE; @@ -1952,12 +1808,12 @@ uint32_t vdp_next_vint(vdp_context * context) if (context->flags2 & FLAG2_VINT_PENDING) { return context->cycles; } - uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; - uint32_t vcycle = MCLKS_LINE * active_lines; - if (context->latched_mode & BIT_H40) { - vcycle += VINT_CYCLE_H40; + uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; + uint32_t vcycle = MCLKS_LINE * inactive_start; + if (context->regs[REG_MODE_4] & BIT_H40) { + vcycle += VINT_SLOT_H40 * MCLKS_SLOT_H40; } else { - vcycle += VINT_CYCLE_H32; + vcycle += VINT_SLOT_H32 * MCLKS_SLOT_H32; } if (vcycle < context->cycles) { return 0xFFFFFFFF; @@ -1967,12 +1823,12 @@ uint32_t vdp_next_vint(vdp_context * context) uint32_t vdp_next_vint_z80(vdp_context * context) { - uint32_t active_lines = context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE; - uint32_t vcycle = MCLKS_LINE * active_lines; - if (context->latched_mode & BIT_H40) { - vcycle += VINT_CYCLE_H40; + uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; + uint32_t vcycle = MCLKS_LINE * inactive_start; + if (context->regs[REG_MODE_4] & BIT_H40) { + vcycle += VINT_SLOT_H40 * MCLKS_SLOT_H40; } else { - vcycle += VINT_CYCLE_H32; + vcycle += VINT_SLOT_H32 * MCLKS_SLOT_H32; } return vcycle; } diff --git a/vdp.h b/vdp.h index 830aa5a..2fa8f36 100644 --- a/vdp.h +++ b/vdp.h @@ -142,9 +142,11 @@ typedef struct { uint32_t colors[CRAM_SIZE*3]; uint32_t debugcolors[1 << (3 + 1 + 1 + 1)];//3 bits for source, 1 bit for priority, 1 bit for shadow, 1 bit for hilight uint16_t vsram[VSRAM_SIZE]; - uint8_t latched_mode; + uint16_t vcounter; + uint16_t hslot; //hcounter/2 uint16_t hscroll_a; uint16_t hscroll_b; + uint8_t latched_mode; uint8_t sprite_index; uint8_t sprite_draws; int8_t slot_counter; -- cgit v1.2.3 From b28dc876ea3d900787f2c953ddd84056924f7308 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 18 Jun 2014 16:30:19 -0700 Subject: Fix most of the breakage caused by the vcounter/hcounter changes --- blastem.c | 53 ++++++++++---------- vdp.c | 167 +++++++++++++++++++++++++++++++++++++++++++++++++++----------- vdp.h | 4 +- 3 files changed, 168 insertions(+), 56 deletions(-) diff --git a/blastem.c b/blastem.c index c4072e3..83c2c23 100644 --- a/blastem.c +++ b/blastem.c @@ -33,7 +33,7 @@ #define MAX_SOUND_CYCLES 100000 -uint32_t mclks_per_frame = MCLKS_LINE*LINES_NTSC; +uint32_t mclk_target = 0; uint16_t cart[CARTRIDGE_WORDS]; uint16_t ram[RAM_WORDS]; @@ -231,15 +231,15 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) z80_context * z_context = gen->z80; uint32_t mclks = context->current_cycle * MCLKS_PER_68K; sync_z80(z_context, mclks); - if (mclks >= mclks_per_frame) { + if (mclks >= mclk_target) { sync_sound(gen, mclks); - gen->ym->current_cycle -= mclks_per_frame; - gen->psg->cycles -= mclks_per_frame; + gen->ym->current_cycle -= mclk_target; + gen->psg->cycles -= mclk_target; if (gen->ym->write_cycle != CYCLE_NEVER) { - gen->ym->write_cycle = gen->ym->write_cycle >= mclks_per_frame/MCLKS_PER_68K ? gen->ym->write_cycle - mclks_per_frame/MCLKS_PER_68K : 0; + gen->ym->write_cycle = gen->ym->write_cycle >= mclk_target/MCLKS_PER_68K ? gen->ym->write_cycle - mclk_target/MCLKS_PER_68K : 0; } //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); - vdp_run_context(v_context, mclks_per_frame); + vdp_run_context(v_context, mclk_target); if (!headless) { break_on_sync |= wait_render_frame(v_context, frame_limit); @@ -250,28 +250,29 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) } } frame++; - mclks -= mclks_per_frame; - vdp_adjust_cycles(v_context, mclks_per_frame); - io_adjust_cycles(gen->ports, context->current_cycle, mclks_per_frame/MCLKS_PER_68K); - io_adjust_cycles(gen->ports+1, context->current_cycle, mclks_per_frame/MCLKS_PER_68K); - io_adjust_cycles(gen->ports+2, context->current_cycle, mclks_per_frame/MCLKS_PER_68K); + mclks -= mclk_target; + vdp_adjust_cycles(v_context, mclk_target); + io_adjust_cycles(gen->ports, context->current_cycle, mclk_target/MCLKS_PER_68K); + io_adjust_cycles(gen->ports+1, context->current_cycle, mclk_target/MCLKS_PER_68K); + io_adjust_cycles(gen->ports+2, context->current_cycle, mclk_target/MCLKS_PER_68K); if (busack_cycle != CYCLE_NEVER) { - if (busack_cycle > mclks_per_frame/MCLKS_PER_68K) { - busack_cycle -= mclks_per_frame/MCLKS_PER_68K; + if (busack_cycle > mclk_target/MCLKS_PER_68K) { + busack_cycle -= mclk_target/MCLKS_PER_68K; } else { busack_cycle = CYCLE_NEVER; busack = new_busack; } } - context->current_cycle -= mclks_per_frame/MCLKS_PER_68K; - if (z_context->current_cycle >= mclks_per_frame/MCLKS_PER_Z80) { - z_context->current_cycle -= mclks_per_frame/MCLKS_PER_Z80; + context->current_cycle -= mclk_target/MCLKS_PER_68K; + if (z_context->current_cycle >= mclk_target/MCLKS_PER_Z80) { + z_context->current_cycle -= mclk_target/MCLKS_PER_Z80; } else { z_context->current_cycle = 0; } if (mclks) { vdp_run_context(v_context, mclks); } + mclk_target = vdp_cycles_to_frame_end(v_context); } else { //printf("running VDP for %d cycles\n", mclks - v_context->cycles); vdp_run_context(v_context, mclks); @@ -317,10 +318,10 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ gen->bus_busy = 1; while (vdp_data_port_write(v_context, value) < 0) { while(v_context->flags & FLAG_DMA_RUN) { - vdp_run_dma_done(v_context, mclks_per_frame); - if (v_context->cycles >= mclks_per_frame) { + vdp_run_dma_done(v_context, mclk_target); + if (v_context->cycles >= mclk_target) { context->current_cycle = v_context->cycles / MCLKS_PER_68K; - if (context->current_cycle * MCLKS_PER_68K < mclks_per_frame) { + if (context->current_cycle * MCLKS_PER_68K < mclk_target) { ++context->current_cycle; } sync_components(context, 0); @@ -334,10 +335,10 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ if (blocked) { while (blocked) { while(v_context->flags & FLAG_DMA_RUN) { - vdp_run_dma_done(v_context, mclks_per_frame); - if (v_context->cycles >= mclks_per_frame) { + vdp_run_dma_done(v_context, mclk_target); + if (v_context->cycles >= mclk_target) { context->current_cycle = v_context->cycles / MCLKS_PER_68K; - if (context->current_cycle * MCLKS_PER_68K < mclks_per_frame) { + if (context->current_cycle * MCLKS_PER_68K < mclk_target) { ++context->current_cycle; } sync_components(context, 0); @@ -966,7 +967,7 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u context.system = gen; //cartridge ROM context.mem_pointers[0] = cart; - context.target_cycle = context.sync_cycle = mclks_per_frame/MCLKS_PER_68K; + context.target_cycle = context.sync_cycle = mclk_target/MCLKS_PER_68K; //work RAM context.mem_pointers[1] = ram; //save RAM/map @@ -1210,7 +1211,6 @@ int main(int argc, char ** argv) height = height < 240 ? (width/320) * 240 : height; uint32_t fps = 60; if (version_reg & 0x40) { - mclks_per_frame = MCLKS_LINE * LINES_PAL; fps = 50; } if (!headless) { @@ -1221,7 +1221,8 @@ int main(int argc, char ** argv) memset(&gen, 0, sizeof(gen)); gen.master_clock = gen.normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL; - init_vdp_context(&v_context); + init_vdp_context(&v_context, version_reg & 0x40); + mclk_target = vdp_cycles_to_frame_end(&v_context); ym2612_context y_context; ym_init(&y_context, render_sample_rate(), gen.master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0); @@ -1236,7 +1237,7 @@ int main(int argc, char ** argv) z_context.system = &gen; z_context.mem_pointers[0] = z80_ram; - z_context.sync_cycle = z_context.target_cycle = mclks_per_frame/MCLKS_PER_Z80; + z_context.sync_cycle = z_context.target_cycle = mclk_target/MCLKS_PER_Z80; z_context.int_cycle = CYCLE_NEVER; z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; diff --git a/vdp.c b/vdp.c index ad8ed00..126e3be 100644 --- a/vdp.c +++ b/vdp.c @@ -46,7 +46,7 @@ uint8_t debug_base[][3] = { uint8_t color_map_init_done; -void init_vdp_context(vdp_context * context) +void init_vdp_context(vdp_context * context, uint8_t region_pal) { memset(context, 0, sizeof(*context)); context->vdpmem = malloc(VRAM_SIZE); @@ -133,6 +133,9 @@ void init_vdp_context(vdp_context * context) context->debugcolors[color] = render_map_color(r, g, b); } } + if (region_pal) { + context->flags2 |= FLAG2_REGION_PAL; + } } int is_refresh(vdp_context * context, uint32_t slot) @@ -1428,7 +1431,7 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) latch_mode(context); } uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; - if (is_h40 && slot == 167 || !is_h40 && slot == 134) { + if (is_h40 && slot == HBLANK_START_H40 || !is_h40 && slot == 134) { if (line >= inactive_start) { context->hint_counter = context->regs[REG_HINT]; } else if (context->hint_counter) { @@ -1467,7 +1470,7 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) if (context->regs[REG_MODE_2] & DISPLAY_ENABLE && active_slot) { //run VDP rendering for a slot or a line if (is_h40) { - if (slot == 167 && line < inactive_start && (target_cycles - context->cycles) >= MCLKS_LINE) { + if (slot == HBLANK_START_H40 && line < inactive_start && (target_cycles - context->cycles) >= MCLKS_LINE) { vdp_h40_line(line, context); inccycles = MCLKS_LINE; context->vcounter++; @@ -1493,7 +1496,7 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) context->hslot++; context->hslot &= 0xFF; if (is_h40) { - if (context->hslot == 167) { + if (context->hslot == HBLANK_START_H40) { context->vcounter++; } else if (context->hslot == 183) { context->hslot = 229; @@ -1507,10 +1510,17 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) } } - if (context->vcounter == 0xEA) { - context->vcounter += 0xFA; - } else { - context->vcounter &= 0x1FF; + context->vcounter &= 0x1FF; + if (context->flags2 & FLAG2_REGION_PAL) { + if (context->latched_mode & BIT_PAL) { + if (context->vcounter == 0x10B) { + context->vcounter = 0x1D2; + } + } else if (context->vcounter == 0x103){ + context->vcounter = 0x1CA; + } + } else if (!(context->latched_mode & BIT_PAL) && context->vcounter == 0xEB) { + context->vcounter = 0x1E5; } context->cycles += inccycles; } @@ -1757,6 +1767,7 @@ uint16_t vdp_hv_counter_read(vdp_context * context) line |= 1; } } + printf("hv_counter_read line: %d, horiz: %d, cycles: %d\n", line, linecyc, context->cycles); return (line << 8) | linecyc; } @@ -1782,6 +1793,88 @@ void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) } } +uint32_t vdp_cycles_next_line(vdp_context * context) +{ + if (context->regs[REG_MODE_4] & BIT_H40) { + if (context->hslot < HBLANK_START_H40) { + return (HBLANK_START_H40 - context->hslot) * MCLKS_SLOT_H40; + } else if (context->hslot < 183) { + return MCLKS_LINE - (context->hslot - HBLANK_START_H40) * MCLKS_SLOT_H40; + } else { + return (256-context->hslot + HBLANK_START_H40) * MCLKS_SLOT_H40; + } + } else { + if (context->hslot < HBLANK_START_H32) { + return (HBLANK_START_H32 - context->hslot) * MCLKS_SLOT_H32; + } else if (context->hslot < 148) { + return MCLKS_LINE - (context->hslot - HBLANK_START_H32) * MCLKS_SLOT_H32; + } else { + return (256-context->hslot + HBLANK_START_H32) * MCLKS_SLOT_H32; + } + } +} + +uint32_t vdp_cycles_to_line(vdp_context * context, uint32_t target) +{ + uint32_t jump_start, jump_dst; + if (context->flags2 & FLAG2_REGION_PAL) { + if (context->latched_mode & BIT_PAL) { + jump_start = 0x10B; + jump_dst = 0x1D2; + } else { + jump_start = 0x103; + jump_dst = 0x1CA; + } + } else { + if (context->latched_mode & BIT_PAL) { + jump_start = 0; + jump_dst = 0; + } else { + jump_start = 0xEB; + jump_dst = 0x1E5; + } + } + uint32_t lines; + if (context->vcounter < target) { + if (target < jump_start) { + lines = target - context->vcounter; + } else { + lines = jump_start - context->vcounter + target - jump_dst; + } + } else { + if (context->vcounter < jump_start) { + lines = jump_start - context->vcounter + 512 - jump_dst; + } else { + lines = 512 - context->vcounter; + } + if (target < jump_start) { + lines += target; + } else { + lines += jump_start + target - jump_dst; + } + } + return MCLKS_LINE * (lines - 1) + vdp_cycles_next_line(context); +} + +uint32_t vdp_cycles_to_frame_end(vdp_context * context) +{ + uint32_t frame_end; + if (context->flags2 & FLAG2_REGION_PAL) { + if (context->latched_mode & BIT_PAL) { + frame_end = PAL_INACTIVE_START + 8; + } else { + frame_end = NTSC_INACTIVE_START + 8; + } + } else { + if (context->latched_mode & BIT_PAL) { + frame_end = 512; + } else { + frame_end = NTSC_INACTIVE_START + 8; + } + } + return context->cycles + vdp_cycles_to_line(context, frame_end); +} + uint32_t vdp_next_hint(vdp_context * context) { if (!(context->regs[REG_MODE_1] & BIT_HINT_EN)) { @@ -1791,13 +1884,14 @@ uint32_t vdp_next_hint(vdp_context * context) return context->cycles; } uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; - uint32_t line = context->cycles / MCLKS_LINE; - if (line >= inactive_start) { - return 0xFFFFFFFF; + uint32_t hint_line; + if (context->vcounter >= inactive_start) { + hint_line = context->regs[REG_HINT]; + } else { + hint_line = context->vcounter + context->hint_counter + 1; } - uint32_t linecyc = context->cycles % MCLKS_LINE; - uint32_t hcycle = context->cycles + context->hint_counter * MCLKS_LINE + MCLKS_LINE - linecyc; - return hcycle; + + return context->cycles + vdp_cycles_to_line(context, hint_line); } uint32_t vdp_next_vint(vdp_context * context) @@ -1808,29 +1902,44 @@ uint32_t vdp_next_vint(vdp_context * context) if (context->flags2 & FLAG2_VINT_PENDING) { return context->cycles; } - uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; - uint32_t vcycle = MCLKS_LINE * inactive_start; - if (context->regs[REG_MODE_4] & BIT_H40) { - vcycle += VINT_SLOT_H40 * MCLKS_SLOT_H40; - } else { - vcycle += VINT_SLOT_H32 * MCLKS_SLOT_H32; - } - if (vcycle < context->cycles) { - return 0xFFFFFFFF; - } - return vcycle; + + + return vdp_next_vint_z80(context); } uint32_t vdp_next_vint_z80(vdp_context * context) { uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; - uint32_t vcycle = MCLKS_LINE * inactive_start; + if (context->vcounter == inactive_start) { + if (context->regs[REG_MODE_4] & BIT_H40) { + if (context->hslot >= HBLANK_START_H40) { + if (context->hslot < 183) { + return context->cycles + (VINT_SLOT_H40 + 183 - context->hslot + 256 - 229) * MCLKS_SLOT_H40; + } else { + return context->cycles + (VINT_SLOT_H40 + 256 - context->hslot) * MCLKS_SLOT_H40; + } + } else if (context->hslot < VINT_SLOT_H40) { + return context->cycles + (VINT_SLOT_H40 - context->hslot) * MCLKS_SLOT_H40; + } + } else { + if (context->hslot >= HBLANK_START_H32) { + if (context->hslot < 148) { + return context->cycles + (VINT_SLOT_H32 + 148 - context->hslot + 256 - 233) * MCLKS_SLOT_H32; + } else { + return context->cycles + (VINT_SLOT_H32 + 256 - context->hslot) * MCLKS_SLOT_H32; + } + } else if (context->hslot < VINT_SLOT_H32) { + return context->cycles + (VINT_SLOT_H32 - context->hslot) * MCLKS_SLOT_H32; + } + } + } + int32_t cycles_to_vint = vdp_cycles_to_line(context, inactive_start); if (context->regs[REG_MODE_4] & BIT_H40) { - vcycle += VINT_SLOT_H40 * MCLKS_SLOT_H40; + cycles_to_vint += (VINT_SLOT_H40 + 183 - HBLANK_START_H40 + 256 - 229) * MCLKS_SLOT_H40; } else { - vcycle += VINT_SLOT_H32 * MCLKS_SLOT_H32; + cycles_to_vint += (VINT_SLOT_H32 + 148 - HBLANK_START_H32 + 256 - 233) * MCLKS_SLOT_H32; } - return vcycle; + return context->cycles + cycles_to_vint; } void vdp_int_ack(vdp_context * context, uint16_t int_num) diff --git a/vdp.h b/vdp.h index 2fa8f36..184521a 100644 --- a/vdp.h +++ b/vdp.h @@ -49,6 +49,7 @@ #define FLAG2_HINT_PENDING 0x02 #define FLAG2_READ_PENDING 0x04 #define FLAG2_SPRITE_COLLIDE 0x08 +#define FLAG2_REGION_PAL 0x10 #define DISPLAY_ENABLE 0x40 @@ -169,7 +170,7 @@ typedef struct { uint8_t *tmp_buf_b; } vdp_context; -void init_vdp_context(vdp_context * context); +void init_vdp_context(vdp_context * context, uint8_t region_pal); void vdp_run_context(vdp_context * context, uint32_t target_cycles); //runs from current cycle count to VBLANK for the current mode, returns ending cycle count uint32_t vdp_run_to_vblank(vdp_context * context); @@ -192,6 +193,7 @@ 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); +uint32_t vdp_cycles_to_frame_end(vdp_context * context); extern int32_t color_map[1 << 12]; -- cgit v1.2.3 From e97e4c2823337d68efdc8191f73d15b532a2130e Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 18 Jun 2014 16:39:42 -0700 Subject: Remove debug printf that escaped into my previous commit --- vdp.c | 1 - 1 file changed, 1 deletion(-) diff --git a/vdp.c b/vdp.c index 126e3be..9eafb67 100644 --- a/vdp.c +++ b/vdp.c @@ -1767,7 +1767,6 @@ uint16_t vdp_hv_counter_read(vdp_context * context) line |= 1; } } - printf("hv_counter_read line: %d, horiz: %d, cycles: %d\n", line, linecyc, context->cycles); return (line << 8) | linecyc; } -- cgit v1.2.3 From e8e8075b59f9e4a6a8e9b1cc96f2fcb447fa508e Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 19 Jun 2014 08:14:35 -0700 Subject: Slight cleanup of vint handling on the Z80 --- blastem.c | 4 ++-- z80_to_x86.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/blastem.c b/blastem.c index 83c2c23..15f7932 100644 --- a/blastem.c +++ b/blastem.c @@ -192,11 +192,11 @@ void sync_z80(z80_context * z_context, uint32_t mclks) } uint32_t vint_cycle = vdp_next_vint_z80(gen->vdp) / MCLKS_PER_Z80; while (z_context->current_cycle < z_context->sync_cycle) { - if (z_context->iff1 && z_context->current_cycle < (vint_cycle + Z80_VINT_DURATION)) { + if (z_context->iff1 && z_context->int_cycle == CYCLE_NEVER && z_context->current_cycle < (vint_cycle + Z80_VINT_DURATION)) { z_context->int_cycle = vint_cycle < z_context->int_enable_cycle ? z_context->int_enable_cycle : vint_cycle; } z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle; - dprintf("Running Z80 from cycle %d to cycle %d. Native PC: %p\n", z_context->current_cycle, z_context->sync_cycle, z_context->native_pc); + dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d\n", z_context->current_cycle, z_context->sync_cycle, z_context->int_cycle); z80_run(z_context); dprintf("Z80 ran to cycle %d\n", z_context->current_cycle); } diff --git a/z80_to_x86.c b/z80_to_x86.c index 2cab1c9..ea07214 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -1964,6 +1964,7 @@ void init_z80_context(z80_context * context, x86_z80_options * options) context->banked_code_map = malloc(sizeof(native_map_slot) * (1 << 9)); memset(context->banked_code_map, 0, sizeof(native_map_slot) * (1 << 9)); context->options = options; + context->int_cycle = 0xFFFFFFFF; } void z80_reset(z80_context * context) -- cgit v1.2.3 From a14794522213f99ddef00aa049785ff806d4b1dd Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 19 Jun 2014 19:50:16 -0700 Subject: Properly handle Z80 breakpoints on self-modifying code and setting Z80 breakpoints before the Z80 program has been loaded --- z80_to_x86.c | 115 +++++++++++++++++++++++++++++++++++------------------------ z80_to_x86.h | 5 ++- 2 files changed, 73 insertions(+), 47 deletions(-) diff --git a/z80_to_x86.c b/z80_to_x86.c index ea07214..584d6e1 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -44,6 +44,8 @@ void z80_halt(); void z80_save_context(); void z80_load_context(); +uint8_t * zbreakpoint_patch(z80_context * context, uint16_t address, uint8_t * native); + uint8_t z80_size(z80inst * inst) { uint8_t reg = (inst->reg & 0x1F); @@ -334,6 +336,9 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context x86_z80_options *opts = context->options; uint8_t * start = dst; dst = z80_check_cycles_int(dst, address); + if (context->breakpoint_flags[address / sizeof(uint8_t)] & (1 << (address % sizeof(uint8_t)))) { + zbreakpoint_patch(context, address, start); + } switch(inst->op) { case Z80_LD: @@ -1975,62 +1980,80 @@ void z80_reset(z80_context * context) context->extra_pc = NULL; } -void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler) +uint8_t * zbreakpoint_patch(z80_context * context, uint16_t address, uint8_t * native) { - static uint8_t * bp_stub = NULL; - uint8_t * native = z80_get_native_address_trans(context, address); - uint8_t * start_native = native; native = mov_ir(native, address, SCRATCH1, SZ_W); - if (!bp_stub) { - x86_z80_options * opts = context->options; - uint8_t * dst = opts->cur_code; - uint8_t * dst_end = opts->code_end; - if (dst_end - dst < 128) { - size_t size = 1024*1024; - dst = alloc_code(&size); - opts->code_end = dst_end = dst + size; - } - bp_stub = dst; - native = call(native, bp_stub); + native = call(native, context->bp_stub); + return native; +} - //Calculate length of prologue - dst = z80_check_cycles_int(dst, address); - int check_int_size = dst-bp_stub; - dst = bp_stub; +void zcreate_stub(z80_context * context) +{ + x86_z80_options * opts = context->options; + uint8_t * dst = opts->cur_code; + uint8_t * dst_end = opts->code_end; + if (dst_end - dst < 128) { + size_t size = 1024*1024; + dst = alloc_code(&size); + opts->code_end = dst_end = dst + size; + } + context->bp_stub = dst; - //Save context and call breakpoint handler - dst = call(dst, (uint8_t *)z80_save_context); - dst = push_r(dst, SCRATCH1); - dst = mov_rr(dst, CONTEXT, RDI, SZ_Q); - dst = mov_rr(dst, SCRATCH1, RSI, SZ_W); - dst = call(dst, bp_handler); - dst = mov_rr(dst, RAX, CONTEXT, SZ_Q); - //Restore context - dst = call(dst, (uint8_t *)z80_load_context); - dst = pop_r(dst, SCRATCH1); - //do prologue stuff - dst = cmp_rr(dst, ZCYCLES, ZLIMIT, SZ_D); - uint8_t * jmp_off = dst+1; - dst = jcc(dst, CC_NC, dst + 7); - dst = pop_r(dst, SCRATCH1); - dst = add_ir(dst, check_int_size - (native-start_native), SCRATCH1, SZ_Q); - dst = push_r(dst, SCRATCH1); - dst = jmp(dst, (uint8_t *)z80_handle_cycle_limit_int); - *jmp_off = dst - (jmp_off+1); - //jump back to body of translated instruction - dst = pop_r(dst, SCRATCH1); - dst = add_ir(dst, check_int_size - (native-start_native), SCRATCH1, SZ_Q); - dst = jmp_r(dst, SCRATCH1); - opts->cur_code = dst; - } else { - native = call(native, bp_stub); + //Calculate length of prologue + int check_int_size = z80_check_cycles_int(dst, 0) - dst; + + //Calculate length of patch + int patch_size = zbreakpoint_patch(context, 0, dst) - dst; + + //Save context and call breakpoint handler + dst = call(dst, (uint8_t *)z80_save_context); + dst = push_r(dst, SCRATCH1); + dst = mov_rr(dst, CONTEXT, RDI, SZ_Q); + dst = mov_rr(dst, SCRATCH1, RSI, SZ_W); + dst = call(dst, context->bp_handler); + dst = mov_rr(dst, RAX, CONTEXT, SZ_Q); + //Restore context + dst = call(dst, (uint8_t *)z80_load_context); + dst = pop_r(dst, SCRATCH1); + //do prologue stuff + dst = cmp_rr(dst, ZCYCLES, ZLIMIT, SZ_D); + uint8_t * jmp_off = dst+1; + dst = jcc(dst, CC_NC, dst + 7); + dst = pop_r(dst, SCRATCH1); + dst = add_ir(dst, check_int_size - patch_size, SCRATCH1, SZ_Q); + dst = push_r(dst, SCRATCH1); + dst = jmp(dst, (uint8_t *)z80_handle_cycle_limit_int); + *jmp_off = dst - (jmp_off+1); + //jump back to body of translated instruction + dst = pop_r(dst, SCRATCH1); + dst = add_ir(dst, check_int_size - patch_size, SCRATCH1, SZ_Q); + dst = jmp_r(dst, SCRATCH1); + opts->cur_code = dst; +} + +void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler) +{ + context->bp_handler = bp_handler; + uint8_t bit = 1 << (address % sizeof(uint8_t)); + if (!(bit & context->breakpoint_flags[address / sizeof(uint8_t)])) { + context->breakpoint_flags[address / sizeof(uint8_t)] |= bit; + if (!context->bp_stub) { + zcreate_stub(context); + } + uint8_t * native = z80_get_native_address(context, address); + if (native) { + zbreakpoint_patch(context, address, native); + } } } void zremove_breakpoint(z80_context * context, uint16_t address) { + context->breakpoint_flags[address / sizeof(uint8_t)] &= 1 << (address % sizeof(uint8_t)); uint8_t * native = z80_get_native_address(context, address); - z80_check_cycles_int(native, address); + if (native) { + z80_check_cycles_int(native, address); + } } diff --git a/z80_to_x86.h b/z80_to_x86.h index dd5864b..28f860f 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -1,6 +1,6 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #ifndef Z80_TO_X86_H_ @@ -55,6 +55,9 @@ typedef struct { void * system; uint8_t ram_code_flags[(8 * 1024)/128/8]; uint32_t int_enable_cycle; + uint8_t breakpoint_flags[(16 * 1024)/sizeof(uint8_t)]; + uint8_t * bp_handler; + uint8_t * bp_stub; uint16_t pc; } z80_context; -- cgit v1.2.3 From 4c06b02583a69756a7cdf6561c0760087eb642ec Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 20 Jun 2014 07:57:32 -0700 Subject: Added some preliminary support for interpreting Z80 code from non-RAM addresses --- z80_to_x86.c | 132 +++++++++++++++++++++++++++++++++++++++++------------------ z80_to_x86.h | 4 +- 2 files changed, 95 insertions(+), 41 deletions(-) diff --git a/z80_to_x86.c b/z80_to_x86.c index 584d6e1..a714991 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -328,16 +328,18 @@ void z80_print_regs_exit(z80_context * context) exit(0); } -uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context, uint16_t address) +uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context, uint16_t address, uint8_t interp) { uint32_t cycles; x86_ea src_op, dst_op; uint8_t size; x86_z80_options *opts = context->options; uint8_t * start = dst; - dst = z80_check_cycles_int(dst, address); - if (context->breakpoint_flags[address / sizeof(uint8_t)] & (1 << (address % sizeof(uint8_t)))) { - zbreakpoint_patch(context, address, start); + if (!interp) { + dst = z80_check_cycles_int(dst, address); + if (context->breakpoint_flags[address / sizeof(uint8_t)] & (1 << (address % sizeof(uint8_t)))) { + zbreakpoint_patch(context, address, start); + } } switch(inst->op) { @@ -1660,18 +1662,73 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context return dst; } +uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context) +{ + if (!context->interp_code[opcode]) { + if (opcode == 0xCB || (opcode >= 0xDD && opcode & 0xF == 0xD)) { + fprintf(stderr, "Encountered prefix byte %X at address %X. Z80 interpeter doesn't support those yet.", opcode, context->pc); + exit(1); + } + uint8_t codebuf[8]; + memset(codebuf, 0, sizeof(codebuf)); + codebuf[0] = opcode; + z80inst inst; + uint8_t * after = z80_decode(codebuf, &inst); + if (after - codebuf > 1) { + fprintf(stderr, "Encountered multi-byte Z80 instruction at %X. Z80 interpeter doesn't support those yet.", context->pc); + exit(1); + } + x86_z80_options * opts = context->options; + if (opts->code_end - opts->cur_code < ZMAX_NATIVE_SIZE) { + size_t size = 1024*1024; + opts->cur_code = alloc_code(&size); + opts->code_end = opts->cur_code + size; + } + context->interp_code[opcode] = opts->cur_code; + opts->cur_code = translate_z80inst(&inst, opts->cur_code, context, 0, 1); + opts->cur_code = mov_rdisp8r(opts->cur_code, CONTEXT, offsetof(z80_context, pc), SCRATCH1, SZ_W); + opts->cur_code = add_ir(opts->cur_code, after - codebuf, SCRATCH1, SZ_W); + opts->cur_code = call(opts->cur_code, (uint8_t *)z80_native_addr); + opts->cur_code = jmp_r(opts->cur_code, SCRATCH1); + } + return context->interp_code[opcode]; +} + +uint8_t * z80_make_interp_stub(z80_context * context, uint16_t address) +{ + x86_z80_options *opts = context->options; + uint8_t *dst = opts->cur_code; + //TODO: make this play well with the breakpoint code + dst = mov_ir(dst, address, SCRATCH1, SZ_W); + dst = call(dst, (uint8_t *)z80_read_byte); + //normal opcode fetch is already factored into instruction timing + //back out the base 3 cycles from a read here + //not quite perfect, but it will have to do for now + dst = sub_ir(dst, 3, ZCYCLES, SZ_D); + dst = z80_check_cycles_int(dst, address); + dst = call(dst, (uint8_t *)z80_save_context); + dst = mov_rr(dst, SCRATCH1, RDI, SZ_B); + dst = mov_irdisp8(dst, address, CONTEXT, offsetof(z80_context, pc), SZ_W); + dst = push_r(dst, CONTEXT); + dst = call(dst, (uint8_t *)z80_interp_handler); + dst = mov_rr(dst, RAX, SCRATCH1, SZ_Q); + dst = pop_r(dst, CONTEXT); + dst = call(dst, (uint8_t *)z80_load_context); + dst = jmp_r(dst, SCRATCH1); + opts->code_end = dst; + return dst; +} + + uint8_t * z80_get_native_address(z80_context * context, uint32_t address) { native_map_slot *map; if (address < 0x4000) { address &= 0x1FFF; map = context->static_code_map; - } else if (address >= 0x8000) { - address &= 0x7FFF; - map = context->banked_code_map + context->bank_reg; } else { - //dprintf("z80_get_native_address: %X NULL\n", address); - return NULL; + address -= 0x4000; + map = context->banked_code_map; } if (!map->base || !map->offsets || map->offsets[address] == INVALID_OFFSET || map->offsets[address] == EXTENSION_WORD) { //dprintf("z80_get_native_address: %X NULL\n", address); @@ -1683,6 +1740,7 @@ uint8_t * z80_get_native_address(z80_context * context, uint32_t address) uint8_t z80_get_native_inst_size(x86_z80_options * opts, uint32_t address) { + //TODO: Fix for addresses >= 0x4000 if (address >= 0x4000) { return 0; } @@ -1700,15 +1758,14 @@ void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * n opts->ram_inst_sizes[address] = native_size; context->ram_code_flags[(address & 0x1C00) >> 10] |= 1 << ((address & 0x380) >> 7); context->ram_code_flags[((address + size) & 0x1C00) >> 10] |= 1 << (((address + size) & 0x380) >> 7); - } else if (address >= 0x8000) { - address &= 0x7FFF; - map = context->banked_code_map + context->bank_reg; + } else { + //HERE + address -= 0x4000; + map = context->banked_code_map; if (!map->offsets) { - map->offsets = malloc(sizeof(int32_t) * 0x8000); - memset(map->offsets, 0xFF, sizeof(int32_t) * 0x8000); + map->offsets = malloc(sizeof(int32_t) * 0xC000); + memset(map->offsets, 0xFF, sizeof(int32_t) * 0xC000); } - } else { - return; } if (!map->base) { map->base = native_address; @@ -1719,15 +1776,13 @@ void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * n if (address < 0x4000) { address &= 0x1FFF; map = context->static_code_map; - } else if (address >= 0x8000) { - address &= 0x7FFF; - map = context->banked_code_map + context->bank_reg; } else { - return; + address -= 0x4000; + map = context->banked_code_map; } if (!map->offsets) { - map->offsets = malloc(sizeof(int32_t) * 0x8000); - memset(map->offsets, 0xFF, sizeof(int32_t) * 0x8000); + map->offsets = malloc(sizeof(int32_t) * 0xC000); + memset(map->offsets, 0xFF, sizeof(int32_t) * 0xC000); } map->offsets[address] = EXTENSION_WORD; } @@ -1737,6 +1792,7 @@ void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * n uint32_t z80_get_instruction_start(native_map_slot * static_code_map, uint32_t address) { + //TODO: Fixme for address >= 0x4000 if (!static_code_map->base || address >= 0x4000) { return INVALID_INSTRUCTION_START; } @@ -1814,12 +1870,12 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o opts->cur_code = dst; } deferred_addr * orig_deferred = opts->deferred; - uint8_t * native_end = translate_z80inst(&instbuf, dst, context, address); + uint8_t * native_end = translate_z80inst(&instbuf, dst, context, address, 0); if ((native_end - dst) <= orig_size) { uint8_t * native_next = z80_get_native_address(context, address + after-inst); if (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - dst)) > 5)) { remove_deferred_until(&opts->deferred, orig_deferred); - native_end = translate_z80inst(&instbuf, orig_start, context, address); + native_end = translate_z80inst(&instbuf, orig_start, context, address, 0); if (native_next == orig_start + orig_size && (native_next-native_end) < 2) { while (native_end < orig_start + orig_size) { *(native_end++) = 0x90; //NOP @@ -1840,7 +1896,7 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o z80_handle_deferred(context); return dst; } else { - dst = translate_z80inst(&instbuf, orig_start, context, address); + dst = translate_z80inst(&instbuf, orig_start, context, address, 0); if (!z80_is_terminal(&instbuf)) { dst = jmp(dst, z80_get_native_address_trans(context, address + after-inst)); } @@ -1860,12 +1916,9 @@ void translate_z80_stream(z80_context * context, uint32_t address) uint8_t * encoded = NULL, *next; if (address < 0x4000) { encoded = context->mem_pointers[0] + (address & 0x1FFF); - } else if(address >= 0x8000 && context->mem_pointers[1]) { - printf("attempt to translate Z80 code from banked area at address %X\n", address); - exit(1); - //encoded = context->mem_pointers[1] + (address & 0x7FFF); } - while (encoded != NULL) + + while (encoded != NULL || address >= 0x4000) { z80inst inst; dprintf("translating Z80 code at address %X\n", address); @@ -1880,9 +1933,10 @@ void translate_z80_stream(z80_context * context, uint32_t address) opts->code_end = opts->cur_code + size; jmp(opts->cur_code, opts->cur_code); } - if (address > 0x4000 && address < 0x8000) { - opts->cur_code = xor_rr(opts->cur_code, RDI, RDI, SZ_D); - opts->cur_code = call(opts->cur_code, (uint8_t *)exit); + if (address >= 0x4000) { + uint8_t *native_start = opts->cur_code; + uint8_t *after = z80_make_interp_stub(context, address); + z80_map_native_address(context, address, opts->cur_code, 1, after - native_start); break; } uint8_t * existing = z80_get_native_address(context, address); @@ -1899,7 +1953,7 @@ void translate_z80_stream(z80_context * context, uint32_t address) printf("%X\t%s\n", address, disbuf); } #endif - uint8_t *after = translate_z80inst(&inst, opts->cur_code, context, address); + uint8_t *after = translate_z80inst(&inst, opts->cur_code, context, address, 0); z80_map_native_address(context, address, opts->cur_code, next-encoded, after - opts->cur_code); opts->cur_code = after; address += next-encoded; @@ -1916,14 +1970,12 @@ void translate_z80_stream(z80_context * context, uint32_t address) dprintf("defferred address: %X\n", address); if (address < 0x4000) { encoded = context->mem_pointers[0] + (address & 0x1FFF); - } else if (address > 0x8000 && context->mem_pointers[1]) { - encoded = context->mem_pointers[1] + (address & 0x7FFF); } else { - printf("attempt to translate non-memory address: %X\n", address); - exit(1); + encoded = NULL; } } else { encoded = NULL; + address = 0; } } } @@ -1966,8 +2018,8 @@ void init_z80_context(z80_context * context, x86_z80_options * options) context->static_code_map->base = NULL; context->static_code_map->offsets = malloc(sizeof(int32_t) * 0x2000); memset(context->static_code_map->offsets, 0xFF, sizeof(int32_t) * 0x2000); - context->banked_code_map = malloc(sizeof(native_map_slot) * (1 << 9)); - memset(context->banked_code_map, 0, sizeof(native_map_slot) * (1 << 9)); + context->banked_code_map = malloc(sizeof(native_map_slot)); + memset(context->banked_code_map, 0, sizeof(native_map_slot)); context->options = options; context->int_cycle = 0xFFFFFFFF; } diff --git a/z80_to_x86.h b/z80_to_x86.h index 28f860f..fc30179 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -55,10 +55,12 @@ typedef struct { void * system; uint8_t ram_code_flags[(8 * 1024)/128/8]; uint32_t int_enable_cycle; + uint16_t pc; uint8_t breakpoint_flags[(16 * 1024)/sizeof(uint8_t)]; uint8_t * bp_handler; uint8_t * bp_stub; - uint16_t pc; + uint8_t * interp_code[256]; + } z80_context; void translate_z80_stream(z80_context * context, uint32_t address); -- cgit v1.2.3 From 24d56647b3b2baa4e7016ac5d66c0167d51688be Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 21 Jun 2014 09:36:15 -0700 Subject: Fix Z80 interrupts --- blastem.c | 35 ++++++++++++++++++++++++++++++++--- z80_to_x86.c | 2 ++ z80_to_x86.h | 2 ++ 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/blastem.c b/blastem.c index 15f7932..18e11b6 100644 --- a/blastem.c +++ b/blastem.c @@ -190,10 +190,14 @@ void sync_z80(z80_context * z_context, uint32_t mclks) z80_reset(z_context); need_reset = 0; } - uint32_t vint_cycle = vdp_next_vint_z80(gen->vdp) / MCLKS_PER_Z80; + while (z_context->current_cycle < z_context->sync_cycle) { - if (z_context->iff1 && z_context->int_cycle == CYCLE_NEVER && z_context->current_cycle < (vint_cycle + Z80_VINT_DURATION)) { - z_context->int_cycle = vint_cycle < z_context->int_enable_cycle ? z_context->int_enable_cycle : vint_cycle; + if (z_context->int_pulse_end < z_context->current_cycle || z_context->int_pulse_end == CYCLE_NEVER) { + z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp) / MCLKS_PER_Z80; + z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION; + } + if (z_context->iff1) { + z_context->int_cycle = z_context->int_pulse_start < z_context->int_enable_cycle ? z_context->int_enable_cycle : z_context->int_pulse_start; } z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle; dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d\n", z_context->current_cycle, z_context->sync_cycle, z_context->int_cycle); @@ -269,6 +273,31 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) } else { z_context->current_cycle = 0; } + if (z_context->int_cycle != CYCLE_NEVER) { + if (z_context->int_cycle >= mclk_target/MCLKS_PER_Z80) { + z_context->int_cycle -= mclk_target/MCLKS_PER_Z80; + } else { + z_context->int_cycle = 0; + } + } + if (z_context->int_pulse_start != CYCLE_NEVER) { + if (z_context->int_pulse_end >= mclk_target/MCLKS_PER_Z80) { + z_context->int_pulse_end -= mclk_target/MCLKS_PER_Z80; + if (z_context->int_pulse_start >= mclk_target/MCLKS_PER_Z80) { + z_context->int_pulse_start -= mclk_target/MCLKS_PER_Z80; + } else { + z_context->int_pulse_start = 0; + } + } + } else { + z_context->int_pulse_start = CYCLE_NEVER; + z_context->int_pulse_end = CYCLE_NEVER; + } + if (z_context->int_enable_cycle >= mclk_target/MCLKS_PER_Z80) { + z_context->int_enable_cycle -= mclk_target/MCLKS_PER_Z80; + } else { + z_context->int_enable_cycle = 0; + } if (mclks) { vdp_run_context(v_context, mclks); } diff --git a/z80_to_x86.c b/z80_to_x86.c index a714991..c46bed8 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -2022,6 +2022,8 @@ void init_z80_context(z80_context * context, x86_z80_options * options) memset(context->banked_code_map, 0, sizeof(native_map_slot)); context->options = options; context->int_cycle = 0xFFFFFFFF; + context->int_pulse_start = 0xFFFFFFFF; + context->int_pulse_end = 0xFFFFFFFF; } void z80_reset(z80_context * context) diff --git a/z80_to_x86.h b/z80_to_x86.h index fc30179..fdf7866 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -56,6 +56,8 @@ typedef struct { uint8_t ram_code_flags[(8 * 1024)/128/8]; uint32_t int_enable_cycle; uint16_t pc; + uint32_t int_pulse_start; + uint32_t int_pulse_end; uint8_t breakpoint_flags[(16 * 1024)/sizeof(uint8_t)]; uint8_t * bp_handler; uint8_t * bp_stub; -- cgit v1.2.3 From 85cfa2bb7834854e587f466cb877b4bf5ed7966e Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Mon, 23 Jun 2014 11:05:55 -0400 Subject: Fix x86_rrindex_sizedir. Pass the correct scale to mov_rindexr in gen_mem_fun. BlastEm now sort of works on OS X. Runs reliably from lldb, but only intermittently from the shell --- gen_x86.c | 10 ++++------ m68k_to_x86.c | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/gen_x86.c b/gen_x86.c index c062ac8..2ec4c00 100644 --- a/gen_x86.c +++ b/gen_x86.c @@ -359,13 +359,11 @@ uint8_t * x86_rrindex_sizedir(uint8_t * out, uint8_t opcode, uint8_t reg, uint8_ opcode |= BIT_SIZE; } *(out++) = opcode | dir; - *(out++) = MODE_REG_INDIRECT | base | (RSP << 3); - if (base == RSP) { - if (scale == 4) { - scale = 3; - } - *(out++) = scale << 6 | (index << 3) | base; + *(out++) = MODE_REG_INDIRECT | RSP | (reg << 3); + if (scale == 4) { + scale = 3; } + *(out++) = scale << 6 | (index << 3) | base; return out; } diff --git a/m68k_to_x86.c b/m68k_to_x86.c index 959d62b..886cc08 100644 --- a/m68k_to_x86.c +++ b/m68k_to_x86.c @@ -4499,7 +4499,7 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk * memmap, uint32_t num_chu dst = mov_rrind(dst, SCRATCH1, SCRATCH2, tmp_size); } else { dst = mov_ir(dst, (intptr_t)memmap[chunk].buffer, SCRATCH2, SZ_PTR); - dst = mov_rindexr(dst, SCRATCH2, SCRATCH1, 1, SCRATCH1, tmp_size); + dst = mov_rindexr(dst, SCRATCH2, SCRATCH1, 0, SCRATCH1, tmp_size); } } if (size != tmp_size && !is_write) { -- cgit v1.2.3 From f1a97be9f7d1a939b3b1920c1764bf872edef10f Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Mon, 23 Jun 2014 11:46:56 -0400 Subject: Save and restore guest address in the write function for a code memory chunk in the "slow" path for inconvenient host addresses. This fixes an intermittent crash on OSX in the code that checks whether the memory written may contain code --- m68k_to_x86.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/m68k_to_x86.c b/m68k_to_x86.c index 886cc08..b46a5c3 100644 --- a/m68k_to_x86.c +++ b/m68k_to_x86.c @@ -4492,11 +4492,17 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk * memmap, uint32_t num_chu } } else { if (is_write) { + if (memmap[chunk].flags & MMAP_CODE) { + dst = push_r(dst, SCRATCH2); + } dst = push_r(dst, SCRATCH1); dst = mov_ir(dst, (intptr_t)memmap[chunk].buffer, SCRATCH1, SZ_PTR); dst = add_rr(dst, SCRATCH1, SCRATCH2, SZ_PTR); dst = pop_r(dst, SCRATCH1); dst = mov_rrind(dst, SCRATCH1, SCRATCH2, tmp_size); + if (memmap[chunk].flags & MMAP_CODE) { + dst = pop_r(dst, SCRATCH2); + } } else { dst = mov_ir(dst, (intptr_t)memmap[chunk].buffer, SCRATCH2, SZ_PTR); dst = mov_rindexr(dst, SCRATCH2, SCRATCH1, 0, SCRATCH1, tmp_size); -- cgit v1.2.3 From 8a7f8bc09c88e9446d475127a82df23a1dcb0c75 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Mon, 23 Jun 2014 13:12:04 -0400 Subject: Ensure proper stack alignment when the Z80 calls into C code. This fixes a crash in optimized builds on OSX --- zruntime.S | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/zruntime.S b/zruntime.S index 1883239..a7bac3f 100644 --- a/zruntime.S +++ b/zruntime.S @@ -150,7 +150,15 @@ z80_read_ym2612: call z80_save_context mov %r13w, %di push %rsi + test $8, %rsp + jnz 0f call z80_read_ym + jmp 1f +0: + sub $8, %rsp + call z80_read_ym + add $8, %rsp +1: pop %rsi mov %al, %r13b call z80_load_context @@ -196,7 +204,15 @@ z80_write_ym2612: call z80_save_context mov %r14w, %di mov %r13b, %dl + test $8, %rsp + jnz 0f + call z80_write_ym + jmp 1f +0: + sub $8, %rsp call z80_write_ym + add $8, %rsp +1: mov %rax, %rsi jmp z80_load_context z80_write_bank_reg: @@ -219,7 +235,15 @@ z80_write_vdp: call z80_save_context mov %r14w, %di mov %r13b, %dl + test $8, %rsp + jnz 0f + call z80_vdp_port_write + jmp 1f +0: + sub $8, %rsp call z80_vdp_port_write + add $8, %rsp +1: mov %rax, %rsi jmp z80_load_context -- cgit v1.2.3 From de4b489931b6deb80fc1e09340c5c501d337aad0 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 14 Aug 2014 09:38:32 -0700 Subject: Small fix to display of DMA source address in vr debug command --- vdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vdp.c b/vdp.c index 9eafb67..55d76b6 100644 --- a/vdp.c +++ b/vdp.c @@ -255,7 +255,7 @@ void vdp_print_reg_explain(vdp_context * context) context->regs[REG_DMASRC_L], context->regs[REG_DMASRC_M], context->regs[REG_DMASRC_H], - context->regs[REG_DMASRC_H] << 17 | context->regs[REG_DMASRC_M] << 9 | context->regs[REG_DMASRC_L], + context->regs[REG_DMASRC_H] << 17 | context->regs[REG_DMASRC_M] << 9 | context->regs[REG_DMASRC_L] << 1, src_types[context->regs[REG_DMASRC_H] >> 6 & 3]); printf("\n**Internal Group**\n" "Address: %X\n" -- cgit v1.2.3 From bee8289f02bc805f2a2e16d523d50374ee56b490 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 8 Oct 2014 22:18:34 -0700 Subject: Improve support for disassembling 68010+ binaries --- 68kinst.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++--------------- 68kinst.h | 71 ++++++++++++++++++++- Makefile | 10 +++ 3 files changed, 241 insertions(+), 52 deletions(-) diff --git a/68kinst.c b/68kinst.c index b9e25aa..37c9a9f 100644 --- a/68kinst.c +++ b/68kinst.c @@ -172,7 +172,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } if (decoded->dst.addr_mode == MODE_REG) { decoded->extra.size = OPSIZE_LONG; @@ -202,7 +202,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } if (decoded->dst.addr_mode == MODE_REG) { decoded->extra.size = OPSIZE_LONG; @@ -248,7 +248,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } break; @@ -287,7 +287,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } break; @@ -314,7 +314,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case 3: @@ -340,7 +340,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case 4: @@ -365,7 +365,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case 5: @@ -403,7 +403,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } break; @@ -427,15 +427,29 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) decoded->src.params.immed = (immed << 16) | *(++istream); break; } - istream = m68k_decode_op_ex(istream, opmode, reg, size, &(decoded->dst)); + istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case 7: - - +#ifdef M68010 + decoded->op = M68K_MOVES; + decoded->extra.size = *istream >> 6 & 0x3; + immed = *(++istream); + reg = immed >> 12 & 0x7; + opmode = immed & 0x8000 ? MODE_AREG : MODE_REG; + if (immed & 0x800) { + m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->src)); + decoded->dst.addr_mode = opmode; + decoded->dst.params.regs.pri = reg; + } else { + decoded->src.addr_mode = opmode; + decoded->src.params.regs.pri = reg; + m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->dst)); + } +#endif break; } } @@ -450,12 +464,12 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); if (!istream || decoded->dst.addr_mode == MODE_IMMEDIATE) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case MISC: @@ -468,7 +482,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { if (*istream & 0x100) { @@ -489,7 +503,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { opmode = (*istream >> 3) & 0x7; @@ -504,7 +518,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } if (decoded->src.addr_mode == MODE_PC_DISPLACE || decoded->src.addr_mode == MODE_PC_INDEX_DISP8) { //adjust displacement to account for extra instruction word @@ -516,7 +530,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } else { @@ -536,7 +550,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream= m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case 1: @@ -546,7 +560,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) decoded->op = M68K_MOVE_FROM_CCR; size = OPSIZE_WORD; #else - return istream+1; + break; #endif } else { decoded->op = M68K_CLR; @@ -555,7 +569,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream= m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case 2: @@ -566,14 +580,14 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream= m68k_decode_op(istream, size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { decoded->op = M68K_NEG; istream= m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } decoded->extra.size = size; @@ -586,14 +600,14 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream= m68k_decode_op(istream, size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { decoded->op = M68K_NOT; istream= m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } decoded->extra.size = size; @@ -648,7 +662,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else if((*istream & 0x1C0) == 0x40) { decoded->op = M68K_PEA; @@ -656,7 +670,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } @@ -678,7 +692,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } @@ -702,7 +716,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, OPSIZE_UNSIZED, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { //it would appear bit 6 needs to be set for it to be a valid instruction here @@ -783,6 +797,32 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) case 7: //MOVEC #ifdef M68010 + decoded->op = M68K_MOVEC; + immed = *(++istream); + reg = immed >> 12 & 0x7; + opmode = immed & 0x8000 ? MODE_AREG : MODE_REG; + if (immed & 0x800) { + if (immed > MAX_HIGH_CR) { + decoded->op = M68K_INVALID; + break; + } else { + immed = immed - 0x800 + CR_USP; + } + } else { + if (immed > MAX_LOW_CR) { + decoded->op = M68K_INVALID; + break; + } + } + if (*start & 1) { + decoded->src.addr_mode = opmode; + decoded->src.params.regs.pri = reg; + decoded->dst.params.immed = immed; + } else { + decoded->dst.addr_mode = opmode; + decoded->dst.params.regs.pri = reg; + decoded->src.params.immed = immed; + } #endif break; } @@ -816,7 +856,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, OPSIZE_BYTE, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } else { @@ -837,7 +877,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } break; @@ -865,7 +905,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) case MOVEQ: if (*istream & 0x100) { decoded->op = M68K_INVALID; - return start+1; + break; } decoded->op = M68K_MOVE; decoded->variant = VAR_QUICK; @@ -891,7 +931,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src)); if (!istream || decoded->src.addr_mode == MODE_AREG) { decoded->op = M68K_INVALID; - return start+1; + break; } break; case 4: @@ -916,7 +956,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src)); if (!istream || decoded->src.addr_mode == MODE_AREG) { decoded->op = M68K_INVALID; - return start+1; + break; } break; } @@ -929,7 +969,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { decoded->dst.addr_mode = MODE_REG; @@ -937,7 +977,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } @@ -956,7 +996,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { decoded->extra.size = size; @@ -965,7 +1005,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } else { @@ -993,7 +1033,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } break; @@ -1011,14 +1051,14 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { reg = m68k_reg_quick_field(*istream); istream = m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } decoded->extra.size = size; if (decoded->dst.addr_mode == MODE_AREG) { @@ -1046,7 +1086,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } break; @@ -1069,7 +1109,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else if(!(*istream & 0xF0)) { decoded->op = M68K_ABCD; @@ -1100,7 +1140,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } else { @@ -1112,7 +1152,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { decoded->op = M68K_AND; @@ -1122,7 +1162,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } @@ -1141,7 +1181,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, OPSIZE_LONG, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else { decoded->extra.size = size; @@ -1150,7 +1190,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, size, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } } else { @@ -1178,7 +1218,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, decoded->extra.size, &(decoded->src)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } break; @@ -1215,7 +1255,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) istream = m68k_decode_op(istream, OPSIZE_WORD, &(decoded->dst)); if (!istream) { decoded->op = M68K_INVALID; - return start+1; + break; } } else if((*istream & 0xC0) != 0xC0) { switch(((*istream >> 2) & 0x6) | ((*istream >> 8) & 1)) @@ -1270,6 +1310,10 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) //TODO: Implement me break; } + if (decoded->op == M68K_INVALID) { + decoded->src.params.immed = *start; + return start + 1; + } return istream+1; } @@ -1416,7 +1460,42 @@ char * mnemonics[] = { "trapv", "tst", "unlk", - "invalid" + "invalid", +#ifdef M68010 + "bkpt", + "move", //from ccr + "movec", + "moves", +#endif +#ifdef M68020 + "bfchg", + "bfclr", + "bfexts", + "bfextu", + "bfffo", + "bfins", + "bfset", + "bftst", + "callm", + "cas", + "cas2", + "chk2", + "cmp2", + "cpbcc", + "cpdbcc", + "cpgen", + "cprestore", + "cpsave", + "cpscc", + "cptrapcc", + "divsl", + "divul", + "extb", + "pack", + "rtm", + "trapcc", + "unpk" +#endif }; char * cond_mnem[] = { @@ -1437,6 +1516,22 @@ char * cond_mnem[] = { "gt", "le" }; +#ifdef M68010 +char * cr_mnem[] = { + "SFC", + "DFC", +#ifdef M68020 + "CACR", +#endif + "USP", + "VBR", +#ifdef M68020 + "CAAR", + "MSP", + "ISP" +#endif +}; +#endif int m68k_disasm_op(m68k_op_info *decoded, char *dst, int need_comma, uint8_t labels, uint32_t address) { @@ -1611,6 +1706,21 @@ int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels) ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address); } return ret; + case M68K_INVALID: + ret = sprintf(dst, "dc.w $%X", decoded->src.params.immed); + return ret; +#ifdef M68010 + case M68K_MOVEC: + ret = sprintf(dst, "%s ", mnemonics[decoded->op]); + if (decoded->src.addr_mode == MODE_UNUSED) { + ret += sprintf(dst + ret, "%s, ", cr_mnem[decoded->src.params.immed]); + ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address); + } else { + ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address); + ret += sprintf(dst + ret, ", %s", cr_mnem[decoded->dst.params.immed]); + } + return ret; +#endif default: size = decoded->extra.size; ret = sprintf(dst, "%s%s%s", diff --git a/68kinst.h b/68kinst.h index 768793f..d1cbd2b 100644 --- a/68kinst.h +++ b/68kinst.h @@ -8,6 +8,13 @@ #include +#ifdef M68030 +#define M68020 +#endif +#ifdef M68020 +#define M68010 +#endif + typedef enum { BIT_MOVEP_IMMED = 0, MOVE_BYTE, @@ -97,7 +104,43 @@ typedef enum { M68K_TRAPV, M68K_TST, M68K_UNLK, - M68K_INVALID + M68K_INVALID, +#ifdef M68010 + M68K_BKPT, + M68K_MOVE_FROM_CCR, + M68K_MOVEC, + M68K_MOVES, + M68K_RTD, +#endif +#ifdef M68020 + M68K_BFCHG, + M68K_BFCLR, + M68K_BFEXTS, + M68K_BFEXTU, + M68K_BFFFO, + M68K_BFINS, + M68K_BFSET, + M68K_BFTST, + M68K_CALLM, + M68K_CAS, + M68K_CAS2, + M68K_CHK2, + M68K_CMP2, + M68K_CP_BCC, + M68K_CP_DBCC, + M68K_CP_GEN, + M68K_CP_RESTORE, + M68K_CP_SAVE, + M68K_CP_SCC, + M68K_CP_TRAPCC, + M68K_DIVSL, + M68K_DIVUL, + M68K_EXTB, + M68K_PACK, + M68K_RTM, + M68K_TRAPCC, + M68K_UNPK, +#endif } m68K_op; typedef enum { @@ -163,6 +206,32 @@ typedef enum { COND_LESS_EQ } m68K_condition; +#ifdef M68010 +typedef enum { + CR_SFC, + CR_DFC, +#ifdef M68020 + CR_CACR, +#endif + CR_USP, + CR_VBR, +#ifdef M68020 + CR_CAAR, + CR_MSP, + CR_ISP +#endif +} m68k_control_reg; + +#ifdef M68020 +#define MAX_HIGH_CR 0x804 +#define MAX_LOW_CR 0x002 +#else +#define MAX_HIGH_CR 0x801 +#define MAX_LOW_CR 0x001 +#endif + +#endif + typedef struct { uint8_t addr_mode; union { diff --git a/Makefile b/Makefile index d9e142e..c707397 100644 --- a/Makefile +++ b/Makefile @@ -18,6 +18,16 @@ ifdef NOGL CFLAGS+= -DDISABLE_OPENGL endif +ifdef M68030 +CFLAGS+= -DM68030 +endif +ifdef M68020 +CFLAGS+= -DM68020 +endif +ifdef M68010 +CFLAGS+= -DM68010 +endif + TRANSOBJS=gen_x86.o x86_backend.o mem.o M68KOBJS=68kinst.o m68k_to_x86.o runtime.o Z80OBJS=z80inst.o z80_to_x86.o zruntime.o -- cgit v1.2.3 From 7237def9b068c5b184cd38041d7eac5fdf8a9438 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 11 Oct 2014 20:32:17 -0700 Subject: Add support for disassembling VOS program modules --- Makefile | 7 +- dis.c | 152 +++++++++++++++++++++++++++---------- tern.c | 12 ++- tern.h | 3 + vos_prog_info.c | 100 +++++++++++++++++++++++++ vos_program_module.c | 208 +++++++++++++++++++++++++++++++++++++++++++++++++++ vos_program_module.h | 134 +++++++++++++++++++++++++++++++++ vos_program_module.o | Bin 0 -> 5360 bytes 8 files changed, 573 insertions(+), 43 deletions(-) create mode 100644 vos_prog_info.c create mode 100644 vos_program_module.c create mode 100644 vos_program_module.h create mode 100644 vos_program_module.o diff --git a/Makefile b/Makefile index c707397..84db28f 100644 --- a/Makefile +++ b/Makefile @@ -39,8 +39,8 @@ all : dis zdis stateview vgmplay blastem blastem : blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS) $(CC) -ggdb -o blastem blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(Z80OBJS) $(TRANSOBJS) $(AUDIOOBJS) $(LDFLAGS) -dis : dis.o 68kinst.o - $(CC) -o dis dis.o 68kinst.o +dis : dis.o 68kinst.o tern.o vos_program_module.o + $(CC) -o dis dis.o 68kinst.o tern.o vos_program_module.o zdis : zdis.o z80inst.o $(CC) -o zdis zdis.o z80inst.o @@ -78,6 +78,9 @@ 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 +vos_prog_info : vos_prog_info.o vos_program_module.o + $(CC) -o vos_prog_info vos_prog_info.o vos_program_module.o + %.o : %.S $(CC) -c -o $@ $< diff --git a/dis.c b/dis.c index 8ec5bb2..b52c4d7 100644 --- a/dis.c +++ b/dis.c @@ -1,11 +1,14 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #include "68kinst.h" #include #include +#include +#include "vos_program_module.h" +#include "tern.h" uint8_t visited[(16*1024*1024)/16]; uint8_t label[(16*1024*1024)/8]; @@ -35,6 +38,36 @@ uint8_t is_label(uint32_t address) return label[address/16] & (1 << (address % 8)); } +typedef struct { + uint32_t num_labels; + uint32_t storage; + char *labels[]; +} label_names; + +tern_node * add_label(tern_node * head, char * name, uint32_t address) +{ + char key[MAX_INT_KEY_SIZE]; + address &= 0xFFFFFF; + reference(address); + tern_int_key(address, key); + label_names * names = tern_find_ptr(head, key); + if (names) + { + if (names->num_labels == names->storage) + { + names->storage = names->storage + (names->storage >> 1); + names = realloc(names, sizeof(label_names) + names->storage * sizeof(char *)); + } + } else { + names = malloc(sizeof(label_names) + 4 * sizeof(char *)); + names->num_labels = 0; + names->storage = 4; + head = tern_insert_ptr(head, key, names); + } + names->labels[names->num_labels++] = strdup(name); + return head; +} + typedef struct deferred { uint32_t address; struct deferred *next; @@ -66,10 +99,6 @@ void check_reference(m68kinst * inst, m68k_op_info * op) } } -uint8_t labels = 0; -uint8_t addr = 0; -uint8_t only = 0; - int main(int argc, char ** argv) { long filesize; @@ -77,14 +106,10 @@ int main(int argc, char ** argv) char disbuf[1024]; m68kinst instbuf; unsigned short * cur; - FILE * f = fopen(argv[1], "rb"); - fseek(f, 0, SEEK_END); - filesize = ftell(f); - fseek(f, 0, SEEK_SET); - filebuf = malloc(filesize); - fread(filebuf, 2, filesize/2, f); - fclose(f); deferred *def = NULL, *tmpd; + + uint8_t labels = 0, addr = 0, only = 0, vos = 0; + for(uint8_t opt = 2; opt < argc; ++opt) { if (argv[opt][0] == '-') { FILE * address_log; @@ -99,6 +124,9 @@ int main(int argc, char ** argv) case 'o': only = 1; break; + case 'v': + vos = 1; + break; case 'f': opt++; if (opt >= argc) { @@ -126,22 +154,70 @@ int main(int argc, char ** argv) reference(address); } } - for(cur = filebuf; cur - filebuf < (filesize/2); ++cur) + + FILE * f = fopen(argv[1], "rb"); + fseek(f, 0, SEEK_END); + filesize = ftell(f); + fseek(f, 0, SEEK_SET); + + tern_node * named_labels = NULL; + char int_key[MAX_INT_KEY_SIZE]; + uint32_t address_off, address_end; + if (vos) { - *cur = (*cur >> 8) | (*cur << 8); + vos_program_module header; + vos_read_header(f, &header); + vos_read_alloc_module_map(f, &header); + address_off = header.user_boundary; + address_end = address_off + filesize - 0x1000; + def = defer(header.main_entry_link.code_address, def); + named_labels = add_label(named_labels, "main_entry_link", header.main_entry_link.code_address); + for (int i = 0; i < header.n_modules; i++) + { + def = defer(header.module_map_entries[i].code_address, def); + named_labels = add_label(named_labels, header.module_map_entries[i].name.str, header.module_map_entries[i].code_address); + } + fseek(f, 0x1000, SEEK_SET); + filebuf = malloc(filesize - 0x1000); + if (fread(filebuf, 2, (filesize - 0x1000)/2, f) != (filesize - 0x1000)/2) + { + fprintf(stderr, "Failure while reading file %s\n", argv[1]); + } + fclose(f); + for(cur = filebuf; cur - filebuf < ((filesize - 0x1000)/2); ++cur) + { + *cur = (*cur >> 8) | (*cur << 8); + } + } else { + address_off = 0; + address_end = filesize; + filebuf = malloc(filesize); + if (fread(filebuf, 2, filesize/2, f) != filesize/2) + { + fprintf(stderr, "Failure while reading file %s\n", argv[1]); + } + fclose(f); + for(cur = filebuf; cur - filebuf < (filesize/2); ++cur) + { + *cur = (*cur >> 8) | (*cur << 8); + } + uint32_t start = filebuf[2] << 16 | filebuf[3]; + uint32_t int_2 = filebuf[0x68/2] << 16 | filebuf[0x6A/2]; + uint32_t int_4 = filebuf[0x70/2] << 16 | filebuf[0x72/2]; + uint32_t int_6 = filebuf[0x78/2] << 16 | filebuf[0x7A/2]; + named_labels = add_label(named_labels, "start", start); + named_labels = add_label(named_labels, "int_2", int_2); + named_labels = add_label(named_labels, "int_4", int_4); + named_labels = add_label(named_labels, "int_6", int_6); + if (!def || !only) { + def = defer(start, def); + def = defer(int_2, def); + def = defer(int_4, def); + def = defer(int_6, def); + } } - uint32_t start = filebuf[2] << 16 | filebuf[3], tmp_addr; - uint32_t int_2 = filebuf[0x68/2] << 16 | filebuf[0x6A/2]; - uint32_t int_4 = filebuf[0x70/2] << 16 | filebuf[0x72/2]; - uint32_t int_6 = filebuf[0x78/2] << 16 | filebuf[0x7A/2]; uint16_t *encoded, *next; - uint32_t size; - if (!def || !only) { - def = defer(start, def); - def = defer(int_2, def); - def = defer(int_4, def); - def = defer(int_6, def); - } + uint32_t size, tmp_addr; uint32_t address; while(def) { do { @@ -218,25 +294,21 @@ int main(int argc, char ** argv) } puts(""); } - for (address = 0; address < filesize; address+=2) { + for (address = address_off; address < filesize; address+=2) { if (is_visited(address)) { - encoded = filebuf + address/2; + encoded = filebuf + (address-address_off)/2; m68k_decode(encoded, &instbuf, address); if (labels) { m68k_disasm_labels(&instbuf, disbuf); - if (address == start) { - puts("start:"); - } - if(address == int_2) { - puts("int_2:"); - } - if(address == int_4) { - puts("int_4:"); - } - if(address == int_6) { - puts("int_6:"); - } - if (is_label(instbuf.address)) { + char keybuf[MAX_INT_KEY_SIZE]; + label_names * names = tern_find_ptr(named_labels, tern_int_key(address, keybuf)); + if (names) + { + for (int i = 0; i < names->num_labels; i++) + { + printf("%s:\n", names->labels[i]); + } + } else if (is_label(instbuf.address)) { printf("ADR_%X:\n", instbuf.address); } if (addr) { diff --git a/tern.c b/tern.c index f61e2aa..73ea08d 100644 --- a/tern.c +++ b/tern.c @@ -122,4 +122,14 @@ tern_node * tern_insert_ptr(tern_node * head, char * key, void * value) return tern_insert(head, key, val); } - +char * tern_int_key(uint32_t key, char * buf) +{ + char * cur = buf; + while (key) + { + *(cur++) = (key & 0x7F) + 1; + key >>= 7; + } + *cur = 0; + return buf; +} diff --git a/tern.h b/tern.h index e95e0c9..cdf6948 100644 --- a/tern.h +++ b/tern.h @@ -8,6 +8,8 @@ #include +#define MAX_INT_KEY_SIZE (sizeof(uint32_t) + 2) + typedef union { void *ptrval; intptr_t intval; @@ -31,5 +33,6 @@ tern_node * tern_insert_int(tern_node * head, char * key, intptr_t value); void * tern_find_ptr_default(tern_node * head, char * key, void * def); void * tern_find_ptr(tern_node * head, char * key); tern_node * tern_insert_ptr(tern_node * head, char * key, void * value); +char * tern_int_key(uint32_t key, char * buf); #endif //TERN_H_ diff --git a/vos_prog_info.c b/vos_prog_info.c new file mode 100644 index 0000000..1fb4895 --- /dev/null +++ b/vos_prog_info.c @@ -0,0 +1,100 @@ +#include +#include "vos_program_module.h" + +int main(int argc, char ** argv) +{ + vos_program_module header; + FILE * f = fopen(argv[1], "rb"); + vos_read_header(f, &header); + vos_read_alloc_module_map(f, &header); + vos_read_alloc_external_vars(f, &header); + + printf("Version: %d\n", header.version); + printf("Binder Version: %s\n", header.binder_version.str); + printf("Binder Options: %s\n", header.binder_options.str); + printf("System name: %s\n", header.system_name.str); + printf("User name: %s\n", header.user_name.str); + printf("Date bound: %d\n", header.date_bound); + printf("Code addresss: 0x%X, Static address: 0x%X\n", + header.main_entry_link.code_address, header.main_entry_link.static_address); + printf("User boundary: 0x%X\n", header.user_boundary); + printf("Num modules: %d\n", header.n_modules); + printf("Num extern vars: %d\n", header.n_external_vars); + printf("Num link names: %d\n", header.n_link_names); + printf("Num unsapped links: %d\n", header.n_unsnapped_links); + printf("Num VM pages: %d\n", header.n_vm_pages); + printf("Num header pages: %d\n", header.n_header_pages); + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 4; j++) { + printf("Info %d:%d\n\tAddress: 0x%X\n\tLength: 0x%X\n", + i, j, header.info[i][j].address, header.info[i][j].len); + } + } + printf("Module map address: 0x%X\n", header.module_map_address); + printf("Module map length: 0x%X\n", header.module_map_len); + printf("External vars map address: 0x%X\n", header.external_vars_map_address); + printf("External vars map length: 0x%X\n", header.external_vars_map_len); + printf("Link names map address: 0x%X\n", header.link_names_map_address); + printf("Link names map length: 0x%X\n", header.link_names_map_len); + printf("Header address: 0x%X\n", header.header_address); + printf("Header length: 0x%X\n", header.header_len); + //printf("Access Info: 0x%X\n", header.header_address); + printf("Flags: 0x%X\n", header.flags); + printf("Num tasks: %d\n", header.n_tasks); + printf("Stack Size: 0x%X\n", header.stack_len); + printf("Num entries: %d\n", header.n_entries); + printf("Entry map address: 0x%X\n", header.entry_map_address); + printf("Entry map length: 0x%X\n", header.entry_map_len); + printf("Pop Version: %d\n", header.pop_version); + printf("Processor: %d\n", header.processor); + printf("Processor family: %d\n", header.processor_family); + printf("Release name: %s\n", header.release_name.str); + printf("Relocation info:\n\tMap Addres: 0x%X\n\tMap Length: 0x%X\n\tNum Relocations: %d\n", + header.relocation_info.map_address, header.relocation_info.map_len, + header.relocation_info.n_relocations); + printf("High water mark: 0x%X\n", header.high_water_mark); + printf("Copyright notice: %s\n", header.program_name.str); + printf("String pool address: 0x%X\n", header.string_pool_address); + printf("String pool length: 0x%X\n", header.string_pool_len); + printf("Object dir map address: 0x%X\n", header.obj_dir_map_address); + printf("Object dir map length: 0x%X\n", header.obj_dir_map_len); + puts("Global offset table addresses:"); + for (int i = 0; i < 3; i++) { + printf("\t%d: 0x%X\n", i, header.global_offset_table_address[i]); + } + for (int i = 0; i < 3; i++) { + printf("Block map info %d\n\tAddress: 0x%X\n\tLength: 0x%X\n", + i, header.block_map_info[i].address, header.block_map_info[i].len); + } + printf("Secton map file address: 0x%X\n", header.section_map_file_address); + printf("Secton map address: 0x%X\n", header.section_map_address); + printf("Secton map length: 0x%X\n", header.section_map_len); + printf("Num sections: %d\n", header.n_sections); + printf("Max heap size: 0x%X\n", header.max_heap_size); + printf("Max program size: 0x%X\n", header.max_program_size); + printf("Max stack size: 0x%X\n", header.max_stack_size); + printf("Stack fence size: 0x%X\n", header.stack_fence_size); + + puts("\nModules"); + for (int i = 0; i < header.n_modules; i++) { + printf("\t%s:\n\t\tCode Address: 0x%X, Length: 0x%X\n", + header.module_map_entries[i].name.str, + header.module_map_entries[i].code_address, + header.module_map_entries[i].code_length); + printf("\t\tFoo Address: 0x%X, Length: 0x%X\n", + header.module_map_entries[i].foo_address, + header.module_map_entries[i].foo_length); + printf("\t\tBar Address: 0x%X, Length: 0x%X\n", + header.module_map_entries[i].bar_address, + header.module_map_entries[i].bar_length); + } + + puts("\nExtrnal Vars"); + for (int i = 0; i < header.n_external_vars; i++) { + printf("\t%s: 0x%X\n", + header.external_vars[i].name.str, header.external_vars[i].address); + } + + vos_header_cleanup(&header); + return 0; +} diff --git a/vos_program_module.c b/vos_program_module.c new file mode 100644 index 0000000..7019623 --- /dev/null +++ b/vos_program_module.c @@ -0,0 +1,208 @@ +#include +#include +#include +#include +#include "vos_program_module.h" + +static uint16_t big16(uint8_t ** src) +{ + uint16_t ret = *((*src)++) << 8; + ret |= *((*src)++); + return ret; +} + +static uint32_t big32(uint8_t ** src) +{ + uint32_t ret = *((*src)++) << 24; + ret |= *((*src)++) << 16; + ret |= *((*src)++) << 8; + ret |= *((*src)++); + return ret; +} + +static void string_(uint8_t ** src, uint16_t *len, char * str, uint32_t storage) +{ + *len = big16(src); + memcpy(str, *src, storage); + *src += storage; + if (*len >= storage) + { + *len = storage; + } else { + str[*len] = 0; + } + if (storage & 1) + { + (*src)++; + } +} + +#define string(src, field) string_(src, &(field).len, (field).str, sizeof((field).str)) + + +int vos_read_header(FILE * f, vos_program_module *out) +{ + uint8_t buffer[4096]; + if (fread(buffer, 1, sizeof(buffer), f) != sizeof(buffer)) + { + return 0; + } + uint8_t *cur = buffer; + out->version = big16(&cur); + string(&cur, out->binder_version); + string(&cur, out->binder_options); + string(&cur, out->system_name); + string(&cur, out->user_name); + out->date_bound = big32(&cur); + out->main_entry_link.code_address = big32(&cur); + out->main_entry_link.static_address = big32(&cur); + out->user_boundary = big32(&cur); + out->n_modules = big16(&cur); + out->n_external_vars = big16(&cur); + out->n_link_names = big16(&cur); + out->n_unsnapped_links = big16(&cur); + out->n_vm_pages = big16(&cur); + out->n_header_pages = big16(&cur); + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 4; j++) + { + out->info[i][j].address = big32(&cur); + out->info[i][j].len = big32(&cur); + } + } + out->module_map_address = big32(&cur); + out->module_map_len = big32(&cur); + out->external_vars_map_address = big32(&cur); + out->external_vars_map_len = big32(&cur); + out->link_names_map_address = big32(&cur); + out->link_names_map_len = big32(&cur); + out->link_map_address = big32(&cur); + out->link_map_len = big32(&cur); + out->header_address = big32(&cur); + out->header_len = big32(&cur); + memcpy(out->access_info, cur, sizeof(out->access_info)); + cur += sizeof(out->access_info); + out->flags = big32(&cur); + out->n_tasks = big16(&cur); + for (int i = 0; i < 3; i++) + { + out->task_static_len[i] = big32(&cur); + } + out->stack_len = big32(&cur); + out->n_entries = big16(&cur); + out->entry_map_address = big32(&cur); + out->entry_map_len = big32(&cur); + out->pop_version = big16(&cur); + out->processor = big16(&cur); + string(&cur, out->release_name); + out->relocation_info.map_address = big32(&cur); + out->relocation_info.map_len = big32(&cur); + out->relocation_info.n_relocations = big32(&cur); + out->high_water_mark = big32(&cur); + string(&cur, out->copyright_notice); + for (int i = 0; i < 14; i++) + { + out->module_origins[i] = big32(&cur); + } + out->processor_family = big16(&cur); + string(&cur, out->program_name); + out->string_pool_address = big32(&cur); + out->string_pool_len = big32(&cur); + out->obj_dir_map_address = big32(&cur); + out->obj_dir_map_len = big32(&cur); + for (int i = 0; i < 3; i++) + { + out->global_offset_table_address[i] = big32(&cur); + } + for (int i = 0; i < 3; i++) + { + out->block_map_info[i].address = big32(&cur); + out->block_map_info[i].len = big32(&cur); + } + out->section_map_file_address = big32(&cur); + out->section_map_address = big32(&cur); + out->section_map_len = big32(&cur); + out->n_sections = big16(&cur); + out->max_heap_size = big32(&cur); + out->max_program_size = big32(&cur); + out->max_stack_size = big32(&cur); + out->stack_fence_size = big32(&cur); + + out->module_map_entries = NULL; + out->external_vars = NULL; + return 1; +} + +#define MODULE_MAP_ENTRY_SIZE 74 + +int vos_read_alloc_module_map(FILE * f, vos_program_module *header) +{ + if (header->module_map_len != header->n_modules * MODULE_MAP_ENTRY_SIZE) + { + return 0; + } + uint8_t * buf = malloc(header->module_map_len); + fseek(f, header->module_map_address + 0x1000 - header->user_boundary, SEEK_SET); + if (fread(buf, 1, header->module_map_len, f) != header->module_map_len) + { + free(buf); + return 0; + } + uint8_t * cur = buf; + header->module_map_entries = malloc(sizeof(vos_module_map_entry) * header->n_modules); + for (int i = 0; i < header->n_modules; i++) + { + string(&cur, header->module_map_entries[i].name); + for (int j = 0; j < 5; j++) + { + header->module_map_entries[i].unknown[j] = big16(&cur); + } + header->module_map_entries[i].code_address = big32(&cur); + header->module_map_entries[i].code_length = big32(&cur); + header->module_map_entries[i].foo_address = big32(&cur); + header->module_map_entries[i].foo_length = big32(&cur); + header->module_map_entries[i].bar_address = big32(&cur); + header->module_map_entries[i].bar_length = big32(&cur); + for (int j = 0; j < 3; j++) + { + header->module_map_entries[i].unknown2[j] = big16(&cur); + } + } + return 1; +} + +#define EXTERNAL_VAR_ENTRY_SIZE 44 + +int vos_read_alloc_external_vars(FILE * f, vos_program_module *header) +{ + if (header->external_vars_map_len != header->n_external_vars * EXTERNAL_VAR_ENTRY_SIZE) + { + return 0; + } + uint8_t * buf = malloc(header->external_vars_map_len); + fseek(f, header->external_vars_map_address + 0x1000 - header->user_boundary, SEEK_SET); + if (fread(buf, 1, header->external_vars_map_len, f) != header->external_vars_map_len) + { + free(buf); + return 0; + } + uint8_t * cur = buf; + header->external_vars = malloc(sizeof(vos_external_var_entry) * header->n_external_vars); + for (int i = 0; i < header->n_external_vars; i++) + { + string(&cur, header->external_vars[i].name); + header->external_vars[i].address = big32(&cur); + for (int j = 0; j < 3; j++) + { + header->external_vars[i].unknown[j] = big16(&cur); + } + } + return 1; +} + +void vos_header_cleanup(vos_program_module *header) +{ + free(header->module_map_entries); + free(header->external_vars); +} diff --git a/vos_program_module.h b/vos_program_module.h new file mode 100644 index 0000000..7febb05 --- /dev/null +++ b/vos_program_module.h @@ -0,0 +1,134 @@ +#ifndef VOS_PROGRAM_MODULE_H_ +#define VOS_PROGRAM_MODULE_H_ + +#include + +typedef struct +{ + struct { + uint16_t len; + char str[32]; + } name; + uint16_t unknown[5]; + uint32_t code_address; + uint32_t code_length; + uint32_t foo_address; + uint32_t foo_length; + uint32_t bar_address; + uint32_t bar_length; + uint16_t unknown2[3]; +} vos_module_map_entry; + +typedef struct +{ + struct { + uint16_t len; + char str[32]; + } name; + uint32_t address; + uint16_t unknown[3]; +} vos_external_var_entry; + +typedef struct +{ + uint16_t version; + struct { + uint16_t len; + char str[32]; + } binder_version; + struct { + uint16_t len; + char str[32]; + } binder_options; + struct { + uint16_t len; + char str[32]; + } system_name; + struct { + uint16_t len; + char str[65]; + } user_name; + uint32_t date_bound; + struct { + uint32_t code_address; + uint32_t static_address; + } main_entry_link; + uint32_t user_boundary; + uint16_t n_modules; + uint16_t n_external_vars; + uint16_t n_link_names; + uint16_t n_unsnapped_links; + uint16_t n_vm_pages; + uint16_t n_header_pages; + struct { + uint32_t address; + uint32_t len; + } info[3][4]; + uint32_t module_map_address; + uint32_t module_map_len; + uint32_t external_vars_map_address; + uint32_t external_vars_map_len; + uint32_t link_names_map_address; + uint32_t link_names_map_len; + uint32_t link_map_address; + uint32_t link_map_len; + uint32_t header_address; + uint32_t header_len; + uint8_t access_info[2048]; + uint32_t flags; + uint16_t n_tasks; + uint32_t task_static_len[3]; + uint32_t stack_len; + uint16_t n_entries; + uint32_t entry_map_address; + uint32_t entry_map_len; + uint16_t pop_version; + uint16_t processor; + struct { + uint16_t len; + char str[32]; + } release_name; + struct { + uint32_t map_address; + uint32_t map_len; + uint32_t n_relocations; + } relocation_info; + uint32_t high_water_mark; + struct { + uint16_t len; + char str[256]; + } copyright_notice; + uint32_t module_origins[14]; + uint16_t processor_family; + struct { + uint16_t len; + char str[32]; + } program_name; + uint32_t string_pool_address; + uint32_t string_pool_len; + uint32_t obj_dir_map_address; + uint32_t obj_dir_map_len; + uint32_t global_offset_table_address[3]; + struct { + uint32_t address; + uint32_t len; + } block_map_info[3]; + uint32_t section_map_file_address; + uint32_t section_map_address; + uint32_t section_map_len; + uint16_t n_sections; + uint32_t max_heap_size; + uint32_t max_program_size; + uint32_t max_stack_size; + uint32_t stack_fence_size; + + vos_module_map_entry *module_map_entries; + vos_external_var_entry *external_vars; +} vos_program_module; + +int vos_read_header(FILE * f, vos_program_module *out); +int vos_read_alloc_module_map(FILE * f, vos_program_module *header); +int vos_read_alloc_external_vars(FILE * f, vos_program_module *header); +void vos_header_cleanup(vos_program_module *header); + +#endif //VOS_PROGRAM_MODULE_H_ diff --git a/vos_program_module.o b/vos_program_module.o new file mode 100644 index 0000000..3066b9d Binary files /dev/null and b/vos_program_module.o differ -- cgit v1.2.3 From fce481d465209790424fe67fa310e6f457fe221c Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 11 Oct 2014 21:20:02 -0700 Subject: Add -r option to indicate VOS program module contains a 68K reset vector --- dis.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/dis.c b/dis.c index b52c4d7..c6216c9 100644 --- a/dis.c +++ b/dis.c @@ -108,7 +108,7 @@ int main(int argc, char ** argv) unsigned short * cur; deferred *def = NULL, *tmpd; - uint8_t labels = 0, addr = 0, only = 0, vos = 0; + uint8_t labels = 0, addr = 0, only = 0, vos = 0, reset = 0; for(uint8_t opt = 2; opt < argc; ++opt) { if (argv[opt][0] == '-') { @@ -127,6 +127,9 @@ int main(int argc, char ** argv) case 'v': vos = 1; break; + case 'r': + reset = 1; + break; case 'f': opt++; if (opt >= argc) { @@ -174,7 +177,10 @@ int main(int argc, char ** argv) named_labels = add_label(named_labels, "main_entry_link", header.main_entry_link.code_address); for (int i = 0; i < header.n_modules; i++) { - def = defer(header.module_map_entries[i].code_address, def); + if (!reset || header.module_map_entries[i].code_address != header.user_boundary) + { + def = defer(header.module_map_entries[i].code_address, def); + } named_labels = add_label(named_labels, header.module_map_entries[i].name.str, header.module_map_entries[i].code_address); } fseek(f, 0x1000, SEEK_SET); @@ -188,6 +194,11 @@ int main(int argc, char ** argv) { *cur = (*cur >> 8) | (*cur << 8); } + if (reset) + { + def = defer(filebuf[2] << 16 | filebuf[3], def); + named_labels = add_label(named_labels, "reset", filebuf[2] << 16 | filebuf[3]); + } } else { address_off = 0; address_end = filesize; -- cgit v1.2.3 From a4b73b992202fb0d0b3da08cee05e0da16be7e59 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 11 Oct 2014 21:42:33 -0700 Subject: Fix translation of 68K address to buffer location when address_off != 0 --- dis.c | 12 ++++++------ vos_program_module.o | Bin 5360 -> 17752 bytes 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dis.c b/dis.c index c6216c9..b7a11fc 100644 --- a/dis.c +++ b/dis.c @@ -235,7 +235,7 @@ int main(int argc, char ** argv) encoded = NULL; address = def->address; if (!is_visited(address)) { - encoded = filebuf + address/2; + encoded = filebuf + (address - address_off)/2; } tmpd = def; def = def->next; @@ -245,7 +245,7 @@ int main(int argc, char ** argv) break; } for(;;) { - if (address > filesize) { + if (address > address_end || address < address_off) { break; } visit(address); @@ -262,7 +262,7 @@ int main(int argc, char ** argv) if (instbuf.op == M68K_BCC || instbuf.op == M68K_DBCC || instbuf.op == M68K_BSR) { if (instbuf.op == M68K_BCC && instbuf.extra.cond == COND_TRUE) { address = instbuf.address + 2 + instbuf.src.params.immed; - encoded = filebuf + address/2; + encoded = filebuf + (address - address_off)/2; reference(address); if (is_visited(address)) { break; @@ -275,13 +275,13 @@ int main(int argc, char ** argv) } else if(instbuf.op == M68K_JMP) { if (instbuf.src.addr_mode == MODE_ABSOLUTE || instbuf.src.addr_mode == MODE_ABSOLUTE_SHORT) { address = instbuf.src.params.immed; - encoded = filebuf + address/2; + encoded = filebuf + (address - address_off)/2; if (is_visited(address)) { break; } } else if (instbuf.src.addr_mode = MODE_PC_DISPLACE) { address = instbuf.src.params.regs.displacement + instbuf.address + 2; - encoded = filebuf + address/2; + encoded = filebuf + (address - address_off)/2; if (is_visited(address)) { break; } @@ -305,7 +305,7 @@ int main(int argc, char ** argv) } puts(""); } - for (address = address_off; address < filesize; address+=2) { + for (address = address_off; address < address_end; address+=2) { if (is_visited(address)) { encoded = filebuf + (address-address_off)/2; m68k_decode(encoded, &instbuf, address); diff --git a/vos_program_module.o b/vos_program_module.o index 3066b9d..5208bcf 100644 Binary files a/vos_program_module.o and b/vos_program_module.o differ -- cgit v1.2.3 From fc252737d7e366c5eccbbc08dc028b6adcb7d793 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 11 Oct 2014 22:18:49 -0700 Subject: Better support for labels sourced from VOS program module header --- 68kinst.c | 70 ++++++++++++++++++++++++++++++++++++++++----------------------- 68kinst.h | 5 ++++- dis.c | 15 +++++++++++++- 3 files changed, 63 insertions(+), 27 deletions(-) diff --git a/68kinst.c b/68kinst.c index 37c9a9f..10df21e 100644 --- a/68kinst.c +++ b/68kinst.c @@ -1533,7 +1533,7 @@ char * cr_mnem[] = { }; #endif -int m68k_disasm_op(m68k_op_info *decoded, char *dst, int need_comma, uint8_t labels, uint32_t address) +int m68k_disasm_op(m68k_op_info *decoded, char *dst, int need_comma, uint8_t labels, uint32_t address, format_label_fun label_fun, void * data) { char * c = need_comma ? "," : ""; switch(decoded->addr_mode) @@ -1556,20 +1556,29 @@ int m68k_disasm_op(m68k_op_info *decoded, char *dst, int need_comma, uint8_t lab case MODE_IMMEDIATE_WORD: return sprintf(dst, (decoded->params.immed <= 128 ? "%s #%d" : "%s #$%X"), c, decoded->params.immed); case MODE_ABSOLUTE_SHORT: - if (labels) { - return sprintf(dst, "%s ADR_%X.w", c, decoded->params.immed); + if (labels) { + int ret = sprintf(dst, "%s ", c); + ret += label_fun(dst+ret, decoded->params.immed, data); + strcat(dst+ret, ".w"); + return ret + 2; } else { return sprintf(dst, "%s $%X.w", c, decoded->params.immed); } case MODE_ABSOLUTE: if (labels) { - return sprintf(dst, "%s ADR_%X.l", c, decoded->params.immed); + int ret = sprintf(dst, "%s ", c); + ret += label_fun(dst+ret, decoded->params.immed, data); + strcat(dst+ret, ".l"); + return ret + 2; } else { return sprintf(dst, "%s $%X", c, decoded->params.immed); } case MODE_PC_DISPLACE: if (labels) { - return sprintf(dst, "%s ADR_%X(pc)", c, address + 2 + decoded->params.regs.displacement); + int ret = sprintf(dst, "%s ", c); + ret += label_fun(dst+ret, address + 2 + decoded->params.regs.displacement, data); + strcat(dst+ret, "(pc)"); + return ret + 4; } else { return sprintf(dst, "%s (%d, pc)", c, decoded->params.regs.displacement); } @@ -1580,7 +1589,7 @@ int m68k_disasm_op(m68k_op_info *decoded, char *dst, int need_comma, uint8_t lab } } -int m68k_disasm_movem_op(m68k_op_info *decoded, m68k_op_info *other, char *dst, int need_comma, uint8_t labels, uint32_t address) +int m68k_disasm_movem_op(m68k_op_info *decoded, m68k_op_info *other, char *dst, int need_comma, uint8_t labels, uint32_t address, format_label_fun label_fun, void * data) { int8_t dir, reg, bit, regnum, last=-1, lastreg, first=-1; char *rtype, *last_rtype; @@ -1634,11 +1643,16 @@ int m68k_disasm_movem_op(m68k_op_info *decoded, m68k_op_info *other, char *dst, } return oplen; } else { - return m68k_disasm_op(decoded, dst, need_comma, labels, address); + return m68k_disasm_op(decoded, dst, need_comma, labels, address, label_fun, data); } } -int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels) +int m68k_default_label_fun(char * dst, uint32_t address, void * data) +{ + return sprintf(dst, "ADR_%X", address); +} + +int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels, format_label_fun label_fun, void * data) { int ret,op1len; uint8_t size; @@ -1656,9 +1670,11 @@ int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels) if (decoded->op != M68K_SCC) { if (labels) { if (decoded->op == M68K_DBCC) { - ret += sprintf(dst+ret, " d%d, ADR_%X", decoded->dst.params.regs.pri, decoded->address + 2 + decoded->src.params.immed); + ret += sprintf(dst+ret, " d%d, ", decoded->dst.params.regs.pri); + ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data); } else { - ret += sprintf(dst+ret, " ADR_%X", decoded->address + 2 + decoded->src.params.immed); + dst[ret++] = ' '; + ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data); } } else { if (decoded->op == M68K_DBCC) { @@ -1672,8 +1688,8 @@ int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels) break; case M68K_BSR: if (labels) { - ret = sprintf(dst, "bsr%s ADR_%X", decoded->variant == VAR_BYTE ? ".s" : "", - decoded->address + 2 + decoded->src.params.immed); + ret = sprintf(dst, "bsr%s ", decoded->variant == VAR_BYTE ? ".s" : ""); + ret += label_fun(dst+ret, decoded->address + 2 + decoded->src.params.immed, data); } else { ret = sprintf(dst, "bsr%s #%d <%X>", decoded->variant == VAR_BYTE ? ".s" : "", decoded->src.params.immed, decoded->address + 2 + decoded->src.params.immed); } @@ -1681,7 +1697,7 @@ int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels) case M68K_MOVE_FROM_SR: ret = sprintf(dst, "%s", mnemonics[decoded->op]); ret += sprintf(dst + ret, " SR"); - ret += m68k_disasm_op(&(decoded->dst), dst + ret, 1, labels, decoded->address); + ret += m68k_disasm_op(&(decoded->dst), dst + ret, 1, labels, decoded->address, label_fun, data); return ret; case M68K_ANDI_SR: case M68K_EORI_SR: @@ -1693,17 +1709,17 @@ int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels) case M68K_MOVE_CCR: case M68K_ORI_CCR: ret = sprintf(dst, "%s", mnemonics[decoded->op]); - ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address); + ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data); ret += sprintf(dst + ret, ", %s", special_op); return ret; case M68K_MOVE_USP: ret = sprintf(dst, "%s", mnemonics[decoded->op]); if (decoded->src.addr_mode != MODE_UNUSED) { - ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address); + ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data); ret += sprintf(dst + ret, ", USP"); } else { ret += sprintf(dst + ret, "USP, "); - ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address); + ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data); } return ret; case M68K_INVALID: @@ -1714,9 +1730,9 @@ int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels) ret = sprintf(dst, "%s ", mnemonics[decoded->op]); if (decoded->src.addr_mode == MODE_UNUSED) { ret += sprintf(dst + ret, "%s, ", cr_mnem[decoded->src.params.immed]); - ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address); + ret += m68k_disasm_op(&(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data); } else { - ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address); + ret += m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data); ret += sprintf(dst + ret, ", %s", cr_mnem[decoded->dst.params.immed]); } return ret; @@ -1729,23 +1745,27 @@ int m68k_disasm_ex(m68kinst * decoded, char * dst, uint8_t labels) size == OPSIZE_BYTE ? ".b" : (size == OPSIZE_WORD ? ".w" : (size == OPSIZE_LONG ? ".l" : ""))); } if (decoded->op == M68K_MOVEM) { - op1len = m68k_disasm_movem_op(&(decoded->src), &(decoded->dst), dst + ret, 0, labels, decoded->address); + op1len = m68k_disasm_movem_op(&(decoded->src), &(decoded->dst), dst + ret, 0, labels, decoded->address, label_fun, data); ret += op1len; - ret += m68k_disasm_movem_op(&(decoded->dst), &(decoded->src), dst + ret, op1len, labels, decoded->address); + ret += m68k_disasm_movem_op(&(decoded->dst), &(decoded->src), dst + ret, op1len, labels, decoded->address, label_fun, data); } else { - op1len = m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address); + op1len = m68k_disasm_op(&(decoded->src), dst + ret, 0, labels, decoded->address, label_fun, data); ret += op1len; - ret += m68k_disasm_op(&(decoded->dst), dst + ret, op1len, labels, decoded->address); + ret += m68k_disasm_op(&(decoded->dst), dst + ret, op1len, labels, decoded->address, label_fun, data); } return ret; } int m68k_disasm(m68kinst * decoded, char * dst) { - return m68k_disasm_ex(decoded, dst, 0); + return m68k_disasm_ex(decoded, dst, 0, NULL, NULL); } -int m68k_disasm_labels(m68kinst * decoded, char * dst) +int m68k_disasm_labels(m68kinst * decoded, char * dst, format_label_fun label_fun, void * data) { - return m68k_disasm_ex(decoded, dst, 1); + if (!label_fun) + { + label_fun = m68k_default_label_fun; + } + return m68k_disasm_ex(decoded, dst, 1, label_fun, data); } diff --git a/68kinst.h b/68kinst.h index d1cbd2b..3441737 100644 --- a/68kinst.h +++ b/68kinst.h @@ -298,12 +298,15 @@ typedef enum { VECTOR_TRAP_15 } m68k_vector; +typedef int (*format_label_fun)(char * dst, uint32_t address, void * data); + uint16_t * m68k_decode(uint16_t * istream, m68kinst * dst, uint32_t address); uint32_t m68k_branch_target(m68kinst * inst, uint32_t *dregs, uint32_t *aregs); uint8_t m68k_is_branch(m68kinst * inst); uint8_t m68k_is_noncall_branch(m68kinst * inst); int m68k_disasm(m68kinst * decoded, char * dst); -int m68k_disasm_labels(m68kinst * decoded, char * dst); +int m68k_disasm_labels(m68kinst * decoded, char * dst, format_label_fun label_fun, void * data); +int m68k_default_label_fun(char * dst, uint32_t address, void * data); #endif diff --git a/dis.c b/dis.c index b7a11fc..06521dd 100644 --- a/dis.c +++ b/dis.c @@ -99,6 +99,19 @@ void check_reference(m68kinst * inst, m68k_op_info * op) } } +int label_fun(char *dst, uint32_t address, void * data) +{ + tern_node * labels = data; + char key[MAX_INT_KEY_SIZE]; + label_names * names = tern_find_ptr(labels, tern_int_key(address & 0xFFFFFF, key)); + if (names) + { + return sprintf(dst, "%s", names->labels[0]); + } else { + return m68k_default_label_fun(dst, address, NULL); + } +} + int main(int argc, char ** argv) { long filesize; @@ -310,7 +323,7 @@ int main(int argc, char ** argv) encoded = filebuf + (address-address_off)/2; m68k_decode(encoded, &instbuf, address); if (labels) { - m68k_disasm_labels(&instbuf, disbuf); + m68k_disasm_labels(&instbuf, disbuf, label_fun, named_labels); char keybuf[MAX_INT_KEY_SIZE]; label_names * names = tern_find_ptr(named_labels, tern_int_key(address, keybuf)); if (names) -- cgit v1.2.3 From 821106e3e1946d0016f02cfeaf4f2c3ca7200ddb Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 12 Oct 2014 19:02:47 -0700 Subject: Fix logic for automatic label generation. --- dis.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dis.c b/dis.c index 06521dd..edd555f 100644 --- a/dis.c +++ b/dis.c @@ -11,7 +11,7 @@ #include "tern.h" uint8_t visited[(16*1024*1024)/16]; -uint8_t label[(16*1024*1024)/8]; +uint16_t label[(16*1024*1024)/8]; void visit(uint32_t address) { @@ -23,7 +23,7 @@ void reference(uint32_t address) { address &= 0xFFFFFF; //printf("referenced: %X\n", address); - label[address/16] |= 1 << (address % 8); + label[address/16] |= 1 << (address % 16); } uint8_t is_visited(uint32_t address) @@ -32,10 +32,10 @@ uint8_t is_visited(uint32_t address) return visited[address/16] & (1 << ((address / 2) % 8)); } -uint8_t is_label(uint32_t address) +uint16_t is_label(uint32_t address) { address &= 0xFFFFFF; - return label[address/16] & (1 << (address % 8)); + return label[address/16] & (1 << (address % 16)); } typedef struct { -- cgit v1.2.3 From 92486a76659f4acd7995d31b11a6bc6cc8621939 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 12 Oct 2014 19:03:05 -0700 Subject: Add support for 68020 bitfield instructions --- 68kinst.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 68kinst.h | 8 +++- 2 files changed, 112 insertions(+), 21 deletions(-) diff --git a/68kinst.c b/68kinst.c index 10df21e..b5a4ec4 100644 --- a/68kinst.c +++ b/68kinst.c @@ -1303,6 +1303,56 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) } else { #ifdef M68020 //TODO: Implement bitfield instructions for M68020+ support + switch (*istream >> 8 & 7) + { + case 0: + decoded->op = M68K_BFTST; // + break; + case 1: + decoded->op = M68K_BFEXTU; //, Dn + break; + case 2: + decoded->op = M68K_BFCHG; // + break; + case 3: + decoded->op = M68K_BFEXTS; //, Dn + break; + case 4: + decoded->op = M68K_BFCLR; // + break; + case 5: + decoded->op = M68K_BFFFO; //, Dn + break; + case 6: + decoded->op = M68K_BFSET; // + break; + case 7: + decoded->op = M68K_BFINS; //Dn, + break; + } + opmode = *istream >> 3 & 0x7; + reg = *istream & 0x7; + m68k_op_info *ea, *other; + if (decoded->op == M68K_BFEXTU || decoded->op == M68K_BFEXTS || decoded->op == M68K_BFFFO) + { + ea = &(decoded->src); + other = &(decoded->dst); + } else { + ea = &(decoded->dst); + other = &(decoded->dst); + } + if (*istream & 0x100) + { + immed = *(istream++); + other->addr_mode = MODE_REG; + other->params.regs.pri = immed >> 12 & 0x7; + } else { + immed = *(istream++); + } + decoded->extra.size = OPSIZE_UNSIZED; + istream = m68k_decode_op_ex(istream, opmode, reg, decoded->extra.size, ea); + ea->addr_mode |= M68K_FLAG_BITFIELD; + ea->bitfield = immed & 0xFFF; #endif } break; @@ -1466,6 +1516,7 @@ char * mnemonics[] = { "move", //from ccr "movec", "moves", + "rtd", #endif #ifdef M68020 "bfchg", @@ -1536,57 +1587,91 @@ char * cr_mnem[] = { int m68k_disasm_op(m68k_op_info *decoded, char *dst, int need_comma, uint8_t labels, uint32_t address, format_label_fun label_fun, void * data) { char * c = need_comma ? "," : ""; - switch(decoded->addr_mode) + int ret = 0; +#ifdef M68020 + uint8_t addr_mode = decoded->addr_mode & (~M68K_FLAG_BITFIELD); +#else + uint8_t addr_mode = decoded->addr_mode; +#endif + switch(addr_mode) { case MODE_REG: - return sprintf(dst, "%s d%d", c, decoded->params.regs.pri); + ret = sprintf(dst, "%s d%d", c, decoded->params.regs.pri); + break; case MODE_AREG: - return sprintf(dst, "%s a%d", c, decoded->params.regs.pri); + ret = sprintf(dst, "%s a%d", c, decoded->params.regs.pri); + break; case MODE_AREG_INDIRECT: - return sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri); + ret = sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri); + break; case MODE_AREG_POSTINC: - return sprintf(dst, "%s (a%d)+", c, decoded->params.regs.pri); + ret = sprintf(dst, "%s (a%d)+", c, decoded->params.regs.pri); + break; case MODE_AREG_PREDEC: - return sprintf(dst, "%s -(a%d)", c, decoded->params.regs.pri); + ret = sprintf(dst, "%s -(a%d)", c, decoded->params.regs.pri); + break; case MODE_AREG_DISPLACE: - return sprintf(dst, "%s (%d, a%d)", c, decoded->params.regs.displacement, decoded->params.regs.pri); + ret = sprintf(dst, "%s (%d, a%d)", c, decoded->params.regs.displacement, decoded->params.regs.pri); + break; case MODE_AREG_INDEX_DISP8: - return sprintf(dst, "%s (%d, a%d, %c%d.%c)", c, decoded->params.regs.displacement, decoded->params.regs.pri, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w'); + ret = sprintf(dst, "%s (%d, a%d, %c%d.%c)", c, decoded->params.regs.displacement, decoded->params.regs.pri, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w'); + break; case MODE_IMMEDIATE: case MODE_IMMEDIATE_WORD: - return sprintf(dst, (decoded->params.immed <= 128 ? "%s #%d" : "%s #$%X"), c, decoded->params.immed); + ret = sprintf(dst, (decoded->params.immed <= 128 ? "%s #%d" : "%s #$%X"), c, decoded->params.immed); + break; case MODE_ABSOLUTE_SHORT: if (labels) { - int ret = sprintf(dst, "%s ", c); + ret = sprintf(dst, "%s ", c); ret += label_fun(dst+ret, decoded->params.immed, data); strcat(dst+ret, ".w"); - return ret + 2; + ret = ret + 2; } else { - return sprintf(dst, "%s $%X.w", c, decoded->params.immed); + ret = sprintf(dst, "%s $%X.w", c, decoded->params.immed); } + break; case MODE_ABSOLUTE: if (labels) { - int ret = sprintf(dst, "%s ", c); + ret = sprintf(dst, "%s ", c); ret += label_fun(dst+ret, decoded->params.immed, data); strcat(dst+ret, ".l"); - return ret + 2; + ret = ret + 2; } else { - return sprintf(dst, "%s $%X", c, decoded->params.immed); + ret = sprintf(dst, "%s $%X", c, decoded->params.immed); } + break; case MODE_PC_DISPLACE: if (labels) { - int ret = sprintf(dst, "%s ", c); + ret = sprintf(dst, "%s ", c); ret += label_fun(dst+ret, address + 2 + decoded->params.regs.displacement, data); strcat(dst+ret, "(pc)"); - return ret + 4; + ret = ret + 4; } else { - return sprintf(dst, "%s (%d, pc)", c, decoded->params.regs.displacement); + ret = sprintf(dst, "%s (%d, pc)", c, decoded->params.regs.displacement); } + break; case MODE_PC_INDEX_DISP8: - return sprintf(dst, "%s (%d, pc, %c%d.%c)", c, decoded->params.regs.displacement, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w'); + ret = sprintf(dst, "%s (%d, pc, %c%d.%c)", c, decoded->params.regs.displacement, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w'); default: - return 0; + ret = 0; } +#ifdef M68020 + if (decoded->addr_mode & M68K_FLAG_BITFIELD) + { + switch (decoded->bitfield & 0x820) + { + case 0: + return ret + sprintf(dst+ret, " {$%X:%d}", decoded->bitfield >> 6 & 0x1F, decoded->bitfield & 0x1F ? decoded->bitfield & 0x1F : 32); + case 0x20: + return ret + sprintf(dst+ret, " {$%X:d%d}", decoded->bitfield >> 6 & 0x1F, decoded->bitfield & 0x7); + case 0x800: + return ret + sprintf(dst+ret, " {d%d:%d}", decoded->bitfield >> 6 & 0x7, decoded->bitfield & 0x1F ? decoded->bitfield & 0x1F : 32); + case 0x820: + return ret + sprintf(dst+ret, " {d%d:d%d}", decoded->bitfield >> 6 & 0x7, decoded->bitfield & 0x7); + } + } +#endif + return ret; } int m68k_disasm_movem_op(m68k_op_info *decoded, m68k_op_info *other, char *dst, int need_comma, uint8_t labels, uint32_t address, format_label_fun label_fun, void * data) diff --git a/68kinst.h b/68kinst.h index 3441737..0529ad8 100644 --- a/68kinst.h +++ b/68kinst.h @@ -186,6 +186,9 @@ typedef enum { MODE_IMMEDIATE_WORD,//used to indicate an immediate operand that only uses a single extension word even for a long operation MODE_UNUSED } m68k_addr_modes; +#ifdef M68020 +#define M68K_FLAG_BITFIELD 0x80 +#endif typedef enum { COND_TRUE, @@ -233,7 +236,10 @@ typedef enum { #endif typedef struct { - uint8_t addr_mode; +#ifdef M68020 + uint16_t bitfield; +#endif + uint8_t addr_mode; union { struct { uint8_t pri; -- cgit v1.2.3 From 34a6a4cf250c764ff58256258009882878558a6b Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 12 Oct 2014 23:55:25 -0700 Subject: Tiny bit of work towards supporting 68020 addressing modes in decoder/disassembler --- 68kinst.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/68kinst.h b/68kinst.h index 0529ad8..ea7aad6 100644 --- a/68kinst.h +++ b/68kinst.h @@ -173,6 +173,7 @@ typedef enum { //expanded values MODE_AREG_INDEX_DISP8, #ifdef M68020 + MODE_AREG_INDEX_DISP16, MODE_AREG_INDEX_DISP32, #endif MODE_ABSOLUTE_SHORT, @@ -244,6 +245,9 @@ typedef struct { struct { uint8_t pri; uint8_t sec; +#ifdef M68020 + uint8_t scale; +#endif int32_t displacement; } regs; uint32_t immed; -- cgit v1.2.3 From 75c4b6df8ebb509134a21ed57ac2f0095c39dd21 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 14 Oct 2014 21:58:03 -0700 Subject: Add support for 68020 addressing modes in decoder and disassembler --- 68kinst.c | 728 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 68kinst.h | 27 ++- 2 files changed, 741 insertions(+), 14 deletions(-) diff --git a/68kinst.c b/68kinst.c index b5a4ec4..a719440 100644 --- a/68kinst.c +++ b/68kinst.c @@ -19,7 +19,7 @@ uint32_t sign_extend8(uint32_t val) uint16_t *m68k_decode_op_ex(uint16_t *cur, uint8_t mode, uint8_t reg, uint8_t size, m68k_op_info *dst) { - uint16_t ext; + uint16_t ext, tmp; dst->addr_mode = mode; switch(mode) { @@ -36,15 +36,95 @@ uint16_t *m68k_decode_op_ex(uint16_t *cur, uint8_t mode, uint8_t reg, uint8_t si dst->params.regs.displacement = sign_extend16(ext); break; case MODE_AREG_INDEX_MEM: - #ifdef M68020 - //TODO: implement me for M68020+ support - #else + dst->params.regs.pri = reg; + ext = *(++cur); + dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit +#ifdef M68020 + dst->params.regs.scale = ext >> 9 & 3; + if (ext & 0x100) + { + dst->params.regs.disp_sizes = ext >> 4 & 3; + switch (dst->params.regs.disp_sizes) + { + case 0: + //reserved + return NULL; + case 1: + dst->params.regs.displacement = 0; + break; + case 2: + dst->params.regs.displacement = sign_extend16(*(cur++)); + break; + case 3: + tmp = *(cur++); + dst->params.regs.displacement = tmp << 16 | *(cur++); + break; + } + if (ext & 0x3) + { + //memory indirect + switch (ext & 0xC4) + { + case 0x00: + dst->addr_mode = MODE_AREG_PREINDEX; + break; + case 0x04: + dst->addr_mode = MODE_AREG_POSTINDEX; + break; + case 0x40: + dst->addr_mode = MODE_AREG_MEM_INDIRECT; + break; + case 0x80: + dst->addr_mode = MODE_PREINDEX; + break; + case 0x84: + dst->addr_mode = MODE_POSTINDEX; + break; + case 0xC0: + dst->addr_mode = MODE_MEM_INDIRECT; + break; + } + dst->params.regs.disp_sizes |= ext << 4 & 0x30; + switch (ext & 0x3) + { + case 0: + //reserved + return NULL; + case 1: + dst->params.regs.outer_disp = 0; + break; + case 2: + dst->params.regs.outer_disp = sign_extend16(*(cur++)); + break; + case 3: + tmp = *(cur++); + dst->params.regs.outer_disp = tmp << 16 | *(cur++); + break; + } + } else { + switch (ext >> 6 & 3) + { + case 0: + dst->addr_mode = MODE_AREG_INDEX_BASE_DISP; + break; + case 1: + dst->addr_mode = MODE_AREG_BASE_DISP; + break; + case 2: + dst->addr_mode = MODE_INDEX_BASE_DISP; + break; + case 3: + dst->addr_mode = MODE_BASE_DISP; + break; + } + } + } else { +#endif dst->addr_mode = MODE_AREG_INDEX_DISP8; - dst->params.regs.pri = reg; - ext = *(++cur); - dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit dst->params.regs.displacement = sign_extend8(ext&0xFF); - #endif +#ifdef M68020 + } +#endif break; case MODE_PC_INDIRECT_ABS_IMMED: switch(reg) @@ -68,6 +148,95 @@ uint16_t *m68k_decode_op_ex(uint16_t *cur, uint8_t mode, uint8_t reg, uint8_t si dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit dst->params.regs.displacement = sign_extend8(ext&0xFF); #endif + + ext = *(++cur); + dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit +#ifdef M68020 + dst->params.regs.scale = ext >> 9 & 3; + if (ext & 0x100) + { + dst->params.regs.disp_sizes = ext >> 4 & 3; + switch (dst->params.regs.disp_sizes) + { + case 0: + //reserved + return NULL; + case 1: + dst->params.regs.displacement = 0; + break; + case 2: + dst->params.regs.displacement = sign_extend16(*(cur++)); + break; + case 3: + tmp = *(cur++); + dst->params.regs.displacement = tmp << 16 | *(cur++); + break; + } + if (ext & 0x3) + { + //memory indirect + switch (ext & 0xC4) + { + case 0x00: + dst->addr_mode = MODE_PC_PREINDEX; + break; + case 0x04: + dst->addr_mode = MODE_PC_POSTINDEX; + break; + case 0x40: + dst->addr_mode = MODE_PC_MEM_INDIRECT; + break; + case 0x80: + dst->addr_mode = MODE_ZPC_PREINDEX; + break; + case 0x84: + dst->addr_mode = MODE_ZPC_POSTINDEX; + break; + case 0xC0: + dst->addr_mode = MODE_ZPC_MEM_INDIRECT; + break; + } + dst->params.regs.disp_sizes |= ext << 4 & 0x30; + switch (ext & 0x3) + { + case 0: + //reserved + return NULL; + case 1: + dst->params.regs.outer_disp = 0; + break; + case 2: + dst->params.regs.outer_disp = sign_extend16(*(cur++)); + break; + case 3: + tmp = *(cur++); + dst->params.regs.outer_disp = tmp << 16 | *(cur++); + break; + } + } else { + switch (ext >> 6 & 3) + { + case 0: + dst->addr_mode = MODE_PC_INDEX_BASE_DISP; + break; + case 1: + dst->addr_mode = MODE_PC_BASE_DISP; + break; + case 2: + dst->addr_mode = MODE_ZPC_INDEX_BASE_DISP; + break; + case 3: + dst->addr_mode = MODE_ZPC_BASE_DISP; + break; + } + } + } else { +#endif + dst->addr_mode = MODE_PC_INDEX_DISP8; + dst->params.regs.displacement = sign_extend8(ext&0xFF); +#ifdef M68020 + } +#endif break; case 2: dst->addr_mode = MODE_PC_DISPLACE; @@ -1614,14 +1783,283 @@ int m68k_disasm_op(m68k_op_info *decoded, char *dst, int need_comma, uint8_t lab ret = sprintf(dst, "%s (%d, a%d)", c, decoded->params.regs.displacement, decoded->params.regs.pri); break; case MODE_AREG_INDEX_DISP8: - ret = sprintf(dst, "%s (%d, a%d, %c%d.%c)", c, decoded->params.regs.displacement, decoded->params.regs.pri, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w'); +#ifdef M68020 + if (decoded->params.regs.scale) + { + ret = sprintf(dst, "%s (%d, a%d, %c%d.%c*%d)", c, decoded->params.regs.displacement, decoded->params.regs.pri, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + } else { +#endif + ret = sprintf(dst, "%s (%d, a%d, %c%d.%c)", c, decoded->params.regs.displacement, decoded->params.regs.pri, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w'); +#ifdef M68020 + } +#endif + break; +#ifdef M68020 + case MODE_AREG_INDEX_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c, a%d, %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + } else { + ret = sprintf(dst, "%s (a%d, %c%d.%c*%d)", c, decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + } + break; + case MODE_AREG_PREINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([a%d, %c%d.%c*%d])", c, decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, a%d, %c%d.%c*%d])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([a%d, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, a%d, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } break; + case MODE_AREG_POSTINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([a%d], %c%d.%c*%d)", c, decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, a%d], %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([a%d], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, a%d], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri, + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_AREG_MEM_INDIRECT: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([a%d])", c, decoded->params.regs.pri); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, a%d])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([a%d], %d.%c)", c, decoded->params.regs.pri, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, a%d], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.pri, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_AREG_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c, a%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', decoded->params.regs.pri); + } else { + //this is a lossy representation of the encoded instruction + //not sure if there's a better way to print it though + ret = sprintf(dst, "%s (a%d)", c, decoded->params.regs.pri); + } + break; + case MODE_INDEX_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c, %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + } else { + ret = sprintf(dst, "%s (%c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + } + break; + case MODE_PREINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([%c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, %c%d.%c*%d])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([%c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_POSTINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c], %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_MEM_INDIRECT: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([])", c); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l'); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([], %d.%c)", c, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l'); + } else { + ret = sprintf(dst, "%s ()", c); + } + break; +#endif case MODE_IMMEDIATE: case MODE_IMMEDIATE_WORD: ret = sprintf(dst, (decoded->params.immed <= 128 ? "%s #%d" : "%s #$%X"), c, decoded->params.immed); break; case MODE_ABSOLUTE_SHORT: - if (labels) { + if (labels) { ret = sprintf(dst, "%s ", c); ret += label_fun(dst+ret, decoded->params.immed, data); strcat(dst+ret, ".w"); @@ -1651,7 +2089,275 @@ int m68k_disasm_op(m68k_op_info *decoded, char *dst, int need_comma, uint8_t lab } break; case MODE_PC_INDEX_DISP8: - ret = sprintf(dst, "%s (%d, pc, %c%d.%c)", c, decoded->params.regs.displacement, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w'); +#ifdef M68020 + if (decoded->params.regs.scale) + { + ret = sprintf(dst, "%s (%d, pc, %c%d.%c*%d)", c, decoded->params.regs.displacement, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + } else { +#endif + ret = sprintf(dst, "%s (%d, pc, %c%d.%c)", c, decoded->params.regs.displacement, (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w'); +#ifdef M68020 + } +#endif + break; +#ifdef M68020 + case MODE_PC_INDEX_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c, pc, %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + } else { + ret = sprintf(dst, "%s (pc, %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + } + break; + case MODE_PC_PREINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([pc, %c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, pc, %c%d.%c*%d])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([pc, %c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, pc, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_PC_POSTINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([pc], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, pc], %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([pc], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, pc], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_PC_MEM_INDIRECT: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([pc])", c); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, pc])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l'); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([pc], %d.%c)", c, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, pc], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_PC_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c, pc)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l'); + } else { + ret = sprintf(dst, "%s (pc)", c); + } + break; + case MODE_ZPC_INDEX_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c, zpc, %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + } else { + ret = sprintf(dst, "%s (zpc, %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + } + break; + case MODE_ZPC_PREINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([zpc, %c%d.%c*%d])", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, zpc, %c%d.%c*%d])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([zpc, %c%d.%c*%d], %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, zpc, %c%d.%c*%d], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_ZPC_POSTINDEX: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([zpc], %c%d.%c*%d)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, zpc], %c%d.%c*%d)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([zpc], %c%d.%c*%d, %d.%c)", c, (decoded->params.regs.sec & 0x10) ? 'a': 'd', + (decoded->params.regs.sec >> 1) & 0x7, (decoded->params.regs.sec & 1) ? 'l': 'w', + 1 << decoded->params.regs.scale, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, zpc], %c%d.%c*%d, %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', + (decoded->params.regs.sec & 0x10) ? 'a': 'd', (decoded->params.regs.sec >> 1) & 0x7, + (decoded->params.regs.sec & 1) ? 'l': 'w', 1 << decoded->params.regs.scale, + decoded->params.regs.outer_disp, decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_ZPC_MEM_INDIRECT: + switch (decoded->params.regs.disp_sizes) + { + case 0x11: + //no base displacement or outer displacement + ret = sprintf(dst, "%s ([zpc])", c); + break; + case 0x12: + case 0x13: + //base displacement only + ret = sprintf(dst, "%s ([%d.%c, zpc])", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l'); + break; + case 0x21: + case 0x31: + //outer displacement only + ret = sprintf(dst, "%s ([zpc], %d.%c)", c, decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + case 0x22: + case 0x23: + case 0x32: + case 0x33: + //both outer and inner displacement + ret = sprintf(dst, "%s ([%d.%c, zpc], %d.%c)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l', decoded->params.regs.outer_disp, + decoded->params.regs.disp_sizes & 0x30 == 0x20 ? 'w' : 'l'); + break; + } + break; + case MODE_ZPC_BASE_DISP: + if (decoded->params.regs.disp_sizes > 1) + { + ret = sprintf(dst, "%s (%d.%c, zpc)", c, decoded->params.regs.displacement, + decoded->params.regs.disp_sizes & 3 == 2 ? 'w' : 'l'); + } else { + ret = sprintf(dst, "%s (zpc)", c); + } + break; +#endif default: ret = 0; } diff --git a/68kinst.h b/68kinst.h index ea7aad6..0d5072f 100644 --- a/68kinst.h +++ b/68kinst.h @@ -173,15 +173,32 @@ typedef enum { //expanded values MODE_AREG_INDEX_DISP8, #ifdef M68020 - MODE_AREG_INDEX_DISP16, - MODE_AREG_INDEX_DISP32, + MODE_AREG_INDEX_BASE_DISP, + MODE_AREG_PREINDEX, + MODE_AREG_POSTINDEX, + MODE_AREG_MEM_INDIRECT, + MODE_AREG_BASE_DISP, + MODE_INDEX_BASE_DISP, + MODE_PREINDEX, + MODE_POSTINDEX, + MODE_MEM_INDIRECT, + MODE_BASE_DISP, #endif MODE_ABSOLUTE_SHORT, MODE_ABSOLUTE, MODE_PC_DISPLACE, MODE_PC_INDEX_DISP8, #ifdef M68020 - MODE_PC_INDEX_DISP32, + MODE_PC_INDEX_BASE_DISP, + MODE_PC_PREINDEX, + MODE_PC_POSTINDEX, + MODE_PC_MEM_INDIRECT, + MODE_PC_BASE_DISP, + MODE_ZPC_INDEX_BASE_DISP, + MODE_ZPC_PREINDEX, + MODE_ZPC_POSTINDEX, + MODE_ZPC_MEM_INDIRECT, + MODE_ZPC_BASE_DISP, #endif MODE_IMMEDIATE, MODE_IMMEDIATE_WORD,//used to indicate an immediate operand that only uses a single extension word even for a long operation @@ -247,8 +264,12 @@ typedef struct { uint8_t sec; #ifdef M68020 uint8_t scale; + uint8_t disp_sizes; #endif int32_t displacement; +#ifdef M68020 + int32_t outer_disp; +#endif } regs; uint32_t immed; } params; -- cgit v1.2.3 From 35e8c2700269528268f1e3994e76217ae9769925 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 14 Oct 2014 21:58:17 -0700 Subject: Ignore odd addresses in calls to defer in disassembler --- dis.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dis.c b/dis.c index edd555f..45c7188 100644 --- a/dis.c +++ b/dis.c @@ -75,7 +75,7 @@ typedef struct deferred { deferred * defer(uint32_t address, deferred * next) { - if (is_visited(address)) { + if (is_visited(address) || address & 1) { return next; } //printf("deferring %X\n", address); -- cgit v1.2.3 From 1d2175e51a7a56242b66f6498306ddd0b25c6d04 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 14 Oct 2014 22:17:42 -0700 Subject: Add equates for address references below address_off --- dis.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dis.c b/dis.c index 45c7188..8b447f3 100644 --- a/dis.c +++ b/dis.c @@ -311,6 +311,11 @@ int main(int argc, char ** argv) } } if (labels) { + for (address = 0; address < address_off; address++) { + if (is_label(address)) { + printf("ADR_%X equ $%X\n", address, address); + } + } for (address = filesize; address < (16*1024*1024); address++) { if (is_label(address)) { printf("ADR_%X equ $%X\n", address, address); -- cgit v1.2.3 From 1718b42809a67d9634b4cf5ac7126b03e3209386 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 15 Oct 2014 00:26:57 -0700 Subject: Fix decoding of movec --- 68kinst.c | 1 + 1 file changed, 1 insertion(+) diff --git a/68kinst.c b/68kinst.c index a719440..4842758 100644 --- a/68kinst.c +++ b/68kinst.c @@ -970,6 +970,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) immed = *(++istream); reg = immed >> 12 & 0x7; opmode = immed & 0x8000 ? MODE_AREG : MODE_REG; + immed &= 0xFFF; if (immed & 0x800) { if (immed > MAX_HIGH_CR) { decoded->op = M68K_INVALID; -- cgit v1.2.3 From 56416afb69f0aa098e252e63c65ce6cd7bcc64c6 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 15 Oct 2014 00:30:19 -0700 Subject: Fix interpretation of moves direction field --- 68kinst.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/68kinst.c b/68kinst.c index 4842758..eaeb2e4 100644 --- a/68kinst.c +++ b/68kinst.c @@ -610,13 +610,13 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) reg = immed >> 12 & 0x7; opmode = immed & 0x8000 ? MODE_AREG : MODE_REG; if (immed & 0x800) { - m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->src)); - decoded->dst.addr_mode = opmode; - decoded->dst.params.regs.pri = reg; - } else { decoded->src.addr_mode = opmode; decoded->src.params.regs.pri = reg; m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->dst)); + } else { + m68k_decode_op_ex(istream, *start >> 3 & 0x7, *start & 0x7, decoded->extra.size, &(decoded->src)); + decoded->dst.addr_mode = opmode; + decoded->dst.params.regs.pri = reg; } #endif break; -- cgit v1.2.3 From 1a37b36e7285a87e49c00f12f746d80a36041e59 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 3 Dec 2014 09:26:07 -0800 Subject: Unbreak PC indexed addressing modes in decoder --- 68kinst.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/68kinst.c b/68kinst.c index eaeb2e4..a05c75c 100644 --- a/68kinst.c +++ b/68kinst.c @@ -140,15 +140,6 @@ uint16_t *m68k_decode_op_ex(uint16_t *cur, uint8_t mode, uint8_t reg, uint8_t si dst->params.immed = ext << 16 | *(++cur); break; case 3: -#ifdef M68020 - //TODO: Implement me for M68020+ support; -#else - dst->addr_mode = MODE_PC_INDEX_DISP8; - ext = *(++cur); - dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit - dst->params.regs.displacement = sign_extend8(ext&0xFF); -#endif - ext = *(++cur); dst->params.regs.sec = ext >> 11;//includes areg/dreg bit, reg num and word/long bit #ifdef M68020 -- cgit v1.2.3 From 5b1f68b82cda5b444fa2168d9b24b7101ba4b434 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 3 Dec 2014 09:30:01 -0800 Subject: Temporarily comment out code to translate Z80 instructions in place as in rare cases it can stomp the next instruction if a branch goes from a short from to a long one --- z80_to_x86.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/z80_to_x86.c b/z80_to_x86.c index c46bed8..dc6cfaf 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -1871,6 +1871,7 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o } deferred_addr * orig_deferred = opts->deferred; uint8_t * native_end = translate_z80inst(&instbuf, dst, context, address, 0); + /* if ((native_end - dst) <= orig_size) { uint8_t * native_next = z80_get_native_address(context, address + after-inst); if (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - dst)) > 5)) { @@ -1887,6 +1888,7 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o return orig_start; } } + */ z80_map_native_address(context, address, dst, after-inst, ZMAX_NATIVE_SIZE); opts->cur_code = dst+ZMAX_NATIVE_SIZE; jmp(orig_start, dst); -- cgit v1.2.3 From 77b05f2312cde22951903192667d2a23823890c5 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 3 Dec 2014 09:32:32 -0800 Subject: Initial support for configurable IO, custom IO and sega transfer board emulation --- blastem.c | 2 +- default.cfg | 7 + io.c | 466 +++++++++++++++++++++++++++++++++++++++++++++------ io.h | 51 +++++- vos_program_module.o | Bin 17752 -> 5360 bytes 5 files changed, 464 insertions(+), 62 deletions(-) diff --git a/blastem.c b/blastem.c index 18e11b6..de2d5a5 100644 --- a/blastem.c +++ b/blastem.c @@ -1289,7 +1289,7 @@ int main(int argc, char ** argv) if (i < 0) { strcpy(sram_filename + fname_size, ".sram"); } - set_keybindings(); + set_keybindings(gen.ports); init_run_cpu(&gen, address_log, statefile, debuggerfun); return 0; diff --git a/default.cfg b/default.cfg index 32df104..1b939be 100644 --- a/default.cfg +++ b/default.cfg @@ -54,6 +54,13 @@ bindings { } } +io { + devices { + 1 gamepad6.1 + 2 gamepad6.2 + } +} + video { width 640 vertex_shader default.v.glsl diff --git a/io.c b/io.c index 4935321..3ec8672 100644 --- a/io.c +++ b/io.c @@ -3,15 +3,44 @@ This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ +#include +#include +#include +#include +#include +#include +#include +#include + #include "io.h" #include "blastem.h" #include "render.h" +const char * device_type_names[] = { + "3-button gamepad", + "6-button gamepad", + "Mega Mouse", + "Menacer", + "Justifier", + "Sega multi-tap", + "EA 4-way Play cable A", + "EA 4-way Play cable B", + "Sega Parallel Transfer Board", + "Generic Device", + "None" +}; + enum { BIND_NONE, + BIND_UI, BIND_GAMEPAD1, BIND_GAMEPAD2, - BIND_UI + BIND_GAMEPAD3, + BIND_GAMEPAD4, + BIND_GAMEPAD5, + BIND_GAMEPAD6, + BIND_GAMEPAD7, + BIND_GAMEPAD8 }; typedef enum { @@ -26,6 +55,7 @@ typedef enum { } ui_action; typedef struct { + io_port *port; uint8_t bind_type; uint8_t subtype_a; uint8_t subtype_b; @@ -117,7 +147,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) { + if (gamepadnum < 1 || gamepadnum > 8) { return; } uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; @@ -126,7 +156,7 @@ void bind_gamepad(int keycode, int gamepadnum, int button) void bind_button_gamepad(int joystick, int joybutton, int gamepadnum, int padbutton) { - if (gamepadnum < 1 || gamepadnum > 2) { + if (gamepadnum < 1 || gamepadnum > 8) { return; } uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; @@ -135,7 +165,7 @@ void bind_button_gamepad(int joystick, int joybutton, int gamepadnum, int padbut void bind_dpad_gamepad(int joystick, int dpad, uint8_t direction, int gamepadnum, int button) { - if (gamepadnum < 1 || gamepadnum > 2) { + if (gamepadnum < 1 || gamepadnum > 8) { return; } uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; @@ -159,17 +189,14 @@ void bind_dpad_ui(int joystick, int dpad, uint8_t direction, ui_action action, u void handle_binding_down(keybinding * binding) { - switch(binding->bind_type) + if (binding->bind_type >= BIND_GAMEPAD1) { - case BIND_GAMEPAD1: - case BIND_GAMEPAD2: - if (binding->subtype_a <= GAMEPAD_EXTRA) { - genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_a] |= binding->value; + if (binding->subtype_a <= GAMEPAD_EXTRA && binding->port) { + binding->port->input[binding->subtype_a] |= binding->value; } - if (binding->subtype_b <= GAMEPAD_EXTRA) { - genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_b] |= binding->value; + if (binding->subtype_b <= GAMEPAD_EXTRA && binding->port) { + binding->port->input[binding->subtype_b] |= binding->value; } - break; } } @@ -206,11 +233,11 @@ void handle_binding_up(keybinding * binding) { case BIND_GAMEPAD1: case BIND_GAMEPAD2: - if (binding->subtype_a <= GAMEPAD_EXTRA) { - genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_a] &= ~binding->value; + if (binding->subtype_a <= GAMEPAD_EXTRA && binding->port) { + binding->port->input[binding->subtype_a] &= ~binding->value; } - if (binding->subtype_b <= GAMEPAD_EXTRA) { - genesis->ports[binding->bind_type - BIND_GAMEPAD1].input[binding->subtype_b] &= ~binding->value; + if (binding->subtype_b <= GAMEPAD_EXTRA && binding->port) { + binding->port->input[binding->subtype_b] &= ~binding->value; } break; case BIND_UI: @@ -447,7 +474,169 @@ void process_speeds(tern_node * cur, char * prefix) } } -void set_keybindings() +void process_device(char * device_type, io_port * port) +{ + port->device_type = IO_NONE; + if (!device_type) + { + return; + } + + const int gamepad_len = strlen("gamepad"); + if (!memcmp(device_type, "gamepad", gamepad_len)) + { + if ( + (device_type[gamepad_len] != '3' && device_type[gamepad_len] != '6') + || device_type[gamepad_len+1] != '.' || device_type[gamepad_len+2] < '1' + || device_type[gamepad_len+2] > '8' || device_type[gamepad_len+3] != 0 + ) + { + fprintf(stderr, "%s is not a valid gamepad type\n", device_type); + } else if (device_type[gamepad_len] == '3') + { + port->device_type = IO_GAMEPAD3; + } else { + port->device_type = IO_GAMEPAD6; + } + port->device.pad.gamepad_num = device_type[gamepad_len+2] - '1'; + } else if(!strcmp(device_type, "sega_parallel")) { + port->device_type = IO_SEGA_PARALLEL; + port->device.stream.data_fd = -1; + port->device.stream.listen_fd = -1; + } else if(!strcmp(device_type, "generic")) { + port->device_type = IO_GENERIC; + port->device.stream.data_fd = -1; + port->device.stream.listen_fd = -1; + } +} + +char * io_name(int i) +{ + switch (i) + { + case 0: + return "1"; + case 1: + return "2"; + case 2: + return "EXT"; + default: + return "invalid"; + } +} + +static char * sockfile_name; +static void cleanup_sockfile() +{ + unlink(sockfile_name); +} + +void setup_io_devices(tern_node * config, io_port * ports) +{ + tern_node *io_nodes = tern_find_prefix(config, "iodevices"); + char * io_1 = tern_find_ptr(io_nodes, "1"); + char * io_2 = tern_find_ptr(io_nodes, "2"); + char * io_ext = tern_find_ptr(io_nodes, "ext"); + + process_device(io_1, ports); + process_device(io_2, ports+1); + process_device(io_ext, ports+2); + + for (int i = 0; i < 3; i++) + { + + if (ports[i].device_type == IO_SEGA_PARALLEL) + { + char *pipe_name = tern_find_ptr(config, "ioparallel_pipe"); + if (!pipe_name) + { + fprintf(stderr, "IO port %s is configured to use the sega parallel board, but no paralell_pipe is set!\n", io_name(i)); + ports[i].device_type = IO_NONE; + } else { + printf("IO port: %s connected to device '%s' with pipe name: %s\n", io_name(i), device_type_names[ports[i].device_type], pipe_name); + if (!strcmp("stdin", pipe_name)) + { + ports[i].device.stream.data_fd = STDIN_FILENO; + } else { + if (mkfifo(pipe_name, 0666) && errno != EEXIST) + { + fprintf(stderr, "Failed to create fifo %s for Sega parallel board emulation: %d %s\n", pipe_name, errno, strerror(errno)); + ports[i].device_type = IO_NONE; + } else { + ports[i].device.stream.data_fd = open(pipe_name, O_NONBLOCK | O_RDONLY); + if (ports[i].device.stream.data_fd == -1) + { + fprintf(stderr, "Failed to open fifo %s for Sega parallel board emulation: %d %s\n", pipe_name, errno, strerror(errno)); + ports[i].device_type = IO_NONE; + } + } + } + } + } else if (ports[i].device_type == IO_GENERIC) { + char *sock_name = tern_find_ptr(config, "iosocket"); + if (!sock_name) + { + fprintf(stderr, "IO port %s is configured to use generic IO, but no socket is set!\n", io_name(i)); + ports[i].device_type = IO_NONE; + } else { + printf("IO port: %s connected to device '%s' with socket name: %s\n", io_name(i), device_type_names[ports[i].device_type], sock_name); + ports[i].device.stream.data_fd = -1; + ports[i].device.stream.listen_fd = socket(AF_UNIX, SOCK_STREAM, 0); + size_t pathlen = strlen(sock_name); + size_t addrlen = offsetof(struct sockaddr_un, sun_path) + pathlen + 1; + struct sockaddr_un *saddr = malloc(addrlen); + saddr->sun_family = AF_UNIX; + memcpy(saddr->sun_path, sock_name, pathlen+1); + if (bind(ports[i].device.stream.listen_fd, (struct sockaddr *)saddr, addrlen)) + { + fprintf(stderr, "Failed to bind socket for IO Port %s to path %s: %d %s\n", io_name(i), sock_name, errno, strerror(errno)); + goto cleanup_sock; + } + if (listen(ports[i].device.stream.listen_fd, 1)) + { + fprintf(stderr, "Failed to listen on socket for IO Port %s: %d %s\n", io_name(i), errno, strerror(errno)); + goto cleanup_sockfile; + } + sockfile_name = sock_name; + atexit(cleanup_sockfile); + continue; +cleanup_sockfile: + unlink(sock_name); +cleanup_sock: + close(ports[i].device.stream.listen_fd); + ports[i].device_type = IO_NONE; + } + } else if (ports[i].device_type == IO_GAMEPAD3 || ports[i].device_type == IO_GAMEPAD6) { + printf("IO port %s connected to gamepad #%d with type '%s'\n", io_name(i), ports[i].device.pad.gamepad_num + 1, device_type_names[ports[i].device_type]); + } else { + printf("IO port %s connected to device '%s'\n", io_name(i), device_type_names[ports[i].device_type]); + } + } +} + +void map_bindings(io_port *ports, keybinding *bindings, int numbindings) +{ + for (int i = 0; i < numbindings; i++) + { + if (bindings[i].bind_type >= BIND_GAMEPAD1) + { + int num = bindings[i].bind_type - BIND_GAMEPAD1; + for (int j = 0; j < 3; j++) + { + if ((ports[j].device_type == IO_GAMEPAD3 + || ports[j].device_type ==IO_GAMEPAD6) + && ports[j].device.pad.gamepad_num == num + ) + { + bindings[i].port = ports + j; + break; + } + } + } + } +} + +void set_keybindings(io_port *ports) { tern_node * special = tern_insert_int(NULL, "up", RENDERKEY_UP); special = tern_insert_int(special, "down", RENDERKEY_DOWN); @@ -532,76 +721,245 @@ void set_keybindings() speeds = malloc(sizeof(uint32_t)); speeds[0] = 100; process_speeds(speed_nodes, NULL); - for (int i = 0; i < num_speeds; i++) { + for (int i = 0; i < num_speeds; i++) + { if (!speeds[i]) { fprintf(stderr, "Speed index %d was not set to a valid percentage!", i); speeds[i] = 100; } } + for (int bucket = 0; bucket < 256; bucket++) + { + if (bindings[bucket]) + { + map_bindings(ports, bindings[bucket], 256); + } + } + for (int stick = 0; stick < MAX_JOYSTICKS; stick++) + { + if (joybindings[stick]) + { + int numbuttons = render_joystick_num_buttons(stick); + map_bindings(ports, joybindings[stick], render_joystick_num_buttons(stick)); + } + if (joydpads[stick]) + { + map_bindings(ports, joydpads[stick]->bindings, 4); + } + } } #define TH 0x40 #define TH_TIMEOUT 8000 -void io_adjust_cycles(io_port * pad, uint32_t current_cycle, uint32_t deduction) +void io_adjust_cycles(io_port * port, uint32_t current_cycle, uint32_t deduction) { /*uint8_t control = pad->control | 0x80; uint8_t th = control & pad->output; if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) { printf("adjust_cycles | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, pad->input[GAMEPAD_TH0], pad->input[GAMEPAD_TH1], pad->th_counter,pad->timeout_cycle, current_cycle); }*/ - if (current_cycle >= pad->timeout_cycle) { - pad->th_counter = 0; - } else { - pad->timeout_cycle -= deduction; + if (port->device_type == IO_GAMEPAD6) + { + if (current_cycle >= port->device.pad.timeout_cycle) + { + port->device.pad.th_counter = 0; + } else { + port->device.pad.timeout_cycle -= deduction; + } + } +} + +static void wait_for_connection(io_port * port) +{ + if (port->device.stream.data_fd == -1) + { + puts("Waiting for socket connection..."); + port->device.stream.data_fd = accept(port->device.stream.listen_fd, NULL, NULL); + fcntl(port->device.stream.data_fd, F_SETFL, O_NONBLOCK | O_RDWR); } } -void io_data_write(io_port * pad, uint8_t value, uint32_t current_cycle) +static void service_pipe(io_port * port) { - if (pad->control & TH) { - //check if TH has changed - if ((pad->output & TH) ^ (value & TH)) { - if (current_cycle >= pad->timeout_cycle) { - pad->th_counter = 0; + uint8_t value; + int numRead = read(port->device.stream.data_fd, &value, sizeof(value)); + if (numRead > 0) + { + port->input[IO_TH0] = (value & 0xF) | 0x10; + port->input[IO_TH1] = (value >> 4) | 0x10; + } else if(numRead == -1 && errno != EAGAIN && errno != EWOULDBLOCK) { + fprintf(stderr, "Error reading pipe for IO port: %d %s\n", errno, strerror(errno)); + } +} + +static void service_socket(io_port *port) +{ + uint8_t buf[32]; + uint8_t blocking = 0; + int numRead = 0; + while (numRead <= 0) + { + numRead = recv(port->device.stream.data_fd, buf, sizeof(buf), 0); + if (numRead > 0) + { + port->input[IO_TH0] = buf[numRead-1]; + if (port->input[IO_STATE] == IO_READ_PENDING) + { + port->input[IO_STATE] = IO_READ; + if (blocking) + { + //pending read satisfied, back to non-blocking mode + fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR | O_NONBLOCK); + } + } else if (port->input[IO_STATE] == IO_WRITTEN) { + port->input[IO_STATE] = IO_READ; } - if (!(value & TH)) { - pad->th_counter++; + } else if (numRead == 0) { + port->device.stream.data_fd = -1; + wait_for_connection(port); + } else if (errno != EAGAIN && errno != EWOULDBLOCK) { + fprintf(stderr, "Error reading from socket for IO port: %d %s\n", errno, strerror(errno)); + close(port->device.stream.data_fd); + wait_for_connection(port); + } else if (port->input[IO_STATE] == IO_READ_PENDING) { + //clear the nonblocking flag so the next read will block + if (!blocking) + { + fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR); + blocking = 1; + } + } else { + //no new data, but that's ok + break; + } + } + + if (port->input[IO_STATE] == IO_WRITE_PENDING) + { + uint8_t value = port->output & port->control; + int written = 0; + blocking = 0; + while (written <= 0) + { + send(port->device.stream.data_fd, &value, sizeof(value), 0); + if (written > 0) + { + port->input[IO_STATE] = IO_WRITTEN; + if (blocking) + { + //pending write satisfied, back to non-blocking mode + fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR | O_NONBLOCK); + } + } else if (written == 0) { + port->device.stream.data_fd = -1; + wait_for_connection(port); + } else if (errno != EAGAIN && errno != EWOULDBLOCK) { + fprintf(stderr, "Error writing to socket for IO port: %d %s\n", errno, strerror(errno)); + close(port->device.stream.data_fd); + wait_for_connection(port); + } else { + //clear the nonblocking flag so the next write will block + if (!blocking) + { + fcntl(port->device.stream.data_fd, F_SETFL, O_RDWR); + blocking = 1; + } } - pad->timeout_cycle = current_cycle + TH_TIMEOUT; } } - pad->output = value; } -uint8_t io_data_read(io_port * pad, uint32_t current_cycle) +void io_data_write(io_port * port, uint8_t value, uint32_t current_cycle) { - uint8_t control = pad->control | 0x80; - uint8_t th = control & pad->output; + switch (port->device_type) + { + case IO_GAMEPAD6: + if (port->control & TH) { + //check if TH has changed + if ((port->output & TH) ^ (value & TH)) { + if (current_cycle >= port->device.pad.timeout_cycle) { + port->device.pad.th_counter = 0; + } + if (!(value & TH)) { + port->device.pad.th_counter++; + } + port->device.pad.timeout_cycle = current_cycle + TH_TIMEOUT; + } + } + port->output = value; + break; + case IO_GENERIC: + wait_for_connection(port); + port->input[IO_STATE] = IO_WRITE_PENDING; + port->output = value; + service_socket(port); + break; + default: + port->output = value; + } + +} + +uint8_t io_data_read(io_port * port, uint32_t current_cycle) +{ + uint8_t control = port->control | 0x80; + uint8_t th = control & port->output & 0x40; uint8_t input; - if (current_cycle >= pad->timeout_cycle) { - pad->th_counter = 0; + switch (port->device_type) + { + case IO_GAMEPAD3: + { + input = port->input[th ? GAMEPAD_TH1 : GAMEPAD_TH0]; + break; } - /*if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) { - printf("io_data_read | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, pad->input[GAMEPAD_TH0], pad->input[GAMEPAD_TH1], pad->th_counter,pad->timeout_cycle, context->current_cycle); - }*/ - if (th) { - if (pad->th_counter == 3) { - input = pad->input[GAMEPAD_EXTRA]; - } else { - input = pad->input[GAMEPAD_TH1]; + case IO_GAMEPAD6: + { + if (current_cycle >= port->device.pad.timeout_cycle) { + port->device.pad.th_counter = 0; } - } else { - if (pad->th_counter == 3) { - input = pad->input[GAMEPAD_TH0] | 0xF; - } else if(pad->th_counter == 4) { - input = pad->input[GAMEPAD_TH0] & 0x30; + /*if (port->input[GAMEPAD_TH0] || port->input[GAMEPAD_TH1]) { + printf("io_data_read | control: %X, TH: %X, GAMEPAD_TH0: %X, GAMEPAD_TH1: %X, TH Counter: %d, Timeout: %d, Cycle: %d\n", control, th, port->input[GAMEPAD_TH0], port->input[GAMEPAD_TH1], port->th_counter,port->timeout_cycle, context->current_cycle); + }*/ + if (th) { + if (port->device.pad.th_counter == 3) { + input = port->input[GAMEPAD_EXTRA]; + } else { + input = port->input[GAMEPAD_TH1]; + } } else { - input = pad->input[GAMEPAD_TH0] | 0xC; + if (port->device.pad.th_counter == 3) { + input = port->input[GAMEPAD_TH0] | 0xF; + } else if(port->device.pad.th_counter == 4) { + input = port->input[GAMEPAD_TH0] & 0x30; + } else { + input = port->input[GAMEPAD_TH0] | 0xC; + } } + break; + } + case IO_SEGA_PARALLEL: + if (!th) + { + service_pipe(port); + } + input = ~port->input[th ? IO_TH1 : IO_TH0]; + break; + case IO_GENERIC: + if (port->input[IO_TH0] & 0x80 && port->input[IO_STATE] == IO_WRITTEN) + { + //device requested a blocking read after writes + port->input[IO_STATE] = IO_READ_PENDING; + } + service_socket(port); + input = ~port->input[IO_TH0]; + break; + default: + input = 0; + break; } - uint8_t value = ((~input) & (~control)) | (pad->output & control); - /*if (pad->input[GAMEPAD_TH0] || pad->input[GAMEPAD_TH1]) { + uint8_t value = ((~input) & (~control)) | (port->output & control); + /*if (port->input[GAMEPAD_TH0] || port->input[GAMEPAD_TH1]) { printf ("value: %X\n", value); }*/ return value; diff --git a/io.h b/io.h index b0fd1e9..b73be67 100644 --- a/io.h +++ b/io.h @@ -1,18 +1,43 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #ifndef IO_H_ #define IO_H_ #include +#include "tern.h" + +enum { + IO_GAMEPAD3, + IO_GAMEPAD6, + IO_MOUSE, + IO_MENACER, + IO_JUSTIFIER, + IO_SEGA_MULTI, + IO_EA_MULTI_A, + IO_EA_MULTI_B, + IO_SEGA_PARALLEL, + IO_GENERIC, + IO_NONE +}; typedef struct { - uint32_t th_counter; - uint32_t timeout_cycle; - uint8_t output; - uint8_t control; - uint8_t input[3]; + union { + struct { + uint32_t timeout_cycle; + uint16_t th_counter; + uint16_t gamepad_num; + } pad; + struct { + int data_fd; + int listen_fd; + } stream; + } device; + uint8_t output; + uint8_t control; + uint8_t input[3]; + uint8_t device_type; } io_port; #define GAMEPAD_TH0 0 @@ -20,7 +45,19 @@ typedef struct { #define GAMEPAD_EXTRA 2 #define GAMEPAD_NONE 0xF -void set_keybindings(); +#define IO_TH0 0 +#define IO_TH1 1 +#define IO_STATE 2 + +enum { + IO_WRITE_PENDING, + IO_WRITTEN, + IO_READ_PENDING, + IO_READ +}; + +void set_keybindings(io_port *ports); +void setup_io_devices(tern_node * config, io_port * ports); void io_adjust_cycles(io_port * pad, uint32_t current_cycle, uint32_t deduction); void io_data_write(io_port * pad, uint8_t value, uint32_t current_cycle); uint8_t io_data_read(io_port * pad, uint32_t current_cycle); diff --git a/vos_program_module.o b/vos_program_module.o index 5208bcf..3066b9d 100644 Binary files a/vos_program_module.o and b/vos_program_module.o differ -- cgit v1.2.3 From d07b907bc7889308890b590d2aaf88dfc44ae616 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 14 Dec 2014 16:45:23 -0800 Subject: WIP effort to update z80 core for code gen changes --- backend.h | 2 +- backend_x86.c | 5 +- blastem.c | 13 +- m68k_core_x86.c | 10 +- z80_to_x86.c | 997 +++++++++++++++++++++++++++++++------------------------- z80_to_x86.h | 17 +- 6 files changed, 592 insertions(+), 452 deletions(-) diff --git a/backend.h b/backend.h index 0106759..97e2ae4 100644 --- a/backend.h +++ b/backend.h @@ -108,7 +108,7 @@ void cycles(cpu_options *opts, uint32_t num); void check_cycles_int(cpu_options *opts, uint32_t address); void check_cycles(cpu_options * opts); -code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk * memmap, uint32_t num_chunks, ftype fun_type); +code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc); #endif //BACKEND_H_ diff --git a/backend_x86.c b/backend_x86.c index 3b291fe..7f75761 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -28,12 +28,15 @@ void check_cycles(cpu_options * opts) *jmp_off = code->cur - (jmp_off+1); } -code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk * memmap, uint32_t num_chunks, ftype fun_type) +code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc) { code_info *code = &opts->code; code_ptr start = code->cur; check_cycles(opts); cycles(opts, opts->bus_cycles); + if (after_inc) { + *after_inc = code->cur; + } if (opts->address_size == SZ_D && opts->address_mask < 0xFFFFFFFF) { and_ir(code, opts->address_mask, opts->scratch1, SZ_D); } diff --git a/blastem.c b/blastem.c index 7d31540..4555f86 100644 --- a/blastem.c +++ b/blastem.c @@ -1072,6 +1072,15 @@ void detect_region() } } } +#ifndef NO_Z80 +const memmap_chunk z80_map[] = { + { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL }, + { 0x8000, 0x10000, 0xFFFF, 1, MMAP_READ | MMAP_WRITE | MMAP_PTR_IDX | MMAP_FUNC_NULL, NULL, NULL, NULL, z80_read_bank, z80_write_bank}, + { 0x4000, 0x6000, 0x0003, 0, MMAP_READ | MMAP_WRITE, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, + { 0x6000, 0x6100, 0xFFFF, 0, MMAP_WRITE | MMAP_CUSTOM, NULL, NULL, NULL, NULL, (write_8_fun)z80_gen_bank_write}, + { 0x7F00, 0x8000, 0x00FF, 0, MMAP_READ | MMAP_WRITE, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} +}; +#endif int main(int argc, char ** argv) { @@ -1237,9 +1246,9 @@ int main(int argc, char ** argv) psg_init(&p_context, render_sample_rate(), gen.master_clock, MCLKS_PER_PSG, render_audio_buffer()); z80_context z_context; - x86_z80_options z_opts; #ifndef NO_Z80 - init_x86_z80_opts(&z_opts); + z80_options z_opts; + init_x86_z80_opts(&z_opts, z80_map, 5); init_z80_context(&z_context, &z_opts); #endif diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 6c37fad..18feea7 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -2390,10 +2390,12 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu *skip_sync = code->cur - (skip_sync+1); retn(code); - opts->read_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_16); - opts->read_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_8); - opts->write_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_16); - opts->write_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_8); + opts->gen.handle_code_write = (code_ptr)m68k_handle_code_write; + + opts->read_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_16, NULL); + opts->read_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_8, NULL); + opts->write_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_16, NULL); + opts->write_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_8, NULL); opts->read_32 = code->cur; push_r(code, opts->gen.scratch1); diff --git a/z80_to_x86.c b/z80_to_x86.c index 2cab1c9..a331308 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -54,24 +54,9 @@ uint8_t z80_size(z80inst * inst) return SZ_B; } -uint8_t * zcycles(uint8_t * dst, uint32_t num_cycles) -{ - return add_ir(dst, num_cycles, ZCYCLES, SZ_D); -} - -uint8_t * z80_check_cycles_int(uint8_t * dst, uint16_t address) -{ - dst = cmp_rr(dst, ZCYCLES, ZLIMIT, SZ_D); - uint8_t * jmp_off = dst+1; - dst = jcc(dst, CC_NC, dst + 7); - dst = mov_ir(dst, address, SCRATCH1, SZ_W); - dst = call(dst, (uint8_t *)z80_handle_cycle_limit_int); - *jmp_off = dst - (jmp_off+1); - return dst; -} - -uint8_t * translate_z80_reg(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_options * opts) +void translate_z80_reg(z80inst * inst, x86_ea * ea, z80_options * opts) { + code_info *code = &opts->gen.code; if (inst->reg == Z80_USE_IMMED) { ea->mode = MODE_IMMED; ea->disp = inst->immed; @@ -81,12 +66,12 @@ uint8_t * translate_z80_reg(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_ ea->mode = MODE_REG_DIRECT; if (inst->reg == Z80_IYH) { if ((inst->addr_mode & 0x1F) == Z80_REG && inst->ea_reg == Z80_IYL) { - dst = mov_rr(dst, opts->regs[Z80_IY], SCRATCH1, SZ_W); - dst = ror_ir(dst, 8, SCRATCH1, SZ_W); - ea->base = SCRATCH1; + mov_rr(code, opts->regs[Z80_IY], opts->gen.scratch1, SZ_W); + ror_ir(code, 8, opts->gen.scratch1, SZ_W); + ea->base = opts->gen.scratch1; } else { ea->base = opts->regs[Z80_IYL]; - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); } } else if(opts->regs[inst->reg] >= 0) { ea->base = opts->regs[inst->reg]; @@ -96,64 +81,64 @@ uint8_t * translate_z80_reg(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_ if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) { //we can't mix an *H reg with a register that requires the REX prefix ea->base = opts->regs[z80_low_reg(inst->reg)]; - dst = ror_ir(dst, 8, ea->base, SZ_W); + ror_ir(code, 8, ea->base, SZ_W); } } else if((inst->addr_mode & 0x1F) != Z80_UNUSED && (inst->addr_mode & 0x1F) != Z80_IMMED) { //temp regs require REX prefix too ea->base = opts->regs[z80_low_reg(inst->reg)]; - dst = ror_ir(dst, 8, ea->base, SZ_W); + ror_ir(code, 8, ea->base, SZ_W); } } } else { ea->mode = MODE_REG_DISPLACE8; - ea->base = CONTEXT; + ea->base = opts->gen.context_reg; ea->disp = offsetof(z80_context, regs) + inst->reg; } } - return dst; } -uint8_t * z80_save_reg(uint8_t * dst, z80inst * inst, x86_z80_options * opts) +void z80_save_reg(z80inst * inst, z80_options * opts) { + code_info *code = &opts->gen.code; if (inst->reg == Z80_IYH) { if ((inst->addr_mode & 0x1F) == Z80_REG && inst->ea_reg == Z80_IYL) { - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); - dst = mov_rr(dst, SCRATCH1, opts->regs[Z80_IYL], SZ_B); - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); + mov_rr(code, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); } else { - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); } } else if (opts->regs[inst->reg] >= AH && opts->regs[inst->reg] <= BH) { if ((inst->addr_mode & 0x1F) == Z80_REG) { uint8_t other_reg = opts->regs[inst->ea_reg]; if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) { //we can't mix an *H reg with a register that requires the REX prefix - dst = ror_ir(dst, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W); + ror_ir(code, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W); } } else if((inst->addr_mode & 0x1F) != Z80_UNUSED && (inst->addr_mode & 0x1F) != Z80_IMMED) { //temp regs require REX prefix too - dst = ror_ir(dst, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W); + ror_ir(code, 8, opts->regs[z80_low_reg(inst->reg)], SZ_W); } } - return dst; } -uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_options * opts, uint8_t read, uint8_t modify) +void translate_z80_ea(z80inst * inst, x86_ea * ea, z80_options * opts, uint8_t read, uint8_t modify) { + code_info *code = &opts->gen.code; uint8_t size, reg, areg; ea->mode = MODE_REG_DIRECT; - areg = read ? SCRATCH1 : SCRATCH2; + areg = read ? opts->gen.scratch1 : opts->gen.scratch2; switch(inst->addr_mode & 0x1F) { case Z80_REG: if (inst->ea_reg == Z80_IYH) { if (inst->reg == Z80_IYL) { - dst = mov_rr(dst, opts->regs[Z80_IY], SCRATCH1, SZ_W); - dst = ror_ir(dst, 8, SCRATCH1, SZ_W); - ea->base = SCRATCH1; + mov_rr(code, opts->regs[Z80_IY], opts->gen.scratch1, SZ_W); + ror_ir(code, 8, opts->gen.scratch1, SZ_W); + ea->base = opts->gen.scratch1; } else { ea->base = opts->regs[Z80_IYL]; - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); } } else { ea->base = opts->regs[inst->ea_reg]; @@ -162,30 +147,30 @@ uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_o if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) { //we can't mix an *H reg with a register that requires the REX prefix ea->base = opts->regs[z80_low_reg(inst->ea_reg)]; - dst = ror_ir(dst, 8, ea->base, SZ_W); + ror_ir(code, 8, ea->base, SZ_W); } } } break; case Z80_REG_INDIRECT: - dst = mov_rr(dst, opts->regs[inst->ea_reg], areg, SZ_W); + mov_rr(code, opts->regs[inst->ea_reg], areg, SZ_W); size = z80_size(inst); if (read) { if (modify) { - //dst = push_r(dst, SCRATCH1); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(z80_context, scratch1), SZ_W); + //push_r(code, opts->gen.scratch1); + mov_rrdisp8(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W); } if (size == SZ_B) { - dst = call(dst, (uint8_t *)z80_read_byte); + call(code, opts->read_8); } else { - dst = call(dst, (uint8_t *)z80_read_word); + dst = call(dst, opts->read_16); } if (modify) { - //dst = pop_r(dst, SCRATCH2); - dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, scratch1), SCRATCH2, SZ_W); + //pop_r(code, opts->gen.scratch2); + mov_rdisp8r(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch2, SZ_W); } } - ea->base = SCRATCH1; + ea->base = opts->gen.scratch1; break; case Z80_IMMED: ea->mode = MODE_IMMED; @@ -196,7 +181,7 @@ uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_o size = z80_size(inst); if (read) { /*if (modify) { - dst = push_r(dst, SCRATCH1); + dst = push_r(dst, opts->gen.scratch1); }*/ if (size == SZ_B) { dst = call(dst, (uint8_t *)z80_read_byte); @@ -204,11 +189,11 @@ uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_o dst = call(dst, (uint8_t *)z80_read_word); } if (modify) { - //dst = pop_r(dst, SCRATCH2); - dst = mov_ir(dst, inst->immed, SCRATCH2, SZ_W); + //dst = pop_r(dst, opts->gen.scratch2); + dst = mov_ir(dst, inst->immed, opts->gen.scratch2, SZ_W); } } - ea->base = SCRATCH1; + ea->base = opts->gen.scratch1; break; case Z80_IX_DISPLACE: case Z80_IY_DISPLACE: @@ -218,8 +203,8 @@ uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_o size = z80_size(inst); if (read) { if (modify) { - //dst = push_r(dst, SCRATCH1); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, offsetof(z80_context, scratch1), SZ_W); + //dst = push_r(dst, opts->gen.scratch1); + dst = mov_rrdisp8(dst, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W); } if (size == SZ_B) { dst = call(dst, (uint8_t *)z80_read_byte); @@ -227,11 +212,11 @@ uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_o dst = call(dst, (uint8_t *)z80_read_word); } if (modify) { - //dst = pop_r(dst, SCRATCH2); - dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, scratch1), SCRATCH2, SZ_W); + //dst = pop_r(dst, opts->gen.scratch2); + dst = mov_rdisp8r(dst, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch2, SZ_W); } } - ea->base = SCRATCH1; + ea->base = opts->gen.scratch1; break; case Z80_UNUSED: ea->mode = MODE_UNUSED; @@ -243,13 +228,13 @@ uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_o return dst; } -uint8_t * z80_save_ea(uint8_t * dst, z80inst * inst, x86_z80_options * opts) +uint8_t * z80_save_ea(uint8_t * dst, z80inst * inst, z80_options * opts) { if ((inst->addr_mode & 0x1F) == Z80_REG) { if (inst->ea_reg == Z80_IYH) { if (inst->reg == Z80_IYL) { dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); - dst = mov_rr(dst, SCRATCH1, opts->regs[Z80_IYL], SZ_B); + dst = mov_rr(dst, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B); dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); } else { dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); @@ -326,14 +311,14 @@ void z80_print_regs_exit(z80_context * context) exit(0); } -uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context, uint16_t address) +uint8_t * translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) { uint32_t cycles; x86_ea src_op, dst_op; uint8_t size; - x86_z80_options *opts = context->options; - uint8_t * start = dst; - dst = z80_check_cycles_int(dst, address); + z80_options *opts = context->options; + uint8_t * start = opts->code.cur; + check_cycles_int(&opts->gen, address); switch(inst->op) { case Z80_LD: @@ -364,7 +349,7 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context if ((inst->reg >= Z80_IXL && inst->reg <= Z80_IYH) || inst->reg == Z80_IX || inst->reg == Z80_IY) { cycles += 4; } - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); if (inst->addr_mode & Z80_DIR) { dst = translate_z80_ea(inst, &dst_op, dst, opts, DONT_READ, MODIFY); dst = translate_z80_reg(inst, &src_op, dst, opts); @@ -390,55 +375,55 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } break; case Z80_PUSH: - dst = zcycles(dst, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5); + dst = cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5); dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W); if (inst->reg == Z80_AF) { - dst = mov_rr(dst, opts->regs[Z80_A], SCRATCH1, SZ_B); - dst = shl_ir(dst, 8, SCRATCH1, SZ_W); - dst = mov_rdisp8r(dst, CONTEXT, zf_off(ZF_S), SCRATCH1, SZ_B); - dst = shl_ir(dst, 1, SCRATCH1, SZ_B); - dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_Z), SCRATCH1, SZ_B); - dst = shl_ir(dst, 2, SCRATCH1, SZ_B); - dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_H), SCRATCH1, SZ_B); - dst = shl_ir(dst, 2, SCRATCH1, SZ_B); - dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_PV), SCRATCH1, SZ_B); - dst = shl_ir(dst, 1, SCRATCH1, SZ_B); - dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_N), SCRATCH1, SZ_B); - dst = shl_ir(dst, 1, SCRATCH1, SZ_B); - dst = or_rdisp8r(dst, CONTEXT, zf_off(ZF_C), SCRATCH1, SZ_B); + dst = mov_rr(dst, opts->regs[Z80_A], opts->gen.scratch1, SZ_B); + dst = shl_ir(dst, 8, opts->gen.scratch1, SZ_W); + dst = mov_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_S), opts->gen.scratch1, SZ_B); + dst = shl_ir(dst, 1, opts->gen.scratch1, SZ_B); + dst = or_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_Z), opts->gen.scratch1, SZ_B); + dst = shl_ir(dst, 2, opts->gen.scratch1, SZ_B); + dst = or_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch1, SZ_B); + dst = shl_ir(dst, 2, opts->gen.scratch1, SZ_B); + dst = or_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_PV), opts->gen.scratch1, SZ_B); + dst = shl_ir(dst, 1, opts->gen.scratch1, SZ_B); + dst = or_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_N), opts->gen.scratch1, SZ_B); + dst = shl_ir(dst, 1, opts->gen.scratch1, SZ_B); + dst = or_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_C), opts->gen.scratch1, SZ_B); } else { dst = translate_z80_reg(inst, &src_op, dst, opts); - dst = mov_rr(dst, src_op.base, SCRATCH1, SZ_W); + dst = mov_rr(dst, src_op.base, opts->gen.scratch1, SZ_W); } - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); dst = call(dst, (uint8_t *)z80_write_word_highfirst); //no call to save_z80_reg needed since there's no chance we'll use the only //the upper half of a register pair break; case Z80_POP: - dst = zcycles(dst, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W); + dst = cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4); + dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_read_word); dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); if (inst->reg == Z80_AF) { - dst = bt_ir(dst, 0, SCRATCH1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = bt_ir(dst, 1, SCRATCH1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_N)); - dst = bt_ir(dst, 2, SCRATCH1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_PV)); - dst = bt_ir(dst, 4, SCRATCH1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_H)); - dst = bt_ir(dst, 6, SCRATCH1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_Z)); - dst = bt_ir(dst, 7, SCRATCH1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_S)); - dst = shr_ir(dst, 8, SCRATCH1, SZ_W); - dst = mov_rr(dst, SCRATCH1, opts->regs[Z80_A], SZ_B); + dst = bt_ir(dst, 0, opts->gen.scratch1, SZ_W); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = bt_ir(dst, 1, opts->gen.scratch1, SZ_W); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_N)); + dst = bt_ir(dst, 2, opts->gen.scratch1, SZ_W); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_PV)); + dst = bt_ir(dst, 4, opts->gen.scratch1, SZ_W); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_H)); + dst = bt_ir(dst, 6, opts->gen.scratch1, SZ_W); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_Z)); + dst = bt_ir(dst, 7, opts->gen.scratch1, SZ_W); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_S)); + dst = shr_ir(dst, 8, opts->gen.scratch1, SZ_W); + dst = mov_rr(dst, opts->gen.scratch1, opts->regs[Z80_A], SZ_B); } else { dst = translate_z80_reg(inst, &src_op, dst, opts); - dst = mov_rr(dst, SCRATCH1, src_op.base, SZ_W); + dst = mov_rr(dst, opts->gen.scratch1, src_op.base, SZ_W); } //no call to save_z80_reg needed since there's no chance we'll use the only //the upper half of a register pair @@ -449,31 +434,31 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else { cycles = 8; } - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); if (inst->addr_mode == Z80_REG) { if(inst->reg == Z80_AF) { - dst = mov_rr(dst, opts->regs[Z80_A], SCRATCH1, SZ_B); - dst = mov_rdisp8r(dst, CONTEXT, zar_off(Z80_A), opts->regs[Z80_A], SZ_B); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zar_off(Z80_A), SZ_B); + dst = mov_rr(dst, opts->regs[Z80_A], opts->gen.scratch1, SZ_B); + dst = mov_rdisp8r(dst, opts->gen.context_reg, zar_off(Z80_A), opts->regs[Z80_A], SZ_B); + dst = mov_rrdisp8(dst, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_A), SZ_B); //Flags are currently word aligned, so we can move //them efficiently a word at a time for (int f = ZF_C; f < ZF_NUM; f+=2) { - dst = mov_rdisp8r(dst, CONTEXT, zf_off(f), SCRATCH1, SZ_W); - dst = mov_rdisp8r(dst, CONTEXT, zaf_off(f), SCRATCH2, SZ_W); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zaf_off(f), SZ_W); - dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, zf_off(f), SZ_W); + dst = mov_rdisp8r(dst, opts->gen.context_reg, zf_off(f), opts->gen.scratch1, SZ_W); + dst = mov_rdisp8r(dst, opts->gen.context_reg, zaf_off(f), opts->gen.scratch2, SZ_W); + dst = mov_rrdisp8(dst, opts->gen.scratch1, opts->gen.context_reg, zaf_off(f), SZ_W); + dst = mov_rrdisp8(dst, opts->gen.scratch2, opts->gen.context_reg, zf_off(f), SZ_W); } } else { dst = xchg_rr(dst, opts->regs[Z80_DE], opts->regs[Z80_HL], SZ_W); } } else { - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_read_byte); - dst = xchg_rr(dst, opts->regs[inst->reg], SCRATCH1, SZ_B); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W); + dst = xchg_rr(dst, opts->regs[inst->reg], opts->gen.scratch1, SZ_B); + dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); dst = call(dst, (uint8_t *)z80_write_byte); - dst = zcycles(dst, 1); + dst = cycles(&opts->gen, 1); uint8_t high_reg = z80_high_reg(inst->reg); uint8_t use_reg; //even though some of the upper halves can be used directly @@ -481,50 +466,50 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context //prevent us from taking advantage of it use_reg = opts->regs[inst->reg]; dst = ror_ir(dst, 8, use_reg, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W); - dst = add_ir(dst, 1, SCRATCH1, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + dst = add_ir(dst, 1, opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_read_byte); - dst = xchg_rr(dst, use_reg, SCRATCH1, SZ_B); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W); - dst = add_ir(dst, 1, SCRATCH2, SZ_W); + dst = xchg_rr(dst, use_reg, opts->gen.scratch1, SZ_B); + dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); + dst = add_ir(dst, 1, opts->gen.scratch2, SZ_W); dst = call(dst, (uint8_t *)z80_write_byte); //restore reg to normal rotation dst = ror_ir(dst, 8, use_reg, SZ_W); - dst = zcycles(dst, 2); + dst = cycles(&opts->gen, 2); } break; case Z80_EXX: - dst = zcycles(dst, 4); - dst = mov_rr(dst, opts->regs[Z80_BC], SCRATCH1, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH2, SZ_W); - dst = mov_rdisp8r(dst, CONTEXT, zar_off(Z80_C), opts->regs[Z80_BC], SZ_W); - dst = mov_rdisp8r(dst, CONTEXT, zar_off(Z80_L), opts->regs[Z80_HL], SZ_W); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zar_off(Z80_C), SZ_W); - dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, zar_off(Z80_L), SZ_W); - dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH1, SZ_W); - dst = mov_rdisp8r(dst, CONTEXT, zar_off(Z80_E), opts->regs[Z80_DE], SZ_W); - dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zar_off(Z80_E), SZ_W); + dst = cycles(&opts->gen, 4); + dst = mov_rr(dst, opts->regs[Z80_BC], opts->gen.scratch1, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); + dst = mov_rdisp8r(dst, opts->gen.context_reg, zar_off(Z80_C), opts->regs[Z80_BC], SZ_W); + dst = mov_rdisp8r(dst, opts->gen.context_reg, zar_off(Z80_L), opts->regs[Z80_HL], SZ_W); + dst = mov_rrdisp8(dst, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_C), SZ_W); + dst = mov_rrdisp8(dst, opts->gen.scratch2, opts->gen.context_reg, zar_off(Z80_L), SZ_W); + dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.scratch1, SZ_W); + dst = mov_rdisp8r(dst, opts->gen.context_reg, zar_off(Z80_E), opts->regs[Z80_DE], SZ_W); + dst = mov_rrdisp8(dst, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_E), SZ_W); break; case Z80_LDI: { - dst = zcycles(dst, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W); + dst = cycles(&opts->gen, 8); + dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_read_byte); - dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); dst = call(dst, (uint8_t *)z80_write_byte); - dst = zcycles(dst, 2); + dst = cycles(&opts->gen, 2); dst = add_ir(dst, 1, opts->regs[Z80_DE], SZ_W); dst = add_ir(dst, 1, opts->regs[Z80_HL], SZ_W); dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W); //TODO: Implement half-carry - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_NZ, CONTEXT, zf_off(ZF_PV)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV)); break; } case Z80_LDIR: { - dst = zcycles(dst, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W); + dst = cycles(&opts->gen, 8); + dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_read_byte); - dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); dst = call(dst, (uint8_t *)z80_write_byte); dst = add_ir(dst, 1, opts->regs[Z80_DE], SZ_W); dst = add_ir(dst, 1, opts->regs[Z80_HL], SZ_W); @@ -532,37 +517,37 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W); uint8_t * cont = dst+1; dst = jcc(dst, CC_Z, dst+2); - dst = zcycles(dst, 7); + dst = cycles(&opts->gen, 7); //TODO: Figure out what the flag state should be here //TODO: Figure out whether an interrupt can interrupt this dst = jmp(dst, start); *cont = dst - (cont + 1); - dst = zcycles(dst, 2); + dst = cycles(&opts->gen, 2); //TODO: Implement half-carry - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; } case Z80_LDD: { - dst = zcycles(dst, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W); + dst = cycles(&opts->gen, 8); + dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_read_byte); - dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); dst = call(dst, (uint8_t *)z80_write_byte); - dst = zcycles(dst, 2); + dst = cycles(&opts->gen, 2); dst = sub_ir(dst, 1, opts->regs[Z80_DE], SZ_W); dst = sub_ir(dst, 1, opts->regs[Z80_HL], SZ_W); dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W); //TODO: Implement half-carry - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_NZ, CONTEXT, zf_off(ZF_PV)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV)); break; } case Z80_LDDR: { - dst = zcycles(dst, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W); + dst = cycles(&opts->gen, 8); + dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_read_byte); - dst = mov_rr(dst, opts->regs[Z80_DE], SCRATCH2, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); dst = call(dst, (uint8_t *)z80_write_byte); dst = sub_ir(dst, 1, opts->regs[Z80_DE], SZ_W); dst = sub_ir(dst, 1, opts->regs[Z80_HL], SZ_W); @@ -570,15 +555,15 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W); uint8_t * cont = dst+1; dst = jcc(dst, CC_Z, dst+2); - dst = zcycles(dst, 7); + dst = cycles(&opts->gen, 7); //TODO: Figure out what the flag state should be here //TODO: Figure out whether an interrupt can interrupt this dst = jmp(dst, start); *cont = dst - (cont + 1); - dst = zcycles(dst, 2); + dst = cycles(&opts->gen, 2); //TODO: Implement half-carry - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; } /*case Z80_CPI: @@ -595,7 +580,7 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else if(z80_size(inst) == SZ_W) { cycles += 4; } - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); dst = translate_z80_reg(inst, &dst_op, dst, opts); dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { @@ -603,13 +588,13 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else { dst = add_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (z80_size(inst) == SZ_B) { - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } dst = z80_save_reg(dst, inst, opts); dst = z80_save_ea(dst, inst, opts); @@ -623,21 +608,21 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else if(z80_size(inst) == SZ_W) { cycles += 4; } - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); dst = translate_z80_reg(inst, &dst_op, dst, opts); dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); - dst = bt_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); + dst = bt_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); if (src_op.mode == MODE_REG_DIRECT) { dst = adc_rr(dst, src_op.base, dst_op.base, z80_size(inst)); } else { dst = adc_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); dst = z80_save_reg(dst, inst, opts); dst = z80_save_ea(dst, inst, opts); break; @@ -648,7 +633,7 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else if(inst->addr_mode == Z80_IMMED) { cycles += 3; } - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); dst = translate_z80_reg(inst, &dst_op, dst, opts); dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { @@ -656,12 +641,12 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else { dst = sub_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); dst = z80_save_reg(dst, inst, opts); dst = z80_save_ea(dst, inst, opts); break; @@ -674,21 +659,21 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else if(z80_size(inst) == SZ_W) { cycles += 4; } - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); dst = translate_z80_reg(inst, &dst_op, dst, opts); dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); - dst = bt_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); + dst = bt_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); if (src_op.mode == MODE_REG_DIRECT) { dst = sbb_rr(dst, src_op.base, dst_op.base, z80_size(inst)); } else { dst = sbb_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); dst = z80_save_reg(dst, inst, opts); dst = z80_save_ea(dst, inst, opts); break; @@ -701,7 +686,7 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else if(z80_size(inst) == SZ_W) { cycles += 4; } - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); dst = translate_z80_reg(inst, &dst_op, dst, opts); dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { @@ -710,13 +695,13 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context dst = and_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); } //TODO: Cleanup flags - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (z80_size(inst) == SZ_B) { - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } dst = z80_save_reg(dst, inst, opts); dst = z80_save_ea(dst, inst, opts); @@ -730,7 +715,7 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else if(z80_size(inst) == SZ_W) { cycles += 4; } - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); dst = translate_z80_reg(inst, &dst_op, dst, opts); dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { @@ -739,13 +724,13 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context dst = or_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); } //TODO: Cleanup flags - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (z80_size(inst) == SZ_B) { - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } dst = z80_save_reg(dst, inst, opts); dst = z80_save_ea(dst, inst, opts); @@ -759,7 +744,7 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else if(z80_size(inst) == SZ_W) { cycles += 4; } - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); dst = translate_z80_reg(inst, &dst_op, dst, opts); dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { @@ -768,13 +753,13 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context dst = xor_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); } //TODO: Cleanup flags - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (z80_size(inst) == SZ_B) { - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } dst = z80_save_reg(dst, inst, opts); dst = z80_save_ea(dst, inst, opts); @@ -786,7 +771,7 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else if(inst->addr_mode == Z80_IMMED) { cycles += 3; } - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); dst = translate_z80_reg(inst, &dst_op, dst, opts); dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { @@ -794,12 +779,12 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else { dst = cmp_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); dst = z80_save_reg(dst, inst, opts); dst = z80_save_ea(dst, inst, opts); break; @@ -812,18 +797,18 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else if(inst->reg == Z80_IXH || inst->reg == Z80_IXL || inst->reg == Z80_IYH || inst->reg == Z80_IYL || inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { cycles += 4; } - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); dst = translate_z80_reg(inst, &dst_op, dst, opts); if (dst_op.mode == MODE_UNUSED) { dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); } dst = add_ir(dst, 1, dst_op.base, z80_size(inst)); if (z80_size(inst) == SZ_B) { - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } dst = z80_save_reg(dst, inst, opts); dst = z80_save_ea(dst, inst, opts); @@ -838,18 +823,18 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else if(inst->reg == Z80_IXH || inst->reg == Z80_IXL || inst->reg == Z80_IYH || inst->reg == Z80_IYL || inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { cycles += 4; } - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); dst = translate_z80_reg(inst, &dst_op, dst, opts); if (dst_op.mode == MODE_UNUSED) { dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); } dst = sub_ir(dst, 1, dst_op.base, z80_size(inst)); if (z80_size(inst) == SZ_B) { - dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B); + dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } dst = z80_save_reg(dst, inst, opts); dst = z80_save_ea(dst, inst, opts); @@ -857,76 +842,76 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context break; //case Z80_DAA: case Z80_CPL: - dst = zcycles(dst, 4); + dst = cycles(&opts->gen, 4); dst = not_r(dst, opts->regs[Z80_A], SZ_B); //TODO: Implement half-carry flag - dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B); + dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); break; case Z80_NEG: - dst = zcycles(dst, 8); + dst = cycles(&opts->gen, 8); dst = neg_r(dst, opts->regs[Z80_A], SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = setcc_rdisp8(dst, CC_O, CONTEXT, zf_off(ZF_PV)); - dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); break; case Z80_CCF: - dst = zcycles(dst, 4); - dst = xor_irdisp8(dst, 1, CONTEXT, zf_off(ZF_C), SZ_B); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = cycles(&opts->gen, 4); + dst = xor_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag break; case Z80_SCF: - dst = zcycles(dst, 4); - dst = mov_irdisp8(dst, 1, CONTEXT, zf_off(ZF_C), SZ_B); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = cycles(&opts->gen, 4); + dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag break; case Z80_NOP: if (inst->immed == 42) { dst = call(dst, (uint8_t *)z80_save_context); - dst = mov_rr(dst, CONTEXT, RDI, SZ_Q); + dst = mov_rr(dst, opts->gen.context_reg, RDI, SZ_Q); dst = jmp(dst, (uint8_t *)z80_print_regs_exit); } else { - dst = zcycles(dst, 4 * inst->immed); + dst = cycles(&opts->gen, 4 * inst->immed); } break; case Z80_HALT: - dst = zcycles(dst, 4); - dst = mov_ir(dst, address, SCRATCH1, SZ_W); + dst = cycles(&opts->gen, 4); + dst = mov_ir(dst, address, opts->gen.scratch1, SZ_W); uint8_t * call_inst = dst; dst = call(dst, (uint8_t *)z80_halt); dst = jmp(dst, call_inst); break; case Z80_DI: - dst = zcycles(dst, 4); - dst = mov_irdisp8(dst, 0, CONTEXT, offsetof(z80_context, iff1), SZ_B); - dst = mov_irdisp8(dst, 0, CONTEXT, offsetof(z80_context, iff2), SZ_B); - dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, sync_cycle), ZLIMIT, SZ_D); - dst = mov_irdisp8(dst, 0xFFFFFFFF, CONTEXT, offsetof(z80_context, int_cycle), SZ_D); + dst = cycles(&opts->gen, 4); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B); + dst = mov_rdisp8r(dst, opts->gen.context_reg, offsetof(z80_context, sync_cycle), opts->gen.limit, SZ_D); + dst = mov_irdisp8(dst, 0xFFFFFFFF, opts->gen.context_reg, offsetof(z80_context, int_cycle), SZ_D); break; case Z80_EI: - dst = zcycles(dst, 4); - dst = mov_rrdisp32(dst, ZCYCLES, CONTEXT, offsetof(z80_context, int_enable_cycle), SZ_D); - dst = mov_irdisp8(dst, 1, CONTEXT, offsetof(z80_context, iff1), SZ_B); - dst = mov_irdisp8(dst, 1, CONTEXT, offsetof(z80_context, iff2), SZ_B); + dst = cycles(&opts->gen, 4); + dst = mov_rrdisp32(dst, opts->gen.cycles, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); + dst = mov_irdisp8(dst, 1, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); + dst = mov_irdisp8(dst, 1, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B); //interrupt enable has a one-instruction latency, minimum instruction duration is 4 cycles - dst = add_irdisp32(dst, 4, CONTEXT, offsetof(z80_context, int_enable_cycle), SZ_D); + dst = add_irdisp32(dst, 4, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); dst = call(dst, (uint8_t *)z80_do_sync); break; case Z80_IM: - dst = zcycles(dst, 4); - dst = mov_irdisp8(dst, inst->immed, CONTEXT, offsetof(z80_context, im), SZ_B); + dst = cycles(&opts->gen, 4); + dst = mov_irdisp8(dst, inst->immed, opts->gen.context_reg, offsetof(z80_context, im), SZ_B); break; case Z80_RLC: cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); if (inst->addr_mode != Z80_UNUSED) { dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = zcycles(dst, 1); + dst = cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; dst = translate_z80_reg(inst, &dst_op, dst, opts); @@ -935,13 +920,13 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context if (src_op.mode != MODE_UNUSED) { dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { dst = z80_save_result(dst, inst); if (src_op.mode != MODE_UNUSED) { @@ -953,27 +938,27 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context break; case Z80_RL: cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); if (inst->addr_mode != Z80_UNUSED) { dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = zcycles(dst, 1); + dst = cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; dst = translate_z80_reg(inst, &dst_op, dst, opts); } - dst = bt_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); + dst = bt_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); dst = rcl_ir(dst, 1, dst_op.base, SZ_B); if (src_op.mode != MODE_UNUSED) { dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { dst = z80_save_result(dst, inst); if (src_op.mode != MODE_UNUSED) { @@ -985,11 +970,11 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context break; case Z80_RRC: cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); if (inst->addr_mode != Z80_UNUSED) { dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = zcycles(dst, 1); + dst = cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; dst = translate_z80_reg(inst, &dst_op, dst, opts); @@ -998,13 +983,13 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context if (src_op.mode != MODE_UNUSED) { dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { dst = z80_save_result(dst, inst); if (src_op.mode != MODE_UNUSED) { @@ -1016,27 +1001,27 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context break; case Z80_RR: cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); if (inst->addr_mode != Z80_UNUSED) { dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = zcycles(dst, 1); + dst = cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; dst = translate_z80_reg(inst, &dst_op, dst, opts); } - dst = bt_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); + dst = bt_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); dst = rcr_ir(dst, 1, dst_op.base, SZ_B); if (src_op.mode != MODE_UNUSED) { dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { dst = z80_save_result(dst, inst); if (src_op.mode != MODE_UNUSED) { @@ -1049,29 +1034,29 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context case Z80_SLA: case Z80_SLL: cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); if (inst->addr_mode != Z80_UNUSED) { dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = zcycles(dst, 1); + dst = cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; dst = translate_z80_reg(inst, &dst_op, dst, opts); } dst = shl_ir(dst, 1, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); if (inst->op == Z80_SLL) { dst = or_ir(dst, 1, dst_op.base, SZ_B); } if (src_op.mode != MODE_UNUSED) { dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); } - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { dst = z80_save_result(dst, inst); if (src_op.mode != MODE_UNUSED) { @@ -1083,11 +1068,11 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context break; case Z80_SRA: cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); if (inst->addr_mode != Z80_UNUSED) { dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = zcycles(dst, 1); + dst = cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; dst = translate_z80_reg(inst, &dst_op, dst, opts); @@ -1096,13 +1081,13 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context if (src_op.mode != MODE_UNUSED) { dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { dst = z80_save_result(dst, inst); if (src_op.mode != MODE_UNUSED) { @@ -1114,11 +1099,11 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context break; case Z80_SRL: cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); if (inst->addr_mode != Z80_UNUSED) { dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = zcycles(dst, 1); + dst = cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; dst = translate_z80_reg(inst, &dst_op, dst, opts); @@ -1127,13 +1112,13 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context if (src_op.mode != MODE_UNUSED) { dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { dst = z80_save_result(dst, inst); if (src_op.mode != MODE_UNUSED) { @@ -1144,65 +1129,65 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } break; case Z80_RLD: - dst = zcycles(dst, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W); + dst = cycles(&opts->gen, 8); + dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_read_byte); //Before: (HL) = 0x12, A = 0x34 //After: (HL) = 0x24, A = 0x31 - dst = mov_rr(dst, opts->regs[Z80_A], SCRATCH2, SZ_B); - dst = shl_ir(dst, 4, SCRATCH1, SZ_W); - dst = and_ir(dst, 0xF, SCRATCH2, SZ_W); - dst = and_ir(dst, 0xFFF, SCRATCH1, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_A], opts->gen.scratch2, SZ_B); + dst = shl_ir(dst, 4, opts->gen.scratch1, SZ_W); + dst = and_ir(dst, 0xF, opts->gen.scratch2, SZ_W); + dst = and_ir(dst, 0xFFF, opts->gen.scratch1, SZ_W); dst = and_ir(dst, 0xF0, opts->regs[Z80_A], SZ_B); - dst = or_rr(dst, SCRATCH2, SCRATCH1, SZ_W); - //SCRATCH1 = 0x0124 - dst = ror_ir(dst, 8, SCRATCH1, SZ_W); - dst = zcycles(dst, 4); - dst = or_rr(dst, SCRATCH1, opts->regs[Z80_A], SZ_B); + dst = or_rr(dst, opts->gen.scratch2, opts->gen.scratch1, SZ_W); + //opts->gen.scratch1 = 0x0124 + dst = ror_ir(dst, 8, opts->gen.scratch1, SZ_W); + dst = cycles(&opts->gen, 4); + dst = or_rr(dst, opts->gen.scratch1, opts->regs[Z80_A], SZ_B); //set flags //TODO: Implement half-carry flag - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH2, SZ_W); - dst = ror_ir(dst, 8, SCRATCH1, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); + dst = ror_ir(dst, 8, opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_write_byte); break; case Z80_RRD: - dst = zcycles(dst, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH1, SZ_W); + dst = cycles(&opts->gen, 8); + dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_read_byte); //Before: (HL) = 0x12, A = 0x34 //After: (HL) = 0x41, A = 0x32 - dst = movzx_rr(dst, opts->regs[Z80_A], SCRATCH2, SZ_B, SZ_W); - dst = ror_ir(dst, 4, SCRATCH1, SZ_W); - dst = shl_ir(dst, 4, SCRATCH2, SZ_W); - dst = and_ir(dst, 0xF00F, SCRATCH1, SZ_W); + dst = movzx_rr(dst, opts->regs[Z80_A], opts->gen.scratch2, SZ_B, SZ_W); + dst = ror_ir(dst, 4, opts->gen.scratch1, SZ_W); + dst = shl_ir(dst, 4, opts->gen.scratch2, SZ_W); + dst = and_ir(dst, 0xF00F, opts->gen.scratch1, SZ_W); dst = and_ir(dst, 0xF0, opts->regs[Z80_A], SZ_B); - //SCRATCH1 = 0x2001 - //SCRATCH2 = 0x0040 - dst = or_rr(dst, SCRATCH2, SCRATCH1, SZ_W); - //SCRATCH1 = 0x2041 - dst = ror_ir(dst, 8, SCRATCH1, SZ_W); - dst = zcycles(dst, 4); - dst = shr_ir(dst, 4, SCRATCH1, SZ_B); - dst = or_rr(dst, SCRATCH1, opts->regs[Z80_A], SZ_B); + //opts->gen.scratch1 = 0x2001 + //opts->gen.scratch2 = 0x0040 + dst = or_rr(dst, opts->gen.scratch2, opts->gen.scratch1, SZ_W); + //opts->gen.scratch1 = 0x2041 + dst = ror_ir(dst, 8, opts->gen.scratch1, SZ_W); + dst = cycles(&opts->gen, 4); + dst = shr_ir(dst, 4, opts->gen.scratch1, SZ_B); + dst = or_rr(dst, opts->gen.scratch1, opts->regs[Z80_A], SZ_B); //set flags //TODO: Implement half-carry flag - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); - dst = mov_rr(dst, opts->regs[Z80_HL], SCRATCH2, SZ_W); - dst = ror_ir(dst, 8, SCRATCH1, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); + dst = ror_ir(dst, 8, opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_write_byte); break; case Z80_BIT: { cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); uint8_t bit; if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { src_op.base = opts->regs[z80_word_reg(inst->ea_reg)]; @@ -1215,23 +1200,23 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } if (inst->addr_mode != Z80_REG) { //Reads normally take 3 cycles, but the read at the end of a bit instruction takes 4 - dst = zcycles(dst, 1); + dst = cycles(&opts->gen, 1); } dst = bt_ir(dst, bit, src_op.base, size); - dst = setcc_rdisp8(dst, CC_NC, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_NC, CONTEXT, zf_off(ZF_PV)); - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); + dst = setcc_rdisp8(dst, CC_NC, opts->gen.context_reg, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_NC, opts->gen.context_reg, zf_off(ZF_PV)); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); if (inst->immed == 7) { dst = cmp_ir(dst, 0, src_op.base, size); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } else { - dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_S), SZ_B); + dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); } break; } case Z80_SET: { cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); uint8_t bit; if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { src_op.base = opts->regs[z80_word_reg(inst->ea_reg)]; @@ -1247,7 +1232,7 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } if (inst->addr_mode != Z80_REG) { //Reads normally take 3 cycles, but the read in the middle of a set instruction takes 4 - dst = zcycles(dst, 1); + dst = cycles(&opts->gen, 1); } dst = bts_ir(dst, bit, src_op.base, size); if (inst->reg != Z80_USE_IMMED) { @@ -1273,7 +1258,7 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } case Z80_RES: { cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); uint8_t bit; if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { src_op.base = opts->regs[z80_word_reg(inst->ea_reg)]; @@ -1289,7 +1274,7 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } if (inst->addr_mode != Z80_REG) { //Reads normally take 3 cycles, but the read in the middle of a set instruction takes 4 - dst = zcycles(dst, 1); + dst = cycles(&opts->gen, 1); } dst = btr_ir(dst, bit, src_op.base, size); if (inst->reg != Z80_USE_IMMED) { @@ -1320,7 +1305,7 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else if(inst->ea_reg == Z80_IX || inst->ea_reg == Z80_IY) { cycles += 4; } - dst = zcycles(dst, cycles); + dst = cycles(&opts->gen, cycles); if (inst->addr_mode != Z80_REG_INDIRECT && inst->immed < 0x4000) { uint8_t * call_dst = z80_get_native_address(context, inst->immed); if (!call_dst) { @@ -1331,44 +1316,44 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context dst = jmp(dst, call_dst); } else { if (inst->addr_mode == Z80_REG_INDIRECT) { - dst = mov_rr(dst, opts->regs[inst->ea_reg], SCRATCH1, SZ_W); + dst = mov_rr(dst, opts->regs[inst->ea_reg], opts->gen.scratch1, SZ_W); } else { - dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_W); + dst = mov_ir(dst, inst->immed, opts->gen.scratch1, SZ_W); } dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + dst = jmp_r(dst, opts->gen.scratch1); } break; } case Z80_JPCC: { - dst = zcycles(dst, 7);//T States: 4,3 + dst = cycles(&opts->gen, 7);//T States: 4,3 uint8_t cond = CC_Z; switch (inst->reg) { case Z80_CC_NZ: cond = CC_NZ; case Z80_CC_Z: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_Z), SZ_B); + dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); break; case Z80_CC_NC: cond = CC_NZ; case Z80_CC_C: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); + dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); break; case Z80_CC_PO: cond = CC_NZ; case Z80_CC_PE: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B); + dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; case Z80_CC_P: cond = CC_NZ; case Z80_CC_M: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_S), SZ_B); + dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); break; } uint8_t *no_jump_off = dst+1; dst = jcc(dst, cond, dst+2); - dst = zcycles(dst, 5);//T States: 5 + dst = cycles(&opts->gen, 5);//T States: 5 uint16_t dest_addr = inst->immed; if (dest_addr < 0x4000) { uint8_t * call_dst = z80_get_native_address(context, dest_addr); @@ -1379,15 +1364,15 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } dst = jmp(dst, call_dst); } else { - dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W); + dst = mov_ir(dst, dest_addr, opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + dst = jmp_r(dst, opts->gen.scratch1); } *no_jump_off = dst - (no_jump_off+1); break; } case Z80_JR: { - dst = zcycles(dst, 12);//T States: 4,3,5 + dst = cycles(&opts->gen, 12);//T States: 4,3,5 uint16_t dest_addr = address + inst->immed + 2; if (dest_addr < 0x4000) { uint8_t * call_dst = z80_get_native_address(context, dest_addr); @@ -1398,31 +1383,31 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } dst = jmp(dst, call_dst); } else { - dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W); + dst = mov_ir(dst, dest_addr, opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + dst = jmp_r(dst, opts->gen.scratch1); } break; } case Z80_JRCC: { - dst = zcycles(dst, 7);//T States: 4,3 + dst = cycles(&opts->gen, 7);//T States: 4,3 uint8_t cond = CC_Z; switch (inst->reg) { case Z80_CC_NZ: cond = CC_NZ; case Z80_CC_Z: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_Z), SZ_B); + dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); break; case Z80_CC_NC: cond = CC_NZ; case Z80_CC_C: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); + dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); break; } uint8_t *no_jump_off = dst+1; dst = jcc(dst, cond, dst+2); - dst = zcycles(dst, 5);//T States: 5 + dst = cycles(&opts->gen, 5);//T States: 5 uint16_t dest_addr = address + inst->immed + 2; if (dest_addr < 0x4000) { uint8_t * call_dst = z80_get_native_address(context, dest_addr); @@ -1433,19 +1418,19 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } dst = jmp(dst, call_dst); } else { - dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W); + dst = mov_ir(dst, dest_addr, opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + dst = jmp_r(dst, opts->gen.scratch1); } *no_jump_off = dst - (no_jump_off+1); break; } case Z80_DJNZ: - dst = zcycles(dst, 8);//T States: 5,3 + dst = cycles(&opts->gen, 8);//T States: 5,3 dst = sub_ir(dst, 1, opts->regs[Z80_B], SZ_B); uint8_t *no_jump_off = dst+1; dst = jcc(dst, CC_Z, dst+2); - dst = zcycles(dst, 5);//T States: 5 + dst = cycles(&opts->gen, 5);//T States: 5 uint16_t dest_addr = address + inst->immed + 2; if (dest_addr < 0x4000) { uint8_t * call_dst = z80_get_native_address(context, dest_addr); @@ -1456,17 +1441,17 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } dst = jmp(dst, call_dst); } else { - dst = mov_ir(dst, dest_addr, SCRATCH1, SZ_W); + dst = mov_ir(dst, dest_addr, opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + dst = jmp_r(dst, opts->gen.scratch1); } *no_jump_off = dst - (no_jump_off+1); break; case Z80_CALL: { - dst = zcycles(dst, 11);//T States: 4,3,4 + dst = cycles(&opts->gen, 11);//T States: 4,3,4 dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = mov_ir(dst, address + 3, SCRATCH1, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W); + dst = mov_ir(dst, address + 3, opts->gen.scratch1, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); dst = call(dst, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 if (inst->immed < 0x4000) { uint8_t * call_dst = z80_get_native_address(context, inst->immed); @@ -1477,44 +1462,44 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } dst = jmp(dst, call_dst); } else { - dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_W); + dst = mov_ir(dst, inst->immed, opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + dst = jmp_r(dst, opts->gen.scratch1); } break; } case Z80_CALLCC: - dst = zcycles(dst, 10);//T States: 4,3,3 (false case) + dst = cycles(&opts->gen, 10);//T States: 4,3,3 (false case) uint8_t cond = CC_Z; switch (inst->reg) { case Z80_CC_NZ: cond = CC_NZ; case Z80_CC_Z: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_Z), SZ_B); + dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); break; case Z80_CC_NC: cond = CC_NZ; case Z80_CC_C: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); + dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); break; case Z80_CC_PO: cond = CC_NZ; case Z80_CC_PE: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B); + dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; case Z80_CC_P: cond = CC_NZ; case Z80_CC_M: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_S), SZ_B); + dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); break; } uint8_t *no_call_off = dst+1; dst = jcc(dst, cond, dst+2); - dst = zcycles(dst, 1);//Last of the above T states takes an extra cycle in the true case + dst = cycles(&opts->gen, 1);//Last of the above T states takes an extra cycle in the true case dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = mov_ir(dst, address + 3, SCRATCH1, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W); + dst = mov_ir(dst, address + 3, opts->gen.scratch1, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); dst = call(dst, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 if (inst->immed < 0x4000) { uint8_t * call_dst = z80_get_native_address(context, inst->immed); @@ -1525,81 +1510,81 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } dst = jmp(dst, call_dst); } else { - dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_W); + dst = mov_ir(dst, inst->immed, opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + dst = jmp_r(dst, opts->gen.scratch1); } *no_call_off = dst - (no_call_off+1); break; case Z80_RET: - dst = zcycles(dst, 4);//T States: 4 - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W); + dst = cycles(&opts->gen, 4);//T States: 4 + dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3 dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + dst = jmp_r(dst, opts->gen.scratch1); break; case Z80_RETCC: { - dst = zcycles(dst, 5);//T States: 5 + dst = cycles(&opts->gen, 5);//T States: 5 uint8_t cond = CC_Z; switch (inst->reg) { case Z80_CC_NZ: cond = CC_NZ; case Z80_CC_Z: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_Z), SZ_B); + dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); break; case Z80_CC_NC: cond = CC_NZ; case Z80_CC_C: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_C), SZ_B); + dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); break; case Z80_CC_PO: cond = CC_NZ; case Z80_CC_PE: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_PV), SZ_B); + dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; case Z80_CC_P: cond = CC_NZ; case Z80_CC_M: - dst = cmp_irdisp8(dst, 0, CONTEXT, zf_off(ZF_S), SZ_B); + dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); break; } uint8_t *no_call_off = dst+1; dst = jcc(dst, cond, dst+2); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3 dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + dst = jmp_r(dst, opts->gen.scratch1); *no_call_off = dst - (no_call_off+1); break; } case Z80_RETI: //For some systems, this may need a callback for signalling interrupt routine completion - dst = zcycles(dst, 8);//T States: 4, 4 - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W); + dst = cycles(&opts->gen, 8);//T States: 4, 4 + dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3 dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + dst = jmp_r(dst, opts->gen.scratch1); break; case Z80_RETN: - dst = zcycles(dst, 8);//T States: 4, 4 - dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, iff2), SCRATCH2, SZ_B); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH1, SZ_W); - dst = mov_rrdisp8(dst, SCRATCH2, CONTEXT, offsetof(z80_context, iff1), SZ_B); + dst = cycles(&opts->gen, 8);//T States: 4, 4 + dst = mov_rdisp8r(dst, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch2, SZ_B); + dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + dst = mov_rrdisp8(dst, opts->gen.scratch2, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3 dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, SCRATCH1); + dst = jmp_r(dst, opts->gen.scratch1); break; case Z80_RST: { //RST is basically CALL to an address in page 0 - dst = zcycles(dst, 5);//T States: 5 + dst = cycles(&opts->gen, 5);//T States: 5 dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = mov_ir(dst, address + 1, SCRATCH1, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_SP], SCRATCH2, SZ_W); + dst = mov_ir(dst, address + 1, opts->gen.scratch1, SZ_W); + dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); dst = call(dst, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 uint8_t * call_dst = z80_get_native_address(context, inst->immed); if (!call_dst) { @@ -1611,15 +1596,15 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context break; } case Z80_IN: - dst = zcycles(dst, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4 + dst = cycles(&opts->gen, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4 if (inst->addr_mode == Z80_IMMED_INDIRECT) { - dst = mov_ir(dst, inst->immed, SCRATCH1, SZ_B); + dst = mov_ir(dst, inst->immed, opts->gen.scratch1, SZ_B); } else { - dst = mov_rr(dst, opts->regs[Z80_C], SCRATCH1, SZ_B); + dst = mov_rr(dst, opts->regs[Z80_C], opts->gen.scratch1, SZ_B); } dst = call(dst, (uint8_t *)z80_io_read); translate_z80_reg(inst, &dst_op, dst, opts); - dst = mov_rr(dst, SCRATCH1, dst_op.base, SZ_B); + dst = mov_rr(dst, opts->gen.scratch1, dst_op.base, SZ_B); dst = z80_save_reg(dst, inst, opts); break; /*case Z80_INI: @@ -1627,14 +1612,14 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context case Z80_IND: case Z80_INDR:*/ case Z80_OUT: - dst = zcycles(dst, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4 + dst = cycles(&opts->gen, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4 if ((inst->addr_mode & 0x1F) == Z80_IMMED_INDIRECT) { - dst = mov_ir(dst, inst->immed, SCRATCH2, SZ_B); + dst = mov_ir(dst, inst->immed, opts->gen.scratch2, SZ_B); } else { - dst = mov_rr(dst, opts->regs[Z80_C], SCRATCH2, SZ_B); + dst = mov_rr(dst, opts->regs[Z80_C], opts->gen.scratch2, SZ_B); } translate_z80_reg(inst, &src_op, dst, opts); - dst = mov_rr(dst, dst_op.base, SCRATCH1, SZ_B); + dst = mov_rr(dst, dst_op.base, opts->gen.scratch1, SZ_B); dst = call(dst, (uint8_t *)z80_io_write); dst = z80_save_reg(dst, inst, opts); break; @@ -1676,7 +1661,7 @@ uint8_t * z80_get_native_address(z80_context * context, uint32_t address) return map->base + map->offsets[address]; } -uint8_t z80_get_native_inst_size(x86_z80_options * opts, uint32_t address) +uint8_t z80_get_native_inst_size(z80_options * opts, uint32_t address) { if (address >= 0x4000) { return 0; @@ -1688,7 +1673,7 @@ void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * n { uint32_t orig_address = address; native_map_slot *map; - x86_z80_options * opts = context->options; + z80_options * opts = context->options; if (address < 0x4000) { address &= 0x1FFF; map = context->static_code_map; @@ -1752,7 +1737,7 @@ z80_context * z80_handle_code_write(uint32_t address, z80_context * context) if (inst_start != INVALID_INSTRUCTION_START) { uint8_t * dst = z80_get_native_address(context, inst_start); dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", dst, inst_start, address); - dst = mov_ir(dst, inst_start, SCRATCH1, SZ_D); + dst = mov_ir(dst, inst_start, opts->gen.scratch1, SZ_D); dst = call(dst, (uint8_t *)z80_retrans_stub); } return context; @@ -1773,7 +1758,7 @@ uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address) void z80_handle_deferred(z80_context * context) { - x86_z80_options * opts = context->options; + z80_options * opts = context->options; process_deferred(&opts->deferred, context, (native_addr_func)z80_get_native_address); if (opts->deferred) { translate_z80_stream(context, opts->deferred->address); @@ -1783,7 +1768,7 @@ void z80_handle_deferred(z80_context * context) void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * orig_start) { char disbuf[80]; - x86_z80_options * opts = context->options; + z80_options * opts = context->options; uint8_t orig_size = z80_get_native_inst_size(opts, address); uint32_t orig = address; address &= 0x1FFF; @@ -1850,7 +1835,7 @@ void translate_z80_stream(z80_context * context, uint32_t address) if (z80_get_native_address(context, address)) { return; } - x86_z80_options * opts = context->options; + z80_options * opts = context->options; uint32_t start_address = address; uint8_t * encoded = NULL, *next; if (address < 0x4000) { @@ -1923,8 +1908,17 @@ void translate_z80_stream(z80_context * context, uint32_t address) } } -void init_x86_z80_opts(x86_z80_options * options) +void init_x86_z80_opts(z80_options * options, memmap_chunk * chunks, uint32_t num_chunks) { + memset(options, 0, sizeof(*options)); + + options->gen.address_size = SZ_W; + options->gen.address_mask = 0xFFFF; + options->gen.max_address = 0x10000; + options->gen.bus_cycles = 3; + options->gen.mem_ptr_off = offsetof(z80_context, mem_pointers); + options->gen.ram_flags_off = offsetof(z80_context, ram_code_flags); + options->flags = 0; options->regs[Z80_B] = BH; options->regs[Z80_C] = RBX; @@ -1946,15 +1940,146 @@ void init_x86_z80_opts(x86_z80_options * options) options->regs[Z80_AF] = -1; options->regs[Z80_IX] = RDX; options->regs[Z80_IY] = R8; - size_t size = 1024 * 1024; - options->cur_code = alloc_code(&size); - options->code_end = options->cur_code + size; - options->ram_inst_sizes = malloc(sizeof(uint8_t) * 0x2000); + + options->bank_reg = R15; + options->bank_pointer = R12; + + options->gen.context_reg = RSI; + options->gen.cycles = RBP; + options->gen.limit = RDI; + options->gen.scratch1 = R13; + options->gen.scratch2 = R14; + + options->gen.native_code_map = malloc(sizeof(native_map_slot)); + memset(options->gen.native_code_map, 0, sizeof(native_map_slot)); + options->gen.deferred = NULL; + options->gen.ram_inst_sizes = malloc(sizeof(uint8_t) * 0x2000); memset(options->ram_inst_sizes, 0, sizeof(uint8_t) * 0x2000); - options->deferred = NULL; + + code_info *code = &options->gen.code; + init_code_info(code); + + options->save_context_scratch = code->cur; + mov_rrdisp(code, options->gen.scratch1, options->gen.context_reg, offsetof(z80_context, scratch1), SZ_W); + mov_rrdisp(code, options->gen.scratch2, options->gen.context_reg, offsetof(z80_context, scratch2), SZ_W); + + options->gen.save_context = code->cur; + for (int i = 0; i <= Z80_A; i++) + { + int reg; + uint8_t size; + if (i < Z80_I) { + int reg = i /2 + Z80_BC; + size = SZ_W; + + } else { + reg = i; + size = SZ_B; + } + if (options->regs[reg] >= 0) { + mov_rrdisp(code, options->regs[reg], options->gen.context_reg, offsetof(z80_context, regs) + i, size); + } + } + if (options->regs[Z80_SP] >= 0) { + mov_rrdisp(code, options->regs[Z80_SP], options->gen.context_reg, offsetof(z80_context, sp), SZ_W); + } + mov_rrdisp(code, options->gen.limit, options->gen.context_reg, offsetof(z80_context, target_cycle), SZ_D); + mov_rrdisp(code, options->gen.cycles, options->gen.context_reg, offsetof(z80_context, current_cycle), SZ_D); + mov_rrdisp(code, options->bank_reg, options->gen.context_reg, offsetof(z80_context, bank_reg), SZ_W); + mov_rrdisp(code, options->bank_pointer, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, SZ_PTR); + + options->load_context_scratch = code->cur; + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch1), options->gen.scratch1, SZ_W); + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch2), options->gen.scratch2, SZ_W); + options->gen.load_context = code->cur; + for (int i = 0; i <= Z80_A; i++) + { + int reg; + uint8_t size; + if (i < Z80_I) { + int reg = i /2 + Z80_BC; + size = SZ_W; + + } else { + reg = i; + size = SZ_B; + } + if (options->regs[reg] >= 0) { + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, regs) + i, options->regs[reg], size); + } + } + if (options->regs[Z80_SP] >= 0) { + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, sp), options->regs[Z80_SP], SZ_W); + } + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.limit, SZ_D); + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, current_cycle), options->gen.cycles, SZ_D); + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, bank_reg), options->bank_reg, SZ_W); + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, options->bank_pointer, SZ_PTR); + + options->gen.handle_cycle_limit = code->cur; + cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D); + code_ptr no_sync = code->cur+1; + jcc(code, CC_B, no_sync); + mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, pc), SZ_W); + call(code, options->save_context_scratch); + pop_r(code, RAX); //return address in read/write func + pop_r(code, RBX); //return address in translated code + sub_ir(code, 5, RAX, SZ_PTR); //adjust return address to point to the call that got us here + mov_rrdisp(code, RBX, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR); + mov_rrind(code, RAX, options->gen.context_reg, SZ_PTR); + //restore callee saved registers + pop_r(code, R15) + pop_r(code, R14) + pop_r(code, R13) + pop_r(code, R12) + pop_r(code, RBP) + pop_r(code, RBX) + *no_sync = code->cur - no_sync; + //return to caller of z80_run + retn(code); + + options->gen.read_8 = gen_mem_fun(&options->gen, chunks, num_chunks, READ_8, NULL); + options->gen.write_8 = gen_mem_fun(&options->gen, chunks, num_chunks, WRITE_8, &options->write_8_noinc); + + options->gen.handle_cycle_limit_int = code->cur; + cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, int_cycle), options->gen.cycles, SZ_D); + code_ptr skip_int = code->cur+1; + jcc(code, CC_B, skip_int); + //set limit to the cycle limit + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.limit, SZ_D); + //disable interrupts + move_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B); + move_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B); + cycles(&options->gen, 7); + //save return address (in scratch1) to Z80 stack + sub_ir(code, 2, options->regs[Z80_SP], SZ_W); + mov_rr(code, options->regs[Z80_SP], options->gen.scratch2, SZ_W); + //we need to do check_cycles and cycles outside of the write_8 call + //so that the stack has the correct depth if we need to return to C + //for a synchronization + check_cycles(&options->gen); + cycles(&options->gen, 3); + //save word to write before call to write_8_noinc + push_r(code, options->gen.scratch1); + call(code, options->write_8_noinc); + //restore word to write + pop_r(code, options->gen.scratch1); + //write high byte to SP+1 + mov_rr(code, options->regs[Z80_SP], options->gen.scratch2, SZ_W); + add_ir(code, 1, options->gen.scratch2, SZ_W); + shr_ir(code, 8, options->gen.scratch1, SZ_W); + check_cycles(&options->gen); + cycles(&options->gen, 3); + call(code, options->write_8_noinc); + //dispose of return address as we'll be jumping somewhere else + pop_r(options->gen.scratch2); + //TODO: Support interrupt mode 0 and 2 + mov_ir(code, 0x38, options->gen.scratch1, SZ_W); + call(code, (code_ptr)z80_native_addr); + jmp_r(code, options->gen.scratch1); } -void init_z80_context(z80_context * context, x86_z80_options * options) +void init_z80_context(z80_context * context, z80_options * options) { memset(context, 0, sizeof(*context)); context->static_code_map = malloc(sizeof(*context->static_code_map)); @@ -1979,9 +2104,9 @@ void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_ha static uint8_t * bp_stub = NULL; uint8_t * native = z80_get_native_address_trans(context, address); uint8_t * start_native = native; - native = mov_ir(native, address, SCRATCH1, SZ_W); + native = mov_ir(native, address, opts->gen.scratch1, SZ_W); if (!bp_stub) { - x86_z80_options * opts = context->options; + z80_options * opts = context->options; uint8_t * dst = opts->cur_code; uint8_t * dst_end = opts->code_end; if (dst_end - dst < 128) { @@ -1999,27 +2124,27 @@ void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_ha //Save context and call breakpoint handler dst = call(dst, (uint8_t *)z80_save_context); - dst = push_r(dst, SCRATCH1); - dst = mov_rr(dst, CONTEXT, RDI, SZ_Q); - dst = mov_rr(dst, SCRATCH1, RSI, SZ_W); + dst = push_r(dst, opts->gen.scratch1); + dst = mov_rr(dst, opts->gen.context_reg, RDI, SZ_Q); + dst = mov_rr(dst, opts->gen.scratch1, RSI, SZ_W); dst = call(dst, bp_handler); - dst = mov_rr(dst, RAX, CONTEXT, SZ_Q); + dst = mov_rr(dst, RAX, opts->gen.context_reg, SZ_Q); //Restore context dst = call(dst, (uint8_t *)z80_load_context); - dst = pop_r(dst, SCRATCH1); + dst = pop_r(dst, opts->gen.scratch1); //do prologue stuff - dst = cmp_rr(dst, ZCYCLES, ZLIMIT, SZ_D); + dst = cmp_rr(dst, opts->gen.cycles, opts->gen.limit, SZ_D); uint8_t * jmp_off = dst+1; dst = jcc(dst, CC_NC, dst + 7); - dst = pop_r(dst, SCRATCH1); - dst = add_ir(dst, check_int_size - (native-start_native), SCRATCH1, SZ_Q); - dst = push_r(dst, SCRATCH1); + dst = pop_r(dst, opts->gen.scratch1); + dst = add_ir(dst, check_int_size - (native-start_native), opts->gen.scratch1, SZ_Q); + dst = push_r(dst, opts->gen.scratch1); dst = jmp(dst, (uint8_t *)z80_handle_cycle_limit_int); *jmp_off = dst - (jmp_off+1); //jump back to body of translated instruction - dst = pop_r(dst, SCRATCH1); - dst = add_ir(dst, check_int_size - (native-start_native), SCRATCH1, SZ_Q); - dst = jmp_r(dst, SCRATCH1); + dst = pop_r(dst, opts->gen.scratch1); + dst = add_ir(dst, check_int_size - (native-start_native), opts->gen.scratch1, SZ_Q); + dst = jmp_r(dst, opts->gen.scratch1); opts->cur_code = dst; } else { native = call(native, bp_stub); diff --git a/z80_to_x86.h b/z80_to_x86.h index ab2c846..b33311e 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -22,13 +22,14 @@ enum { }; typedef struct { - uint8_t * cur_code; - uint8_t * code_end; - uint8_t *ram_inst_sizes; - deferred_addr * deferred; + cpu_options gen; + code_ptr save_context_scratch; + code_ptr load_context_scratch; + code_ptr write_8_noinc; + uint32_t flags; int8_t regs[Z80_UNUSED]; -} x86_z80_options; +} z80_options; typedef struct { void * native_pc; @@ -51,7 +52,7 @@ typedef struct { uint32_t int_cycle; native_map_slot * static_code_map; native_map_slot * banked_code_map; - void * options; + z80_options * options; void * system; uint8_t ram_code_flags[(8 * 1024)/128/8]; uint32_t int_enable_cycle; @@ -59,8 +60,8 @@ typedef struct { } z80_context; void translate_z80_stream(z80_context * context, uint32_t address); -void init_x86_z80_opts(x86_z80_options * options); -void init_z80_context(z80_context * context, x86_z80_options * options); +void init_x86_z80_opts(z80_options * options, memmap_chunk * chunks, uint32_t num_chunks); +void init_z80_context(z80_context * context, z80_options * options); uint8_t * z80_get_native_address(z80_context * context, uint32_t address); uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address); z80_context * z80_handle_code_write(uint32_t address, z80_context * context); -- cgit v1.2.3 From 59894dbded604fba7e0bdbd5c2116b9cfd3b431d Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 14 Dec 2014 18:12:00 -0800 Subject: Produce a listing file when assembling 68K test ROMs --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 84db28f..833c4ae 100644 --- a/Makefile +++ b/Makefile @@ -88,7 +88,7 @@ vos_prog_info : vos_prog_info.o vos_program_module.o $(CC) $(CFLAGS) -c -o $@ $< %.bin : %.s68 - vasmm68k_mot -Fbin -m68000 -no-opt -spaces -o $@ $< + vasmm68k_mot -Fbin -m68000 -no-opt -spaces -o $@ -L $@.list $< %.bin : %.sz8 vasmz80_mot -Fbin -spaces -o $@ $< -- cgit v1.2.3 From 6179a20c840ef62fc58e9b7cd5e79b8e7485894c Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 14 Dec 2014 18:14:50 -0800 Subject: Fix the HV counter and adjust the slots of certain VDP events --- vdp.c | 118 +++++++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 73 insertions(+), 45 deletions(-) diff --git a/vdp.c b/vdp.c index 55d76b6..6250e0e 100644 --- a/vdp.c +++ b/vdp.c @@ -27,10 +27,12 @@ #define HSYNC_SLOT_H40 240 #define HSYNC_END_H40 (240+17) #define HSYNC_END_H32 (33 * MCLKS_SLOT_H32) -#define HBLANK_START_H40 167 -#define HBLANK_END_H40 11 //should be 10.25 according to Nemesis IIRC -#define HBLANK_START_H32 134 -#define HBLANK_END_H32 8 //should be 7.5 according to Nemesis IIRC +#define HBLANK_START_H40 178 //should be 179 according to Nemesis, but 178 seems to fit slightly better with my test ROM results +#define HBLANK_END_H40 0 //should be 5.5 according to Nemesis, but 0 seems to fit better with my test ROM results +#define HBLANK_START_H32 233 //should be 147 according to Nemesis which is very different from my test ROM result +#define HBLANK_END_H32 0 //should be 5 according to Nemesis, but 0 seems to fit better with my test ROM results +#define LINE_CHANGE_H40 165 +#define LINE_CHANGE_H32 132 #define FIFO_LATENCY 3 int32_t color_map[1 << 12]; @@ -260,8 +262,11 @@ void vdp_print_reg_explain(vdp_context * context) printf("\n**Internal Group**\n" "Address: %X\n" "CD: %X\n" - "Pending: %s\n", - context->address, context->cd, (context->flags & FLAG_PENDING) ? "true" : "false"); + "Pending: %s\n" + "VCounter: %d\n" + "HCounter: %d\n", + context->address, context->cd, (context->flags & FLAG_PENDING) ? "true" : "false", + context->vcounter, context->hslot*2); //TODO: Window Group, DMA Group } @@ -911,10 +916,12 @@ void vdp_h40(uint32_t line, uint32_t linecyc, vdp_context * context) uint32_t mask; switch(linecyc) { + case 165: + case 166: + external_slot(context); + break; //sprite render to line buffer starts case 167: - context->cur_slot = MAX_DRAWS-1; - memset(context->linebuf, 0, LINEBUF_SIZE); case 168: case 169: case 170: @@ -927,8 +934,6 @@ void vdp_h40(uint32_t line, uint32_t linecyc, vdp_context * context) //sprite attribute table scan starts case 171: render_sprite_cells( context); - context->sprite_index = 0x80; - context->slot_counter = MAX_SPRITES_LINE; scan_sprite_table(line, context); break; case 172: @@ -1049,10 +1054,6 @@ void vdp_h40(uint32_t line, uint32_t linecyc, vdp_context * context) COLUMN_RENDER_BLOCK(36, 141) COLUMN_RENDER_BLOCK(38, 149) COLUMN_RENDER_BLOCK_REFRESH(40, 157) - case 165: - case 166: - external_slot(context); - break; } } @@ -1062,10 +1063,12 @@ void vdp_h32(uint32_t line, uint32_t linecyc, vdp_context * context) uint32_t mask; switch(linecyc) { + case 132: + case 133: + external_slot(context); + break; //sprite render to line buffer starts case 134: - context->cur_slot = MAX_DRAWS_H32-1; - memset(context->linebuf, 0, LINEBUF_SIZE); case 135: case 136: case 137: @@ -1078,8 +1081,6 @@ void vdp_h32(uint32_t line, uint32_t linecyc, vdp_context * context) //sprite attribute table scan starts case 138: render_sprite_cells( context); - context->sprite_index = 0x80; - context->slot_counter = MAX_SPRITES_LINE_H32; scan_sprite_table(line, context); break; case 139: @@ -1190,10 +1191,6 @@ void vdp_h32(uint32_t line, uint32_t linecyc, vdp_context * context) COLUMN_RENDER_BLOCK(28, 108) COLUMN_RENDER_BLOCK(30, 116) COLUMN_RENDER_BLOCK_REFRESH(32, 124) - case 132: - case 133: - external_slot(context); - break; } } @@ -1218,6 +1215,14 @@ void vdp_h40_line(uint32_t line, vdp_context * context) if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, 0); } + external_slot(context); + if (context->flags & FLAG_DMA_RUN) { + run_dma_src(context, 0); + } + external_slot(context); + if (context->flags & FLAG_DMA_RUN) { + run_dma_src(context, 0); + } for (int i = 0; i < 19; i++) { scan_sprite_table(line, context); @@ -1255,13 +1260,17 @@ void vdp_h40_line(uint32_t line, vdp_context * context) read_sprite_x(line, context); } - external_slot(context); - if (context->flags & FLAG_DMA_RUN) { - run_dma_src(context, 0); - } - external_slot(context); + return; } + external_slot(context); + if (context->flags & FLAG_DMA_RUN) { + run_dma_src(context, 0); + } + external_slot(context); + if (context->flags & FLAG_DMA_RUN) { + run_dma_src(context, 0); + } render_sprite_cells(context); render_sprite_cells(context); @@ -1371,11 +1380,6 @@ void vdp_h40_line(uint32_t line, vdp_context * context) render_map_3(context); render_map_output(line, column, context); } - external_slot(context); - if (context->flags & FLAG_DMA_RUN) { - run_dma_src(context, 0); - } - external_slot(context); } void latch_mode(vdp_context * context) @@ -1430,8 +1434,26 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) if (!line && !slot) { latch_mode(context); } + uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; - if (is_h40 && slot == HBLANK_START_H40 || !is_h40 && slot == 134) { + if (is_h40) { + if (slot == 167) { + context->cur_slot = MAX_DRAWS-1; + memset(context->linebuf, 0, LINEBUF_SIZE); + } else if (slot == 171) { + context->sprite_index = 0x80; + context->slot_counter = MAX_SPRITES_LINE; + } + } else { + if (slot == 134) { + context->cur_slot = MAX_DRAWS_H32-1; + memset(context->linebuf, 0, LINEBUF_SIZE); + } else if (slot == 138) { + context->sprite_index = 0x80; + context->slot_counter = MAX_SPRITES_LINE_H32; + } + } + if (is_h40 && slot == LINE_CHANGE_H40 || !is_h40 && slot == LINE_CHANGE_H32) { if (line >= inactive_start) { context->hint_counter = context->regs[REG_HINT]; } else if (context->hint_counter) { @@ -1470,7 +1492,7 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) if (context->regs[REG_MODE_2] & DISPLAY_ENABLE && active_slot) { //run VDP rendering for a slot or a line if (is_h40) { - if (slot == HBLANK_START_H40 && line < inactive_start && (target_cycles - context->cycles) >= MCLKS_LINE) { + if (slot == LINE_CHANGE_H40 && line < inactive_start && (target_cycles - context->cycles) >= MCLKS_LINE) { vdp_h40_line(line, context); inccycles = MCLKS_LINE; context->vcounter++; @@ -1496,13 +1518,13 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) context->hslot++; context->hslot &= 0xFF; if (is_h40) { - if (context->hslot == HBLANK_START_H40) { + if (context->hslot == LINE_CHANGE_H40) { context->vcounter++; } else if (context->hslot == 183) { context->hslot = 229; } } else { - if (context->hslot == 134) { + if (context->hslot == LINE_CHANGE_H32) { context->vcounter++; } else if (context->hslot == 148) { context->hslot = 233; @@ -1681,7 +1703,13 @@ uint16_t vdp_control_port_read(vdp_context * context) } uint32_t line= context->vcounter; uint32_t slot = context->hslot; - if (line >= (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) { + if ( + ( + line >= (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START) + && line < 0x1FF + ) + || !(context->regs[REG_MODE_2] & BIT_DISP_EN) + ) { value |= 0x8; } if (context->regs[REG_MODE_4] & BIT_H40) { @@ -1759,7 +1787,7 @@ uint16_t vdp_hv_counter_read(vdp_context * context) return context->hv_latch; } uint32_t line= context->vcounter & 0xFF; - uint32_t linecyc = (context->hslot * 2) & 0xFF; + uint32_t linecyc = context->hslot; linecyc &= 0xFF; if (context->double_res) { line <<= 1; @@ -1795,20 +1823,20 @@ void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) uint32_t vdp_cycles_next_line(vdp_context * context) { if (context->regs[REG_MODE_4] & BIT_H40) { - if (context->hslot < HBLANK_START_H40) { + if (context->hslot < LINE_CHANGE_H40) { return (HBLANK_START_H40 - context->hslot) * MCLKS_SLOT_H40; } else if (context->hslot < 183) { - return MCLKS_LINE - (context->hslot - HBLANK_START_H40) * MCLKS_SLOT_H40; + return MCLKS_LINE - (context->hslot - LINE_CHANGE_H40) * MCLKS_SLOT_H40; } else { - return (256-context->hslot + HBLANK_START_H40) * MCLKS_SLOT_H40; + return (256-context->hslot + LINE_CHANGE_H40) * MCLKS_SLOT_H40; } } else { - if (context->hslot < HBLANK_START_H32) { - return (HBLANK_START_H32 - context->hslot) * MCLKS_SLOT_H32; + if (context->hslot < LINE_CHANGE_H32) { + return (LINE_CHANGE_H32 - context->hslot) * MCLKS_SLOT_H32; } else if (context->hslot < 148) { - return MCLKS_LINE - (context->hslot - HBLANK_START_H32) * MCLKS_SLOT_H32; + return MCLKS_LINE - (context->hslot - LINE_CHANGE_H32) * MCLKS_SLOT_H32; } else { - return (256-context->hslot + HBLANK_START_H32) * MCLKS_SLOT_H32; + return (256-context->hslot + LINE_CHANGE_H32) * MCLKS_SLOT_H32; } } } -- cgit v1.2.3 From 69e48d3410a932588b58ec385d3e75517b9a8f73 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 14 Dec 2014 18:16:14 -0800 Subject: Remove object file that was accidentally added --- vos_program_module.o | Bin 5360 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 vos_program_module.o diff --git a/vos_program_module.o b/vos_program_module.o deleted file mode 100644 index 3066b9d..0000000 Binary files a/vos_program_module.o and /dev/null differ -- cgit v1.2.3 From b100269776335ff82349bb83871dd415e92a0799 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 14 Dec 2014 18:17:29 -0800 Subject: Added HV counter test ROM source --- .hgignore | 1 + gen_test_hv.s68 | 631 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 632 insertions(+) create mode 100644 gen_test_hv.s68 diff --git a/.hgignore b/.hgignore index 5fd2fe1..9133381 100644 --- a/.hgignore +++ b/.hgignore @@ -12,6 +12,7 @@ vdpreverse/* nemesis/* html/* *.o +*.list blastem dis stateview diff --git a/gen_test_hv.s68 b/gen_test_hv.s68 new file mode 100644 index 0000000..0ee0c22 --- /dev/null +++ b/gen_test_hv.s68 @@ -0,0 +1,631 @@ + dc.l $0, start + dc.l empty_handler + dc.l empty_handler + ;$10 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$20 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$30 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$40 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$50 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$60 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$70 + dc.l int_4 + dc.l empty_handler + dc.l int_6 + dc.l empty_handler + ;$80 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$90 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$A0 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$B0 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$C0 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$D0 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$E0 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + ;$F0 + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.l empty_handler + dc.b "SEGA" +empty_handler: +int_6: + rte +int_4: + move.w (a2), d0 + ori.w #$8000, d0 + move.w d0, (a4)+ + rte + +start: + lea $C00000, a0 + lea $C00004, a1 + move.w #$8104, (a1) ;Mode 5, everything turned off + move.w #$8004, (a1) + move.w #$8220, (a1) ;Scroll a table $8000 + move.w #$8404, (a1) ;Scroll b table $8000 + move.w #$8560, (a1) ;SAT table $C000 + move.w #$8700, (a1) ;backdrop color 0 + move.w #$8B00, (a1) ;full screen scroll + move.w #$8C81, (a1) ;40 cell mode, no interlace + move.w #$8C81, (mode).w + move.w #$8D00, (a1) ;hscroll table at 0 + move.w #$8F02, (a1) ;autoinc 2 + move.w #$9011, (a1) ;64x64 scroll size + move.l #$C0000000, (a1) + move.w #$000, (a0) + move.w #$EEE, (a0) + + ;clear scroll table + move.l #$40000000, (a1) + move.l #0, (a0) + + ;load tiles + move.l #$44000000, (a1) + lea font(pc), a2 + move.w #((fontend-font)/4 - 1), d0 +tloop: + move.l (a2)+, (a0) + dbra d0, tloop + + + + ;clear name table + move.l #$40000002, (a1) + moveq #32, d0 + move.w #(64*64-1), d1 +ploop: + move.w d0, (a0) + dbra d1, ploop + + + lea $FF0000, a4 + move.b #$40, (a4, 6) + move.w #$8144, (a1) ;enable display + move #$2300, sr + + lea (4, a1), a2 ;hv counter line address + lea (2, a1), a3 ;second contro/status address + + move.b #254, d0 +init_wait: + cmp.b (a2), d0 + beq init_wait + +top: + move.b #254, d0 + lea $FF0000, a4 + move.w #$8F00, (a1) ;autoinc of 0 + move.l #$40040000, (a1) ;unused VRAM address +wait_active: + cmp.b (a2), d0 + bne.s wait_active + + move.l #$8A718014, (a1) ;enable Hints + + ;sync to VDP by attempting to fill FIFO + ;being in vblank makes this a bit difficult + + rept 8 + move.l d0, (a0) + endr + + ;sample data for vblank flag off + rept 82 ;two lines worth of move.l + move.l (a3), (a4)+ + endr + + move.l a4, a5 ;save end of first buffer + + move.b (a2), d0 +wait_new_line: + cmp.b (a2), d0 + beq.s wait_new_line + + ;sync to VDP by filling FIFO + move.l d0, (a0) + move.l d0, (a0) + move.w d0, (a0) + + ;sample data for line change HV value + rept 45 ;one line worth of move.l + move.l (a2), (a4)+ + endr + + move.l a4, usp ;save end of second buffer + + moveq #$70, d0 +wait_hint_line: + cmp.b (a2), d0 + bne.s wait_hint_line + + ;sample data for line change HV value + rept 45 ;one line worth of move.l + move.l (a2), (a4)+ + endr + + move.l a4, a6 + + move.b #223, d0 +wait_inactive: + cmp.b (a2), d0 + bne.s wait_inactive + + ;sync to VDP by filling FIFO + move.l d0, (a0) + move.l d0, (a0) + move.w d0, (a0) + + ;sample data for vblank on + rept 82 ;two lines worth of move.l + move.l (a3), (a4)+ + endr + + move.l #$8AFF8004, (a1) ;disable Hints + + rsset $FFFF8000 +vblank_start_min rs.w 1 +vblank_start_max rs.w 1 +vblank_end_min rs.w 1 +vblank_end_max rs.w 1 +hblank_start_min rs.w 1 +hblank_start_max rs.w 1 +hblank_end_min rs.w 1 +hblank_end_max rs.w 1 +line_change_min rs.w 1 +line_change_max rs.w 1 +hint_min rs.w 1 +hint_max rs.w 1 +mode rs.w 1 +printed_hv_dump rs.b 1 +button_state rs.b 1 + + lea $FF0001, a4 +.loop: + btst.b #3, (a4) + beq.s found_vblank_off + move.w 1(a4), d6 + addq #4, a4 + bra.s .loop +found_vblank_off: + + move.w (vblank_end_max).w, d0 + beq .new_max + cmp.w d0, d6 + blo .no_new_max +.new_max + move.w d6, (vblank_end_max).w +.no_new_max: + + + move.w 1(a4), d6 + + move.w (vblank_end_min).w, d0 + beq .new_min + cmp.w d0, d6 + bhi .no_new_min +.new_min + move.w d6, (vblank_end_min).w +.no_new_min: + + lea $FF0001, a4 +;first find a point where HBLANK is not set + bra.s .start +.loop: + addq #4, a4 +.start + btst.b #2, (a4) + bne.s .loop + +;then find a point after that where it switches to on +.loop2: + btst.b #2, (a4) + bne.s found_hblank_on + move.w 1(a4), d5 + addq #4, a4 + bra.s .loop2 +found_hblank_on: + + move.w (hblank_start_max).w, d0 + beq .new_max + cmp.w d0, d5 + blo .no_new_max +.new_max + move.w d5, (hblank_start_max).w +.no_new_max: + + + move.w 1(a4), d5 + + move.w (hblank_start_min).w, d0 + beq .new_min + cmp.w d0, d5 + bhi .no_new_min +.new_min + move.w d5, (hblank_start_min).w +.no_new_min: + +;finally find a point after that where it switches back off +.loop2: + btst.b #2, (a4) + beq.s found_hblank_off + move.w 1(a4), d5 + addq #4, a4 + bra.s .loop2 +found_hblank_off: + + move.w (hblank_end_max).w, d0 + beq .new_max + cmp.w d0, d5 + blo .no_new_max +.new_max + move.w d5, (hblank_end_max).w +.no_new_max: + + + move.w 1(a4), d5 + + move.w (hblank_end_min).w, d0 + beq .new_min + cmp.w d0, d5 + bhi .no_new_min +.new_min + move.w d5, (hblank_end_min).w +.no_new_min: + + move.l a5, a4 ;save line change buffer for later + move.b (a5), d0 +.loop + move.w (a5), d7 + addq #2, a5 + cmp.b (a5), d0 + beq .loop +found_line_change: + + move.w (line_change_max).w, d0 + beq .new_max + cmp.w d0, d7 + blo .no_new_max +.new_max + move.w d7, (line_change_max).w +.no_new_max: + + move.w (a5), d7 + + move.w (line_change_min).w, d0 + beq .new_min + cmp.w d0, d7 + bhi .no_new_min +.new_min + move.w d7, (line_change_min).w +.no_new_min: + + addq #1, a6 +.loop: + btst.b #3, (a6) + bne.s found_vblank_on + move.w 1(a6), d5 + addq #4, a6 + bra.s .loop +found_vblank_on: + + move.w (vblank_start_max).w, d0 + beq .new_max + cmp.w d0, d5 + blo .no_new_max +.new_max + move.w d5, (vblank_start_max).w +.no_new_max: + + move.w 1(a6), d5 + + move.w (vblank_start_min).w, d0 + beq .new_min + cmp.b d0, d5 + bhi .no_new_min +.new_min + move.w d5, (vblank_start_min).w +.no_new_min: + + move usp, a5 +.loop: + btst.b #7, (a5) + bne.s found_hint + move.w (a5), d1 + addq #2, a5 + bra.s .loop +found_hint: + + move.w (hint_max).w, d0 + beq .new_max + cmp.w d0, d1 + blo .no_new_max +.new_max + move.w d1, (hint_max).w +.no_new_max: + + move.w (a5), d1 + and.w #$7FFF, d1 + + move.w (hint_min).w, d0 + beq .new_min + cmp.b d0, d1 + bhi .no_new_min +.new_min + move.w d1, (hint_min).w +.no_new_min: + +draw_info: + ;draw data + move.w #$8F02, (a1) ;autoinc of 2 + move.l #$40840002, (a1) + + moveq #0, d0 + lea VBlankStart(pc), a6 + bsr print_string + + + move.w (vblank_start_max), d0 + moveq #0, d1 + bsr print_hexw + + move.w #32, (a0) + move.w d5, d0 + bsr print_hexw + + move.w #32, (a0) + move.w (vblank_start_min), d0 + bsr print_hexw + + moveq #0, d0 + move.l #$41040002, (a1) + lea VBlankEnd(pc), a6 + bsr print_string + + ;max value before vblank end + moveq #0, d1 + move.w (vblank_end_max), d0 + bsr print_hexw + + move.w #32, (a0) + move.w d6, d0 + bsr print_hexw + + ;min value after vblank end + move.w (vblank_end_min), d0 + move.w #32, (a0) + bsr print_hexw + + moveq #0, d0 + move.l #$41840002, (a1) + lea LineChange(pc), a6 + bsr print_string + + move.w (line_change_max), d0 + moveq #0, d1 + bsr print_hexw + + move.w #32, (a0) + move.w d7, d0 + bsr print_hexw + + move.w (line_change_min), d0 + move.w #32, (a0) + bsr print_hexw + + moveq #0, d0 + move.l #$42040002, (a1) + lea HBlankStart(pc), a6 + bsr print_string + + move.w (hblank_start_max), d0 + moveq #0, d1 + bsr print_hexw + + move.w (hblank_start_min), d0 + move.w #32, (a0) + bsr print_hexw + + moveq #0, d0 + move.l #$42840002, (a1) + lea HBlankEnd(pc), a6 + bsr print_string + + move.w (hblank_end_max), d0 + moveq #0, d1 + bsr print_hexw + + move.w (hblank_end_min), d0 + move.w #32, (a0) + bsr print_hexw + + moveq #0, d0 + move.l #$43040002, (a1) + lea HInterrupt(pc), a6 + bsr print_string + + move.w (hint_max), d0 + moveq #0, d1 + bsr print_hexw + + move.w (hint_min), d0 + move.w #32, (a0) + bsr print_hexw + + ;read pad + move.b #$40, $A10003 + move.b $A10003, d0 + move.b #$00, $A10003 + and.b #$3f, d0 + move.b $A10003, d1 + and.b #$30, d1 + lsl.b #2, d1 + or.b d1, d0 + not.b d0 + move.b (button_state).w, d2 + eor.b d0, d2 + and.b d0, d2 + move.b d2, d3 ;d3 contains newly pressed buttons, SACBRLDU + move.b d0, (button_state).w + + btst.l #7, d3 + beq not_pressed + + moveq #0, d0 + move.l d0, (vblank_start_min).w + move.l d0, (vblank_end_min).w + move.l d0, (hblank_start_min).w + move.l d0, (hblank_end_min).w + move.l d0, (line_change_min).w + move.l d0, (hint_min).w + move.b d0, (printed_hv_dump).w + move.w (mode).w, d0 + eor.w #$81, d0 + move.w d0, (mode).w + move.w d0, (a1) + bra top + +not_pressed + + move.b (printed_hv_dump).w, d0 + bne top + move.b #1, (printed_hv_dump).w + + moveq #0, d1 + moveq #89, d4 + moveq #6, d5 + move.l #$45820002, d6 + move.l d6, (a1) + +print_loop: + dbra d5, .no_line_change + ;#$45820002 + add.l #$00800000, d6 + move.l d6, (a1) + moveq #5, d5 +.no_line_change + move.w #32, (a0) + move.w (a4)+, d0 + bsr print_hexw + dbra d4, print_loop + + add.l #$01020000, d6 + move.l d6, (a1) + moveq #0, d0 + lea Instructions(pc), a6 + bsr print_string + + bra top + +VBlankStart: + dc.b "VBlank Start: ", 0 +VBlankEnd: + dc.b "VBlank End: ", 0 +LineChange: + dc.b "Line Change: ", 0 +HBlankStart: + dc.b "HBlank Start: ", 0 +HBlankEnd: + dc.b "HBlank End: ", 0 +HInterrupt: + dc.b "HInterrupt: ", 0 +Instructions: + dc.b "Press Start to switch modes", 0 + + align 1 +;Prints a number in hex format +;d0.w - number to print +;d1.w - base tile attribute +;a0 - VDP data port +; +;Clobbers: d2.l, d3.l +; +print_hexw: + moveq #3, d3 +.digitloop + rol.w #4, d0 + moveq #$F, d2 + and.b d0, d2 + cmp.b #$A, d2 + bge .hex + add.w #$30, d2 + bra .makeattrib +.hex + add.w #($41-$A), d2 +.makeattrib + add.w d1, d2 + move.w d2, (a0) + dbra d3, .digitloop + rts + +;Prints a null terminated string +;a6 - pointer to string +;a0 - VDP data port +;d0 - base tile attribute +; +;Clobbers: d1.w +print_string: +.loop + moveq #0, d1 + move.b (a6)+, d1 + beq .end + add.w d0, d1 + move.w d1, (a0) + bra .loop +.end + rts + + align 1 +font: + incbin font.tiles +fontend + -- cgit v1.2.3 From 07f9e99eefacb94e2847af379dcf37ecfd871b34 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 16 Dec 2014 01:05:00 -0800 Subject: Set the busy flag after a YM-2612 address write --- ym2612.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ym2612.c b/ym2612.c index 3e43b63..2d3404a 100644 --- a/ym2612.c +++ b/ym2612.c @@ -521,6 +521,7 @@ void ym_address_write_part1(ym2612_context * context, uint8_t address) context->selected_part = 0; context->write_cycle = context->current_cycle; context->busy_cycles = BUSY_CYCLES_ADDRESS; + context->status |= 0x80; } void ym_address_write_part2(ym2612_context * context, uint8_t address) @@ -530,6 +531,7 @@ void ym_address_write_part2(ym2612_context * context, uint8_t address) context->selected_part = 1; context->write_cycle = context->current_cycle; context->busy_cycles = BUSY_CYCLES_ADDRESS; + context->status |= 0x80; } uint8_t fnum_to_keycode[] = { -- cgit v1.2.3 From 3c8d04a6b51184d9856cebd2e445791e451cb56a Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 16 Dec 2014 01:10:54 -0800 Subject: Fix flags for rra, rrca, rla and rlca. Fix timing for rr, rrc, rl and rlc when using IX or IY. Fix access to I and R registers (R still needs to be made 7-bit though). Fix flags for ld a, i. The fix for access to I fixes PCM playback in Titan Overdrive and music playback in Crackdown. --- z80_to_x86.c | 62 ++++++++++++++++++++++++++++++++++++++++++------------------ z80inst.c | 38 ++++++++++++++++++------------------- 2 files changed, 63 insertions(+), 37 deletions(-) diff --git a/z80_to_x86.c b/z80_to_x86.c index dc6cfaf..b529766 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -157,7 +157,7 @@ uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_o ea->base = opts->regs[Z80_IYL]; dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); } - } else { + } else if(opts->regs[inst->ea_reg] >= 0) { ea->base = opts->regs[inst->ea_reg]; if (ea->base >= AH && ea->base <= BH && inst->reg != Z80_UNUSED && inst->reg != Z80_USE_IMMED) { uint8_t other_reg = opts->regs[inst->reg]; @@ -167,6 +167,10 @@ uint8_t * translate_z80_ea(z80inst * inst, x86_ea * ea, uint8_t * dst, x86_z80_o dst = ror_ir(dst, 8, ea->base, SZ_W); } } + } else { + ea->mode = MODE_REG_DISPLACE8; + ea->base = CONTEXT; + ea->disp = offsetof(z80_context, regs) + inst->ea_reg; } break; case Z80_REG_INDIRECT: @@ -390,6 +394,16 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context } else { dst = mov_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, size); } + if (inst->ea_reg == Z80_I && inst->addr_mode == Z80_REG) { + //ld a, i sets some flags + //TODO: Implement half-carry flag + dst = cmp_ir(dst, 0, dst_op.base, SZ_B); + dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B);; + dst = mov_rdisp8r(dst, CONTEXT, offsetof(z80_context, iff2), SCRATCH1, SZ_B); + dst = mov_rrdisp8(dst, SCRATCH1, CONTEXT, zf_off(ZF_PV), SZ_B); + } dst = z80_save_reg(dst, inst, opts); dst = z80_save_ea(dst, inst, opts); if (inst->addr_mode & Z80_DIR) { @@ -945,10 +959,13 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + if (inst->immed) { + //rlca does not set these flags + dst = cmp_ir(dst, 0, dst_op.base, SZ_B); + dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + } if (inst->addr_mode != Z80_UNUSED) { dst = z80_save_result(dst, inst); if (src_op.mode != MODE_UNUSED) { @@ -977,10 +994,13 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + if (inst->immed) { + //rla does not set these flags + dst = cmp_ir(dst, 0, dst_op.base, SZ_B); + dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + } if (inst->addr_mode != Z80_UNUSED) { dst = z80_save_result(dst, inst); if (src_op.mode != MODE_UNUSED) { @@ -1008,10 +1028,13 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + if (inst->immed) { + //rrca does not set these flags + dst = cmp_ir(dst, 0, dst_op.base, SZ_B); + dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + } if (inst->addr_mode != Z80_UNUSED) { dst = z80_save_result(dst, inst); if (src_op.mode != MODE_UNUSED) { @@ -1040,10 +1063,13 @@ uint8_t * translate_z80inst(z80inst * inst, uint8_t * dst, z80_context * context dst = setcc_rdisp8(dst, CC_C, CONTEXT, zf_off(ZF_C)); dst = mov_irdisp8(dst, 0, CONTEXT, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + if (inst->immed) { + //rra does not set these flags + dst = cmp_ir(dst, 0, dst_op.base, SZ_B); + dst = setcc_rdisp8(dst, CC_P, CONTEXT, zf_off(ZF_PV)); + dst = setcc_rdisp8(dst, CC_Z, CONTEXT, zf_off(ZF_Z)); + dst = setcc_rdisp8(dst, CC_S, CONTEXT, zf_off(ZF_S)); + } if (inst->addr_mode != Z80_UNUSED) { dst = z80_save_result(dst, inst); if (src_op.mode != MODE_UNUSED) { @@ -2105,7 +2131,7 @@ void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_ha void zremove_breakpoint(z80_context * context, uint16_t address) { - context->breakpoint_flags[address / sizeof(uint8_t)] &= 1 << (address % sizeof(uint8_t)); + context->breakpoint_flags[address / sizeof(uint8_t)] &= ~(1 << (address % sizeof(uint8_t))); uint8_t * native = z80_get_native_address(context, address); if (native) { z80_check_cycles_int(native, address); diff --git a/z80inst.c b/z80inst.c index 0605ebc..cecce6e 100644 --- a/z80inst.c +++ b/z80inst.c @@ -1,6 +1,6 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #include "z80inst.h" @@ -433,7 +433,7 @@ z80inst z80_tbl_extd[0xC0-0x40] = { {op, Z80_L, Z80_UNUSED, Z80_UNUSED, 1},\ {op, Z80_UNUSED, Z80_REG_INDIRECT, Z80_HL, 1},\ {op, Z80_A, Z80_UNUSED, Z80_UNUSED, 1} - + #define BIT_BLOCK(op, bit) \ {op, Z80_USE_IMMED, Z80_REG, Z80_B, bit},\ {op, Z80_USE_IMMED, Z80_REG, Z80_C, bit},\ @@ -771,14 +771,14 @@ z80inst z80_tbl_ix[256] = { }; #define SHIFT_BLOCK_IX(op) \ - {op, Z80_B, Z80_IX_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_C, Z80_IX_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_D, Z80_IX_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_E, Z80_IX_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_H, Z80_IX_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_L, Z80_IX_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_UNUSED, Z80_IX_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_A, Z80_IX_DISPLACE | Z80_DIR, 0, 0} + {op, Z80_B, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_C, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_D, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_E, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_H, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_L, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_UNUSED, Z80_IX_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_A, Z80_IX_DISPLACE | Z80_DIR, 0, 1} #define BIT_BLOCK_IX(bit) \ {Z80_BIT, Z80_USE_IMMED, Z80_IX_DISPLACE, 0, bit},\ @@ -1129,14 +1129,14 @@ z80inst z80_tbl_iy[256] = { }; #define SHIFT_BLOCK_IY(op) \ - {op, Z80_B, Z80_IY_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_C, Z80_IY_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_D, Z80_IY_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_E, Z80_IY_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_H, Z80_IY_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_L, Z80_IY_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_UNUSED, Z80_IY_DISPLACE | Z80_DIR, 0, 0},\ - {op, Z80_A, Z80_IY_DISPLACE | Z80_DIR, 0, 0} + {op, Z80_B, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_C, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_D, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_E, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_H, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_L, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_UNUSED, Z80_IY_DISPLACE | Z80_DIR, 0, 1},\ + {op, Z80_A, Z80_IY_DISPLACE | Z80_DIR, 0, 1} #define BIT_BLOCK_IY(bit) \ {Z80_BIT, Z80_USE_IMMED, Z80_IY_DISPLACE, 0, bit},\ @@ -1250,7 +1250,7 @@ uint8_t * z80_decode(uint8_t * istream, z80inst * decoded) } } else { memcpy(decoded, z80_tbl_a + *istream, sizeof(z80inst)); - + } if ((decoded->addr_mode & 0x1F) == Z80_IMMED && decoded->op != Z80_RST && decoded->op != Z80_IM) { decoded->immed = *(++istream); -- cgit v1.2.3 From 9dc3feb135af0a8853798bd79cff754cd86dbd0f Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 17 Dec 2014 09:53:51 -0800 Subject: Get Z80 core back into compileable state --- gen_x86.h | 1 + z80_to_x86.c | 1643 +++++++++++++++++++++++++++++----------------------------- z80_to_x86.h | 11 +- 3 files changed, 826 insertions(+), 829 deletions(-) diff --git a/gen_x86.h b/gen_x86.h index abc9f2a..07eae3a 100644 --- a/gen_x86.h +++ b/gen_x86.h @@ -36,6 +36,7 @@ enum { CC_O = 0, CC_NO, CC_C, + CC_B = CC_C, CC_NC, CC_Z, CC_NZ, diff --git a/z80_to_x86.c b/z80_to_x86.c index a331308..ba4fc66 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -54,7 +54,7 @@ uint8_t z80_size(z80inst * inst) return SZ_B; } -void translate_z80_reg(z80inst * inst, x86_ea * ea, z80_options * opts) +void translate_z80_reg(z80inst * inst, host_ea * ea, z80_options * opts) { code_info *code = &opts->gen.code; if (inst->reg == Z80_USE_IMMED) { @@ -122,7 +122,7 @@ void z80_save_reg(z80inst * inst, z80_options * opts) } } -void translate_z80_ea(z80inst * inst, x86_ea * ea, z80_options * opts, uint8_t read, uint8_t modify) +void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t read, uint8_t modify) { code_info *code = &opts->gen.code; uint8_t size, reg, areg; @@ -158,16 +158,16 @@ void translate_z80_ea(z80inst * inst, x86_ea * ea, z80_options * opts, uint8_t r if (read) { if (modify) { //push_r(code, opts->gen.scratch1); - mov_rrdisp8(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W); } if (size == SZ_B) { call(code, opts->read_8); } else { - dst = call(dst, opts->read_16); + call(code, opts->read_16); } if (modify) { //pop_r(code, opts->gen.scratch2); - mov_rdisp8r(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch2, SZ_W); + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch2, SZ_W); } } ea->base = opts->gen.scratch1; @@ -177,20 +177,20 @@ void translate_z80_ea(z80inst * inst, x86_ea * ea, z80_options * opts, uint8_t r ea->disp = inst->immed; break; case Z80_IMMED_INDIRECT: - dst = mov_ir(dst, inst->immed, areg, SZ_W); + mov_ir(code, inst->immed, areg, SZ_W); size = z80_size(inst); if (read) { /*if (modify) { - dst = push_r(dst, opts->gen.scratch1); + push_r(code, opts->gen.scratch1); }*/ if (size == SZ_B) { - dst = call(dst, (uint8_t *)z80_read_byte); + call(code, (uint8_t *)z80_read_byte); } else { - dst = call(dst, (uint8_t *)z80_read_word); + call(code, (uint8_t *)z80_read_word); } if (modify) { - //dst = pop_r(dst, opts->gen.scratch2); - dst = mov_ir(dst, inst->immed, opts->gen.scratch2, SZ_W); + //pop_r(code, opts->gen.scratch2); + mov_ir(code, inst->immed, opts->gen.scratch2, SZ_W); } } ea->base = opts->gen.scratch1; @@ -198,22 +198,22 @@ void translate_z80_ea(z80inst * inst, x86_ea * ea, z80_options * opts, uint8_t r case Z80_IX_DISPLACE: case Z80_IY_DISPLACE: reg = opts->regs[(inst->addr_mode & 0x1F) == Z80_IX_DISPLACE ? Z80_IX : Z80_IY]; - dst = mov_rr(dst, reg, areg, SZ_W); - dst = add_ir(dst, inst->ea_reg & 0x80 ? inst->ea_reg - 256 : inst->ea_reg, areg, SZ_W); + mov_rr(code, reg, areg, SZ_W); + add_ir(code, inst->ea_reg & 0x80 ? inst->ea_reg - 256 : inst->ea_reg, areg, SZ_W); size = z80_size(inst); if (read) { if (modify) { - //dst = push_r(dst, opts->gen.scratch1); - dst = mov_rrdisp8(dst, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W); + //push_r(code, opts->gen.scratch1); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W); } if (size == SZ_B) { - dst = call(dst, (uint8_t *)z80_read_byte); + call(code, (uint8_t *)z80_read_byte); } else { - dst = call(dst, (uint8_t *)z80_read_word); + call(code, (uint8_t *)z80_read_word); } if (modify) { - //dst = pop_r(dst, opts->gen.scratch2); - dst = mov_rdisp8r(dst, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch2, SZ_W); + //pop_r(code, opts->gen.scratch2); + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, scratch1), opts->gen.scratch2, SZ_W); } } ea->base = opts->gen.scratch1; @@ -225,32 +225,30 @@ void translate_z80_ea(z80inst * inst, x86_ea * ea, z80_options * opts, uint8_t r fprintf(stderr, "Unrecognized Z80 addressing mode %d\n", inst->addr_mode & 0x1F); exit(1); } - return dst; } -uint8_t * z80_save_ea(uint8_t * dst, z80inst * inst, z80_options * opts) +void z80_save_ea(code_info *code, z80inst * inst, z80_options * opts) { if ((inst->addr_mode & 0x1F) == Z80_REG) { if (inst->ea_reg == Z80_IYH) { if (inst->reg == Z80_IYL) { - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); - dst = mov_rr(dst, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B); - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); + mov_rr(code, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); } else { - dst = ror_ir(dst, 8, opts->regs[Z80_IY], SZ_W); + ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); } } else if (inst->reg != Z80_UNUSED && inst->reg != Z80_USE_IMMED && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { uint8_t other_reg = opts->regs[inst->reg]; if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) { //we can't mix an *H reg with a register that requires the REX prefix - dst = ror_ir(dst, 8, opts->regs[z80_low_reg(inst->ea_reg)], SZ_W); + ror_ir(code, 8, opts->regs[z80_low_reg(inst->ea_reg)], SZ_W); } } } - return dst; } -uint8_t * z80_save_result(uint8_t * dst, z80inst * inst) +void z80_save_result(code_info *code, z80inst * inst) { switch(inst->addr_mode & 0x1f) { @@ -259,12 +257,11 @@ uint8_t * z80_save_result(uint8_t * dst, z80inst * inst) case Z80_IX_DISPLACE: case Z80_IY_DISPLACE: if (z80_size(inst) == SZ_B) { - dst = call(dst, (uint8_t *)z80_write_byte); + call(code, (uint8_t *)z80_write_byte); } else { - dst = call(dst, (uint8_t *)z80_write_word_lowfirst); + call(code, (uint8_t *)z80_write_word_lowfirst); } } - return dst; } enum { @@ -311,13 +308,14 @@ void z80_print_regs_exit(z80_context * context) exit(0); } -uint8_t * translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) +void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) { - uint32_t cycles; - x86_ea src_op, dst_op; + uint32_t num_cycles; + host_ea src_op, dst_op; uint8_t size; z80_options *opts = context->options; - uint8_t * start = opts->code.cur; + uint8_t * start = opts->gen.code.cur; + code_info *code = &opts->gen.code; check_cycles_int(&opts->gen, address); switch(inst->op) { @@ -327,243 +325,243 @@ uint8_t * translate_z80inst(z80inst * inst, z80_context * context, uint16_t addr { case Z80_REG: case Z80_REG_INDIRECT: - cycles = size == SZ_B ? 4 : 6; + num_cycles = size == SZ_B ? 4 : 6; if (inst->ea_reg == Z80_IX || inst->ea_reg == Z80_IY) { - cycles += 4; + num_cycles += 4; } if (inst->reg == Z80_I || inst->ea_reg == Z80_I) { - cycles += 5; + num_cycles += 5; } break; case Z80_IMMED: - cycles = size == SZ_B ? 7 : 10; + num_cycles = size == SZ_B ? 7 : 10; break; case Z80_IMMED_INDIRECT: - cycles = 10; + num_cycles = 10; break; case Z80_IX_DISPLACE: case Z80_IY_DISPLACE: - cycles = 16; + num_cycles = 16; break; } if ((inst->reg >= Z80_IXL && inst->reg <= Z80_IYH) || inst->reg == Z80_IX || inst->reg == Z80_IY) { - cycles += 4; + num_cycles += 4; } - dst = cycles(&opts->gen, cycles); + cycles(&opts->gen, num_cycles); if (inst->addr_mode & Z80_DIR) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, DONT_READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); + translate_z80_ea(inst, &dst_op, opts, DONT_READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); } else { - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); + translate_z80_reg(inst, &dst_op, opts); } if (src_op.mode == MODE_REG_DIRECT) { if(dst_op.mode == MODE_REG_DISPLACE8) { - dst = mov_rrdisp8(dst, src_op.base, dst_op.base, dst_op.disp, size); + mov_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, size); } else { - dst = mov_rr(dst, src_op.base, dst_op.base, size); + mov_rr(code, src_op.base, dst_op.base, size); } } else if(src_op.mode == MODE_IMMED) { - dst = mov_ir(dst, src_op.disp, dst_op.base, size); + mov_ir(code, src_op.disp, dst_op.base, size); } else { - dst = mov_rdisp8r(dst, src_op.base, src_op.disp, dst_op.base, size); + mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, size); } - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); if (inst->addr_mode & Z80_DIR) { - dst = z80_save_result(dst, inst); + z80_save_result(code, inst); } break; case Z80_PUSH: - dst = cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5); - dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W); + cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5); + sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); if (inst->reg == Z80_AF) { - dst = mov_rr(dst, opts->regs[Z80_A], opts->gen.scratch1, SZ_B); - dst = shl_ir(dst, 8, opts->gen.scratch1, SZ_W); - dst = mov_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_S), opts->gen.scratch1, SZ_B); - dst = shl_ir(dst, 1, opts->gen.scratch1, SZ_B); - dst = or_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_Z), opts->gen.scratch1, SZ_B); - dst = shl_ir(dst, 2, opts->gen.scratch1, SZ_B); - dst = or_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch1, SZ_B); - dst = shl_ir(dst, 2, opts->gen.scratch1, SZ_B); - dst = or_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_PV), opts->gen.scratch1, SZ_B); - dst = shl_ir(dst, 1, opts->gen.scratch1, SZ_B); - dst = or_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_N), opts->gen.scratch1, SZ_B); - dst = shl_ir(dst, 1, opts->gen.scratch1, SZ_B); - dst = or_rdisp8r(dst, opts->gen.context_reg, zf_off(ZF_C), opts->gen.scratch1, SZ_B); + mov_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B); + shl_ir(code, 8, opts->gen.scratch1, SZ_W); + mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_S), opts->gen.scratch1, SZ_B); + shl_ir(code, 1, opts->gen.scratch1, SZ_B); + or_rdispr(code, opts->gen.context_reg, zf_off(ZF_Z), opts->gen.scratch1, SZ_B); + shl_ir(code, 2, opts->gen.scratch1, SZ_B); + or_rdispr(code, opts->gen.context_reg, zf_off(ZF_H), opts->gen.scratch1, SZ_B); + shl_ir(code, 2, opts->gen.scratch1, SZ_B); + or_rdispr(code, opts->gen.context_reg, zf_off(ZF_PV), opts->gen.scratch1, SZ_B); + shl_ir(code, 1, opts->gen.scratch1, SZ_B); + or_rdispr(code, opts->gen.context_reg, zf_off(ZF_N), opts->gen.scratch1, SZ_B); + shl_ir(code, 1, opts->gen.scratch1, SZ_B); + or_rdispr(code, opts->gen.context_reg, zf_off(ZF_C), opts->gen.scratch1, SZ_B); } else { - dst = translate_z80_reg(inst, &src_op, dst, opts); - dst = mov_rr(dst, src_op.base, opts->gen.scratch1, SZ_W); + translate_z80_reg(inst, &src_op, opts); + mov_rr(code, src_op.base, opts->gen.scratch1, SZ_W); } - dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_word_highfirst); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); + call(code, (uint8_t *)z80_write_word_highfirst); //no call to save_z80_reg needed since there's no chance we'll use the only //the upper half of a register pair break; case Z80_POP: - dst = cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4); - dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_word); - dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); + cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_read_word); + add_ir(code, 2, opts->regs[Z80_SP], SZ_W); if (inst->reg == Z80_AF) { - dst = bt_ir(dst, 0, opts->gen.scratch1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = bt_ir(dst, 1, opts->gen.scratch1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_N)); - dst = bt_ir(dst, 2, opts->gen.scratch1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_PV)); - dst = bt_ir(dst, 4, opts->gen.scratch1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_H)); - dst = bt_ir(dst, 6, opts->gen.scratch1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_Z)); - dst = bt_ir(dst, 7, opts->gen.scratch1, SZ_W); - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_S)); - dst = shr_ir(dst, 8, opts->gen.scratch1, SZ_W); - dst = mov_rr(dst, opts->gen.scratch1, opts->regs[Z80_A], SZ_B); + bt_ir(code, 0, opts->gen.scratch1, SZ_W); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + bt_ir(code, 1, opts->gen.scratch1, SZ_W); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_N)); + bt_ir(code, 2, opts->gen.scratch1, SZ_W); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_PV)); + bt_ir(code, 4, opts->gen.scratch1, SZ_W); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_H)); + bt_ir(code, 6, opts->gen.scratch1, SZ_W); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_Z)); + bt_ir(code, 7, opts->gen.scratch1, SZ_W); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_S)); + shr_ir(code, 8, opts->gen.scratch1, SZ_W); + mov_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B); } else { - dst = translate_z80_reg(inst, &src_op, dst, opts); - dst = mov_rr(dst, opts->gen.scratch1, src_op.base, SZ_W); + translate_z80_reg(inst, &src_op, opts); + mov_rr(code, opts->gen.scratch1, src_op.base, SZ_W); } //no call to save_z80_reg needed since there's no chance we'll use the only //the upper half of a register pair break; case Z80_EX: if (inst->addr_mode == Z80_REG || inst->reg == Z80_HL) { - cycles = 4; + num_cycles = 4; } else { - cycles = 8; + num_cycles = 8; } - dst = cycles(&opts->gen, cycles); + cycles(&opts->gen, num_cycles); if (inst->addr_mode == Z80_REG) { if(inst->reg == Z80_AF) { - dst = mov_rr(dst, opts->regs[Z80_A], opts->gen.scratch1, SZ_B); - dst = mov_rdisp8r(dst, opts->gen.context_reg, zar_off(Z80_A), opts->regs[Z80_A], SZ_B); - dst = mov_rrdisp8(dst, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_A), SZ_B); + mov_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B); + mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_A), opts->regs[Z80_A], SZ_B); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_A), SZ_B); //Flags are currently word aligned, so we can move //them efficiently a word at a time for (int f = ZF_C; f < ZF_NUM; f+=2) { - dst = mov_rdisp8r(dst, opts->gen.context_reg, zf_off(f), opts->gen.scratch1, SZ_W); - dst = mov_rdisp8r(dst, opts->gen.context_reg, zaf_off(f), opts->gen.scratch2, SZ_W); - dst = mov_rrdisp8(dst, opts->gen.scratch1, opts->gen.context_reg, zaf_off(f), SZ_W); - dst = mov_rrdisp8(dst, opts->gen.scratch2, opts->gen.context_reg, zf_off(f), SZ_W); + mov_rdispr(code, opts->gen.context_reg, zf_off(f), opts->gen.scratch1, SZ_W); + mov_rdispr(code, opts->gen.context_reg, zaf_off(f), opts->gen.scratch2, SZ_W); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zaf_off(f), SZ_W); + mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(f), SZ_W); } } else { - dst = xchg_rr(dst, opts->regs[Z80_DE], opts->regs[Z80_HL], SZ_W); + xchg_rr(code, opts->regs[Z80_DE], opts->regs[Z80_HL], SZ_W); } } else { - dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); - dst = xchg_rr(dst, opts->regs[inst->reg], opts->gen.scratch1, SZ_B); - dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); - dst = cycles(&opts->gen, 1); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_read_byte); + xchg_rr(code, opts->regs[inst->reg], opts->gen.scratch1, SZ_B); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); + call(code, (uint8_t *)z80_write_byte); + cycles(&opts->gen, 1); uint8_t high_reg = z80_high_reg(inst->reg); uint8_t use_reg; //even though some of the upper halves can be used directly //the limitations on mixing *H regs with the REX prefix //prevent us from taking advantage of it use_reg = opts->regs[inst->reg]; - dst = ror_ir(dst, 8, use_reg, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); - dst = add_ir(dst, 1, opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); - dst = xchg_rr(dst, use_reg, opts->gen.scratch1, SZ_B); - dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); - dst = add_ir(dst, 1, opts->gen.scratch2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); + ror_ir(code, 8, use_reg, SZ_W); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + add_ir(code, 1, opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_read_byte); + xchg_rr(code, use_reg, opts->gen.scratch1, SZ_B); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); + add_ir(code, 1, opts->gen.scratch2, SZ_W); + call(code, (uint8_t *)z80_write_byte); //restore reg to normal rotation - dst = ror_ir(dst, 8, use_reg, SZ_W); - dst = cycles(&opts->gen, 2); + ror_ir(code, 8, use_reg, SZ_W); + cycles(&opts->gen, 2); } break; case Z80_EXX: - dst = cycles(&opts->gen, 4); - dst = mov_rr(dst, opts->regs[Z80_BC], opts->gen.scratch1, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); - dst = mov_rdisp8r(dst, opts->gen.context_reg, zar_off(Z80_C), opts->regs[Z80_BC], SZ_W); - dst = mov_rdisp8r(dst, opts->gen.context_reg, zar_off(Z80_L), opts->regs[Z80_HL], SZ_W); - dst = mov_rrdisp8(dst, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_C), SZ_W); - dst = mov_rrdisp8(dst, opts->gen.scratch2, opts->gen.context_reg, zar_off(Z80_L), SZ_W); - dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.scratch1, SZ_W); - dst = mov_rdisp8r(dst, opts->gen.context_reg, zar_off(Z80_E), opts->regs[Z80_DE], SZ_W); - dst = mov_rrdisp8(dst, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_E), SZ_W); + cycles(&opts->gen, 4); + mov_rr(code, opts->regs[Z80_BC], opts->gen.scratch1, SZ_W); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); + mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_C), opts->regs[Z80_BC], SZ_W); + mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_L), opts->regs[Z80_HL], SZ_W); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_C), SZ_W); + mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zar_off(Z80_L), SZ_W); + mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch1, SZ_W); + mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_E), opts->regs[Z80_DE], SZ_W); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_E), SZ_W); break; case Z80_LDI: { - dst = cycles(&opts->gen, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); - dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); - dst = cycles(&opts->gen, 2); - dst = add_ir(dst, 1, opts->regs[Z80_DE], SZ_W); - dst = add_ir(dst, 1, opts->regs[Z80_HL], SZ_W); - dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W); + cycles(&opts->gen, 8); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_read_byte); + mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); + call(code, (uint8_t *)z80_write_byte); + cycles(&opts->gen, 2); + add_ir(code, 1, opts->regs[Z80_DE], SZ_W); + add_ir(code, 1, opts->regs[Z80_HL], SZ_W); + sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); //TODO: Implement half-carry - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV)); break; } case Z80_LDIR: { - dst = cycles(&opts->gen, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); - dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); - dst = add_ir(dst, 1, opts->regs[Z80_DE], SZ_W); - dst = add_ir(dst, 1, opts->regs[Z80_HL], SZ_W); + cycles(&opts->gen, 8); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_read_byte); + mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); + call(code, (uint8_t *)z80_write_byte); + add_ir(code, 1, opts->regs[Z80_DE], SZ_W); + add_ir(code, 1, opts->regs[Z80_HL], SZ_W); - dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W); - uint8_t * cont = dst+1; - dst = jcc(dst, CC_Z, dst+2); - dst = cycles(&opts->gen, 7); + sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); + uint8_t * cont = code->cur+1; + jcc(code, CC_Z, code->cur+2); + cycles(&opts->gen, 7); //TODO: Figure out what the flag state should be here //TODO: Figure out whether an interrupt can interrupt this - dst = jmp(dst, start); - *cont = dst - (cont + 1); - dst = cycles(&opts->gen, 2); + jmp(code, start); + *cont = code->cur - (cont + 1); + cycles(&opts->gen, 2); //TODO: Implement half-carry - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; } case Z80_LDD: { - dst = cycles(&opts->gen, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); - dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); - dst = cycles(&opts->gen, 2); - dst = sub_ir(dst, 1, opts->regs[Z80_DE], SZ_W); - dst = sub_ir(dst, 1, opts->regs[Z80_HL], SZ_W); - dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W); + cycles(&opts->gen, 8); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_read_byte); + mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); + call(code, (uint8_t *)z80_write_byte); + cycles(&opts->gen, 2); + sub_ir(code, 1, opts->regs[Z80_DE], SZ_W); + sub_ir(code, 1, opts->regs[Z80_HL], SZ_W); + sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); //TODO: Implement half-carry - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV)); break; } case Z80_LDDR: { - dst = cycles(&opts->gen, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); - dst = mov_rr(dst, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); - dst = sub_ir(dst, 1, opts->regs[Z80_DE], SZ_W); - dst = sub_ir(dst, 1, opts->regs[Z80_HL], SZ_W); + cycles(&opts->gen, 8); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_read_byte); + mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); + call(code, (uint8_t *)z80_write_byte); + sub_ir(code, 1, opts->regs[Z80_DE], SZ_W); + sub_ir(code, 1, opts->regs[Z80_HL], SZ_W); - dst = sub_ir(dst, 1, opts->regs[Z80_BC], SZ_W); - uint8_t * cont = dst+1; - dst = jcc(dst, CC_Z, dst+2); - dst = cycles(&opts->gen, 7); + sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); + uint8_t * cont = code->cur+1; + jcc(code, CC_Z, code->cur+2); + cycles(&opts->gen, 7); //TODO: Figure out what the flag state should be here //TODO: Figure out whether an interrupt can interrupt this - dst = jmp(dst, start); - *cont = dst - (cont + 1); - dst = cycles(&opts->gen, 2); + jmp(code, start); + *cont = code->cur - (cont + 1); + cycles(&opts->gen, 2); //TODO: Implement half-carry - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; } /*case Z80_CPI: @@ -572,622 +570,622 @@ uint8_t * translate_z80inst(z80inst * inst, z80_context * context, uint16_t addr case Z80_CPDR: break;*/ case Z80_ADD: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } else if(z80_size(inst) == SZ_W) { - cycles += 4; + num_cycles += 4; } - dst = cycles(&opts->gen, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { - dst = add_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + add_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = add_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + add_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (z80_size(inst) == SZ_B) { - dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_ADC: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } else if(z80_size(inst) == SZ_W) { - cycles += 4; + num_cycles += 4; } - dst = cycles(&opts->gen, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); - dst = bt_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); + bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); if (src_op.mode == MODE_REG_DIRECT) { - dst = adc_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + adc_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = adc_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + adc_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_SUB: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } - dst = cycles(&opts->gen, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { - dst = sub_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + sub_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = sub_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + sub_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_SBC: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } else if(z80_size(inst) == SZ_W) { - cycles += 4; + num_cycles += 4; } - dst = cycles(&opts->gen, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); - dst = bt_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); + bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); if (src_op.mode == MODE_REG_DIRECT) { - dst = sbb_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + sbb_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = sbb_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + sbb_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_AND: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } else if(z80_size(inst) == SZ_W) { - cycles += 4; + num_cycles += 4; } - dst = cycles(&opts->gen, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { - dst = and_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + and_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = and_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + and_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } //TODO: Cleanup flags - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (z80_size(inst) == SZ_B) { - dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_OR: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } else if(z80_size(inst) == SZ_W) { - cycles += 4; + num_cycles += 4; } - dst = cycles(&opts->gen, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { - dst = or_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + or_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = or_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + or_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } //TODO: Cleanup flags - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (z80_size(inst) == SZ_B) { - dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_XOR: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } else if(z80_size(inst) == SZ_W) { - cycles += 4; + num_cycles += 4; } - dst = cycles(&opts->gen, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { - dst = xor_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + xor_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = xor_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + xor_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } //TODO: Cleanup flags - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (z80_size(inst) == SZ_B) { - dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_CP: - cycles = 4; + num_cycles = 4; if (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 12; + num_cycles += 12; } else if(inst->addr_mode == Z80_IMMED) { - cycles += 3; + num_cycles += 3; } - dst = cycles(&opts->gen, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { - dst = cmp_rr(dst, src_op.base, dst_op.base, z80_size(inst)); + cmp_rr(code, src_op.base, dst_op.base, z80_size(inst)); } else { - dst = cmp_ir(dst, src_op.disp, dst_op.base, z80_size(inst)); + cmp_ir(code, src_op.disp, dst_op.base, z80_size(inst)); } - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); break; case Z80_INC: - cycles = 4; + num_cycles = 4; if (inst->reg == Z80_IX || inst->reg == Z80_IY) { - cycles += 6; + num_cycles += 6; } else if(z80_size(inst) == SZ_W) { - cycles += 2; + num_cycles += 2; } else if(inst->reg == Z80_IXH || inst->reg == Z80_IXL || inst->reg == Z80_IYH || inst->reg == Z80_IYL || inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 4; + num_cycles += 4; } - dst = cycles(&opts->gen, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); if (dst_op.mode == MODE_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); } - dst = add_ir(dst, 1, dst_op.base, z80_size(inst)); + add_ir(code, 1, dst_op.base, z80_size(inst)); if (z80_size(inst) == SZ_B) { - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); - dst = z80_save_result(dst, inst); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); + z80_save_result(code, inst); break; case Z80_DEC: - cycles = 4; + num_cycles = 4; if (inst->reg == Z80_IX || inst->reg == Z80_IY) { - cycles += 6; + num_cycles += 6; } else if(z80_size(inst) == SZ_W) { - cycles += 2; + num_cycles += 2; } else if(inst->reg == Z80_IXH || inst->reg == Z80_IXL || inst->reg == Z80_IYH || inst->reg == Z80_IYL || inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) { - cycles += 4; + num_cycles += 4; } - dst = cycles(&opts->gen, cycles); - dst = translate_z80_reg(inst, &dst_op, dst, opts); + cycles(&opts->gen, num_cycles); + translate_z80_reg(inst, &dst_op, opts); if (dst_op.mode == MODE_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); } - dst = sub_ir(dst, 1, dst_op.base, z80_size(inst)); + sub_ir(code, 1, dst_op.base, z80_size(inst)); if (z80_size(inst) == SZ_B) { - dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } - dst = z80_save_reg(dst, inst, opts); - dst = z80_save_ea(dst, inst, opts); - dst = z80_save_result(dst, inst); + z80_save_reg(inst, opts); + z80_save_ea(code, inst, opts); + z80_save_result(code, inst); break; //case Z80_DAA: case Z80_CPL: - dst = cycles(&opts->gen, 4); - dst = not_r(dst, opts->regs[Z80_A], SZ_B); + cycles(&opts->gen, 4); + not_r(code, opts->regs[Z80_A], SZ_B); //TODO: Implement half-carry flag - dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); break; case Z80_NEG: - dst = cycles(&opts->gen, 8); - dst = neg_r(dst, opts->regs[Z80_A], SZ_B); + cycles(&opts->gen, 8); + neg_r(code, opts->regs[Z80_A], SZ_B); //TODO: Implement half-carry flag - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = setcc_rdisp8(dst, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); - dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + setcc_rdisp(code, CC_O, opts->gen.context_reg, zf_off(ZF_PV)); + mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); break; case Z80_CCF: - dst = cycles(&opts->gen, 4); - dst = xor_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + cycles(&opts->gen, 4); + xor_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag break; case Z80_SCF: - dst = cycles(&opts->gen, 4); - dst = mov_irdisp8(dst, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + cycles(&opts->gen, 4); + mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag break; case Z80_NOP: if (inst->immed == 42) { - dst = call(dst, (uint8_t *)z80_save_context); - dst = mov_rr(dst, opts->gen.context_reg, RDI, SZ_Q); - dst = jmp(dst, (uint8_t *)z80_print_regs_exit); + call(code, (uint8_t *)z80_save_context); + mov_rr(code, opts->gen.context_reg, RDI, SZ_Q); + jmp(code, (uint8_t *)z80_print_regs_exit); } else { - dst = cycles(&opts->gen, 4 * inst->immed); + cycles(&opts->gen, 4 * inst->immed); } break; case Z80_HALT: - dst = cycles(&opts->gen, 4); - dst = mov_ir(dst, address, opts->gen.scratch1, SZ_W); - uint8_t * call_inst = dst; - dst = call(dst, (uint8_t *)z80_halt); - dst = jmp(dst, call_inst); + cycles(&opts->gen, 4); + mov_ir(code, address, opts->gen.scratch1, SZ_W); + uint8_t * call_inst = code->cur; + call(code, (uint8_t *)z80_halt); + jmp(code, call_inst); break; case Z80_DI: - dst = cycles(&opts->gen, 4); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B); - dst = mov_rdisp8r(dst, opts->gen.context_reg, offsetof(z80_context, sync_cycle), opts->gen.limit, SZ_D); - dst = mov_irdisp8(dst, 0xFFFFFFFF, opts->gen.context_reg, offsetof(z80_context, int_cycle), SZ_D); + cycles(&opts->gen, 4); + mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B); + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, sync_cycle), opts->gen.limit, SZ_D); + mov_irdisp(code, 0xFFFFFFFF, opts->gen.context_reg, offsetof(z80_context, int_cycle), SZ_D); break; case Z80_EI: - dst = cycles(&opts->gen, 4); - dst = mov_rrdisp32(dst, opts->gen.cycles, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); - dst = mov_irdisp8(dst, 1, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); - dst = mov_irdisp8(dst, 1, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B); + cycles(&opts->gen, 4); + mov_rrdisp(code, opts->gen.cycles, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); + mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); + mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B); //interrupt enable has a one-instruction latency, minimum instruction duration is 4 cycles - dst = add_irdisp32(dst, 4, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); - dst = call(dst, (uint8_t *)z80_do_sync); + add_irdisp(code, 4, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); + call(code, (uint8_t *)z80_do_sync); break; case Z80_IM: - dst = cycles(&opts->gen, 4); - dst = mov_irdisp8(dst, inst->immed, opts->gen.context_reg, offsetof(z80_context, im), SZ_B); + cycles(&opts->gen, 4); + mov_irdisp(code, inst->immed, opts->gen.context_reg, offsetof(z80_context, im), SZ_B); break; case Z80_RLC: - cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); - dst = cycles(&opts->gen, cycles); + num_cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = cycles(&opts->gen, 1); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register + cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } - dst = rol_ir(dst, 1, dst_op.base, SZ_B); + rol_ir(code, 1, dst_op.base, SZ_B); if (src_op.mode != MODE_UNUSED) { - dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); + mov_rr(code, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - dst = z80_save_result(dst, inst); + z80_save_result(code, inst); if (src_op.mode != MODE_UNUSED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } else { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } break; case Z80_RL: - cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); - dst = cycles(&opts->gen, cycles); + num_cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = cycles(&opts->gen, 1); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register + cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } - dst = bt_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); - dst = rcl_ir(dst, 1, dst_op.base, SZ_B); + bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + rcl_ir(code, 1, dst_op.base, SZ_B); if (src_op.mode != MODE_UNUSED) { - dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); + mov_rr(code, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - dst = z80_save_result(dst, inst); + z80_save_result(code, inst); if (src_op.mode != MODE_UNUSED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } else { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } break; case Z80_RRC: - cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); - dst = cycles(&opts->gen, cycles); + num_cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = cycles(&opts->gen, 1); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register + cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } - dst = ror_ir(dst, 1, dst_op.base, SZ_B); + ror_ir(code, 1, dst_op.base, SZ_B); if (src_op.mode != MODE_UNUSED) { - dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); + mov_rr(code, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - dst = z80_save_result(dst, inst); + z80_save_result(code, inst); if (src_op.mode != MODE_UNUSED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } else { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } break; case Z80_RR: - cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); - dst = cycles(&opts->gen, cycles); + num_cycles = inst->immed == 0 ? 4 : (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8); + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = cycles(&opts->gen, 1); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register + cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } - dst = bt_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); - dst = rcr_ir(dst, 1, dst_op.base, SZ_B); + bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + rcr_ir(code, 1, dst_op.base, SZ_B); if (src_op.mode != MODE_UNUSED) { - dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); + mov_rr(code, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - dst = z80_save_result(dst, inst); + z80_save_result(code, inst); if (src_op.mode != MODE_UNUSED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } else { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } break; case Z80_SLA: case Z80_SLL: - cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; - dst = cycles(&opts->gen, cycles); + num_cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = cycles(&opts->gen, 1); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register + cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } - dst = shl_ir(dst, 1, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + shl_ir(code, 1, dst_op.base, SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); if (inst->op == Z80_SLL) { - dst = or_ir(dst, 1, dst_op.base, SZ_B); + or_ir(code, 1, dst_op.base, SZ_B); } if (src_op.mode != MODE_UNUSED) { - dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); + mov_rr(code, dst_op.base, src_op.base, SZ_B); } - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - dst = z80_save_result(dst, inst); + z80_save_result(code, inst); if (src_op.mode != MODE_UNUSED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } else { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } break; case Z80_SRA: - cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; - dst = cycles(&opts->gen, cycles); + num_cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = cycles(&opts->gen, 1); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register + cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } - dst = sar_ir(dst, 1, dst_op.base, SZ_B); + sar_ir(code, 1, dst_op.base, SZ_B); if (src_op.mode != MODE_UNUSED) { - dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); + mov_rr(code, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - dst = z80_save_result(dst, inst); + z80_save_result(code, inst); if (src_op.mode != MODE_UNUSED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } else { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } break; case Z80_SRL: - cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; - dst = cycles(&opts->gen, cycles); + num_cycles = inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE ? 16 : 8; + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_UNUSED) { - dst = translate_z80_ea(inst, &dst_op, dst, opts, READ, MODIFY); - dst = translate_z80_reg(inst, &src_op, dst, opts); //For IX/IY variants that also write to a register - dst = cycles(&opts->gen, 1); + translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); + translate_z80_reg(inst, &src_op, opts); //For IX/IY variants that also write to a register + cycles(&opts->gen, 1); } else { src_op.mode = MODE_UNUSED; - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } - dst = shr_ir(dst, 1, dst_op.base, SZ_B); + shr_ir(code, 1, dst_op.base, SZ_B); if (src_op.mode != MODE_UNUSED) { - dst = mov_rr(dst, dst_op.base, src_op.base, SZ_B); + mov_rr(code, dst_op.base, src_op.base, SZ_B); } - dst = setcc_rdisp8(dst, CC_C, opts->gen.context_reg, zf_off(ZF_C)); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - dst = cmp_ir(dst, 0, dst_op.base, SZ_B); - dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - dst = z80_save_result(dst, inst); + z80_save_result(code, inst); if (src_op.mode != MODE_UNUSED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } else { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } break; case Z80_RLD: - dst = cycles(&opts->gen, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); + cycles(&opts->gen, 8); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_read_byte); //Before: (HL) = 0x12, A = 0x34 //After: (HL) = 0x24, A = 0x31 - dst = mov_rr(dst, opts->regs[Z80_A], opts->gen.scratch2, SZ_B); - dst = shl_ir(dst, 4, opts->gen.scratch1, SZ_W); - dst = and_ir(dst, 0xF, opts->gen.scratch2, SZ_W); - dst = and_ir(dst, 0xFFF, opts->gen.scratch1, SZ_W); - dst = and_ir(dst, 0xF0, opts->regs[Z80_A], SZ_B); - dst = or_rr(dst, opts->gen.scratch2, opts->gen.scratch1, SZ_W); + mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B); + shl_ir(code, 4, opts->gen.scratch1, SZ_W); + and_ir(code, 0xF, opts->gen.scratch2, SZ_W); + and_ir(code, 0xFFF, opts->gen.scratch1, SZ_W); + and_ir(code, 0xF0, opts->regs[Z80_A], SZ_B); + or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W); //opts->gen.scratch1 = 0x0124 - dst = ror_ir(dst, 8, opts->gen.scratch1, SZ_W); - dst = cycles(&opts->gen, 4); - dst = or_rr(dst, opts->gen.scratch1, opts->regs[Z80_A], SZ_B); + ror_ir(code, 8, opts->gen.scratch1, SZ_W); + cycles(&opts->gen, 4); + or_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B); //set flags //TODO: Implement half-carry flag - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); - dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); - dst = ror_ir(dst, 8, opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); + ror_ir(code, 8, opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_write_byte); break; case Z80_RRD: - dst = cycles(&opts->gen, 8); - dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_byte); + cycles(&opts->gen, 8); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_read_byte); //Before: (HL) = 0x12, A = 0x34 //After: (HL) = 0x41, A = 0x32 - dst = movzx_rr(dst, opts->regs[Z80_A], opts->gen.scratch2, SZ_B, SZ_W); - dst = ror_ir(dst, 4, opts->gen.scratch1, SZ_W); - dst = shl_ir(dst, 4, opts->gen.scratch2, SZ_W); - dst = and_ir(dst, 0xF00F, opts->gen.scratch1, SZ_W); - dst = and_ir(dst, 0xF0, opts->regs[Z80_A], SZ_B); + movzx_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B, SZ_W); + ror_ir(code, 4, opts->gen.scratch1, SZ_W); + shl_ir(code, 4, opts->gen.scratch2, SZ_W); + and_ir(code, 0xF00F, opts->gen.scratch1, SZ_W); + and_ir(code, 0xF0, opts->regs[Z80_A], SZ_B); //opts->gen.scratch1 = 0x2001 //opts->gen.scratch2 = 0x0040 - dst = or_rr(dst, opts->gen.scratch2, opts->gen.scratch1, SZ_W); + or_rr(code, opts->gen.scratch2, opts->gen.scratch1, SZ_W); //opts->gen.scratch1 = 0x2041 - dst = ror_ir(dst, 8, opts->gen.scratch1, SZ_W); - dst = cycles(&opts->gen, 4); - dst = shr_ir(dst, 4, opts->gen.scratch1, SZ_B); - dst = or_rr(dst, opts->gen.scratch1, opts->regs[Z80_A], SZ_B); + ror_ir(code, 8, opts->gen.scratch1, SZ_W); + cycles(&opts->gen, 4); + shr_ir(code, 4, opts->gen.scratch1, SZ_B); + or_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B); //set flags //TODO: Implement half-carry flag - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); - dst = setcc_rdisp8(dst, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - dst = setcc_rdisp8(dst, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); - dst = mov_rr(dst, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); - dst = ror_ir(dst, 8, opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_write_byte); + mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); + ror_ir(code, 8, opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_write_byte); break; case Z80_BIT: { - cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; - dst = cycles(&opts->gen, cycles); + num_cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; + cycles(&opts->gen, num_cycles); uint8_t bit; if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { src_op.base = opts->regs[z80_word_reg(inst->ea_reg)]; @@ -1196,27 +1194,27 @@ uint8_t * translate_z80inst(z80inst * inst, z80_context * context, uint16_t addr } else { size = SZ_B; bit = inst->immed; - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, DONT_MODIFY); + translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); } if (inst->addr_mode != Z80_REG) { //Reads normally take 3 cycles, but the read at the end of a bit instruction takes 4 - dst = cycles(&opts->gen, 1); + cycles(&opts->gen, 1); } - dst = bt_ir(dst, bit, src_op.base, size); - dst = setcc_rdisp8(dst, CC_NC, opts->gen.context_reg, zf_off(ZF_Z)); - dst = setcc_rdisp8(dst, CC_NC, opts->gen.context_reg, zf_off(ZF_PV)); - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); + bt_ir(code, bit, src_op.base, size); + setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_PV)); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); if (inst->immed == 7) { - dst = cmp_ir(dst, 0, src_op.base, size); - dst = setcc_rdisp8(dst, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + cmp_ir(code, 0, src_op.base, size); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } else { - dst = mov_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); + mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); } break; } case Z80_SET: { - cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; - dst = cycles(&opts->gen, cycles); + num_cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; + cycles(&opts->gen, num_cycles); uint8_t bit; if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { src_op.base = opts->regs[z80_word_reg(inst->ea_reg)]; @@ -1225,40 +1223,40 @@ uint8_t * translate_z80inst(z80inst * inst, z80_context * context, uint16_t addr } else { size = SZ_B; bit = inst->immed; - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, MODIFY); + translate_z80_ea(inst, &src_op, opts, READ, MODIFY); } if (inst->reg != Z80_USE_IMMED) { - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } if (inst->addr_mode != Z80_REG) { //Reads normally take 3 cycles, but the read in the middle of a set instruction takes 4 - dst = cycles(&opts->gen, 1); + cycles(&opts->gen, 1); } - dst = bts_ir(dst, bit, src_op.base, size); + bts_ir(code, bit, src_op.base, size); if (inst->reg != Z80_USE_IMMED) { if (size == SZ_W) { if (dst_op.base >= R8) { - dst = ror_ir(dst, 8, src_op.base, SZ_W); - dst = mov_rr(dst, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B); - dst = ror_ir(dst, 8, src_op.base, SZ_W); + ror_ir(code, 8, src_op.base, SZ_W); + mov_rr(code, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B); + ror_ir(code, 8, src_op.base, SZ_W); } else { - dst = mov_rr(dst, opts->regs[inst->ea_reg], dst_op.base, SZ_B); + mov_rr(code, opts->regs[inst->ea_reg], dst_op.base, SZ_B); } } else { - dst = mov_rr(dst, src_op.base, dst_op.base, SZ_B); + mov_rr(code, src_op.base, dst_op.base, SZ_B); } } if ((inst->addr_mode & 0x1F) != Z80_REG) { - dst = z80_save_result(dst, inst); + z80_save_result(code, inst); if (inst->reg != Z80_USE_IMMED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } break; } case Z80_RES: { - cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; - dst = cycles(&opts->gen, cycles); + num_cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; + cycles(&opts->gen, num_cycles); uint8_t bit; if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { src_op.base = opts->regs[z80_word_reg(inst->ea_reg)]; @@ -1267,361 +1265,361 @@ uint8_t * translate_z80inst(z80inst * inst, z80_context * context, uint16_t addr } else { size = SZ_B; bit = inst->immed; - dst = translate_z80_ea(inst, &src_op, dst, opts, READ, MODIFY); + translate_z80_ea(inst, &src_op, opts, READ, MODIFY); } if (inst->reg != Z80_USE_IMMED) { - dst = translate_z80_reg(inst, &dst_op, dst, opts); + translate_z80_reg(inst, &dst_op, opts); } if (inst->addr_mode != Z80_REG) { //Reads normally take 3 cycles, but the read in the middle of a set instruction takes 4 - dst = cycles(&opts->gen, 1); + cycles(&opts->gen, 1); } - dst = btr_ir(dst, bit, src_op.base, size); + btr_ir(code, bit, src_op.base, size); if (inst->reg != Z80_USE_IMMED) { if (size == SZ_W) { if (dst_op.base >= R8) { - dst = ror_ir(dst, 8, src_op.base, SZ_W); - dst = mov_rr(dst, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B); - dst = ror_ir(dst, 8, src_op.base, SZ_W); + ror_ir(code, 8, src_op.base, SZ_W); + mov_rr(code, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B); + ror_ir(code, 8, src_op.base, SZ_W); } else { - dst = mov_rr(dst, opts->regs[inst->ea_reg], dst_op.base, SZ_B); + mov_rr(code, opts->regs[inst->ea_reg], dst_op.base, SZ_B); } } else { - dst = mov_rr(dst, src_op.base, dst_op.base, SZ_B); + mov_rr(code, src_op.base, dst_op.base, SZ_B); } } if (inst->addr_mode != Z80_REG) { - dst = z80_save_result(dst, inst); + z80_save_result(code, inst); if (inst->reg != Z80_USE_IMMED) { - dst = z80_save_reg(dst, inst, opts); + z80_save_reg(inst, opts); } } break; } case Z80_JP: { - cycles = 4; + num_cycles = 4; if (inst->addr_mode != Z80_REG_INDIRECT) { - cycles += 6; + num_cycles += 6; } else if(inst->ea_reg == Z80_IX || inst->ea_reg == Z80_IY) { - cycles += 4; + num_cycles += 4; } - dst = cycles(&opts->gen, cycles); + cycles(&opts->gen, num_cycles); if (inst->addr_mode != Z80_REG_INDIRECT && inst->immed < 0x4000) { - uint8_t * call_dst = z80_get_native_address(context, inst->immed); + code_ptr call_dst = z80_get_native_address(context, inst->immed); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, inst->immed, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); } else { if (inst->addr_mode == Z80_REG_INDIRECT) { - dst = mov_rr(dst, opts->regs[inst->ea_reg], opts->gen.scratch1, SZ_W); + mov_rr(code, opts->regs[inst->ea_reg], opts->gen.scratch1, SZ_W); } else { - dst = mov_ir(dst, inst->immed, opts->gen.scratch1, SZ_W); + mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); } - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, opts->gen.scratch1); + call(code, (uint8_t *)z80_native_addr); + jmp_r(code, opts->gen.scratch1); } break; } case Z80_JPCC: { - dst = cycles(&opts->gen, 7);//T States: 4,3 + cycles(&opts->gen, 7);//T States: 4,3 uint8_t cond = CC_Z; switch (inst->reg) { case Z80_CC_NZ: cond = CC_NZ; case Z80_CC_Z: - dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); break; case Z80_CC_NC: cond = CC_NZ; case Z80_CC_C: - dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); break; case Z80_CC_PO: cond = CC_NZ; case Z80_CC_PE: - dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; case Z80_CC_P: cond = CC_NZ; case Z80_CC_M: - dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); break; } - uint8_t *no_jump_off = dst+1; - dst = jcc(dst, cond, dst+2); - dst = cycles(&opts->gen, 5);//T States: 5 + uint8_t *no_jump_off = code->cur+1; + jcc(code, cond, code->cur+2); + cycles(&opts->gen, 5);//T States: 5 uint16_t dest_addr = inst->immed; if (dest_addr < 0x4000) { - uint8_t * call_dst = z80_get_native_address(context, dest_addr); + code_ptr call_dst = z80_get_native_address(context, dest_addr); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, dest_addr, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); } else { - dst = mov_ir(dst, dest_addr, opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, opts->gen.scratch1); + mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_native_addr); + jmp_r(code, opts->gen.scratch1); } - *no_jump_off = dst - (no_jump_off+1); + *no_jump_off = code->cur - (no_jump_off+1); break; } case Z80_JR: { - dst = cycles(&opts->gen, 12);//T States: 4,3,5 + cycles(&opts->gen, 12);//T States: 4,3,5 uint16_t dest_addr = address + inst->immed + 2; if (dest_addr < 0x4000) { - uint8_t * call_dst = z80_get_native_address(context, dest_addr); + code_ptr call_dst = z80_get_native_address(context, dest_addr); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, dest_addr, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); } else { - dst = mov_ir(dst, dest_addr, opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, opts->gen.scratch1); + mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_native_addr); + jmp_r(code, opts->gen.scratch1); } break; } case Z80_JRCC: { - dst = cycles(&opts->gen, 7);//T States: 4,3 + cycles(&opts->gen, 7);//T States: 4,3 uint8_t cond = CC_Z; switch (inst->reg) { case Z80_CC_NZ: cond = CC_NZ; case Z80_CC_Z: - dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); break; case Z80_CC_NC: cond = CC_NZ; case Z80_CC_C: - dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); break; } - uint8_t *no_jump_off = dst+1; - dst = jcc(dst, cond, dst+2); - dst = cycles(&opts->gen, 5);//T States: 5 + uint8_t *no_jump_off = code->cur+1; + jcc(code, cond, code->cur+2); + cycles(&opts->gen, 5);//T States: 5 uint16_t dest_addr = address + inst->immed + 2; if (dest_addr < 0x4000) { - uint8_t * call_dst = z80_get_native_address(context, dest_addr); + code_ptr call_dst = z80_get_native_address(context, dest_addr); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, dest_addr, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); } else { - dst = mov_ir(dst, dest_addr, opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, opts->gen.scratch1); + mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_native_addr); + jmp_r(code, opts->gen.scratch1); } - *no_jump_off = dst - (no_jump_off+1); + *no_jump_off = code->cur - (no_jump_off+1); break; } case Z80_DJNZ: - dst = cycles(&opts->gen, 8);//T States: 5,3 - dst = sub_ir(dst, 1, opts->regs[Z80_B], SZ_B); - uint8_t *no_jump_off = dst+1; - dst = jcc(dst, CC_Z, dst+2); - dst = cycles(&opts->gen, 5);//T States: 5 + cycles(&opts->gen, 8);//T States: 5,3 + sub_ir(code, 1, opts->regs[Z80_B], SZ_B); + uint8_t *no_jump_off = code->cur+1; + jcc(code, CC_Z, code->cur+2); + cycles(&opts->gen, 5);//T States: 5 uint16_t dest_addr = address + inst->immed + 2; if (dest_addr < 0x4000) { - uint8_t * call_dst = z80_get_native_address(context, dest_addr); + code_ptr call_dst = z80_get_native_address(context, dest_addr); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, dest_addr, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); } else { - dst = mov_ir(dst, dest_addr, opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, opts->gen.scratch1); + mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_native_addr); + jmp_r(code, opts->gen.scratch1); } - *no_jump_off = dst - (no_jump_off+1); + *no_jump_off = code->cur - (no_jump_off+1); break; case Z80_CALL: { - dst = cycles(&opts->gen, 11);//T States: 4,3,4 - dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = mov_ir(dst, address + 3, opts->gen.scratch1, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 + cycles(&opts->gen, 11);//T States: 4,3,4 + sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); + mov_ir(code, address + 3, opts->gen.scratch1, SZ_W); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); + call(code, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 if (inst->immed < 0x4000) { - uint8_t * call_dst = z80_get_native_address(context, inst->immed); + code_ptr call_dst = z80_get_native_address(context, inst->immed); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, inst->immed, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); } else { - dst = mov_ir(dst, inst->immed, opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, opts->gen.scratch1); + mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_native_addr); + jmp_r(code, opts->gen.scratch1); } break; } case Z80_CALLCC: - dst = cycles(&opts->gen, 10);//T States: 4,3,3 (false case) + cycles(&opts->gen, 10);//T States: 4,3,3 (false case) uint8_t cond = CC_Z; switch (inst->reg) { case Z80_CC_NZ: cond = CC_NZ; case Z80_CC_Z: - dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); break; case Z80_CC_NC: cond = CC_NZ; case Z80_CC_C: - dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); break; case Z80_CC_PO: cond = CC_NZ; case Z80_CC_PE: - dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; case Z80_CC_P: cond = CC_NZ; case Z80_CC_M: - dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); break; } - uint8_t *no_call_off = dst+1; - dst = jcc(dst, cond, dst+2); - dst = cycles(&opts->gen, 1);//Last of the above T states takes an extra cycle in the true case - dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = mov_ir(dst, address + 3, opts->gen.scratch1, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 + uint8_t *no_call_off = code->cur+1; + jcc(code, cond, code->cur+2); + cycles(&opts->gen, 1);//Last of the above T states takes an extra cycle in the true case + sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); + mov_ir(code, address + 3, opts->gen.scratch1, SZ_W); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); + call(code, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 if (inst->immed < 0x4000) { - uint8_t * call_dst = z80_get_native_address(context, inst->immed); + code_ptr call_dst = z80_get_native_address(context, inst->immed); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, inst->immed, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); } else { - dst = mov_ir(dst, inst->immed, opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, opts->gen.scratch1); + mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_native_addr); + jmp_r(code, opts->gen.scratch1); } - *no_call_off = dst - (no_call_off+1); + *no_call_off = code->cur - (no_call_off+1); break; case Z80_RET: - dst = cycles(&opts->gen, 4);//T States: 4 - dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3 - dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, opts->gen.scratch1); + cycles(&opts->gen, 4);//T States: 4 + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_read_word);//T STates: 3, 3 + add_ir(code, 2, opts->regs[Z80_SP], SZ_W); + call(code, (uint8_t *)z80_native_addr); + jmp_r(code, opts->gen.scratch1); break; case Z80_RETCC: { - dst = cycles(&opts->gen, 5);//T States: 5 + cycles(&opts->gen, 5);//T States: 5 uint8_t cond = CC_Z; switch (inst->reg) { case Z80_CC_NZ: cond = CC_NZ; case Z80_CC_Z: - dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_Z), SZ_B); break; case Z80_CC_NC: cond = CC_NZ; case Z80_CC_C: - dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); break; case Z80_CC_PO: cond = CC_NZ; case Z80_CC_PE: - dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); break; case Z80_CC_P: cond = CC_NZ; case Z80_CC_M: - dst = cmp_irdisp8(dst, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); + cmp_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); break; } - uint8_t *no_call_off = dst+1; - dst = jcc(dst, cond, dst+2); - dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3 - dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, opts->gen.scratch1); - *no_call_off = dst - (no_call_off+1); + uint8_t *no_call_off = code->cur+1; + jcc(code, cond, code->cur+2); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_read_word);//T STates: 3, 3 + add_ir(code, 2, opts->regs[Z80_SP], SZ_W); + call(code, (uint8_t *)z80_native_addr); + jmp_r(code, opts->gen.scratch1); + *no_call_off = code->cur - (no_call_off+1); break; } case Z80_RETI: //For some systems, this may need a callback for signalling interrupt routine completion - dst = cycles(&opts->gen, 8);//T States: 4, 4 - dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); - dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3 - dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, opts->gen.scratch1); + cycles(&opts->gen, 8);//T States: 4, 4 + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + call(code, (uint8_t *)z80_read_word);//T STates: 3, 3 + add_ir(code, 2, opts->regs[Z80_SP], SZ_W); + call(code, (uint8_t *)z80_native_addr); + jmp_r(code, opts->gen.scratch1); break; case Z80_RETN: - dst = cycles(&opts->gen, 8);//T States: 4, 4 - dst = mov_rdisp8r(dst, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch2, SZ_B); - dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); - dst = mov_rrdisp8(dst, opts->gen.scratch2, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); - dst = call(dst, (uint8_t *)z80_read_word);//T STates: 3, 3 - dst = add_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = call(dst, (uint8_t *)z80_native_addr); - dst = jmp_r(dst, opts->gen.scratch1); + cycles(&opts->gen, 8);//T States: 4, 4 + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch2, SZ_B); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); + mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); + call(code, (uint8_t *)z80_read_word);//T STates: 3, 3 + add_ir(code, 2, opts->regs[Z80_SP], SZ_W); + call(code, (uint8_t *)z80_native_addr); + jmp_r(code, opts->gen.scratch1); break; case Z80_RST: { //RST is basically CALL to an address in page 0 - dst = cycles(&opts->gen, 5);//T States: 5 - dst = sub_ir(dst, 2, opts->regs[Z80_SP], SZ_W); - dst = mov_ir(dst, address + 1, opts->gen.scratch1, SZ_W); - dst = mov_rr(dst, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); - dst = call(dst, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 - uint8_t * call_dst = z80_get_native_address(context, inst->immed); + cycles(&opts->gen, 5);//T States: 5 + sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); + mov_ir(code, address + 1, opts->gen.scratch1, SZ_W); + mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); + call(code, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 + code_ptr call_dst = z80_get_native_address(context, inst->immed); if (!call_dst) { - opts->deferred = defer_address(opts->deferred, inst->immed, dst + 1); + opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); //fake address to force large displacement - call_dst = dst + 256; + call_dst + 256; } - dst = jmp(dst, call_dst); + jmp(code, call_dst); break; } case Z80_IN: - dst = cycles(&opts->gen, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4 + cycles(&opts->gen, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4 if (inst->addr_mode == Z80_IMMED_INDIRECT) { - dst = mov_ir(dst, inst->immed, opts->gen.scratch1, SZ_B); + mov_ir(code, inst->immed, opts->gen.scratch1, SZ_B); } else { - dst = mov_rr(dst, opts->regs[Z80_C], opts->gen.scratch1, SZ_B); + mov_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B); } - dst = call(dst, (uint8_t *)z80_io_read); - translate_z80_reg(inst, &dst_op, dst, opts); - dst = mov_rr(dst, opts->gen.scratch1, dst_op.base, SZ_B); - dst = z80_save_reg(dst, inst, opts); + call(code, (uint8_t *)z80_io_read); + translate_z80_reg(inst, &dst_op, opts); + mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_B); + z80_save_reg(inst, opts); break; /*case Z80_INI: case Z80_INIR: case Z80_IND: case Z80_INDR:*/ case Z80_OUT: - dst = cycles(&opts->gen, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4 + cycles(&opts->gen, inst->reg == Z80_A ? 7 : 8);//T States: 4 3/4 if ((inst->addr_mode & 0x1F) == Z80_IMMED_INDIRECT) { - dst = mov_ir(dst, inst->immed, opts->gen.scratch2, SZ_B); + mov_ir(code, inst->immed, opts->gen.scratch2, SZ_B); } else { - dst = mov_rr(dst, opts->regs[Z80_C], opts->gen.scratch2, SZ_B); + mov_rr(code, opts->regs[Z80_C], opts->gen.scratch2, SZ_B); } - translate_z80_reg(inst, &src_op, dst, opts); - dst = mov_rr(dst, dst_op.base, opts->gen.scratch1, SZ_B); - dst = call(dst, (uint8_t *)z80_io_write); - dst = z80_save_reg(dst, inst, opts); + translate_z80_reg(inst, &src_op, opts); + mov_rr(code, dst_op.base, opts->gen.scratch1, SZ_B); + call(code, (uint8_t *)z80_io_write); + z80_save_reg(inst, opts); break; /*case Z80_OUTI: case Z80_OTIR: @@ -1637,7 +1635,6 @@ uint8_t * translate_z80inst(z80inst * inst, z80_context * context, uint16_t addr exit(1); } } - return dst; } uint8_t * z80_get_native_address(z80_context * context, uint32_t address) @@ -1666,7 +1663,7 @@ uint8_t z80_get_native_inst_size(z80_options * opts, uint32_t address) if (address >= 0x4000) { return 0; } - return opts->ram_inst_sizes[address & 0x1FFF]; + return opts->gen.ram_inst_sizes[0][address & 0x1FFF]; } void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * native_address, uint8_t size, uint8_t native_size) @@ -1677,7 +1674,7 @@ void z80_map_native_address(z80_context * context, uint32_t address, uint8_t * n if (address < 0x4000) { address &= 0x1FFF; map = context->static_code_map; - opts->ram_inst_sizes[address] = native_size; + opts->gen.ram_inst_sizes[0][address] = native_size; context->ram_code_flags[(address & 0x1C00) >> 10] |= 1 << ((address & 0x380) >> 7); context->ram_code_flags[((address + size) & 0x1C00) >> 10] |= 1 << (((address + size) & 0x380) >> 7); } else if (address >= 0x8000) { @@ -1735,10 +1732,12 @@ z80_context * z80_handle_code_write(uint32_t address, z80_context * context) { uint32_t inst_start = z80_get_instruction_start(context->static_code_map, address); if (inst_start != INVALID_INSTRUCTION_START) { - uint8_t * dst = z80_get_native_address(context, inst_start); - dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", dst, inst_start, address); - dst = mov_ir(dst, inst_start, opts->gen.scratch1, SZ_D); - dst = call(dst, (uint8_t *)z80_retrans_stub); + code_ptr dst = z80_get_native_address(context, inst_start); + code_info code = {dst, dst+16}; + z80_options * opts = context->options; + dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code, inst_start, address); + mov_ir(&code, inst_start, opts->gen.scratch1, SZ_D); + call(&code, (uint8_t *)z80_retrans_stub); } return context; } @@ -1759,9 +1758,9 @@ uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address) void z80_handle_deferred(z80_context * context) { z80_options * opts = context->options; - process_deferred(&opts->deferred, context, (native_addr_func)z80_get_native_address); - if (opts->deferred) { - translate_z80_stream(context, opts->deferred->address); + process_deferred(&opts->gen.deferred, context, (native_addr_func)z80_get_native_address); + if (opts->gen.deferred) { + translate_z80_stream(context, opts->gen.deferred->address); } } @@ -1772,8 +1771,7 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o uint8_t orig_size = z80_get_native_inst_size(opts, address); uint32_t orig = address; address &= 0x1FFF; - uint8_t * dst = opts->cur_code; - uint8_t * dst_end = opts->code_end; + code_info *code = &opts->gen.code; uint8_t *after, *inst = context->mem_pointers[0] + address; z80inst instbuf; dprintf("Retranslating code at Z80 address %X, native address %p\n", address, orig_start); @@ -1787,18 +1785,14 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o } #endif if (orig_size != ZMAX_NATIVE_SIZE) { - if (dst_end - dst < ZMAX_NATIVE_SIZE) { - size_t size = 1024*1024; - dst = alloc_code(&size); - opts->code_end = dst_end = dst + size; - opts->cur_code = dst; - } - deferred_addr * orig_deferred = opts->deferred; - uint8_t * native_end = translate_z80inst(&instbuf, dst, context, address); + code_ptr start = code->cur; + deferred_addr * orig_deferred = opts->gen.deferred; + translate_z80inst(&instbuf, context, address); + /* if ((native_end - dst) <= orig_size) { uint8_t * native_next = z80_get_native_address(context, address + after-inst); if (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - dst)) > 5)) { - remove_deferred_until(&opts->deferred, orig_deferred); + remove_deferred_until(&opts->gen.deferred, orig_deferred); native_end = translate_z80inst(&instbuf, orig_start, context, address); if (native_next == orig_start + orig_size && (native_next-native_end) < 2) { while (native_end < orig_start + orig_size) { @@ -1810,20 +1804,25 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o z80_handle_deferred(context); return orig_start; } - } - z80_map_native_address(context, address, dst, after-inst, ZMAX_NATIVE_SIZE); - opts->cur_code = dst+ZMAX_NATIVE_SIZE; - jmp(orig_start, dst); + }*/ + z80_map_native_address(context, address, start, after-inst, ZMAX_NATIVE_SIZE); + code_info tmp_code = {orig_start, orig_start + 16}; + jmp(&tmp_code, start); if (!z80_is_terminal(&instbuf)) { - jmp(native_end, z80_get_native_address_trans(context, address + after-inst)); + jmp(code, z80_get_native_address_trans(context, address + after-inst)); } + code->cur = start + ZMAX_NATIVE_SIZE; z80_handle_deferred(context); - return dst; + return start; } else { - dst = translate_z80inst(&instbuf, orig_start, context, address); + code_info tmp_code = *code; + code->cur = orig_start; + code->last = orig_start + ZMAX_NATIVE_SIZE; + translate_z80inst(&instbuf, context, address); if (!z80_is_terminal(&instbuf)) { - dst = jmp(dst, z80_get_native_address_trans(context, address + after-inst)); + jmp(code, z80_get_native_address_trans(context, address + after-inst)); } + *code = tmp_code; z80_handle_deferred(context); return orig_start; } @@ -1850,24 +1849,14 @@ void translate_z80_stream(z80_context * context, uint32_t address) z80inst inst; dprintf("translating Z80 code at address %X\n", address); do { - if (opts->code_end-opts->cur_code < ZMAX_NATIVE_SIZE) { - if (opts->code_end-opts->cur_code < 5) { - puts("out of code memory, not enough space for jmp to next chunk"); - exit(1); - } - size_t size = 1024*1024; - opts->cur_code = alloc_code(&size); - opts->code_end = opts->cur_code + size; - jmp(opts->cur_code, opts->cur_code); - } if (address > 0x4000 && address < 0x8000) { - opts->cur_code = xor_rr(opts->cur_code, RDI, RDI, SZ_D); - opts->cur_code = call(opts->cur_code, (uint8_t *)exit); + xor_rr(&opts->gen.code, RDI, RDI, SZ_D); + call(&opts->gen.code, (uint8_t *)exit); break; } uint8_t * existing = z80_get_native_address(context, address); if (existing) { - opts->cur_code = jmp(opts->cur_code, existing); + jmp(&opts->gen.code, existing); break; } next = z80_decode(encoded, &inst); @@ -1879,9 +1868,9 @@ void translate_z80_stream(z80_context * context, uint32_t address) printf("%X\t%s\n", address, disbuf); } #endif - uint8_t *after = translate_z80inst(&inst, opts->cur_code, context, address); - z80_map_native_address(context, address, opts->cur_code, next-encoded, after - opts->cur_code); - opts->cur_code = after; + code_ptr start = opts->gen.code.cur; + translate_z80inst(&inst, context, address); + z80_map_native_address(context, address, start, next-encoded, opts->gen.code.cur - start); address += next-encoded; if (address > 0xFFFF) { address &= 0xFFFF; @@ -1890,9 +1879,9 @@ void translate_z80_stream(z80_context * context, uint32_t address) encoded = next; } } while (!z80_is_terminal(&inst)); - process_deferred(&opts->deferred, context, (native_addr_func)z80_get_native_address); - if (opts->deferred) { - address = opts->deferred->address; + process_deferred(&opts->gen.deferred, context, (native_addr_func)z80_get_native_address); + if (opts->gen.deferred) { + address = opts->gen.deferred->address; dprintf("defferred address: %X\n", address); if (address < 0x4000) { encoded = context->mem_pointers[0] + (address & 0x1FFF); @@ -1953,8 +1942,9 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk * chunks, uint32_t nu options->gen.native_code_map = malloc(sizeof(native_map_slot)); memset(options->gen.native_code_map, 0, sizeof(native_map_slot)); options->gen.deferred = NULL; - options->gen.ram_inst_sizes = malloc(sizeof(uint8_t) * 0x2000); - memset(options->ram_inst_sizes, 0, sizeof(uint8_t) * 0x2000); + options->gen.ram_inst_sizes = malloc(sizeof(uint8_t) * 0x2000 + sizeof(uint8_t *)); + options->gen.ram_inst_sizes[0] = (uint8_t *)(options->gen.ram_inst_sizes + 1); + memset(options->gen.ram_inst_sizes[0], 0, sizeof(uint8_t) * 0x2000); code_info *code = &options->gen.code; init_code_info(code); @@ -2028,18 +2018,18 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk * chunks, uint32_t nu mov_rrdisp(code, RBX, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR); mov_rrind(code, RAX, options->gen.context_reg, SZ_PTR); //restore callee saved registers - pop_r(code, R15) - pop_r(code, R14) - pop_r(code, R13) - pop_r(code, R12) - pop_r(code, RBP) - pop_r(code, RBX) + pop_r(code, R15); + pop_r(code, R14); + pop_r(code, R13); + pop_r(code, R12); + pop_r(code, RBP); + pop_r(code, RBX); *no_sync = code->cur - no_sync; //return to caller of z80_run retn(code); - options->gen.read_8 = gen_mem_fun(&options->gen, chunks, num_chunks, READ_8, NULL); - options->gen.write_8 = gen_mem_fun(&options->gen, chunks, num_chunks, WRITE_8, &options->write_8_noinc); + options->read_8 = gen_mem_fun(&options->gen, chunks, num_chunks, READ_8, NULL); + options->write_8 = gen_mem_fun(&options->gen, chunks, num_chunks, WRITE_8, &options->write_8_noinc); options->gen.handle_cycle_limit_int = code->cur; cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, int_cycle), options->gen.cycles, SZ_D); @@ -2048,8 +2038,8 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk * chunks, uint32_t nu //set limit to the cycle limit mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.limit, SZ_D); //disable interrupts - move_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B); - move_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B); + mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff1), SZ_B); + mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, iff2), SZ_B); cycles(&options->gen, 7); //save return address (in scratch1) to Z80 stack sub_ir(code, 2, options->regs[Z80_SP], SZ_W); @@ -2072,7 +2062,7 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk * chunks, uint32_t nu cycles(&options->gen, 3); call(code, options->write_8_noinc); //dispose of return address as we'll be jumping somewhere else - pop_r(options->gen.scratch2); + pop_r(code, options->gen.scratch2); //TODO: Support interrupt mode 0 and 2 mov_ir(code, 0x38, options->gen.scratch1, SZ_W); call(code, (code_ptr)z80_native_addr); @@ -2102,59 +2092,58 @@ void z80_reset(z80_context * context) void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler) { static uint8_t * bp_stub = NULL; + z80_options * opts = context->options; uint8_t * native = z80_get_native_address_trans(context, address); - uint8_t * start_native = native; - native = mov_ir(native, address, opts->gen.scratch1, SZ_W); + code_info tmp_code = {native, native+16}; + mov_ir(&tmp_code, address, opts->gen.scratch1, SZ_W); if (!bp_stub) { - z80_options * opts = context->options; - uint8_t * dst = opts->cur_code; - uint8_t * dst_end = opts->code_end; - if (dst_end - dst < 128) { - size_t size = 1024*1024; - dst = alloc_code(&size); - opts->code_end = dst_end = dst + size; - } - bp_stub = dst; - native = call(native, bp_stub); + code_info *code = &opts->gen.code; + //TODO: do an alloc check here to make sure the prologue length calc works + bp_stub = code->cur; + call(&tmp_code, bp_stub); //Calculate length of prologue - dst = z80_check_cycles_int(dst, address); - int check_int_size = dst-bp_stub; - dst = bp_stub; + check_cycles_int(&opts->gen, address); + int check_int_size = code->cur-bp_stub; + code->cur = bp_stub; //Save context and call breakpoint handler - dst = call(dst, (uint8_t *)z80_save_context); - dst = push_r(dst, opts->gen.scratch1); - dst = mov_rr(dst, opts->gen.context_reg, RDI, SZ_Q); - dst = mov_rr(dst, opts->gen.scratch1, RSI, SZ_W); - dst = call(dst, bp_handler); - dst = mov_rr(dst, RAX, opts->gen.context_reg, SZ_Q); + call(code, (uint8_t *)z80_save_context); + push_r(code, opts->gen.scratch1); + mov_rr(code, opts->gen.context_reg, RDI, SZ_Q); + mov_rr(code, opts->gen.scratch1, RSI, SZ_W); + call(code, bp_handler); + mov_rr(code, RAX, opts->gen.context_reg, SZ_Q); //Restore context - dst = call(dst, (uint8_t *)z80_load_context); - dst = pop_r(dst, opts->gen.scratch1); + call(code, (uint8_t *)z80_load_context); + pop_r(code, opts->gen.scratch1); //do prologue stuff - dst = cmp_rr(dst, opts->gen.cycles, opts->gen.limit, SZ_D); - uint8_t * jmp_off = dst+1; - dst = jcc(dst, CC_NC, dst + 7); - dst = pop_r(dst, opts->gen.scratch1); - dst = add_ir(dst, check_int_size - (native-start_native), opts->gen.scratch1, SZ_Q); - dst = push_r(dst, opts->gen.scratch1); - dst = jmp(dst, (uint8_t *)z80_handle_cycle_limit_int); - *jmp_off = dst - (jmp_off+1); + cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D); + uint8_t * jmp_off = code->cur+1; + jcc(code, CC_NC, code->cur + 7); + pop_r(code, opts->gen.scratch1); + add_ir(code, check_int_size - (code->cur-native), opts->gen.scratch1, SZ_Q); + push_r(code, opts->gen.scratch1); + jmp(code, (uint8_t *)z80_handle_cycle_limit_int); + *jmp_off = code->cur - (jmp_off+1); //jump back to body of translated instruction - dst = pop_r(dst, opts->gen.scratch1); - dst = add_ir(dst, check_int_size - (native-start_native), opts->gen.scratch1, SZ_Q); - dst = jmp_r(dst, opts->gen.scratch1); - opts->cur_code = dst; + pop_r(code, opts->gen.scratch1); + add_ir(code, check_int_size - (code->cur-native), opts->gen.scratch1, SZ_Q); + jmp_r(code, opts->gen.scratch1); } else { - native = call(native, bp_stub); + call(&tmp_code, bp_stub); } } void zremove_breakpoint(z80_context * context, uint16_t address) { uint8_t * native = z80_get_native_address(context, address); - z80_check_cycles_int(native, address); + z80_options * opts = context->options; + code_info tmp_code = opts->gen.code; + opts->gen.code.cur = native; + opts->gen.code.last = native + 16; + check_cycles_int(&opts->gen, address); + opts->gen.code = tmp_code; } diff --git a/z80_to_x86.h b/z80_to_x86.h index b33311e..fa9db33 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -25,10 +25,17 @@ typedef struct { cpu_options gen; code_ptr save_context_scratch; code_ptr load_context_scratch; + code_ptr read_8; + code_ptr write_8; code_ptr write_8_noinc; + code_ptr read_16; + code_ptr write_16_highfirst; + code_ptr write_16_lowfirst; uint32_t flags; int8_t regs[Z80_UNUSED]; + int8_t bank_reg; + int8_t bank_pointer; } z80_options; typedef struct { @@ -62,8 +69,8 @@ typedef struct { void translate_z80_stream(z80_context * context, uint32_t address); void init_x86_z80_opts(z80_options * options, memmap_chunk * chunks, uint32_t num_chunks); void init_z80_context(z80_context * context, z80_options * options); -uint8_t * z80_get_native_address(z80_context * context, uint32_t address); -uint8_t * z80_get_native_address_trans(z80_context * context, uint32_t address); +code_ptr z80_get_native_address(z80_context * context, uint32_t address); +code_ptr z80_get_native_address_trans(z80_context * context, uint32_t address); z80_context * z80_handle_code_write(uint32_t address, z80_context * context); void z80_run(z80_context * context); void z80_reset(z80_context * context); -- cgit v1.2.3 From 4cad512b6d7ac0f7042b90e1029626fb14788bf0 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 17 Dec 2014 23:03:19 -0800 Subject: Get rest of emulator compiling again with Z80 core enabled --- backend.h | 1 + blastem.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++--- z80_to_x86.c | 9 ++++++++- z80_to_x86.h | 3 ++- 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/backend.h b/backend.h index 97e2ae4..a228d13 100644 --- a/backend.h +++ b/backend.h @@ -79,6 +79,7 @@ typedef struct { #define MMAP_ONLY_ODD 0x10 #define MMAP_ONLY_EVEN 0x20 #define MMAP_FUNC_NULL 0x40 +#define MMAP_CUSTOM 0x80 typedef uint16_t (*read_16_fun)(uint32_t address, void * context); typedef uint8_t (*read_8_fun)(uint32_t address, void * context); diff --git a/blastem.c b/blastem.c index 4555f86..2659fa4 100644 --- a/blastem.c +++ b/blastem.c @@ -383,8 +383,9 @@ m68k_context * vdp_port_write_b(uint32_t vdp_port, m68k_context * context, uint8 return vdp_port_write(vdp_port, context, vdp_port < 0x10 ? value | value << 8 : ((vdp_port & 1) ? value : 0)); } -z80_context * z80_vdp_port_write(uint16_t vdp_port, z80_context * context, uint8_t value) +void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value) { + z80_context * context = vcontext; genesis_context * gen = context->system; if (vdp_port & 0xE0) { printf("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port); @@ -453,6 +454,34 @@ uint8_t vdp_port_read_b(uint32_t vdp_port, m68k_context * context) } } +uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext) +{ + z80_context * context = vcontext; + if (vdp_port & 0xE0) { + printf("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port); + exit(1); + } + genesis_context * gen = context->system; + vdp_port &= 0x1F; + 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 * MCLKS_PER_Z80); + if (vdp_port < 4) { + ret = vdp_data_port_read(gen->vdp); + } else if (vdp_port < 8) { + ret = vdp_control_port_read(gen->vdp); + } else { + printf("Illegal write to HV Counter port %X\n", vdp_port); + exit(1); + } + } else { + //TODO: Figure out the correct value today + ret = 0xFFFF; + } + return vdp_port & 1 ? ret : ret >> 8; +} + uint32_t zram_counter = 0; #define Z80_ACK_DELAY 3 #define Z80_BUSY_DELAY 1//TODO: Find the actual value for this @@ -674,8 +703,9 @@ uint16_t io_read_w(uint32_t location, m68k_context * context) return value; } -z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value) +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 * MCLKS_PER_Z80); if (location & 1) { @@ -688,13 +718,28 @@ z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t val return context; } -uint8_t z80_read_ym(uint16_t location, z80_context * context) +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 * MCLKS_PER_Z80); return ym_read_status(gen->ym); } +uint8_t z80_read_bank(uint32_t location, void * vcontext) +{ + z80_context * context = vcontext; + //TODO: Implement me + return 0; +} + +void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value) +{ + z80_context * context = vcontext; + //TODO: Implement me + return context; +} + uint16_t read_sram_w(uint32_t address, m68k_context * context) { genesis_context * gen = context->system; diff --git a/z80_to_x86.c b/z80_to_x86.c index ba4fc66..6d5f928 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -1897,7 +1897,7 @@ void translate_z80_stream(z80_context * context, uint32_t address) } } -void init_x86_z80_opts(z80_options * options, memmap_chunk * chunks, uint32_t num_chunks) +void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks) { memset(options, 0, sizeof(*options)); @@ -2069,6 +2069,13 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk * chunks, uint32_t nu jmp_r(code, options->gen.scratch1); } +void * z80_gen_bank_write(uint32_t start_address, void * voptions) +{ + z80_options * options = voptions; + //TODO: Handle writes to bank register + return options; +} + void init_z80_context(z80_context * context, z80_options * options) { memset(context, 0, sizeof(*context)); diff --git a/z80_to_x86.h b/z80_to_x86.h index fa9db33..d5d232c 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -67,7 +67,7 @@ typedef struct { } z80_context; void translate_z80_stream(z80_context * context, uint32_t address); -void init_x86_z80_opts(z80_options * options, memmap_chunk * chunks, uint32_t num_chunks); +void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks); void init_z80_context(z80_context * context, z80_options * options); code_ptr z80_get_native_address(z80_context * context, uint32_t address); code_ptr z80_get_native_address_trans(z80_context * context, uint32_t address); @@ -76,6 +76,7 @@ void z80_run(z80_context * context); void z80_reset(z80_context * context); void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler); void zremove_breakpoint(z80_context * context, uint16_t address); +void * z80_gen_bank_write(uint32_t start_address, void * voptions); #endif //Z80_TO_X86_H_ -- cgit v1.2.3 From 12c73dc400c1b6b61531df4ff0fd1efe4ef7ae12 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 22 Dec 2014 20:55:10 -0800 Subject: Z80 core is sort of working again --- Makefile | 2 +- backend.h | 2 +- backend_x86.c | 2 +- blastem.c | 2 +- gen_x86.c | 34 +++++++++ gen_x86.h | 3 + z80_to_x86.c | 237 ++++++++++++++++++++++++++++++++++++++-------------------- z80_to_x86.h | 23 ++++-- ztestrun.c | 53 +++++-------- 9 files changed, 228 insertions(+), 130 deletions(-) diff --git a/Makefile b/Makefile index 61e8a19..272605d 100644 --- a/Makefile +++ b/Makefile @@ -38,7 +38,7 @@ NOZ80:=1 endif endif -Z80OBJS=z80inst.o z80_to_x86.o zruntime.o +Z80OBJS=z80inst.o z80_to_x86.o AUDIOOBJS=ym2612.o psg.o wave.o CONFIGOBJS=config.o tern.o util.o diff --git a/backend.h b/backend.h index a228d13..131314c 100644 --- a/backend.h +++ b/backend.h @@ -109,7 +109,7 @@ void cycles(cpu_options *opts, uint32_t num); void check_cycles_int(cpu_options *opts, uint32_t address); void check_cycles(cpu_options * opts); -code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc); +code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc); #endif //BACKEND_H_ diff --git a/backend_x86.c b/backend_x86.c index 7f75761..6ba1a7a 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -28,7 +28,7 @@ void check_cycles(cpu_options * opts) *jmp_off = code->cur - (jmp_off+1); } -code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc) +code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc) { code_info *code = &opts->code; code_ptr start = code->cur; diff --git a/blastem.c b/blastem.c index 2659fa4..c704ef2 100644 --- a/blastem.c +++ b/blastem.c @@ -198,7 +198,7 @@ void sync_z80(z80_context * z_context, uint32_t mclks) } z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle; dprintf("Running Z80 from cycle %d to cycle %d. Native PC: %p\n", z_context->current_cycle, z_context->sync_cycle, z_context->native_pc); - z80_run(z_context); + z_context->run(z_context); dprintf("Z80 ran to cycle %d\n", z_context->current_cycle); } } diff --git a/gen_x86.c b/gen_x86.c index ccc03eb..b1b48d4 100644 --- a/gen_x86.c +++ b/gen_x86.c @@ -33,6 +33,7 @@ #define OP_TEST 0x84 #define OP_XCHG 0x86 #define OP_MOV 0x88 +#define PRE_XOP 0x8F #define OP_XCHG_AX 0x90 #define OP_CDQ 0x99 #define OP_PUSHF 0x9C @@ -1516,6 +1517,13 @@ void push_r(code_info *code, uint8_t reg) code->cur = out; } +void push_rdisp(code_info *code, uint8_t base, int32_t disp) +{ + //This instruction has no explicit size, so we pass SZ_B + //to avoid any prefixes or bits being set + x86_rdisp_size(code, OP_SINGLE_EA, OP_EX_PUSH_EA, base, disp, SZ_B); +} + void pop_r(code_info *code, uint8_t reg) { check_alloc_code(code, 2); @@ -1528,6 +1536,19 @@ void pop_r(code_info *code, uint8_t reg) code->cur = out; } +void pop_rind(code_info *code, uint8_t reg) +{ + check_alloc_code(code, 3); + code_ptr out = code->cur; + if (reg >= R8) { + *(out++) = PRE_REX | REX_RM_FIELD; + reg -= R8 - X86_R8; + } + *(out++) = PRE_XOP; + *(out++) = MODE_REG_INDIRECT | reg; + code->cur = out; +} + void setcc_r(code_info *code, uint8_t cc, uint8_t dst) { check_alloc_code(code, 4); @@ -1855,6 +1876,19 @@ void jmp_r(code_info *code, uint8_t dst) code->cur = out; } +void jmp_rind(code_info *code, uint8_t dst) +{ + check_alloc_code(code, 3); + code_ptr out = code->cur; + if (dst >= R8) { + dst -= R8 - X86_R8; + *(out++) = PRE_REX | REX_RM_FIELD; + } + *(out++) = OP_SINGLE_EA; + *(out++) = MODE_REG_INDIRECT | dst | (OP_EX_JMP_EA << 3); + code->cur = out; +} + void call(code_info *code, code_ptr fun) { check_alloc_code(code, 5); diff --git a/gen_x86.h b/gen_x86.h index 07eae3a..583808b 100644 --- a/gen_x86.h +++ b/gen_x86.h @@ -187,7 +187,9 @@ void xchg_rr(code_info *code, uint8_t src, uint8_t dst, uint8_t size); void pushf(code_info *code); void popf(code_info *code); void push_r(code_info *code, uint8_t reg); +void push_rdisp(code_info *code, uint8_t base, int32_t disp); void pop_r(code_info *code, uint8_t reg); +void pop_rind(code_info *code, uint8_t reg); void setcc_r(code_info *code, uint8_t cc, uint8_t dst); void setcc_rind(code_info *code, uint8_t cc, uint8_t dst); void setcc_rdisp(code_info *code, uint8_t cc, uint8_t dst, int32_t disp); @@ -208,6 +210,7 @@ void btc_rrdisp(code_info *code, uint8_t src, uint8_t dst_base, int32_t dst_disp void btc_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); void btc_irdisp(code_info *code, uint8_t val, uint8_t dst_base, int32_t dst_disp, uint8_t size); void jcc(code_info *code, uint8_t cc, code_ptr dest); +void jmp_rind(code_info *code, uint8_t dst); void call_r(code_info *code, uint8_t dst); void retn(code_info *code); void cdq(code_info *code); diff --git a/z80_to_x86.c b/z80_to_x86.c index 6d5f928..b556b57 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -28,22 +28,6 @@ #define dprintf #endif -void z80_read_byte(); -void z80_read_word(); -void z80_write_byte(); -void z80_write_word_highfirst(); -void z80_write_word_lowfirst(); -void z80_save_context(); -void z80_native_addr(); -void z80_do_sync(); -void z80_handle_cycle_limit_int(); -void z80_retrans_stub(); -void z80_io_read(); -void z80_io_write(); -void z80_halt(); -void z80_save_context(); -void z80_load_context(); - uint8_t z80_size(z80inst * inst) { uint8_t reg = (inst->reg & 0x1F); @@ -184,9 +168,9 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t push_r(code, opts->gen.scratch1); }*/ if (size == SZ_B) { - call(code, (uint8_t *)z80_read_byte); + call(code, opts->read_8); } else { - call(code, (uint8_t *)z80_read_word); + call(code, opts->read_16); } if (modify) { //pop_r(code, opts->gen.scratch2); @@ -207,9 +191,9 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, offsetof(z80_context, scratch1), SZ_W); } if (size == SZ_B) { - call(code, (uint8_t *)z80_read_byte); + call(code, opts->read_8); } else { - call(code, (uint8_t *)z80_read_word); + call(code, opts->read_16); } if (modify) { //pop_r(code, opts->gen.scratch2); @@ -248,7 +232,7 @@ void z80_save_ea(code_info *code, z80inst * inst, z80_options * opts) } } -void z80_save_result(code_info *code, z80inst * inst) +void z80_save_result(z80_options *opts, z80inst * inst) { switch(inst->addr_mode & 0x1f) { @@ -257,9 +241,9 @@ void z80_save_result(code_info *code, z80inst * inst) case Z80_IX_DISPLACE: case Z80_IY_DISPLACE: if (z80_size(inst) == SZ_B) { - call(code, (uint8_t *)z80_write_byte); + call(&opts->gen.code, opts->write_8); } else { - call(code, (uint8_t *)z80_write_word_lowfirst); + call(&opts->gen.code, opts->write_16_lowfirst); } } } @@ -369,7 +353,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) z80_save_reg(inst, opts); z80_save_ea(code, inst, opts); if (inst->addr_mode & Z80_DIR) { - z80_save_result(code, inst); + z80_save_result(opts, inst); } break; case Z80_PUSH: @@ -394,14 +378,14 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) mov_rr(code, src_op.base, opts->gen.scratch1, SZ_W); } mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); - call(code, (uint8_t *)z80_write_word_highfirst); + call(code, opts->write_16_highfirst); //no call to save_z80_reg needed since there's no chance we'll use the only //the upper half of a register pair break; case Z80_POP: cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 8 : 4); mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_read_word); + call(code, opts->read_16); add_ir(code, 2, opts->regs[Z80_SP], SZ_W); if (inst->reg == Z80_AF) { @@ -452,10 +436,10 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) } } else { mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_read_byte); + call(code, opts->read_8); xchg_rr(code, opts->regs[inst->reg], opts->gen.scratch1, SZ_B); mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); - call(code, (uint8_t *)z80_write_byte); + call(code, opts->write_8); cycles(&opts->gen, 1); uint8_t high_reg = z80_high_reg(inst->reg); uint8_t use_reg; @@ -466,11 +450,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) ror_ir(code, 8, use_reg, SZ_W); mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); add_ir(code, 1, opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_read_byte); + call(code, opts->read_8); xchg_rr(code, use_reg, opts->gen.scratch1, SZ_B); mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); add_ir(code, 1, opts->gen.scratch2, SZ_W); - call(code, (uint8_t *)z80_write_byte); + call(code, opts->write_8); //restore reg to normal rotation ror_ir(code, 8, use_reg, SZ_W); cycles(&opts->gen, 2); @@ -491,9 +475,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) case Z80_LDI: { cycles(&opts->gen, 8); mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_read_byte); + call(code, opts->read_8); mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); - call(code, (uint8_t *)z80_write_byte); + call(code, opts->write_8); cycles(&opts->gen, 2); add_ir(code, 1, opts->regs[Z80_DE], SZ_W); add_ir(code, 1, opts->regs[Z80_HL], SZ_W); @@ -506,9 +490,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) case Z80_LDIR: { cycles(&opts->gen, 8); mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_read_byte); + call(code, opts->read_8); mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); - call(code, (uint8_t *)z80_write_byte); + call(code, opts->write_8); add_ir(code, 1, opts->regs[Z80_DE], SZ_W); add_ir(code, 1, opts->regs[Z80_HL], SZ_W); @@ -529,9 +513,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) case Z80_LDD: { cycles(&opts->gen, 8); mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_read_byte); + call(code, opts->read_8); mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); - call(code, (uint8_t *)z80_write_byte); + call(code, opts->write_8); cycles(&opts->gen, 2); sub_ir(code, 1, opts->regs[Z80_DE], SZ_W); sub_ir(code, 1, opts->regs[Z80_HL], SZ_W); @@ -544,9 +528,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) case Z80_LDDR: { cycles(&opts->gen, 8); mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_read_byte); + call(code, opts->read_8); mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); - call(code, (uint8_t *)z80_write_byte); + call(code, opts->write_8); sub_ir(code, 1, opts->regs[Z80_DE], SZ_W); sub_ir(code, 1, opts->regs[Z80_HL], SZ_W); @@ -810,7 +794,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) } z80_save_reg(inst, opts); z80_save_ea(code, inst, opts); - z80_save_result(code, inst); + z80_save_result(opts, inst); break; case Z80_DEC: num_cycles = 4; @@ -836,7 +820,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) } z80_save_reg(inst, opts); z80_save_ea(code, inst, opts); - z80_save_result(code, inst); + z80_save_result(opts, inst); break; //case Z80_DAA: case Z80_CPL: @@ -869,20 +853,30 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) break; case Z80_NOP: if (inst->immed == 42) { - call(code, (uint8_t *)z80_save_context); + call(code, opts->gen.save_context); mov_rr(code, opts->gen.context_reg, RDI, SZ_Q); jmp(code, (uint8_t *)z80_print_regs_exit); } else { cycles(&opts->gen, 4 * inst->immed); } break; - case Z80_HALT: + case Z80_HALT: { cycles(&opts->gen, 4); mov_ir(code, address, opts->gen.scratch1, SZ_W); uint8_t * call_inst = code->cur; - call(code, (uint8_t *)z80_halt); + mov_rr(code, opts->gen.limit, opts->gen.scratch2, SZ_D); + sub_rr(code, opts->gen.cycles, opts->gen.scratch2, SZ_D); + and_ir(code, 0xFFFFFFFC, opts->gen.scratch2, SZ_D); + add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D); + cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); + code_ptr skip_last = code->cur+1; + jcc(code, CC_B, opts->gen.handle_cycle_limit_int); + cycles(&opts->gen, 4); + *skip_last = code->cur - (skip_last+1); + call(code, opts->gen.handle_cycle_limit_int); jmp(code, call_inst); break; + } case Z80_DI: cycles(&opts->gen, 4); mov_irdisp(code, 0, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); @@ -897,7 +891,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B); //interrupt enable has a one-instruction latency, minimum instruction duration is 4 cycles add_irdisp(code, 4, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); - call(code, (uint8_t *)z80_do_sync); + call(code, opts->do_sync); break; case Z80_IM: cycles(&opts->gen, 4); @@ -926,7 +920,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - z80_save_result(code, inst); + z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { z80_save_reg(inst, opts); } @@ -958,7 +952,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - z80_save_result(code, inst); + z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { z80_save_reg(inst, opts); } @@ -989,7 +983,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - z80_save_result(code, inst); + z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { z80_save_reg(inst, opts); } @@ -1021,7 +1015,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - z80_save_result(code, inst); + z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { z80_save_reg(inst, opts); } @@ -1056,7 +1050,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - z80_save_result(code, inst); + z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { z80_save_reg(inst, opts); } @@ -1087,7 +1081,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - z80_save_result(code, inst); + z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { z80_save_reg(inst, opts); } @@ -1118,7 +1112,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); if (inst->addr_mode != Z80_UNUSED) { - z80_save_result(code, inst); + z80_save_result(opts, inst); if (src_op.mode != MODE_UNUSED) { z80_save_reg(inst, opts); } @@ -1129,7 +1123,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) case Z80_RLD: cycles(&opts->gen, 8); mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_read_byte); + call(code, opts->read_8); //Before: (HL) = 0x12, A = 0x34 //After: (HL) = 0x24, A = 0x31 mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B); @@ -1151,12 +1145,12 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); ror_ir(code, 8, opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_write_byte); + call(code, opts->write_8); break; case Z80_RRD: cycles(&opts->gen, 8); mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_read_byte); + call(code, opts->read_8); //Before: (HL) = 0x12, A = 0x34 //After: (HL) = 0x41, A = 0x32 movzx_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B, SZ_W); @@ -1181,7 +1175,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); ror_ir(code, 8, opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_write_byte); + call(code, opts->write_8); break; case Z80_BIT: { num_cycles = (inst->addr_mode == Z80_IX_DISPLACE || inst->addr_mode == Z80_IY_DISPLACE) ? 8 : 16; @@ -1247,7 +1241,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) } } if ((inst->addr_mode & 0x1F) != Z80_REG) { - z80_save_result(code, inst); + z80_save_result(opts, inst); if (inst->reg != Z80_USE_IMMED) { z80_save_reg(inst, opts); } @@ -1289,7 +1283,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) } } if (inst->addr_mode != Z80_REG) { - z80_save_result(code, inst); + z80_save_result(opts, inst); if (inst->reg != Z80_USE_IMMED) { z80_save_reg(inst, opts); } @@ -1318,7 +1312,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) } else { mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); } - call(code, (uint8_t *)z80_native_addr); + call(code, opts->native_addr); jmp_r(code, opts->gen.scratch1); } break; @@ -1363,7 +1357,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) jmp(code, call_dst); } else { mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_native_addr); + call(code, opts->native_addr); jmp_r(code, opts->gen.scratch1); } *no_jump_off = code->cur - (no_jump_off+1); @@ -1382,7 +1376,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) jmp(code, call_dst); } else { mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_native_addr); + call(code, opts->native_addr); jmp_r(code, opts->gen.scratch1); } break; @@ -1417,7 +1411,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) jmp(code, call_dst); } else { mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_native_addr); + call(code, opts->native_addr); jmp_r(code, opts->gen.scratch1); } *no_jump_off = code->cur - (no_jump_off+1); @@ -1440,7 +1434,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) jmp(code, call_dst); } else { mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_native_addr); + call(code, opts->native_addr); jmp_r(code, opts->gen.scratch1); } *no_jump_off = code->cur - (no_jump_off+1); @@ -1450,7 +1444,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); mov_ir(code, address + 3, opts->gen.scratch1, SZ_W); mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); - call(code, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 + call(code, opts->write_16_highfirst);//T States: 3, 3 if (inst->immed < 0x4000) { code_ptr call_dst = z80_get_native_address(context, inst->immed); if (!call_dst) { @@ -1461,7 +1455,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) jmp(code, call_dst); } else { mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_native_addr); + call(code, opts->native_addr); jmp_r(code, opts->gen.scratch1); } break; @@ -1498,7 +1492,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); mov_ir(code, address + 3, opts->gen.scratch1, SZ_W); mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); - call(code, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 + call(code, opts->write_16_highfirst);//T States: 3, 3 if (inst->immed < 0x4000) { code_ptr call_dst = z80_get_native_address(context, inst->immed); if (!call_dst) { @@ -1509,7 +1503,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) jmp(code, call_dst); } else { mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_native_addr); + call(code, opts->native_addr); jmp_r(code, opts->gen.scratch1); } *no_call_off = code->cur - (no_call_off+1); @@ -1517,9 +1511,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) case Z80_RET: cycles(&opts->gen, 4);//T States: 4 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_read_word);//T STates: 3, 3 + call(code, opts->read_16);//T STates: 3, 3 add_ir(code, 2, opts->regs[Z80_SP], SZ_W); - call(code, (uint8_t *)z80_native_addr); + call(code, opts->native_addr); jmp_r(code, opts->gen.scratch1); break; case Z80_RETCC: { @@ -1551,9 +1545,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) uint8_t *no_call_off = code->cur+1; jcc(code, cond, code->cur+2); mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_read_word);//T STates: 3, 3 + call(code, opts->read_16);//T STates: 3, 3 add_ir(code, 2, opts->regs[Z80_SP], SZ_W); - call(code, (uint8_t *)z80_native_addr); + call(code, opts->native_addr); jmp_r(code, opts->gen.scratch1); *no_call_off = code->cur - (no_call_off+1); break; @@ -1562,9 +1556,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) //For some systems, this may need a callback for signalling interrupt routine completion cycles(&opts->gen, 8);//T States: 4, 4 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); - call(code, (uint8_t *)z80_read_word);//T STates: 3, 3 + call(code, opts->read_16);//T STates: 3, 3 add_ir(code, 2, opts->regs[Z80_SP], SZ_W); - call(code, (uint8_t *)z80_native_addr); + call(code, opts->native_addr); jmp_r(code, opts->gen.scratch1); break; case Z80_RETN: @@ -1572,9 +1566,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch2, SZ_B); mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); - call(code, (uint8_t *)z80_read_word);//T STates: 3, 3 + call(code, opts->read_16);//T STates: 3, 3 add_ir(code, 2, opts->regs[Z80_SP], SZ_W); - call(code, (uint8_t *)z80_native_addr); + call(code, opts->native_addr); jmp_r(code, opts->gen.scratch1); break; case Z80_RST: { @@ -1583,7 +1577,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); mov_ir(code, address + 1, opts->gen.scratch1, SZ_W); mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); - call(code, (uint8_t *)z80_write_word_highfirst);//T States: 3, 3 + call(code, opts->write_16_highfirst);//T States: 3, 3 code_ptr call_dst = z80_get_native_address(context, inst->immed); if (!call_dst) { opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); @@ -1600,7 +1594,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) } else { mov_rr(code, opts->regs[Z80_C], opts->gen.scratch1, SZ_B); } - call(code, (uint8_t *)z80_io_read); + call(code, opts->read_io); translate_z80_reg(inst, &dst_op, opts); mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_B); z80_save_reg(inst, opts); @@ -1618,7 +1612,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) } translate_z80_reg(inst, &src_op, opts); mov_rr(code, dst_op.base, opts->gen.scratch1, SZ_B); - call(code, (uint8_t *)z80_io_write); + call(code, opts->write_io); z80_save_reg(inst, opts); break; /*case Z80_OUTI: @@ -1737,7 +1731,7 @@ z80_context * z80_handle_code_write(uint32_t address, z80_context * context) z80_options * opts = context->options; dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code, inst_start, address); mov_ir(&code, inst_start, opts->gen.scratch1, SZ_D); - call(&code, (uint8_t *)z80_retrans_stub); + call(&code, opts->retrans_stub); } return context; } @@ -1959,8 +1953,9 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 int reg; uint8_t size; if (i < Z80_I) { - int reg = i /2 + Z80_BC; + reg = i /2 + Z80_BC; size = SZ_W; + i++; } else { reg = i; @@ -1977,6 +1972,7 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 mov_rrdisp(code, options->gen.cycles, options->gen.context_reg, offsetof(z80_context, current_cycle), SZ_D); mov_rrdisp(code, options->bank_reg, options->gen.context_reg, offsetof(z80_context, bank_reg), SZ_W); mov_rrdisp(code, options->bank_pointer, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, SZ_PTR); + retn(code); options->load_context_scratch = code->cur; mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch1), options->gen.scratch1, SZ_W); @@ -2005,6 +2001,18 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, current_cycle), options->gen.cycles, SZ_D); mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, bank_reg), options->bank_reg, SZ_W); mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, options->bank_pointer, SZ_PTR); + retn(code); + + options->native_addr = code->cur; + call(code, options->gen.save_context); + push_r(code, options->gen.context_reg); + mov_rr(code, options->gen.context_reg, RDI, SZ_PTR); + movzx_rr(code, options->gen.scratch1, RSI, SZ_W, SZ_D); + call(code, (code_ptr)z80_get_native_address_trans); + mov_rr(code, RAX, options->gen.scratch1, SZ_PTR); + pop_r(code, options->gen.context_reg); + call(code, options->gen.load_context); + retn(code); options->gen.handle_cycle_limit = code->cur; cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D); @@ -2065,8 +2073,70 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 pop_r(code, options->gen.scratch2); //TODO: Support interrupt mode 0 and 2 mov_ir(code, 0x38, options->gen.scratch1, SZ_W); - call(code, (code_ptr)z80_native_addr); + call(code, options->native_addr); + jmp_r(code, options->gen.scratch1); + *skip_int = code->cur - (skip_int+1); + cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D); + code_ptr skip_sync = code->cur + 1; + jcc(code, CC_B, skip_sync); + options->do_sync = code->cur; + call(code, options->gen.save_context); + pop_rind(code, options->gen.context_reg); + //restore callee saved registers + pop_r(code, R15); + pop_r(code, R14); + pop_r(code, R13); + pop_r(code, R12); + pop_r(code, RBP); + pop_r(code, RBX); + //return to caller of z80_run + *skip_sync = code->cur - (skip_sync+1); + retn(code); + + options->read_io = code->cur; + check_cycles(&options->gen); + cycles(&options->gen, 4); + //Genesis has no IO hardware and always returns FF + //eventually this should use a second memory map array + mov_ir(code, 0xFF, options->gen.scratch1, SZ_B); + retn(code); + + options->write_io = code->cur; + check_cycles(&options->gen); + cycles(&options->gen, 4); + retn(code); + + options->retrans_stub = code->cur; + //pop return address + pop_r(code, options->gen.scratch2); + call(code, options->gen.save_context); + //adjust pointer before move and call instructions that got us here + sub_ir(code, 11, options->gen.scratch2, SZ_PTR); + mov_rr(code, options->gen.scratch1, RDI, SZ_D); + mov_rr(code, options->gen.scratch2, RDX, SZ_PTR); + push_r(code, options->gen.context_reg); + call(code, (code_ptr)z80_retranslate_inst); + pop_r(code, options->gen.context_reg); + mov_rr(code, RAX, options->gen.scratch1, SZ_PTR); + call(code, options->gen.load_context); jmp_r(code, options->gen.scratch1); + + options->run = (z80_run_fun)code->cur; + //save callee save registers + push_r(code, RBX); + push_r(code, RBP); + push_r(code, R12); + push_r(code, R13); + push_r(code, R14); + push_r(code, R15); + mov_rr(code, RDI, options->gen.context_reg, SZ_PTR); + cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR); + code_ptr no_extra = code->cur+1; + jcc(code, CC_Z, no_extra); + push_rdisp(code, options->gen.context_reg, offsetof(z80_context, extra_pc)); + mov_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR); + *no_extra = code->cur - (no_extra + 1); + jmp_rind(code, options->gen.context_reg); } void * z80_gen_bank_write(uint32_t start_address, void * voptions) @@ -2086,6 +2156,7 @@ void init_z80_context(z80_context * context, z80_options * options) context->banked_code_map = malloc(sizeof(native_map_slot) * (1 << 9)); memset(context->banked_code_map, 0, sizeof(native_map_slot) * (1 << 9)); context->options = options; + context->run = options->run; } void z80_reset(z80_context * context) @@ -2115,14 +2186,14 @@ void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_ha code->cur = bp_stub; //Save context and call breakpoint handler - call(code, (uint8_t *)z80_save_context); + call(code, opts->gen.save_context); push_r(code, opts->gen.scratch1); mov_rr(code, opts->gen.context_reg, RDI, SZ_Q); mov_rr(code, opts->gen.scratch1, RSI, SZ_W); call(code, bp_handler); mov_rr(code, RAX, opts->gen.context_reg, SZ_Q); //Restore context - call(code, (uint8_t *)z80_load_context); + call(code, opts->gen.load_context); pop_r(code, opts->gen.scratch1); //do prologue stuff cmp_rr(code, opts->gen.cycles, opts->gen.limit, SZ_D); @@ -2131,7 +2202,7 @@ void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_ha pop_r(code, opts->gen.scratch1); add_ir(code, check_int_size - (code->cur-native), opts->gen.scratch1, SZ_Q); push_r(code, opts->gen.scratch1); - jmp(code, (uint8_t *)z80_handle_cycle_limit_int); + jmp(code, opts->gen.handle_cycle_limit_int); *jmp_off = code->cur - (jmp_off+1); //jump back to body of translated instruction pop_r(code, opts->gen.scratch1); diff --git a/z80_to_x86.h b/z80_to_x86.h index d5d232c..6870343 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -21,21 +21,29 @@ enum { ZF_NUM }; +typedef void (*z80_run_fun)(void * context); + typedef struct { cpu_options gen; code_ptr save_context_scratch; code_ptr load_context_scratch; - code_ptr read_8; - code_ptr write_8; + code_ptr native_addr; + code_ptr retrans_stub; + code_ptr do_sync; + code_ptr read_8; + code_ptr write_8; code_ptr write_8_noinc; - code_ptr read_16; - code_ptr write_16_highfirst; - code_ptr write_16_lowfirst; + code_ptr read_16; + code_ptr write_16_highfirst; + code_ptr write_16_lowfirst; + code_ptr read_io; + code_ptr write_io; uint32_t flags; int8_t regs[Z80_UNUSED]; - int8_t bank_reg; - int8_t bank_pointer; + int8_t bank_reg; + int8_t bank_pointer; + z80_run_fun run; } z80_options; typedef struct { @@ -63,6 +71,7 @@ typedef struct { void * system; uint8_t ram_code_flags[(8 * 1024)/128/8]; uint32_t int_enable_cycle; + z80_run_fun run; uint16_t pc; } z80_context; diff --git a/ztestrun.c b/ztestrun.c index 9f500f1..781afa9 100644 --- a/ztestrun.c +++ b/ztestrun.c @@ -1,6 +1,6 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #include "z80inst.h" @@ -11,7 +11,6 @@ #include uint8_t z80_ram[0x2000]; -uint16_t cart[0x200000]; #define MCLKS_PER_Z80 15 //TODO: Figure out the exact value for this @@ -19,26 +18,26 @@ uint16_t cart[0x200000]; #define VINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_Z80) #define CYCLE_NEVER 0xFFFFFFFF -uint8_t z80_read_ym(uint16_t location, z80_context * context) +uint8_t z80_unmapped_read(uint32_t location, void * context) { return 0xFF; } -z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value) +void * z80_unmapped_write(uint32_t location, void * context, uint8_t value) { return context; } -z80_context * z80_vdp_port_write(uint16_t location, z80_context * context, uint8_t value) -{ - return context; -} +const memmap_chunk z80_map[] = { + { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL }, + { 0x4000, 0x10000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE, NULL, NULL, NULL, z80_unmapped_read, z80_unmapped_write} +}; int main(int argc, char ** argv) { long filesize; uint8_t *filebuf; - x86_z80_options opts; + z80_options opts; z80_context context; if (argc < 2) { fputs("usage: transz80 zrom [cartrom]\n", stderr); @@ -54,47 +53,29 @@ int main(int argc, char ** argv) fseek(f, 0, SEEK_SET); fread(z80_ram, 1, filesize < sizeof(z80_ram) ? filesize : sizeof(z80_ram), f); fclose(f); - if (argc > 2) { - f = fopen(argv[2], "rb"); - if (!f) { - fprintf(stderr, "unable to open file %s\n", argv[2]); - exit(1); - } - fseek(f, 0, SEEK_END); - filesize = ftell(f); - fseek(f, 0, SEEK_SET); - fread(cart, 1, filesize < sizeof(cart) ? filesize : sizeof(cart), f); - fclose(f); - for(unsigned short * cur = cart; cur - cart < (filesize/2); ++cur) - { - *cur = (*cur >> 8) | (*cur << 8); - } - } - init_x86_z80_opts(&opts); + init_x86_z80_opts(&opts, z80_map, 2); init_z80_context(&context, &opts); //Z80 RAM context.mem_pointers[0] = z80_ram; context.sync_cycle = context.target_cycle = 1000; context.int_cycle = CYCLE_NEVER; - //cartridge/bank - context.mem_pointers[1] = context.mem_pointers[2] = (uint8_t *)cart; z80_reset(&context); while (context.current_cycle < 1000) { - z80_run(&context); + context.run(&context); } - printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n", + printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n", context.regs[Z80_A], context.regs[Z80_B], context.regs[Z80_C], - context.regs[Z80_D], context.regs[Z80_E], - (context.regs[Z80_H] << 8) | context.regs[Z80_L], - (context.regs[Z80_IXH] << 8) | context.regs[Z80_IXL], - (context.regs[Z80_IYH] << 8) | context.regs[Z80_IYL], + context.regs[Z80_D], context.regs[Z80_E], + (context.regs[Z80_H] << 8) | context.regs[Z80_L], + (context.regs[Z80_IXH] << 8) | context.regs[Z80_IXL], + (context.regs[Z80_IYH] << 8) | context.regs[Z80_IYL], context.sp, context.im, context.iff1, context.iff2); printf("Flags: SZVNC\n" " %d%d%d%d%d\n", context.flags[ZF_S], context.flags[ZF_Z], context.flags[ZF_PV], context.flags[ZF_N], context.flags[ZF_C]); puts("--Alternate Regs--"); - printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\n", + printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\n", context.alt_regs[Z80_A], context.alt_regs[Z80_B], context.alt_regs[Z80_C], - context.alt_regs[Z80_D], context.alt_regs[Z80_E], + context.alt_regs[Z80_D], context.alt_regs[Z80_E], (context.alt_regs[Z80_H] << 8) | context.alt_regs[Z80_L]); return 0; } -- cgit v1.2.3 From 55471707f6478f63fc07b2d260f6755ca259b6a2 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 26 Dec 2014 12:34:41 -0800 Subject: Add in missing generated Z80 helper functions. Fix a small bug in Z80_HALT. Fix generation of save and load context for Z80 --- gen_x86.h | 1 + z80_to_x86.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------ z80_to_x86.h | 1 + 3 files changed, 64 insertions(+), 7 deletions(-) diff --git a/gen_x86.h b/gen_x86.h index 583808b..97bb9c2 100644 --- a/gen_x86.h +++ b/gen_x86.h @@ -38,6 +38,7 @@ enum { CC_C, CC_B = CC_C, CC_NC, + CC_NB = CC_NC, CC_Z, CC_NZ, CC_BE, diff --git a/z80_to_x86.c b/z80_to_x86.c index b556b57..c402ad5 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -870,7 +870,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D); cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); code_ptr skip_last = code->cur+1; - jcc(code, CC_B, opts->gen.handle_cycle_limit_int); + jcc(code, CC_NB, code->cur+2); cycles(&opts->gen, 4); *skip_last = code->cur - (skip_last+1); call(code, opts->gen.handle_cycle_limit_int); @@ -1953,10 +1953,8 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 int reg; uint8_t size; if (i < Z80_I) { - reg = i /2 + Z80_BC; + reg = i /2 + Z80_BC + (i > Z80_H ? 2 : 0); size = SZ_W; - i++; - } else { reg = i; size = SZ_B; @@ -1964,6 +1962,9 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 if (options->regs[reg] >= 0) { mov_rrdisp(code, options->regs[reg], options->gen.context_reg, offsetof(z80_context, regs) + i, size); } + if (size == SZ_W) { + i++; + } } if (options->regs[Z80_SP] >= 0) { mov_rrdisp(code, options->regs[Z80_SP], options->gen.context_reg, offsetof(z80_context, sp), SZ_W); @@ -1983,9 +1984,8 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 int reg; uint8_t size; if (i < Z80_I) { - int reg = i /2 + Z80_BC; + reg = i /2 + Z80_BC + (i > Z80_H ? 2 : 0); size = SZ_W; - } else { reg = i; size = SZ_B; @@ -1993,6 +1993,9 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 if (options->regs[reg] >= 0) { mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, regs) + i, options->regs[reg], size); } + if (size == SZ_W) { + i++; + } } if (options->regs[Z80_SP] >= 0) { mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, sp), options->regs[Z80_SP], SZ_W); @@ -2035,8 +2038,10 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 *no_sync = code->cur - no_sync; //return to caller of z80_run retn(code); + + options->gen.handle_code_write = (code_ptr)z80_handle_code_write; - options->read_8 = gen_mem_fun(&options->gen, chunks, num_chunks, READ_8, NULL); + options->read_8 = gen_mem_fun(&options->gen, chunks, num_chunks, READ_8, &options->read_8_noinc); options->write_8 = gen_mem_fun(&options->gen, chunks, num_chunks, WRITE_8, &options->write_8_noinc); options->gen.handle_cycle_limit_int = code->cur; @@ -2105,6 +2110,55 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 check_cycles(&options->gen); cycles(&options->gen, 4); retn(code); + + options->read_16 = code->cur; + cycles(&options->gen, 3); + check_cycles(&options->gen); + //TODO: figure out how to handle the extra wait state for word reads to bank area + //may also need special handling to avoid too much stack depth when acces is blocked + push_r(code, options->gen.scratch1); + call(code, options->read_8_noinc); + mov_rr(code, options->gen.scratch1, options->gen.scratch2, SZ_B); + pop_r(code, options->gen.scratch1); + add_ir(code, 1, options->gen.scratch1, SZ_W); + cycles(&options->gen, 3); + check_cycles(&options->gen); + call(code, options->read_8_noinc); + shl_ir(code, 8, options->gen.scratch1, SZ_W); + mov_rr(code, options->gen.scratch2, options->gen.scratch1, SZ_B); + retn(code); + + options->write_16_highfirst = code->cur; + cycles(&options->gen, 3); + check_cycles(&options->gen); + push_r(code, options->gen.scratch2); + push_r(code, options->gen.scratch1); + add_ir(code, 1, options->gen.scratch2, SZ_W); + shr_ir(code, 8, options->gen.scratch1, SZ_W); + call(code, options->write_8_noinc); + pop_r(code, options->gen.scratch1); + pop_r(code, options->gen.scratch2); + cycles(&options->gen, 3); + check_cycles(&options->gen); + //TODO: Check if we can get away with TCO here + call(code, options->write_8_noinc); + retn(code); + + options->write_16_lowfirst = code->cur; + cycles(&options->gen, 3); + check_cycles(&options->gen); + push_r(code, options->gen.scratch2); + push_r(code, options->gen.scratch1); + call(code, options->write_8_noinc); + pop_r(code, options->gen.scratch1); + pop_r(code, options->gen.scratch2); + add_ir(code, 1, options->gen.scratch2, SZ_W); + shr_ir(code, 8, options->gen.scratch1, SZ_W); + cycles(&options->gen, 3); + check_cycles(&options->gen); + //TODO: Check if we can get away with TCO here + call(code, options->write_8_noinc); + retn(code); options->retrans_stub = code->cur; //pop return address @@ -2130,6 +2184,7 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 push_r(code, R14); push_r(code, R15); mov_rr(code, RDI, options->gen.context_reg, SZ_PTR); + call(code, options->load_context_scratch); cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR); code_ptr no_extra = code->cur+1; jcc(code, CC_Z, no_extra); diff --git a/z80_to_x86.h b/z80_to_x86.h index 6870343..507965d 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -32,6 +32,7 @@ typedef struct { code_ptr do_sync; code_ptr read_8; code_ptr write_8; + code_ptr read_8_noinc; code_ptr write_8_noinc; code_ptr read_16; code_ptr write_16_highfirst; -- cgit v1.2.3 From d53d8f8d28c067bd80c5a66607973f5b125a0034 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 26 Dec 2014 12:36:54 -0800 Subject: Add a couple of missing checks for the byte_swap and address_size parameters in gen_mem_fun --- backend_x86.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backend_x86.c b/backend_x86.c index 6ba1a7a..482e9c3 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -154,7 +154,7 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n retn(code); *good_addr = code->cur - (good_addr + 1); shr_ir(code, 1, adr_reg, opts->address_size); - } else { + } else if (opts->byte_swap) { xor_ir(code, 1, adr_reg, opts->address_size); } } else if ((memmap[chunk].flags & MMAP_ONLY_ODD) || (memmap[chunk].flags & MMAP_ONLY_EVEN)) { @@ -164,6 +164,9 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n shr_ir(code, 8, opts->scratch1, SZ_W); } } + if (opts->address_size != SZ_D) { + movzx_rr(code, adr_reg, adr_reg, opts->address_size, SZ_D); + } if ((intptr_t)memmap[chunk].buffer <= 0x7FFFFFFF && (intptr_t)memmap[chunk].buffer >= -2147483648) { if (is_write) { mov_rrdisp(code, opts->scratch1, opts->scratch2, (intptr_t)memmap[chunk].buffer, tmp_size); -- cgit v1.2.3 From 58056e06047d7777dbb2fe500fe6801fa92785f9 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 26 Dec 2014 12:37:27 -0800 Subject: Set the byte_swap flag in the M68K core so gen_mem_fun correctly inserts xor instructions for byte access functions --- m68k_core_x86.c | 1 + 1 file changed, 1 insertion(+) diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 18feea7..0f89a82 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -2169,6 +2169,7 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu memset(opts, 0, sizeof(*opts)); opts->gen.address_size = SZ_D; opts->gen.address_mask = 0xFFFFFF; + opts->gen.byte_swap = 1; opts->gen.max_address = 0x1000000; opts->gen.bus_cycles = BUS; opts->gen.mem_ptr_off = offsetof(m68k_context, mem_pointers); -- cgit v1.2.3 From 669d5ebf9474cb7efcd6aee6a84c28b3910b9348 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 26 Dec 2014 12:52:13 -0800 Subject: Update code->cur before calling z80_get_address_trans in z80_retranslate_inst to avoid any newly translated instructions from being placed in the "buffer zone". Save the current value of the code_info struct for placing the final jmp instruction in the correct place --- z80_to_x86.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/z80_to_x86.c b/z80_to_x86.c index c402ad5..fd30d56 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -1779,6 +1779,7 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o } #endif if (orig_size != ZMAX_NATIVE_SIZE) { + check_alloc_code(code, ZMAX_NATIVE_SIZE); code_ptr start = code->cur; deferred_addr * orig_deferred = opts->gen.deferred; translate_z80inst(&instbuf, context, address); @@ -1802,10 +1803,11 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o z80_map_native_address(context, address, start, after-inst, ZMAX_NATIVE_SIZE); code_info tmp_code = {orig_start, orig_start + 16}; jmp(&tmp_code, start); + tmp_code = *code; + code->cur = start + ZMAX_NATIVE_SIZE; if (!z80_is_terminal(&instbuf)) { - jmp(code, z80_get_native_address_trans(context, address + after-inst)); + jmp(&tmp_code, z80_get_native_address_trans(context, address + after-inst)); } - code->cur = start + ZMAX_NATIVE_SIZE; z80_handle_deferred(context); return start; } else { -- cgit v1.2.3 From 48d4b66ac0a36c584d03e59062f58a9c4de9d33b Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 26 Dec 2014 12:56:53 -0800 Subject: Fix an off-by-one error in a branch destination in the generation of handle_cycle_limit for the Z80 --- z80_to_x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/z80_to_x86.c b/z80_to_x86.c index fd30d56..1fcd24f 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -2037,7 +2037,7 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 pop_r(code, R12); pop_r(code, RBP); pop_r(code, RBX); - *no_sync = code->cur - no_sync; + *no_sync = code->cur - (no_sync + 1); //return to caller of z80_run retn(code); -- cgit v1.2.3 From cdea87c8284b91323c169f3fd61d536e7f710959 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 26 Dec 2014 13:41:45 -0800 Subject: Update .hgignore --- .hgignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.hgignore b/.hgignore index 5fd2fe1..9efd7b3 100644 --- a/.hgignore +++ b/.hgignore @@ -8,6 +8,7 @@ syntax: glob *.tar.gz *~ starscream/* +gxz80/* vdpreverse/* nemesis/* html/* @@ -16,4 +17,6 @@ blastem dis stateview trans - +zdis +ztestrun +address.log -- cgit v1.2.3 From 8ab499c765335f363aa39c3a7e1c56ba0b5fb9eb Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 26 Dec 2014 13:42:25 -0800 Subject: Add Z80 test runner Python script I wrote a while back and forgot to commit --- zcompare.py | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100755 zcompare.py diff --git a/zcompare.py b/zcompare.py new file mode 100755 index 0000000..d6eacea --- /dev/null +++ b/zcompare.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +from glob import glob +import subprocess +from sys import exit,argv + +prefixes = [] +skip = set() +for i in range(1, len(argv)): + if '.' in argv[i]: + f = open(argv[i]) + for line in f: + parts = line.split() + for part in parts: + if part.endswith('.bin'): + skip.add(part) + f.close() + print 'Skipping',len(skip),'entries from previous report.' + else: + prefixes.append(argv[i]) + +for path in glob('ztests/*/*.bin'): + if path in skip: + continue + if prefixes: + good = False + fname = path.split('/')[-1] + for prefix in prefixes: + if fname.startswith(prefix): + good = True + break + if not good: + continue + try: + b = subprocess.check_output(['./ztestrun', path]) + try: + m = subprocess.check_output(['gxz80/gxzrun', path]) + #_,_,b = b.partition('\n') + if b != m: + print '-----------------------------' + print 'Mismatch in ' + path + print 'blastem output:' + print b + print 'gxz80 output:' + print m + print '-----------------------------' + else: + print path, 'passed' + except subprocess.CalledProcessError as e: + print '-----------------------------' + print 'gxz80 exited with code', e.returncode, 'for test', path + print 'blastem output:' + print b + print '-----------------------------' + except subprocess.CalledProcessError as e: + print '-----------------------------' + print 'blastem exited with code', e.returncode, 'for test', path + print '-----------------------------' + -- cgit v1.2.3 From e8a9c14ec2e0b75eb1aef1c2a77936c6f7fd8326 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 26 Dec 2014 15:45:31 -0800 Subject: Fix a few bugs introduced in the Z80 core from the adjustments to fit with the code gen refactor --- backend.h | 1 + backend_x86.c | 5 +++++ m68k_core_x86.c | 5 ----- m68k_internal.h | 1 - z80_to_x86.c | 32 ++++++++++++++++++-------------- 5 files changed, 24 insertions(+), 20 deletions(-) diff --git a/backend.h b/backend.h index 131314c..fd0f120 100644 --- a/backend.h +++ b/backend.h @@ -108,6 +108,7 @@ void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_fun void cycles(cpu_options *opts, uint32_t num); void check_cycles_int(cpu_options *opts, uint32_t address); void check_cycles(cpu_options * opts); +void check_code_prologue(code_info *code); code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc); diff --git a/backend_x86.c b/backend_x86.c index 482e9c3..ec16a16 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -28,6 +28,11 @@ void check_cycles(cpu_options * opts) *jmp_off = code->cur - (jmp_off+1); } +void check_code_prologue(code_info *code) +{ + check_alloc_code(code, MAX_INST_LEN*4); +} + code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc) { code_info *code = &opts->code; diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 0f89a82..96e1cfa 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -2061,11 +2061,6 @@ void translate_out_of_bounds(code_info *code) call(code, (code_ptr)exit); } -void check_code_prologue(code_info *code) -{ - check_alloc_code(code, MAX_INST_LEN*4); -}; - void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst) { if (next_inst == old_end && next_inst - code->cur < 2) { diff --git a/m68k_internal.h b/m68k_internal.h index 1a06e03..a556505 100644 --- a/m68k_internal.h +++ b/m68k_internal.h @@ -10,7 +10,6 @@ //functions implemented in host CPU specfic file void translate_out_of_bounds(code_info *code); -void check_code_prologue(code_info *code); void areg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg); void dreg_to_native(m68k_options *opts, uint8_t reg, uint8_t native_reg); void areg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg); diff --git a/z80_to_x86.c b/z80_to_x86.c index 1fcd24f..c785e8a 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -1303,7 +1303,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) if (!call_dst) { opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); //fake address to force large displacement - call_dst + 256; + call_dst = code->cur + 256; } jmp(code, call_dst); } else { @@ -1352,7 +1352,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) if (!call_dst) { opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); //fake address to force large displacement - call_dst + 256; + call_dst = code->cur + 256; } jmp(code, call_dst); } else { @@ -1371,7 +1371,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) if (!call_dst) { opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); //fake address to force large displacement - call_dst + 256; + call_dst = code->cur + 256; } jmp(code, call_dst); } else { @@ -1406,7 +1406,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) if (!call_dst) { opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); //fake address to force large displacement - call_dst + 256; + call_dst = code->cur + 256; } jmp(code, call_dst); } else { @@ -1429,7 +1429,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) if (!call_dst) { opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); //fake address to force large displacement - call_dst + 256; + call_dst = code->cur + 256; } jmp(code, call_dst); } else { @@ -1450,7 +1450,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) if (!call_dst) { opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); //fake address to force large displacement - call_dst + 256; + call_dst = code->cur + 256; } jmp(code, call_dst); } else { @@ -1498,7 +1498,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) if (!call_dst) { opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); //fake address to force large displacement - call_dst + 256; + call_dst = code->cur + 256; } jmp(code, call_dst); } else { @@ -1582,7 +1582,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address) if (!call_dst) { opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); //fake address to force large displacement - call_dst + 256; + call_dst = code->cur + 256; } jmp(code, call_dst); break; @@ -1815,10 +1815,12 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o code->cur = orig_start; code->last = orig_start + ZMAX_NATIVE_SIZE; translate_z80inst(&instbuf, context, address); + code_info tmp2 = *code; + *code = tmp_code; if (!z80_is_terminal(&instbuf)) { - jmp(code, z80_get_native_address_trans(context, address + after-inst)); + + jmp(&tmp2, z80_get_native_address_trans(context, address + after-inst)); } - *code = tmp_code; z80_handle_deferred(context); return orig_start; } @@ -1855,6 +1857,8 @@ void translate_z80_stream(z80_context * context, uint32_t address) jmp(&opts->gen.code, existing); break; } + //make sure prologue is in a contiguous chunk of code + check_code_prologue(&opts->gen.code); next = z80_decode(encoded, &inst); #ifdef DO_DEBUG_PRINT z80_disasm(&inst, disbuf, address); @@ -2228,12 +2232,12 @@ void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_ha { static uint8_t * bp_stub = NULL; z80_options * opts = context->options; - uint8_t * native = z80_get_native_address_trans(context, address); + code_ptr native = z80_get_native_address_trans(context, address); code_info tmp_code = {native, native+16}; mov_ir(&tmp_code, address, opts->gen.scratch1, SZ_W); if (!bp_stub) { code_info *code = &opts->gen.code; - //TODO: do an alloc check here to make sure the prologue length calc works + check_code_prologue(code); bp_stub = code->cur; call(&tmp_code, bp_stub); @@ -2257,13 +2261,13 @@ void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_ha uint8_t * jmp_off = code->cur+1; jcc(code, CC_NC, code->cur + 7); pop_r(code, opts->gen.scratch1); - add_ir(code, check_int_size - (code->cur-native), opts->gen.scratch1, SZ_Q); + add_ir(code, check_int_size - (tmp_code.cur-native), opts->gen.scratch1, SZ_Q); push_r(code, opts->gen.scratch1); jmp(code, opts->gen.handle_cycle_limit_int); *jmp_off = code->cur - (jmp_off+1); //jump back to body of translated instruction pop_r(code, opts->gen.scratch1); - add_ir(code, check_int_size - (code->cur-native), opts->gen.scratch1, SZ_Q); + add_ir(code, check_int_size - (tmp_code.cur-native), opts->gen.scratch1, SZ_Q); jmp_r(code, opts->gen.scratch1); } else { call(&tmp_code, bp_stub); -- cgit v1.2.3 From f9dade6a1ea8e660735a684ce9b80168e50064f7 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 26 Dec 2014 15:46:53 -0800 Subject: Set int_cycle to CYCLE_NEVER in sync_z80 so that the interrupt routine isn't taken inappropriately now that the kludge in handle_cycle_limit_int has been removed --- blastem.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/blastem.c b/blastem.c index c704ef2..13b3429 100644 --- a/blastem.c +++ b/blastem.c @@ -195,6 +195,8 @@ void sync_z80(z80_context * z_context, uint32_t mclks) while (z_context->current_cycle < z_context->sync_cycle) { if (z_context->iff1 && z_context->current_cycle < (vint_cycle + Z80_VINT_DURATION)) { z_context->int_cycle = vint_cycle < z_context->int_enable_cycle ? z_context->int_enable_cycle : vint_cycle; + } else { + z_context->int_cycle = CYCLE_NEVER; } z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle; dprintf("Running Z80 from cycle %d to cycle %d. Native PC: %p\n", z_context->current_cycle, z_context->sync_cycle, z_context->native_pc); -- cgit v1.2.3 From 4302e0d4fde15ebc79bc2e0f0cc2cf1246ba1074 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 26 Dec 2014 19:36:41 -0800 Subject: Fix reg-indirect mode for RBP/R13 --- gen_x86.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/gen_x86.c b/gen_x86.c index b1b48d4..b1988fe 100644 --- a/gen_x86.c +++ b/gen_x86.c @@ -322,10 +322,17 @@ void x86_rrind_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t bas opcode |= BIT_SIZE; } *(out++) = opcode | dir; - *(out++) = MODE_REG_INDIRECT | base | (reg << 3); - if (base == RSP) { - //add SIB byte, with no index and RSP as base - *(out++) = (RSP << 3) | RSP; + if (base == RBP) { + //add a dummy 8-bit displacement since MODE_REG_INDIRECT with + //an R/M field of RBP selects RIP, relative addressing + *(out++) = MODE_REG_DISPLACE8 | base | (reg << 3); + *(out++) = 0; + } else { + *(out++) = MODE_REG_INDIRECT | base | (reg << 3); + if (base == RSP) { + //add SIB byte, with no index and RSP as base + *(out++) = (RSP << 3) | RSP; + } } code->cur = out; } -- cgit v1.2.3 From 21cbee7575fce46e9730bef9df4d1e7eea819793 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 26 Dec 2014 19:37:59 -0800 Subject: Get Z80 banked access sort of working again --- backend.h | 2 +- backend_x86.c | 6 +++--- blastem.c | 35 ++++++++++++++++++++++++++++------- 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/backend.h b/backend.h index fd0f120..58f8a47 100644 --- a/backend.h +++ b/backend.h @@ -79,7 +79,7 @@ typedef struct { #define MMAP_ONLY_ODD 0x10 #define MMAP_ONLY_EVEN 0x20 #define MMAP_FUNC_NULL 0x40 -#define MMAP_CUSTOM 0x80 +#define MMAP_BYTESWAP 0x80 typedef uint16_t (*read_16_fun)(uint32_t address, void * context); typedef uint8_t (*read_8_fun)(uint32_t address, void * context); diff --git a/backend_x86.c b/backend_x86.c index ec16a16..631c6c7 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -84,7 +84,7 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n default: cfun = NULL; } - if(memmap[chunk].buffer && memmap[chunk].flags & access_flag) { + if(memmap[chunk].flags & access_flag) { if (memmap[chunk].flags & MMAP_PTR_IDX) { if (memmap[chunk].flags & MMAP_FUNC_NULL) { cmp_irdisp(code, 0, opts->context_reg, opts->mem_ptr_off + sizeof(void*) * memmap[chunk].ptr_index, SZ_PTR); @@ -133,7 +133,7 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n *not_null = code->cur - (not_null + 1); } - if (opts->byte_swap && size == SZ_B) { + if ((opts->byte_swap || memmap[chunk].flags & MMAP_BYTESWAP) && size == SZ_B) { xor_ir(code, 1, adr_reg, opts->address_size); } if (opts->address_size != SZ_D) { @@ -159,7 +159,7 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n retn(code); *good_addr = code->cur - (good_addr + 1); shr_ir(code, 1, adr_reg, opts->address_size); - } else if (opts->byte_swap) { + } else if (opts->byte_swap || memmap[chunk].flags & MMAP_BYTESWAP) { xor_ir(code, 1, adr_reg, opts->address_size); } } else if ((memmap[chunk].flags & MMAP_ONLY_ODD) || (memmap[chunk].flags & MMAP_ONLY_EVEN)) { diff --git a/blastem.c b/blastem.c index 13b3429..3500ec3 100644 --- a/blastem.c +++ b/blastem.c @@ -731,14 +731,35 @@ uint8_t z80_read_ym(uint32_t location, void * vcontext) uint8_t z80_read_bank(uint32_t location, void * vcontext) { z80_context * context = vcontext; - //TODO: Implement me + uint32_t address = context->bank_reg << 15 | location; + fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area\n", address); return 0; } void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value) { z80_context * context = vcontext; - //TODO: Implement me + uint32_t address = context->bank_reg << 15 | location; + if (address >= 0xE00000) { + address &= 0xFFFF; + ((uint8_t *)ram)[address ^ 1] = value; + } else { + fprintf(stderr, "Unhandled write by Z80 to address %X through banked memory area\n", address); + } + return context; +} + +void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value) +{ + z80_context * context = vcontext; + + context->bank_reg = (context->bank_reg >> 1 | value << 8) & 0x1FF; + if (context->bank_reg < 0x80) { + context->mem_pointers[1] = context->mem_pointers[2] + (context->bank_reg << 15); + } else { + context->mem_pointers[1] = NULL; + } + return context; } @@ -1121,11 +1142,11 @@ void detect_region() } #ifndef NO_Z80 const memmap_chunk z80_map[] = { - { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL }, - { 0x8000, 0x10000, 0xFFFF, 1, MMAP_READ | MMAP_WRITE | MMAP_PTR_IDX | MMAP_FUNC_NULL, NULL, NULL, NULL, z80_read_bank, z80_write_bank}, - { 0x4000, 0x6000, 0x0003, 0, MMAP_READ | MMAP_WRITE, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, - { 0x6000, 0x6100, 0xFFFF, 0, MMAP_WRITE | MMAP_CUSTOM, NULL, NULL, NULL, NULL, (write_8_fun)z80_gen_bank_write}, - { 0x7F00, 0x8000, 0x00FF, 0, MMAP_READ | MMAP_WRITE, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} + { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL }, + { 0x8000, 0x10000, 0xFFFF, 1, MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL | MMAP_BYTESWAP, NULL, NULL, NULL, z80_read_bank, z80_write_bank}, + { 0x4000, 0x6000, 0x0003, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, + { 0x6000, 0x6100, 0xFFFF, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg}, + { 0x7F00, 0x8000, 0x00FF, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} }; #endif -- cgit v1.2.3 From 77b305b44b0857a3e4bb6fd22ee96e4bb42323cc Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 26 Dec 2014 19:38:27 -0800 Subject: Fix a bug in ori to SR that was swapping USP and SSP inappropriately --- m68k_core_x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 96e1cfa..ef84721 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -1896,7 +1896,7 @@ void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst) } else { or_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); } - if ((base_flag == X0) ^ (((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR)) > 0)) { + if (inst->op == M68K_ANDI_SR && !(inst->src.params.immed & (1 << (BIT_SUPERVISOR + 8)))) { //leave supervisor mode swap_ssp_usp(opts); } -- cgit v1.2.3 From 1d301541a75bbc1cde775ce5deaef43c5cbb663f Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 26 Dec 2014 20:46:56 -0800 Subject: Fix mask for bank area in Z80 memory map --- blastem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/blastem.c b/blastem.c index 3500ec3..02e2450 100644 --- a/blastem.c +++ b/blastem.c @@ -1143,7 +1143,7 @@ void detect_region() #ifndef NO_Z80 const memmap_chunk z80_map[] = { { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL }, - { 0x8000, 0x10000, 0xFFFF, 1, MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL | MMAP_BYTESWAP, NULL, NULL, NULL, z80_read_bank, z80_write_bank}, + { 0x8000, 0x10000, 0x7FFF, 1, MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL | MMAP_BYTESWAP, NULL, NULL, NULL, z80_read_bank, z80_write_bank}, { 0x4000, 0x6000, 0x0003, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, { 0x6000, 0x6100, 0xFFFF, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg}, { 0x7F00, 0x8000, 0x00FF, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} -- cgit v1.2.3 From 4bf9f13589dc4c9e59ead0a864dac28a518949f0 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 26 Dec 2014 21:26:25 -0800 Subject: Fix memory map flags in ztestrun --- ztestrun.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ztestrun.c b/ztestrun.c index 781afa9..1c7c6d8 100644 --- a/ztestrun.c +++ b/ztestrun.c @@ -30,7 +30,7 @@ void * z80_unmapped_write(uint32_t location, void * context, uint8_t value) const memmap_chunk z80_map[] = { { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL }, - { 0x4000, 0x10000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE, NULL, NULL, NULL, z80_unmapped_read, z80_unmapped_write} + { 0x4000, 0x10000, 0xFFFF, 0, 0, NULL, NULL, NULL, z80_unmapped_read, z80_unmapped_write} }; int main(int argc, char ** argv) -- cgit v1.2.3 From 60afc143f247bf58fa01cff73516d30511c97c82 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 27 Dec 2014 14:50:28 -0800 Subject: Don't use out of bounds displacements in indexed mode even if our targeted address is out of RAM range --- gentests.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gentests.py b/gentests.py index 000f73e..428d6a0 100755 --- a/gentests.py +++ b/gentests.py @@ -178,9 +178,17 @@ class Indexed(object): self.disp -= (address & 0xFFFFFF) else: self.disp += 0xE00000-(address & 0xFFFFFF) + if self.disp > 127: + self.disp = 127 + elif self.disp < -128: + self.disp = -128 address = base + index + self.disp elif (address & 0xFFFFFF) > 0xFFFFFC: self.disp -= (address & 0xFFFFFF) - 0xFFFFFC + if self.disp > 127: + self.disp = 127 + elif self.disp < -128: + self.disp = -128 address = base + index + self.disp if size != 'b' and address & 1: self.disp = self.disp ^ 1 -- cgit v1.2.3 From 33f11a9c6f4b7497ba6830130501f1df1b90c463 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 27 Dec 2014 14:50:50 -0800 Subject: Uncomment 68000 testcases --- testcases.txt | 168 +++++++++++++++++++++++++++++----------------------------- 1 file changed, 84 insertions(+), 84 deletions(-) diff --git a/testcases.txt b/testcases.txt index 3ece10a..c0f2692 100644 --- a/testcases.txt +++ b/testcases.txt @@ -1,88 +1,88 @@ Name Sizes Src Modes Dst Modes -#add bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#add bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#adda wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a -#addi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#addq bwl #(1-8) d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#addx bwl d d -#addx bwl -(a) -(a) -#and bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#and bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#andi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#asl bwl d;#(1-8) d -#asr bwl d;#(1-8) d -#lsl bwl d;#(1-8) d -#lsr bwl d;#(1-8) d -#sub bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#sub bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#suba wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a -#subi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#subq bwl #(1-8) d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#subx bwl d d -#subx bwl -(a) -(a) -#bchg b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#bchg l d;#(0-255) d -#bset b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#bset l d;#(0-255) d -#bclr b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#bclr l d;#(0-255) d -#btst b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#btst l d;#(0-255) d -#rol bwl d;#(1-8) d -#ror bwl d;#(1-8) d -#abcd b d d -#abcd b -(a) -(a) -#sbcd b d d -#sbcd b -(a) -(a) -#muls w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#mulu w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#move bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#movea wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a -#moveq l #(-128-127) d -#roxl bwl d;#(1-8) d -#roxr bwl d;#(1-8) d -#divs w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#divu w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#chk w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#cmp bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#cmpa wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a -#cmpi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#cmpm bwl (a)+ (a)+ -#eor bwl d d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#eori bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#exg l d d;a -#exg l a a -#link w a #n -#or bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d -#or bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#ori bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#clr bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#ext wl d -#neg bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#negx bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#not bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#pea l (a);(n,a);(n,a,x);(n).w;(n).l;(n,pc);(n,pc,x) -#rol w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#ror w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#roxl w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#roxr w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#st b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#sf b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#shi b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#sls b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#scc b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#scs b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#sne b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#seq b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#svc b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#svs b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#spl b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#smi b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#sge b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#slt b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#sgt b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#sle b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l -#swap w d +add bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +add bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +adda wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a +addi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +addq bwl #(1-8) d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +addx bwl d d +addx bwl -(a) -(a) +and bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +and bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +andi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +asl bwl d;#(1-8) d +asr bwl d;#(1-8) d +lsl bwl d;#(1-8) d +lsr bwl d;#(1-8) d +sub bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +sub bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +suba wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a +subi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +subq bwl #(1-8) d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +subx bwl d d +subx bwl -(a) -(a) +bchg b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +bchg l d;#(0-255) d +bset b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +bset l d;#(0-255) d +bclr b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +bclr l d;#(0-255) d +btst b d;#(0-255) (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +btst l d;#(0-255) d +rol bwl d;#(1-8) d +ror bwl d;#(1-8) d +abcd b d d +abcd b -(a) -(a) +sbcd b d d +sbcd b -(a) -(a) +muls w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +mulu w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +move bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +movea wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a +moveq l #(-128-127) d +roxl bwl d;#(1-8) d +roxr bwl d;#(1-8) d +divs w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +divu w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +chk w d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +cmp bwl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +cmpa wl d;a;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) a +cmpi bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +cmpm bwl (a)+ (a)+ +eor bwl d d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +eori bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +exg l d d;a +exg l a a +link w a #n +or bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l;#n;(n,pc);(n,pc,x) d +or bwl d (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +ori bwl #n d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +clr bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +ext wl d +neg bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +negx bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +not bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +pea l (a);(n,a);(n,a,x);(n).w;(n).l;(n,pc);(n,pc,x) +rol w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +ror w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +roxl w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +roxr w (a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +st b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +sf b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +shi b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +sls b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +scc b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +scs b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +sne b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +seq b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +svc b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +svs b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +spl b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +smi b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +sge b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +slt b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +sgt b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +sle b d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l +swap w d tst bwl d;(a);(a)+;-(a);(n,a);(n,a,x);(n).w;(n).l lea l (a);(n,a);(n,a,x);(n).w;(n).l;(n,pc);(n,pc,x) a -- cgit v1.2.3 From 7103c11ebae317680cbea6b4ae2c724206d8a6d4 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 27 Dec 2014 14:51:50 -0800 Subject: Decrement address register after fetching source in move with -(ax) dest to avoid bug when src is the dst addres reg --- m68k_core_x86.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/m68k_core_x86.c b/m68k_core_x86.c index ef84721..4169389 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -604,10 +604,8 @@ void translate_m68k_move(m68k_options * opts, m68kinst * inst) break; case MODE_AREG_PREDEC: dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1)); - subi_areg(opts, dec_amount, inst->dst.params.regs.pri); case MODE_AREG_INDIRECT: case MODE_AREG_POSTINC: - areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2); if (src.mode == MODE_REG_DIRECT) { if (src.base != opts->gen.scratch1) { mov_rr(code, src.base, opts->gen.scratch1, inst->extra.size); @@ -617,6 +615,10 @@ void translate_m68k_move(m68k_options * opts, m68kinst * inst) } else { mov_ir(code, src.disp, opts->gen.scratch1, inst->extra.size); } + if (inst->dst.addr_mode == MODE_AREG_PREDEC) { + subi_areg(opts, dec_amount, inst->dst.params.regs.pri); + } + areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2); break; case MODE_AREG_DISPLACE: cycles(&opts->gen, BUS); -- cgit v1.2.3 From ec6bd7cf6e237ba3f24af06d2c52e629c4029207 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 27 Dec 2014 15:49:15 -0800 Subject: Fix divide by zero exception return address when div instruction is bigger than 1 word --- m68k_core_x86.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 4169389..710fe58 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -1604,6 +1604,20 @@ void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D); } } + uint32_t isize = 2; + switch(inst->src.addr_mode) + { + case MODE_AREG_DISPLACE: + case MODE_AREG_INDEX_DISP8: + case MODE_ABSOLUTE_SHORT: + case MODE_PC_INDEX_DISP8: + case MODE_IMMEDIATE: + isize = 4; + break; + case MODE_ABSOLUTE: + isize = 6; + break; + } cmp_ir(code, 0, opts->gen.scratch2, SZ_D); check_alloc_code(code, 6*MAX_INST_LEN); code_ptr not_zero = code->cur + 1; @@ -1611,7 +1625,7 @@ void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos pop_r(code, RAX); pop_r(code, RDX); mov_ir(code, VECTOR_INT_DIV_ZERO, opts->gen.scratch2, SZ_D); - mov_ir(code, inst->address+2, opts->gen.scratch1, SZ_D); + mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); jmp(code, opts->trap); *not_zero = code->cur - (not_zero+1); if (inst->op == M68K_DIVS) { -- cgit v1.2.3 From 08d8620cd9bfe4a2bcaaa9156f8a46a1c0b9e659 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 28 Dec 2014 17:25:36 -0800 Subject: Removed bcd_add and bcd_sub from runtime.S and generated the logic inline with the rest of abcd and sbcd translation. Fixed some edge cases and undefined flag behavior in the process --- m68k_core_x86.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++------ runtime.S | 58 --------------------------------------------------- runtime_32.S | 57 -------------------------------------------------- 3 files changed, 58 insertions(+), 121 deletions(-) diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 710fe58..d4e0a1c 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -1404,17 +1404,69 @@ void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_o mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, SZ_B); } } + uint8_t other_reg; + //WARNING: This may need adjustment if register assignments change + if (opts->gen.scratch2 > RBX) { + other_reg = RAX; + xchg_rr(code, opts->gen.scratch2, RAX, SZ_D); + } else { + other_reg = opts->gen.scratch2; + } + mov_rr(code, opts->gen.scratch1, opts->gen.scratch1 + (AH-RAX), SZ_B); + mov_rr(code, other_reg, other_reg + (AH-RAX), SZ_B); + and_ir(code, 0xF0, opts->gen.scratch1, SZ_B); + and_ir(code, 0xF0, other_reg, SZ_B); + and_ir(code, 0xF, opts->gen.scratch1 + (AH-RAX), SZ_B); + and_ir(code, 0xF, other_reg + (AH-RAX), SZ_B); + //do op on low nibble flag_to_carry(opts, FLAG_X); - jcc(code, CC_NC, code->cur + 5); if (inst->op == M68K_ABCD) { - add_ir(code, 1, opts->gen.scratch1, SZ_B); + adc_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B); + } else { + sbb_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B); + } + cmp_ir(code, 0xA, opts->gen.scratch1 + (AH-RAX), SZ_B); + code_ptr no_adjust = code->cur+1; + //add correction factor if necessary + jcc(code, CC_B, no_adjust); + if (inst->op == M68K_ABCD) { + add_ir(code, 6, opts->gen.scratch1 + (AH-RAX), SZ_B); + } else { + sub_ir(code, 6, opts->gen.scratch1 + (AH-RAX), SZ_B); + } + *no_adjust = code->cur - (no_adjust+1); + //add low nibble result to one of the high nibble operands + add_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1, SZ_B); + if (inst->op == M68K_ABCD) { + add_rr(code, other_reg, opts->gen.scratch1, SZ_B); } else { - sub_ir(code, 1, opts->gen.scratch1, SZ_B); + sub_rr(code, other_reg, opts->gen.scratch1, SZ_B); } - call(code, (code_ptr) (inst->op == M68K_ABCD ? bcd_add : bcd_sub)); - reg_to_flag(opts, CH, FLAG_C); - reg_to_flag(opts, CH, FLAG_X); + if (opts->gen.scratch2 > RBX) { + mov_rr(code, opts->gen.scratch2, RAX, SZ_D); + } + set_flag(opts, 0, FLAG_C); + set_flag(opts, 0, FLAG_V); + code_ptr def_adjust = code->cur+1; + jcc(code, CC_C, def_adjust); + cmp_ir(code, 0xA0, opts->gen.scratch1, SZ_B); + no_adjust = code->cur+1; + jcc(code, CC_B, no_adjust); + *def_adjust = code->cur - (def_adjust + 1); + set_flag(opts, 1, FLAG_C); + if (inst->op == M68K_ABCD) { + add_ir(code, 0x60, opts->gen.scratch1, SZ_B); + } else { + sub_ir(code, 0x60, opts->gen.scratch1, SZ_B); + } + //V flag is set based on the result of the addition of the + //result and the correction factor + set_flag_cond(opts, CC_O, FLAG_V); + *no_adjust = code->cur - (no_adjust+1); + flag_to_flag(opts, FLAG_C, FLAG_X); + cmp_ir(code, 0, opts->gen.scratch1, SZ_B); + set_flag_cond(opts, CC_S, FLAG_N); jcc(code, CC_Z, code->cur + 4); set_flag(opts, 0, FLAG_Z); if (dst_op->base != opts->gen.scratch1) { diff --git a/runtime.S b/runtime.S index e66b158..5595eb1 100644 --- a/runtime.S +++ b/runtime.S @@ -12,63 +12,5 @@ m68k_invalid: mov $1, %rdi call exit - .global bcd_add -bcd_add: - xchg %rax, %rdi - - mov %cl, %ch - mov %al, %ah - and $0xF, %ch - and $0xF, %ah - and $0xF0, %cl - and $0xF0, %al - add %ah, %ch - cmp $10, %ch - jb no_adjust - add $6, %ch -no_adjust: - add %ch, %al - add %al, %cl - mov $0, %ch - jc def_adjust - cmp $0xA0, %cl - jb no_adjust_h -def_adjust: - add $0x60, %cl - mov $1, %ch -no_adjust_h: - - mov %rdi, %rax - ret - - .global bcd_sub -bcd_sub: - xchg %rax, %rdi - - mov %cl, %ch - mov %al, %ah - and $0xF, %ch - and $0xF, %ah - and $0xF0, %cl - and $0xF0, %al - sub %ah, %ch - cmp $10, %ch - jb no_adjusts - sub $6, %ch -no_adjusts: - add %ch, %cl - sub %al, %cl - mov $0, %ch - jc def_adjusts - cmp $0xA0, %cl - jb no_adjust_hs -def_adjusts: - sub $0x60, %cl - mov $1, %ch -no_adjust_hs: - - mov %rdi, %rax - ret - diff --git a/runtime_32.S b/runtime_32.S index 1f0c503..50117f1 100644 --- a/runtime_32.S +++ b/runtime_32.S @@ -12,63 +12,6 @@ m68k_invalid: push $1 call exit - .global bcd_add -bcd_add: - xchg %eax, %edi - - mov %cl, %ch - mov %al, %ah - and $0xF, %ch - and $0xF, %ah - and $0xF0, %cl - and $0xF0, %al - add %ah, %ch - cmp $10, %ch - jb no_adjust - add $6, %ch -no_adjust: - add %ch, %al - add %al, %cl - mov $0, %ch - jc def_adjust - cmp $0xA0, %cl - jb no_adjust_h -def_adjust: - add $0x60, %cl - mov $1, %ch -no_adjust_h: - - mov %edi, %eax - ret - - .global bcd_sub -bcd_sub: - xchg %eax, %edi - - mov %cl, %ch - mov %al, %ah - and $0xF, %ch - and $0xF, %ah - and $0xF0, %cl - and $0xF0, %al - sub %ah, %ch - cmp $10, %ch - jb no_adjusts - sub $6, %ch -no_adjusts: - add %ch, %cl - sub %al, %cl - mov $0, %ch - jc def_adjusts - cmp $0xA0, %cl - jb no_adjust_hs -def_adjusts: - sub $0x60, %cl - mov $1, %ch -no_adjust_hs: - - mov %edi, %eax - ret -- cgit v1.2.3 From 1a5707d6777884cacae1f51bddd7559d6f25bae5 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 28 Dec 2014 17:58:43 -0800 Subject: Fix opsize for sbcd in 68K instruction decoder. This fixes the timer bug in Strider 2 --- 68kinst.c | 1 + 1 file changed, 1 insertion(+) diff --git a/68kinst.c b/68kinst.c index b9e25aa..2ca1e02 100644 --- a/68kinst.c +++ b/68kinst.c @@ -896,6 +896,7 @@ uint16_t * m68k_decode(uint16_t * istream, m68kinst * decoded, uint32_t address) break; case 4: decoded->op = M68K_SBCD; + decoded->extra.size = OPSIZE_BYTE; decoded->dst.addr_mode = decoded->src.addr_mode = *istream & 0x8 ? MODE_AREG_PREDEC : MODE_REG; decoded->src.params.regs.pri = *istream & 0x7; decoded->dst.params.regs.pri = (*istream >> 9) & 0x7; -- cgit v1.2.3 From a7517fb92477c8fc62bcff2b97ca0e9c66a2244d Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 29 Dec 2014 00:14:21 -0800 Subject: Fix flag mask for m68k not --- m68k_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/m68k_core.c b/m68k_core.c index d3cc208..7fc31e3 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -649,7 +649,7 @@ impl_info m68k_impls[] = { RAW_IMPL(M68K_EXT, translate_m68k_ext), UNARY_IMPL(M68K_NEG, X|N|Z|V|C), OP_IMPL(M68K_NEGX, translate_m68k_negx), - UNARY_IMPL(M68K_NOT, X|N|Z|V|C), + UNARY_IMPL(M68K_NOT, N|Z|V|C), UNARY_IMPL(M68K_TST, N|Z|V0|C0), //shift/rotate -- cgit v1.2.3 From 48c6f35700f1f985b36b56ced2683a7f8e622b37 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 29 Dec 2014 00:14:33 -0800 Subject: Update .hgignore --- .hgignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.hgignore b/.hgignore index 9efd7b3..6484579 100644 --- a/.hgignore +++ b/.hgignore @@ -6,12 +6,16 @@ syntax: glob *.jpg *.pdf *.tar.gz +*.list *~ starscream/* gxz80/* +musashi/* vdpreverse/* nemesis/* html/* +generated_tests/* +ztests/* *.o blastem dis -- cgit v1.2.3 From dcaf14476d62f2d20420226b968156f14d394450 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 29 Dec 2014 00:41:36 -0800 Subject: Add support for Z80 access to VDP via bank area --- blastem.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/blastem.c b/blastem.c index 02e2450..0ffa4ea 100644 --- a/blastem.c +++ b/blastem.c @@ -732,7 +732,11 @@ uint8_t z80_read_bank(uint32_t location, void * vcontext) { z80_context * context = vcontext; uint32_t address = context->bank_reg << 15 | location; - fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area\n", address); + 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\n", address); + } return 0; } @@ -743,6 +747,8 @@ void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value) if (address >= 0xE00000) { address &= 0xFFFF; ((uint8_t *)ram)[address ^ 1] = value; + } else if (address >= 0xC00000) { + z80_vdp_port_write(location & 0xFF, context, value); } else { fprintf(stderr, "Unhandled write by Z80 to address %X through banked memory area\n", address); } -- cgit v1.2.3 From fb82ca4cdd5f4ea98cc83cf4a88df7c730a4b4d9 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 29 Dec 2014 20:56:05 -0800 Subject: Added support for JP in Z80 test generator --- ztestgen.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 8 deletions(-) diff --git a/ztestgen.c b/ztestgen.c index e74c38a..453659e 100644 --- a/ztestgen.c +++ b/ztestgen.c @@ -24,6 +24,7 @@ extern char * z80_regs[Z80_USE_IMMED]; #define PRE_IX 0xDD #define PRE_IY 0xFD #define LD_IR16 0x01 +#define INC_R8 0x04 #define LD_IR8 0x06 #define LD_RR8 0x40 #define AND_R 0xA0 @@ -143,6 +144,43 @@ uint8_t * and_r(uint8_t * dst, uint8_t reg) } } +uint8_t * inc_r(uint8_t *dst, uint8_t reg) +{ + if (reg == Z80_IXH || reg == Z80_IXL) { + *(dst++) = PRE_IX; + return inc_r(dst, reg - (Z80_IXL - Z80_L)); + } else if(reg == Z80_IYH || reg == Z80_IYL) { + *(dst++) = PRE_IY; + return inc_r(dst, reg - (Z80_IYL - Z80_L)); + } else { + *(dst++) = INC_R8 | reg << 3; + return dst; + } +} + +void mark_used8(uint8_t *reg_usage, uint16_t *reg_values, uint8_t reg, uint8_t init_value) +{ + reg_usage[reg] = 1; + reg_values[reg] = init_value; + uint8_t word_reg = z80_word_reg(reg); + if (word_reg != Z80_UNUSED) { + reg_usage[word_reg] = 1; + reg_values[word_reg] = (reg_values[z80_high_reg(word_reg)] << 8) | (reg_values[z80_low_reg(word_reg)] & 0xFF); + } +} + +uint8_t alloc_reg8(uint8_t *reg_usage, uint16_t *reg_values, uint8_t init_value) +{ + for (uint8_t reg = 0; reg < Z80_BC; reg++) + { + if (!reg_usage[reg]) { + mark_used8(reg_usage, reg_values, reg, init_value); + return reg; + } + } + return Z80_UNUSED; +} + void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) { z80inst copy; @@ -184,12 +222,7 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) reg_values[z80_low_reg(inst->ea_reg)] = reg_values[inst->ea_reg] & 0xFF; reg_usage[z80_low_reg(inst->ea_reg)] = 1; } else { - reg_values[inst->ea_reg] = rand() % 256; - uint8_t word_reg = z80_word_reg(inst->ea_reg); - if (word_reg != Z80_UNUSED) { - reg_usage[word_reg] = 1; - reg_values[word_reg] = (reg_values[z80_high_reg(word_reg)] << 8) | (reg_values[z80_low_reg(word_reg)] & 0xFF); - } + mark_used8(reg_usage, reg_values, inst->ea_reg, rand() % 256); } break; case Z80_REG_INDIRECT: @@ -255,6 +288,10 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) } reg_usage[inst->reg] = 1; } + uint8_t counter_reg = Z80_UNUSED; + if (inst->op == Z80_JP) { + counter_reg = alloc_reg8(reg_usage, reg_values, 0); + } puts("--------------"); for (uint8_t reg = 0; reg < Z80_UNUSED; reg++) { if (reg_values[reg]) { @@ -293,11 +330,16 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) //setup other regs for (uint8_t reg = Z80_BC; reg <= Z80_IY; reg++) { - if (reg != Z80_AF && reg != Z80_SP) { + if (reg != Z80_AF && reg != Z80_SP && (inst->op != Z80_JP || addr_mode != Z80_REG_INDIRECT || inst->ea_reg != reg)) { cur = ld_ir16(cur, reg, reg_values[reg]); } } + if (inst->op == Z80_JP && addr_mode == Z80_REG_INDIRECT) { + uint16_t address = cur - prog + (inst->ea_reg == Z80_HL ? 3 : 4) + instlen + 1; + cur = ld_ir16(cur, inst->ea_reg, address); + } + //copy instruction if (instlen == 3) { memcpy(cur, instbuf, 2); @@ -310,6 +352,11 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) //immed/displacement byte(s) if (addr_mode == Z80_IX_DISPLACE || addr_mode == Z80_IY_DISPLACE) { *(cur++) = inst->ea_reg; + } else if (inst->op == Z80_JP && addr_mode == Z80_IMMED) { + uint16_t address = cur - prog + 5; //2 for immed address, 3 for instruction to skip + *(cur++) = address; + *(cur++) = address >> 8; + cur = ld_ir16(cur, Z80_HL, 0xDEAD); } else if (addr_mode == Z80_IMMED & inst->op != Z80_IM) { *(cur++) = inst->immed & 0xFF; if (word_sized) { @@ -325,6 +372,9 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) if (instlen == 3) { *(cur++) = instbuf[2]; } + if (inst->op == Z80_JP && addr_mode == Z80_REG_INDIRECT) { + cur = inc_r(cur, counter_reg); + } if (!i) { //Save AF from first run cur = push(cur, Z80_AF); @@ -399,7 +449,7 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) uint8_t should_skip(z80inst * inst) { - return inst->op >= Z80_JP || (inst->op >= Z80_LDI && inst->op <= Z80_CPDR) || inst->op == Z80_HALT + return inst->op >= Z80_JPCC || (inst->op >= Z80_LDI && inst->op <= Z80_CPDR) || inst->op == Z80_HALT || inst->op == Z80_DAA || inst->op == Z80_RLD || inst->op == Z80_RRD || inst->op == Z80_NOP || inst->op == Z80_DI || inst->op == Z80_EI; } -- cgit v1.2.3 From ef7df44f69080781c0e2e22977ef3cf2877b5337 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 29 Dec 2014 21:24:12 -0800 Subject: Added support for JPcc in Z80 test generator --- ztestgen.c | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/ztestgen.c b/ztestgen.c index 453659e..cc1a5a3 100644 --- a/ztestgen.c +++ b/ztestgen.c @@ -289,7 +289,7 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) reg_usage[inst->reg] = 1; } uint8_t counter_reg = Z80_UNUSED; - if (inst->op == Z80_JP) { + if (inst->op == Z80_JP || inst->op == Z80_JPCC) { counter_reg = alloc_reg8(reg_usage, reg_values, 0); } puts("--------------"); @@ -331,12 +331,22 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) //setup other regs for (uint8_t reg = Z80_BC; reg <= Z80_IY; reg++) { if (reg != Z80_AF && reg != Z80_SP && (inst->op != Z80_JP || addr_mode != Z80_REG_INDIRECT || inst->ea_reg != reg)) { - cur = ld_ir16(cur, reg, reg_values[reg]); + if (i == 1 && (z80_high_reg(reg) == counter_reg || z80_low_reg(reg) == counter_reg)) { + if (z80_high_reg(reg) == counter_reg) { + if (reg_usage[z80_low_reg(reg)]) { + cur = ld_ir8(cur, z80_low_reg(reg), reg_values[z80_low_reg(reg)]); + } + } else if (reg_usage[z80_high_reg(reg)]) { + cur = ld_ir8(cur, z80_high_reg(reg), reg_values[z80_high_reg(reg)]); + } + } else { + cur = ld_ir16(cur, reg, reg_values[reg]); + } } } if (inst->op == Z80_JP && addr_mode == Z80_REG_INDIRECT) { - uint16_t address = cur - prog + (inst->ea_reg == Z80_HL ? 3 : 4) + instlen + 1; + uint16_t address = cur - prog + (inst->ea_reg == Z80_HL ? 3 : 4) + instlen + 1 + i; cur = ld_ir16(cur, inst->ea_reg, address); } @@ -352,11 +362,10 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) //immed/displacement byte(s) if (addr_mode == Z80_IX_DISPLACE || addr_mode == Z80_IY_DISPLACE) { *(cur++) = inst->ea_reg; - } else if (inst->op == Z80_JP && addr_mode == Z80_IMMED) { - uint16_t address = cur - prog + 5; //2 for immed address, 3 for instruction to skip + } else if ((inst->op == Z80_JP || inst->op == Z80_JPCC) && addr_mode == Z80_IMMED) { + uint16_t address = cur - prog + 3 + i; //2 for immed address, 1/2 for instruction(s) to skip *(cur++) = address; *(cur++) = address >> 8; - cur = ld_ir16(cur, Z80_HL, 0xDEAD); } else if (addr_mode == Z80_IMMED & inst->op != Z80_IM) { *(cur++) = inst->immed & 0xFF; if (word_sized) { @@ -372,8 +381,12 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) if (instlen == 3) { *(cur++) = instbuf[2]; } - if (inst->op == Z80_JP && addr_mode == Z80_REG_INDIRECT) { + if (inst->op == Z80_JP || inst->op == Z80_JPCC) { cur = inc_r(cur, counter_reg); + if (i) { + //inc twice on second iteration so we can differentiate the two + cur = inc_r(cur, counter_reg); + } } if (!i) { //Save AF from first run @@ -449,7 +462,7 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) uint8_t should_skip(z80inst * inst) { - return inst->op >= Z80_JPCC || (inst->op >= Z80_LDI && inst->op <= Z80_CPDR) || inst->op == Z80_HALT + return inst->op >= Z80_JR || (inst->op >= Z80_LDI && inst->op <= Z80_CPDR) || inst->op == Z80_HALT || inst->op == Z80_DAA || inst->op == Z80_RLD || inst->op == Z80_RRD || inst->op == Z80_NOP || inst->op == Z80_DI || inst->op == Z80_EI; } -- cgit v1.2.3 From c6beba019312aaaf7bd8718bb239b7c632477852 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 29 Dec 2014 21:36:17 -0800 Subject: Added support for JR and JRcc in Z80 test generator --- ztestgen.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ztestgen.c b/ztestgen.c index cc1a5a3..bbdc22b 100644 --- a/ztestgen.c +++ b/ztestgen.c @@ -289,7 +289,7 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) reg_usage[inst->reg] = 1; } uint8_t counter_reg = Z80_UNUSED; - if (inst->op == Z80_JP || inst->op == Z80_JPCC) { + if (inst->op >= Z80_JP && inst->op <= Z80_JRCC) { counter_reg = alloc_reg8(reg_usage, reg_values, 0); } puts("--------------"); @@ -366,6 +366,8 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) uint16_t address = cur - prog + 3 + i; //2 for immed address, 1/2 for instruction(s) to skip *(cur++) = address; *(cur++) = address >> 8; + } else if(inst->op == Z80_JR || inst->op == Z80_JRCC) { + *(cur++) = 1 + i; //skip one or 2 instructions based on value of i } else if (addr_mode == Z80_IMMED & inst->op != Z80_IM) { *(cur++) = inst->immed & 0xFF; if (word_sized) { @@ -381,7 +383,7 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) if (instlen == 3) { *(cur++) = instbuf[2]; } - if (inst->op == Z80_JP || inst->op == Z80_JPCC) { + if (inst->op >= Z80_JP && inst->op <= Z80_JRCC) { cur = inc_r(cur, counter_reg); if (i) { //inc twice on second iteration so we can differentiate the two @@ -462,7 +464,7 @@ void z80_gen_test(z80inst * inst, uint8_t *instbuf, uint8_t instlen) uint8_t should_skip(z80inst * inst) { - return inst->op >= Z80_JR || (inst->op >= Z80_LDI && inst->op <= Z80_CPDR) || inst->op == Z80_HALT + return inst->op >= Z80_DJNZ || (inst->op >= Z80_LDI && inst->op <= Z80_CPDR) || inst->op == Z80_HALT || inst->op == Z80_DAA || inst->op == Z80_RLD || inst->op == Z80_RRD || inst->op == Z80_NOP || inst->op == Z80_DI || inst->op == Z80_EI; } -- cgit v1.2.3 From c61ca95add7b82aadef09aea8b4c48774e079069 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 29 Dec 2014 23:08:39 -0800 Subject: Fix handling of code writes for Z80 core. This seems to get things close to being back to where they were before the big refactor that broke the Z80 core. Some problems remain. Notably the sound driver in Sonic 2 is still quite broken. --- backend.h | 1 + backend_x86.c | 7 +++++-- m68k_core_x86.c | 1 + z80_to_x86.c | 1 + 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/backend.h b/backend.h index 58f8a47..18c3752 100644 --- a/backend.h +++ b/backend.h @@ -62,6 +62,7 @@ typedef struct { uint32_t bus_cycles; int32_t mem_ptr_off; int32_t ram_flags_off; + uint8_t ram_flags_shift; uint8_t address_size; uint8_t byte_swap; uint8_t context_reg; diff --git a/backend_x86.c b/backend_x86.c index 631c6c7..71eaf28 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -200,9 +200,8 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n } } if (is_write && (memmap[chunk].flags & MMAP_CODE)) { - //TODO: Fixme for Z80 mov_rr(code, opts->scratch2, opts->scratch1, opts->address_size); - shr_ir(code, 11, opts->scratch1, opts->address_size); + shr_ir(code, opts->ram_flags_shift, opts->scratch1, opts->address_size); bt_rrdisp(code, opts->scratch1, opts->context_reg, opts->ram_flags_off, opts->address_size); code_ptr not_code = code->cur + 1; jcc(code, CC_NC, code->cur + 2); @@ -210,6 +209,10 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n #ifdef X86_32 push_r(code, opts->context_reg); push_r(code, opts->scratch2); +#else + if (opts->scratch2 != RDI) { + mov_rr(code, opts->scratch2, RDI, opts->address_size); + } #endif call(code, opts->handle_code_write); #ifdef X86_32 diff --git a/m68k_core_x86.c b/m68k_core_x86.c index d4e0a1c..7e97886 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -2237,6 +2237,7 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu opts->gen.bus_cycles = BUS; opts->gen.mem_ptr_off = offsetof(m68k_context, mem_pointers); opts->gen.ram_flags_off = offsetof(m68k_context, ram_code_flags); + opts->gen.ram_flags_shift = 11; for (int i = 0; i < 8; i++) { opts->dregs[i] = opts->aregs[i] = -1; diff --git a/z80_to_x86.c b/z80_to_x86.c index c785e8a..bb701a6 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -1907,6 +1907,7 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 options->gen.bus_cycles = 3; options->gen.mem_ptr_off = offsetof(z80_context, mem_pointers); options->gen.ram_flags_off = offsetof(z80_context, ram_code_flags); + options->gen.ram_flags_shift = 7; options->flags = 0; options->regs[Z80_B] = BH; -- cgit v1.2.3 From ec4eed4f35910aa27ca353fceea38155806ef188 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 1 Jan 2015 14:36:55 -0800 Subject: Remove some of the hard coded assumptions about the memory map from the CPU cores --- backend.c | 21 ++++++++ backend.h | 56 ++++++++++---------- m68k_core.c | 39 ++++---------- m68k_core.h | 2 +- m68k_core_x86.c | 6 ++- z80_to_x86.c | 157 +++++++++++++++++++------------------------------------- 6 files changed, 119 insertions(+), 162 deletions(-) diff --git a/backend.c b/backend.c index eaae9d7..86bc4b5 100644 --- a/backend.c +++ b/backend.c @@ -51,3 +51,24 @@ void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_fun } } +void * get_native_pointer(uint32_t address, void ** mem_pointers, cpu_options * opts) +{ + memmap_chunk * memmap = opts->memmap; + address &= opts->address_mask; + for (uint32_t chunk = 0; chunk < opts->memmap_chunks; chunk++) + { + if (address >= memmap[chunk].start && address < memmap[chunk].end) { + if (!(memmap[chunk].flags & MMAP_READ)) { + return NULL; + } + uint8_t * base = memmap[chunk].flags & MMAP_PTR_IDX + ? mem_pointers[memmap[chunk].ptr_index] + : memmap[chunk].buffer; + if (!base) { + return NULL; + } + return base + (address & memmap[chunk].mask); + } + } + return NULL; +} diff --git a/backend.h b/backend.h index 18c3752..c3e0c76 100644 --- a/backend.h +++ b/backend.h @@ -46,33 +46,6 @@ typedef enum { WRITE_8 } ftype; -typedef struct { - uint32_t flags; - native_map_slot *native_code_map; - deferred_addr *deferred; - code_info code; - uint8_t **ram_inst_sizes; - code_ptr save_context; - code_ptr load_context; - code_ptr handle_cycle_limit; - code_ptr handle_cycle_limit_int; - code_ptr handle_code_write; - uint32_t address_mask; - uint32_t max_address; - uint32_t bus_cycles; - int32_t mem_ptr_off; - int32_t ram_flags_off; - uint8_t ram_flags_shift; - uint8_t address_size; - uint8_t byte_swap; - uint8_t context_reg; - uint8_t cycles; - uint8_t limit; - uint8_t scratch1; - uint8_t scratch2; -} cpu_options; - - #define MMAP_READ 0x01 #define MMAP_WRITE 0x02 #define MMAP_CODE 0x04 @@ -100,6 +73,34 @@ typedef struct { write_8_fun write_8; } memmap_chunk; +typedef struct { + uint32_t flags; + native_map_slot *native_code_map; + deferred_addr *deferred; + code_info code; + uint8_t **ram_inst_sizes; + memmap_chunk const *memmap; + code_ptr save_context; + code_ptr load_context; + code_ptr handle_cycle_limit; + code_ptr handle_cycle_limit_int; + code_ptr handle_code_write; + uint32_t memmap_chunks; + uint32_t address_mask; + uint32_t max_address; + uint32_t bus_cycles; + int32_t mem_ptr_off; + int32_t ram_flags_off; + uint8_t ram_flags_shift; + uint8_t address_size; + uint8_t byte_swap; + uint8_t context_reg; + uint8_t cycles; + uint8_t limit; + uint8_t scratch1; + uint8_t scratch2; +} cpu_options; + typedef uint8_t * (*native_addr_func)(void * context, uint32_t address); deferred_addr * defer_address(deferred_addr * old_head, uint32_t address, uint8_t *dest); @@ -112,6 +113,7 @@ void check_cycles(cpu_options * opts); void check_code_prologue(code_info *code); code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc); +void * get_native_pointer(uint32_t address, void ** mem_pointers, cpu_options * opts); #endif //BACKEND_H_ diff --git a/m68k_core.c b/m68k_core.c index 7fc31e3..1c0e65d 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -754,26 +754,17 @@ void translate_m68k_stream(uint32_t address, m68k_context * context) m68kinst instbuf; m68k_options * opts = context->options; code_info *code = &opts->gen.code; - address &= 0xFFFFFF; if(get_native_address(opts->gen.native_code_map, address)) { return; } - char disbuf[1024]; uint16_t *encoded, *next; - if ((address & 0xFFFFFF) < 0x400000) { - encoded = context->mem_pointers[0] + (address & 0xFFFFFF)/2; - } else if ((address & 0xFFFFFF) > 0xE00000) { - encoded = context->mem_pointers[1] + (address & 0xFFFF)/2; - } else { - printf("attempt to translate non-memory address: %X\n", address); - exit(1); - } do { if (opts->address_log) { fprintf(opts->address_log, "%X\n", address); } do { - if (address >= 0x400000 && address < 0xE00000) { + encoded = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen); + if (!encoded) { translate_out_of_bounds(code); break; } @@ -788,7 +779,7 @@ void translate_m68k_stream(uint32_t address, m68k_context * context) } uint16_t m68k_size = (next-encoded)*2; address += m68k_size; - encoded = next; + //char disbuf[1024]; //m68k_disasm(&instbuf, disbuf); //printf("%X: %s\n", instbuf.address, disbuf); @@ -802,18 +793,8 @@ void translate_m68k_stream(uint32_t address, m68k_context * context) process_deferred(&opts->gen.deferred, context, (native_addr_func)get_native_from_context); if (opts->gen.deferred) { address = opts->gen.deferred->address; - if ((address & 0xFFFFFF) < 0x400000) { - encoded = context->mem_pointers[0] + (address & 0xFFFFFF)/2; - } else if ((address & 0xFFFFFF) > 0xE00000) { - encoded = context->mem_pointers[1] + (address & 0xFFFF)/2; - } else { - printf("attempt to translate non-memory address: %X\n", address); - exit(1); - } - } else { - encoded = NULL; } - } while(encoded != NULL); + } while(opts->gen.deferred); } void * m68k_retranslate_inst(uint32_t address, m68k_context * context) @@ -826,8 +807,7 @@ void * m68k_retranslate_inst(uint32_t address, m68k_context * context) code_info orig_code; orig_code.cur = orig_start; orig_code.last = orig_start + orig_size + 5; - address &= 0xFFFF; - uint16_t *after, *inst = context->mem_pointers[1] + address/2; + uint16_t *after, *inst = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen); m68kinst instbuf; after = m68k_decode(inst, &instbuf, orig); if (orig_size != MAX_NATIVE_SIZE) { @@ -910,7 +890,7 @@ code_ptr get_native_address_trans(m68k_context * context, uint32_t address) void remove_breakpoint(m68k_context * context, uint32_t address) { code_ptr native = get_native_address(context->native_code_map, address); - check_cycles_int(context->options, address); + check_cycles_int(&context->options->gen, address); } void start_68k_context(m68k_context * context, uint32_t address) @@ -922,9 +902,10 @@ void start_68k_context(m68k_context * context, uint32_t address) void m68k_reset(m68k_context * context) { - //TODO: Make this actually use the normal read functions - context->aregs[7] = context->mem_pointers[0][0] << 16 | context->mem_pointers[0][1]; - uint32_t address = context->mem_pointers[0][2] << 16 | context->mem_pointers[0][3]; + //TODO: Actually execute the M68K reset vector rather than simulating some of its behavior + uint16_t *reset_vec = get_native_pointer(0, (void **)context->mem_pointers, &context->options->gen); + context->aregs[7] = reset_vec[0] << 16 | reset_vec[1]; + uint32_t address = reset_vec[2] << 16 | reset_vec[3]; start_68k_context(context, address); } diff --git a/m68k_core.h b/m68k_core.h index 370aa1e..31ca320 100644 --- a/m68k_core.h +++ b/m68k_core.h @@ -59,7 +59,7 @@ typedef struct { uint16_t reserved; native_map_slot *native_code_map; - void *options; + m68k_options *options; uint8_t ram_code_flags[32/8]; void *system; } m68k_context; diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 7e97886..c0964bd 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -1464,7 +1464,7 @@ void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_o set_flag_cond(opts, CC_O, FLAG_V); *no_adjust = code->cur - (no_adjust+1); flag_to_flag(opts, FLAG_C, FLAG_X); - + cmp_ir(code, 0, opts->gen.scratch1, SZ_B); set_flag_cond(opts, CC_S, FLAG_N); jcc(code, CC_Z, code->cur + 4); @@ -1664,7 +1664,7 @@ void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos case MODE_ABSOLUTE_SHORT: case MODE_PC_INDEX_DISP8: case MODE_IMMEDIATE: - isize = 4; + isize = 4; break; case MODE_ABSOLUTE: isize = 6; @@ -2230,6 +2230,8 @@ void insert_breakpoint(m68k_context * context, uint32_t address, code_ptr bp_han void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks) { memset(opts, 0, sizeof(*opts)); + opts->gen.memmap = memmap; + opts->gen.memmap_chunks = num_chunks; opts->gen.address_size = SZ_D; opts->gen.address_mask = 0xFFFFFF; opts->gen.byte_swap = 1; diff --git a/z80_to_x86.c b/z80_to_x86.c index 6da2321..dc38cae 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -1331,7 +1331,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, num_cycles += 4; } cycles(&opts->gen, num_cycles); - if (inst->addr_mode != Z80_REG_INDIRECT && inst->immed < 0x4000) { + if (inst->addr_mode != Z80_REG_INDIRECT) { code_ptr call_dst = z80_get_native_address(context, inst->immed); if (!call_dst) { opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); @@ -1380,38 +1380,26 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, jcc(code, cond, code->cur+2); cycles(&opts->gen, 5);//T States: 5 uint16_t dest_addr = inst->immed; - if (dest_addr < 0x4000) { - code_ptr call_dst = z80_get_native_address(context, dest_addr); - if (!call_dst) { - opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); - //fake address to force large displacement - call_dst = code->cur + 256; - } - jmp(code, call_dst); - } else { - mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); - call(code, opts->native_addr); - jmp_r(code, opts->gen.scratch1); + code_ptr call_dst = z80_get_native_address(context, dest_addr); + if (!call_dst) { + opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); + //fake address to force large displacement + call_dst = code->cur + 256; } + jmp(code, call_dst); *no_jump_off = code->cur - (no_jump_off+1); break; } case Z80_JR: { cycles(&opts->gen, 12);//T States: 4,3,5 uint16_t dest_addr = address + inst->immed + 2; - if (dest_addr < 0x4000) { - code_ptr call_dst = z80_get_native_address(context, dest_addr); - if (!call_dst) { - opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); - //fake address to force large displacement - call_dst = code->cur + 256; - } - jmp(code, call_dst); - } else { - mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); - call(code, opts->native_addr); - jmp_r(code, opts->gen.scratch1); + code_ptr call_dst = z80_get_native_address(context, dest_addr); + if (!call_dst) { + opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); + //fake address to force large displacement + call_dst = code->cur + 256; } + jmp(code, call_dst); break; } case Z80_JRCC: { @@ -1434,66 +1422,49 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, jcc(code, cond, code->cur+2); cycles(&opts->gen, 5);//T States: 5 uint16_t dest_addr = address + inst->immed + 2; - if (dest_addr < 0x4000) { - code_ptr call_dst = z80_get_native_address(context, dest_addr); - if (!call_dst) { - opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); - //fake address to force large displacement - call_dst = code->cur + 256; - } - jmp(code, call_dst); - } else { - mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); - call(code, opts->native_addr); - jmp_r(code, opts->gen.scratch1); + code_ptr call_dst = z80_get_native_address(context, dest_addr); + if (!call_dst) { + opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); + //fake address to force large displacement + call_dst = code->cur + 256; } + jmp(code, call_dst); *no_jump_off = code->cur - (no_jump_off+1); break; } - case Z80_DJNZ: + case Z80_DJNZ: { cycles(&opts->gen, 8);//T States: 5,3 sub_ir(code, 1, opts->regs[Z80_B], SZ_B); uint8_t *no_jump_off = code->cur+1; jcc(code, CC_Z, code->cur+2); cycles(&opts->gen, 5);//T States: 5 uint16_t dest_addr = address + inst->immed + 2; - if (dest_addr < 0x4000) { - code_ptr call_dst = z80_get_native_address(context, dest_addr); - if (!call_dst) { - opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); - //fake address to force large displacement - call_dst = code->cur + 256; - } - jmp(code, call_dst); - } else { - mov_ir(code, dest_addr, opts->gen.scratch1, SZ_W); - call(code, opts->native_addr); - jmp_r(code, opts->gen.scratch1); + code_ptr call_dst = z80_get_native_address(context, dest_addr); + if (!call_dst) { + opts->gen.deferred = defer_address(opts->gen.deferred, dest_addr, code->cur + 1); + //fake address to force large displacement + call_dst = code->cur + 256; } + jmp(code, call_dst); *no_jump_off = code->cur - (no_jump_off+1); break; + } case Z80_CALL: { cycles(&opts->gen, 11);//T States: 4,3,4 sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); mov_ir(code, address + 3, opts->gen.scratch1, SZ_W); mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); call(code, opts->write_16_highfirst);//T States: 3, 3 - if (inst->immed < 0x4000) { - code_ptr call_dst = z80_get_native_address(context, inst->immed); - if (!call_dst) { - opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); - //fake address to force large displacement - call_dst = code->cur + 256; - } - jmp(code, call_dst); - } else { - mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); - call(code, opts->native_addr); - jmp_r(code, opts->gen.scratch1); + code_ptr call_dst = z80_get_native_address(context, inst->immed); + if (!call_dst) { + opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); + //fake address to force large displacement + call_dst = code->cur + 256; } + jmp(code, call_dst); break; } - case Z80_CALLCC: + case Z80_CALLCC: { cycles(&opts->gen, 10);//T States: 4,3,3 (false case) uint8_t cond = CC_Z; switch (inst->reg) @@ -1526,21 +1497,16 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, mov_ir(code, address + 3, opts->gen.scratch1, SZ_W); mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); call(code, opts->write_16_highfirst);//T States: 3, 3 - if (inst->immed < 0x4000) { - code_ptr call_dst = z80_get_native_address(context, inst->immed); - if (!call_dst) { - opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); - //fake address to force large displacement - call_dst = code->cur + 256; - } - jmp(code, call_dst); - } else { - mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); - call(code, opts->native_addr); - jmp_r(code, opts->gen.scratch1); + code_ptr call_dst = z80_get_native_address(context, inst->immed); + if (!call_dst) { + opts->gen.deferred = defer_address(opts->gen.deferred, inst->immed, code->cur + 1); + //fake address to force large displacement + call_dst = code->cur + 256; } + jmp(code, call_dst); *no_call_off = code->cur - (no_call_off+1); break; + } case Z80_RET: cycles(&opts->gen, 4);//T States: 4 mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); @@ -1850,10 +1816,8 @@ void * z80_retranslate_inst(uint32_t address, z80_context * context, uint8_t * o char disbuf[80]; z80_options * opts = context->options; uint8_t orig_size = z80_get_native_inst_size(opts, address); - uint32_t orig = address; - address &= 0x1FFF; code_info *code = &opts->gen.code; - uint8_t *after, *inst = context->mem_pointers[0] + address; + uint8_t *after, *inst = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen); z80inst instbuf; dprintf("Retranslating code at Z80 address %X, native address %p\n", address, orig_start); after = z80_decode(inst, &instbuf); @@ -1921,26 +1885,24 @@ void translate_z80_stream(z80_context * context, uint32_t address) } z80_options * opts = context->options; uint32_t start_address = address; - uint8_t * encoded = NULL, *next; - if (address < 0x4000) { - encoded = context->mem_pointers[0] + (address & 0x1FFF); - } - while (encoded != NULL || address >= 0x4000) + do { z80inst inst; dprintf("translating Z80 code at address %X\n", address); do { - if (address >= 0x4000) { - code_info stub = z80_make_interp_stub(context, address); - z80_map_native_address(context, address, stub.cur, 1, stub.last - stub.cur); - break; - } uint8_t * existing = z80_get_native_address(context, address); if (existing) { jmp(&opts->gen.code, existing); break; } + uint8_t * encoded, *next; + encoded = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen); + if (!encoded) { + code_info stub = z80_make_interp_stub(context, address); + z80_map_native_address(context, address, stub.cur, 1, stub.last - stub.cur); + break; + } //make sure prologue is in a contiguous chunk of code check_code_prologue(&opts->gen.code); next = z80_decode(encoded, &inst); @@ -1956,33 +1918,22 @@ void translate_z80_stream(z80_context * context, uint32_t address) translate_z80inst(&inst, context, address, 0); z80_map_native_address(context, address, start, next-encoded, opts->gen.code.cur - start); address += next-encoded; - if (address > 0xFFFF) { - address &= 0xFFFF; - - } else { - encoded = next; - } + address &= 0xFFFF; } while (!z80_is_terminal(&inst)); process_deferred(&opts->gen.deferred, context, (native_addr_func)z80_get_native_address); if (opts->gen.deferred) { address = opts->gen.deferred->address; dprintf("defferred address: %X\n", address); - if (address < 0x4000) { - encoded = context->mem_pointers[0] + (address & 0x1FFF); - } else { - encoded = NULL; - } - } else { - encoded = NULL; - address = 0; } - } + } while (opts->gen.deferred); } void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks) { memset(options, 0, sizeof(*options)); + options->gen.memmap = chunks; + options->gen.memmap_chunks = num_chunks; options->gen.address_size = SZ_W; options->gen.address_mask = 0xFFFF; options->gen.max_address = 0x10000; -- cgit v1.2.3 From 574281b6ea14c8534582f088b1cbf128ba6b1d76 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 1 Jan 2015 17:31:59 -0800 Subject: Fix some issues with 68K instruction retranslation --- backend.c | 2 +- gen.h | 2 ++ gen_x86.h | 2 -- m68k_core.c | 23 +++++++++++------------ m68k_core_x86.c | 2 +- 5 files changed, 15 insertions(+), 16 deletions(-) diff --git a/backend.c b/backend.c index 86bc4b5..8f65f25 100644 --- a/backend.c +++ b/backend.c @@ -53,7 +53,7 @@ void process_deferred(deferred_addr ** head_ptr, void * context, native_addr_fun void * get_native_pointer(uint32_t address, void ** mem_pointers, cpu_options * opts) { - memmap_chunk * memmap = opts->memmap; + memmap_chunk const * memmap = opts->memmap; address &= opts->address_mask; for (uint32_t chunk = 0; chunk < opts->memmap_chunks; chunk++) { diff --git a/gen.h b/gen.h index e1492fc..b0fe5e1 100644 --- a/gen.h +++ b/gen.h @@ -17,6 +17,8 @@ typedef struct { code_ptr last; } code_info; +void check_alloc_code(code_info *code, uint32_t inst_size); + void init_code_info(code_info *code); void call(code_info *code, code_ptr fun); void jmp(code_info *code, code_ptr dest); diff --git a/gen_x86.h b/gen_x86.h index 97bb9c2..0e614dc 100644 --- a/gen_x86.h +++ b/gen_x86.h @@ -80,8 +80,6 @@ enum { MODE_IMMED = 0xFF } x86_modes; -void check_alloc_code(code_info *code, uint32_t inst_size); - void rol_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); void ror_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); void rcl_ir(code_info *code, uint8_t val, uint8_t dst, uint8_t size); diff --git a/m68k_core.c b/m68k_core.c index 1c0e65d..fd2f406 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -761,6 +761,7 @@ void translate_m68k_stream(uint32_t address, m68k_context * context) do { if (opts->address_log) { fprintf(opts->address_log, "%X\n", address); + fflush(opts->address_log); } do { encoded = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen); @@ -813,18 +814,19 @@ void * m68k_retranslate_inst(uint32_t address, m68k_context * context) if (orig_size != MAX_NATIVE_SIZE) { deferred_addr * orig_deferred = opts->gen.deferred; - //make sure the beginning of the code for an instruction is contiguous - check_code_prologue(code); + //make sure we have enough code space for the max size instruction + check_alloc_code(code, MAX_NATIVE_SIZE); code_ptr native_start = code->cur; translate_m68k(opts, &instbuf); code_ptr native_end = code->cur; - uint8_t is_terminal = m68k_is_terminal(&instbuf); + /*uint8_t is_terminal = m68k_is_terminal(&instbuf); if ((native_end - native_start) <= orig_size) { code_ptr native_next; if (!is_terminal) { native_next = get_native_address(context->native_code_map, orig + (after-inst)*2); } if (is_terminal || (native_next && ((native_next == orig_start + orig_size) || (orig_size - (native_end - native_start)) > 5))) { + printf("Using original location: %p\n", orig_code.cur); remove_deferred_until(&opts->gen.deferred, orig_deferred); code_info tmp; tmp.cur = code->cur; @@ -841,7 +843,7 @@ void * m68k_retranslate_inst(uint32_t address, m68k_context * context) m68k_handle_deferred(context); return orig_start; } - } + }*/ map_native_address(context, instbuf.address, native_start, (after-inst)*2, MAX_NATIVE_SIZE); @@ -860,17 +862,14 @@ void * m68k_retranslate_inst(uint32_t address, m68k_context * context) m68k_handle_deferred(context); return native_start; } else { - code_info tmp; - tmp.cur = code->cur; - tmp.last = code->last; - code->cur = orig_code.cur; - code->last = orig_code.last; + code_info tmp = *code; + *code = orig_code; translate_m68k(opts, &instbuf); + orig_code = *code; + *code = tmp; if (!m68k_is_terminal(&instbuf)) { - jmp(code, get_native_address_trans(context, orig + (after-inst)*2)); + jmp(&orig_code, get_native_address_trans(context, orig + (after-inst)*2)); } - code->cur = tmp.cur; - code->last = tmp.last; m68k_handle_deferred(context); return orig_start; } diff --git a/m68k_core_x86.c b/m68k_core_x86.c index c0964bd..8d9fc6a 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -2185,7 +2185,7 @@ void insert_breakpoint(m68k_context * context, uint32_t address, code_ptr bp_han mov_ir(&native, address, opts->gen.scratch1, SZ_D); if (!bp_stub) { code_info *code = &opts->gen.code; - check_alloc_code(code, 5); + check_code_prologue(code); bp_stub = code->cur; call(&native, bp_stub); -- cgit v1.2.3 From 60b9f591475238df486ee45d25e888e417ac8e91 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 1 Jan 2015 17:36:23 -0800 Subject: Avoid calling atexit(SDL_Quit) until after OpenGL initialization to avoid a segfault on exit when using fglrx --- render_sdl.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/render_sdl.c b/render_sdl.c index 9f635a8..f50c476 100644 --- a/render_sdl.c +++ b/render_sdl.c @@ -220,8 +220,6 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); exit(1); } - atexit(SDL_Quit); - atexit(render_close_audio); printf("width: %d, height: %d\n", width, height); uint32_t flags = SDL_ANYFORMAT; @@ -250,10 +248,12 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full screen = SDL_SetVideoMode(width, height, 32, flags); if (!screen) { fprintf(stderr, "Unable to get SDL surface: %s\n", SDL_GetError()); + SDL_Quit(); exit(1); } if (!use_gl && screen->format->BytesPerPixel != 2 && screen->format->BytesPerPixel != 4) { fprintf(stderr, "BlastEm requires a 16-bit or 32-bit surface, SDL returned a %d-bit surface\n", screen->format->BytesPerPixel * 8); + SDL_Quit(); exit(1); } #ifndef DISABLE_OPENGL @@ -263,10 +263,12 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full GLenum res = glewInit(); if (res != GLEW_OK) { fprintf(stderr, "Initialization of GLEW failed with code %d\n", res); + SDL_Quit(); exit(1); } if (!GLEW_VERSION_2_0) { fputs("OpenGL 2.0 is unable, falling back to standard SDL rendering\n", stderr); + SDL_Quit(); exit(1); } float aspect = (float)width / height; @@ -327,6 +329,7 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full if (SDL_OpenAudio(&desired, &actual) < 0) { fprintf(stderr, "Unable to open SDL audio: %s\n", SDL_GetError()); + SDL_Quit(); exit(1); } buffer_samples = actual.samples; @@ -345,6 +348,9 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full } } SDL_JoystickEventState(SDL_ENABLE); + + atexit(SDL_Quit); + atexit(render_close_audio); } #ifndef DISABLE_OPENGL void render_context_gl(vdp_context * context) -- cgit v1.2.3 From dac14d1f29445b77fee5b570e6eb73c28b1860a4 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 1 Jan 2015 19:15:05 -0800 Subject: Added 2 new functions to gen_x86.c for handling passing args according to the C abi of the host system and adapted the code in m68k_core_x86.c to use that instead of doing everything by hand --- gen.h | 4 ++ gen_x86.c | 86 ++++++++++++++++++++++++++++++ m68k_core_x86.c | 163 ++++++++------------------------------------------------ 3 files changed, 113 insertions(+), 140 deletions(-) diff --git a/gen.h b/gen.h index b0fe5e1..e6ed928 100644 --- a/gen.h +++ b/gen.h @@ -23,5 +23,9 @@ void init_code_info(code_info *code); void call(code_info *code, code_ptr fun); void jmp(code_info *code, code_ptr dest); void jmp_r(code_info *code, uint8_t dst); +//call a function and put the arguments in the appropriate place according to the host ABI +void call_args(code_info *code, code_ptr fun, uint32_t num_args, ...); +//like the above, but follows other aspects of the ABI like stack alignment +void call_args_abi(code_info *code, code_ptr fun, uint32_t num_args, ...); #endif //GEN_H_ diff --git a/gen_x86.c b/gen_x86.c index b1988fe..b0e209c 100644 --- a/gen_x86.c +++ b/gen_x86.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #define REX_RM_FIELD 0x1 #define REX_SIB_FIELD 0x2 @@ -1953,3 +1955,87 @@ void loop(code_info *code, code_ptr dst) code->cur = out; } +uint32_t prep_args(code_info *code, uint32_t num_args, va_list args) +{ + uint8_t *arg_arr = malloc(num_args); + for (int i = 0; i < num_args; i ++) + { + arg_arr[i] = va_arg(args, int); + } +#ifdef X86_64 + uint32_t stack_args = 0; + uint8_t abi_regs[] = {RDI, RSI, RDX, RCX, R8, R9}; + int8_t reg_swap[R15+1]; + uint32_t usage = 0; + memset(reg_swap, -1, sizeof(reg_swap)); + for (int i = 0; i < num_args; i ++) + { + usage |= 1 << arg_arr[i]; + } + for (int i = 0; i < num_args; i ++) + { + uint8_t reg_arg = arg_arr[i]; + if (i < sizeof(abi_regs)) { + if (reg_swap[reg_arg] >= 0) { + reg_arg = reg_swap[reg_arg]; + } + if (reg_arg != abi_regs[i]) { + if (usage & (1 << abi_regs[i])) { + xchg_rr(code, reg_arg, abi_regs[i], SZ_PTR); + reg_swap[abi_regs[i]] = reg_arg; + } else { + mov_rr(code, reg_arg, abi_regs[i], SZ_PTR); + } + } + } else { + arg_arr[stack_args++] = reg_arg; + } + } +#else +#define stack_args num_args +#endif + for (int i = stack_args -1; i >= 0; i--) + { + push_r(code, arg_arr[i]); + } + + return stack_args * sizeof(void *); +} + +void call_args(code_info *code, code_ptr fun, uint32_t num_args, ...) +{ + va_list args; + va_start(args, num_args); + uint32_t adjust = prep_args(code, num_args, args); + va_end(args); + call(code, fun); + if (adjust) { + add_ir(code, adjust, RSP, SZ_PTR); + } +} + +void call_args_abi(code_info *code, code_ptr fun, uint32_t num_args, ...) +{ + va_list args; + va_start(args, num_args); + uint32_t adjust = prep_args(code, num_args, args); + va_end(args); +#ifdef X86_64 + test_ir(code, 8, RSP, SZ_PTR); //check stack alignment + code_ptr do_adjust_rsp = code->cur + 1; + jcc(code, CC_NZ, code->cur + 2); +#endif + call(code, fun); + if (adjust) { + add_ir(code, adjust, RSP, SZ_PTR); + } +#ifdef X86_64 + code_ptr no_adjust_rsp = code->cur + 1; + jmp(code, code->cur + 2); + *do_adjust_rsp = code->cur - (do_adjust_rsp+1); + sub_ir(code, 8, RSP, SZ_PTR); + call(code, fun); + add_ir(code, adjust + 8 , RSP, SZ_PTR); + *no_adjust_rsp = code->cur - (no_adjust_rsp+1); +#endif +} diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 8d9fc6a..1914599 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -14,17 +14,6 @@ #include #include -#define CYCLES RAX -#define LIMIT RBP -#define CONTEXT RSI -#define SCRATCH1 RCX - -#ifdef X86_64 -#define SCRATCH2 RDI -#else -#define SCRATCH2 RBX -#endif - enum { FLAG_X, FLAG_N, @@ -1077,8 +1066,8 @@ void translate_shift(m68k_options * opts, m68kinst * inst, host_ea *src_op, host jmp(code, code->cur + 2); *nz_off = code->cur - (nz_off + 1); //add 2 cycles for every bit shifted - add_rr(code, RCX, CYCLES, SZ_D); - add_rr(code, RCX, CYCLES, SZ_D); + add_rr(code, RCX, opts->gen.cycles, SZ_D); + add_rr(code, RCX, opts->gen.cycles, SZ_D); if (inst->op == M68K_ASL) { //ASL has Overflow flag behavior that depends on all of the bits shifted through the MSB //Easiest way to deal with this is to shift one bit at a time @@ -1876,8 +1865,8 @@ void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos and_ir(code, 63, opts->gen.scratch1, SZ_D); code_ptr zero_off = code->cur + 1; jcc(code, CC_Z, code->cur + 2); - add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); - add_rr(code, opts->gen.scratch1, CYCLES, SZ_D); + add_rr(code, opts->gen.scratch1, opts->gen.cycles, SZ_D); + add_rr(code, opts->gen.scratch1, opts->gen.cycles, SZ_D); cmp_ir(code, 32, opts->gen.scratch1, SZ_B); code_ptr norm_off = code->cur + 1; jcc(code, CC_L, code->cur + 2); @@ -1933,12 +1922,7 @@ void translate_m68k_illegal(m68k_options *opts, m68kinst *inst) { code_info *code = &opts->gen.code; call(code, opts->gen.save_context); -#ifdef X86_64 - mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); -#else - push_r(code, opts->gen.context_reg); -#endif - call(code, (code_ptr)print_regs_exit); + call_args(code, (code_ptr)print_regs_exit, 1, opts->gen.context_reg); } #define BIT_SUPERVISOR 5 @@ -2088,12 +2072,7 @@ void translate_m68k_reset(m68k_options *opts, m68kinst *inst) { code_info *code = &opts->gen.code; call(code, opts->gen.save_context); -#ifdef X86_64 - mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); -#else - push_r(code, opts->gen.context_reg); -#endif - call(code, (code_ptr)print_regs_exit); + call_args(code, (code_ptr)print_regs_exit, 1, opts->gen.context_reg); } void translate_m68k_rte(m68k_options *opts, m68kinst *inst) @@ -2123,10 +2102,7 @@ void translate_m68k_rte(m68k_options *opts, m68kinst *inst) void translate_out_of_bounds(code_info *code) { xor_rr(code, RDI, RDI, SZ_D); -#ifdef X86_32 - push_r(code, RDI); -#endif - call(code, (code_ptr)exit); + call_args(code, (code_ptr)exit, 1, RDI); } void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst) @@ -2156,14 +2132,7 @@ m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context) options->retrans_stub = code->cur; call(code, options->gen.save_context); push_r(code, options->gen.context_reg); -#ifdef X86_32 - push_r(code, options->gen.context_reg); - push_r(code, options->gen.scratch2); -#endif - call(code, (code_ptr)m68k_retranslate_inst); -#ifdef X86_32 - add_ir(code, 8, RSP, SZ_D); -#endif + call_args(code,(code_ptr)m68k_retranslate_inst, 2, options->gen.scratch2, options->gen.context_reg); pop_r(code, options->gen.context_reg); mov_rr(code, RAX, options->gen.scratch1, SZ_PTR); call(code, options->gen.load_context); @@ -2197,17 +2166,7 @@ void insert_breakpoint(m68k_context * context, uint32_t address, code_ptr bp_han //Save context and call breakpoint handler call(code, opts->gen.save_context); push_r(code, opts->gen.scratch1); -#ifdef X86_64 - mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); - mov_rr(code, opts->gen.scratch1, RSI, SZ_D); -#else - push_r(code, opts->gen.scratch1); - push_r(code, opts->gen.context_reg); -#endif - call(code, bp_handler); -#ifdef X86_32 - add_ir(code, 8, RSP, SZ_D); -#endif + call_args(code, bp_handler, 2, opts->gen.context_reg, opts->gen.scratch1); mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); //Restore context call(code, opts->gen.load_context); @@ -2317,8 +2276,8 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, aregs) + sizeof(uint32_t) * i, opts->aregs[i], SZ_D); } } - mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, current_cycle), CYCLES, SZ_D); - mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, target_cycle), LIMIT, SZ_D); + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, current_cycle), opts->gen.cycles, SZ_D); + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, target_cycle), opts->gen.limit, SZ_D); retn(code); opts->start_context = (start_fun)code->cur; @@ -2363,17 +2322,7 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu opts->native_addr = code->cur; call(code, opts->gen.save_context); push_r(code, opts->gen.context_reg); -#ifdef X86_64 - mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); //move context to 1st arg reg - mov_rr(code, opts->gen.scratch1, RSI, SZ_D); //move address to 2nd arg reg -#else - push_r(code, opts->gen.scratch1); - push_r(code, opts->gen.context_reg); -#endif - call(code, (code_ptr)get_native_address_trans); -#ifdef X86_32 - add_ir(code, 8, RSP, SZ_D); -#endif + call_args(code, (code_ptr)get_native_address_trans, 2, opts->gen.context_reg, opts->gen.scratch1); mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); //move result to scratch reg pop_r(code, opts->gen.context_reg); call(code, opts->gen.load_context); @@ -2382,74 +2331,27 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu opts->native_addr_and_sync = code->cur; call(code, opts->gen.save_context); push_r(code, opts->gen.scratch1); -#ifdef X86_64 - mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); - xor_rr(code, RSI, RSI, SZ_D); - test_ir(code, 8, RSP, SZ_PTR); //check stack alignment - code_ptr do_adjust_rsp = code->cur + 1; - jcc(code, CC_NZ, code->cur + 2); - call(code, (code_ptr)sync_components); - code_ptr no_adjust_rsp = code->cur + 1; - jmp(code, code->cur + 2); - *do_adjust_rsp = code->cur - (do_adjust_rsp+1); - sub_ir(code, 8, RSP, SZ_PTR); - call(code, (code_ptr)sync_components); - add_ir(code, 8, RSP, SZ_PTR); - *no_adjust_rsp = code->cur - (no_adjust_rsp+1); - pop_r(code, RSI); - push_r(code, RAX); - mov_rr(code, RAX, RDI, SZ_PTR); - call(code, (code_ptr)get_native_address_trans); -#else - //TODO: Add support for pushing a constant in gen_x86 - xor_rr(code, RAX, RAX, SZ_D); - push_r(code, RAX); - push_r(code, opts->gen.context_reg); - call(code, (code_ptr)sync_components); - add_ir(code, 8, RSP, SZ_D); + + xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D); + call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1); pop_r(code, RSI); //restore saved address from opts->gen.scratch1 push_r(code, RAX); //save context pointer for later - push_r(code, RSI); //2nd arg -- address - push_r(code, RAX); //1st arg -- context pointer - call(code, (code_ptr)get_native_address_trans); - add_ir(code, 8, RSP, SZ_D); -#endif - + call_args(code, (code_ptr)get_native_address_trans, 2, RAX, RSI); mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); //move result to scratch reg pop_r(code, opts->gen.context_reg); call(code, opts->gen.load_context); retn(code); opts->gen.handle_cycle_limit = code->cur; - cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), CYCLES, SZ_D); + cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.cycles, SZ_D); code_ptr skip_sync = code->cur + 1; jcc(code, CC_C, code->cur + 2); opts->do_sync = code->cur; push_r(code, opts->gen.scratch1); push_r(code, opts->gen.scratch2); call(code, opts->gen.save_context); -#ifdef X86_64 - mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); - xor_rr(code, RSI, RSI, SZ_D); - test_ir(code, 8, RSP, SZ_D); - code_ptr adjust_rsp = code->cur + 1; - jcc(code, CC_NZ, code->cur + 2); - call(code, (code_ptr)sync_components); - code_ptr no_adjust = code->cur + 1; - jmp(code, code->cur + 2); - *adjust_rsp = code->cur - (adjust_rsp + 1); - sub_ir(code, 8, RSP, SZ_PTR); - call(code, (code_ptr)sync_components); - add_ir(code, 8, RSP, SZ_PTR); - *no_adjust = code->cur - (no_adjust+1); -#else - //TODO: Add support for pushing a constant in gen_x86 - xor_rr(code, RAX, RAX, SZ_D); - push_r(code, RAX); - push_r(code, opts->gen.context_reg); - call(code, (code_ptr)sync_components); - add_ir(code, 8, RSP, SZ_D); -#endif + xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D); + call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1); mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); call(code, opts->gen.load_context); pop_r(code, opts->gen.scratch2); @@ -2559,40 +2461,21 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu retn(code); opts->gen.handle_cycle_limit_int = code->cur; - cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), CYCLES, SZ_D); + cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D); code_ptr do_int = code->cur + 1; jcc(code, CC_NC, code->cur + 2); - cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), CYCLES, SZ_D); + cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.cycles, SZ_D); skip_sync = code->cur + 1; jcc(code, CC_C, code->cur + 2); call(code, opts->gen.save_context); -#ifdef X86_64 - mov_rr(code, opts->gen.context_reg, RDI, SZ_PTR); - mov_rr(code, opts->gen.scratch1, RSI, SZ_D); - test_ir(code, 8, RSP, SZ_D); - adjust_rsp = code->cur + 1; - jcc(code, CC_NZ, code->cur + 2); - call(code, (code_ptr)sync_components); - no_adjust = code->cur + 1; - jmp(code, code->cur + 2); - *adjust_rsp = code->cur - (adjust_rsp + 1); - sub_ir(code, 8, RSP, SZ_PTR); - call(code, (code_ptr)sync_components); - add_ir(code, 8, RSP, SZ_PTR); - *no_adjust = code->cur - (no_adjust+1); -#else - push_r(code, opts->gen.scratch1); - push_r(code, opts->gen.context_reg); - call(code, (code_ptr)sync_components); - add_ir(code, 8, RSP, SZ_D); -#endif + call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1); mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); jmp(code, opts->gen.load_context); *skip_sync = code->cur - (skip_sync+1); retn(code); *do_int = code->cur - (do_int+1); //set target cycle to sync cycle - mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), LIMIT, SZ_D); + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.limit, SZ_D); //swap USP and SSP if not already in supervisor mode bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); code_ptr already_supervisor = code->cur + 1; -- cgit v1.2.3 From 9e0779e64b71a60ee9287ed01330baf020cfd932 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 1 Jan 2015 20:07:47 -0800 Subject: Use call_args and call_args_abi in Z80 core --- m68k_core_x86.c | 2 +- z80_to_x86.c | 21 +++++++-------------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 1914599..aed617f 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -2166,7 +2166,7 @@ void insert_breakpoint(m68k_context * context, uint32_t address, code_ptr bp_han //Save context and call breakpoint handler call(code, opts->gen.save_context); push_r(code, opts->gen.scratch1); - call_args(code, bp_handler, 2, opts->gen.context_reg, opts->gen.scratch1); + call_args_abi(code, bp_handler, 2, opts->gen.context_reg, opts->gen.scratch1); mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); //Restore context call(code, opts->gen.load_context); diff --git a/z80_to_x86.c b/z80_to_x86.c index dc38cae..1912b89 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -875,8 +875,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, case Z80_NOP: if (inst->immed == 42) { call(code, opts->gen.save_context); - mov_rr(code, opts->gen.context_reg, RDI, SZ_Q); - jmp(code, (uint8_t *)z80_print_regs_exit); + call_args(code, (code_ptr)z80_print_regs_exit, 1, opts->gen.context_reg); } else { cycles(&opts->gen, 4 * inst->immed); } @@ -1675,10 +1674,9 @@ code_info z80_make_interp_stub(z80_context * context, uint16_t address) cycles(&opts->gen, -3); check_cycles_int(&opts->gen, address); call(code, opts->gen.save_context); - mov_rr(code, opts->gen.scratch1, RDI, SZ_B); mov_irdisp(code, address, opts->gen.context_reg, offsetof(z80_context, pc), SZ_W); push_r(code, opts->gen.context_reg); - call(code, (code_ptr)z80_interp_handler); + call_args(code, (code_ptr)z80_interp_handler, 2, opts->gen.scratch1, opts->gen.scratch2); mov_rr(code, RAX, opts->gen.scratch1, SZ_Q); pop_r(code, opts->gen.context_reg); call(code, opts->gen.load_context); @@ -2049,9 +2047,8 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 options->native_addr = code->cur; call(code, options->gen.save_context); push_r(code, options->gen.context_reg); - mov_rr(code, options->gen.context_reg, RDI, SZ_PTR); - movzx_rr(code, options->gen.scratch1, RSI, SZ_W, SZ_D); - call(code, (code_ptr)z80_get_native_address_trans); + movzx_rr(code, options->gen.scratch1, options->gen.scratch1, SZ_W, SZ_D); + call_args(code, (code_ptr)z80_get_native_address_trans, 2, options->gen.context_reg, options->gen.scratch1); mov_rr(code, RAX, options->gen.scratch1, SZ_PTR); pop_r(code, options->gen.context_reg); call(code, options->gen.load_context); @@ -2155,7 +2152,7 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 cycles(&options->gen, 3); check_cycles(&options->gen); //TODO: figure out how to handle the extra wait state for word reads to bank area - //may also need special handling to avoid too much stack depth when acces is blocked + //may also need special handling to avoid too much stack depth when access is blocked push_r(code, options->gen.scratch1); call(code, options->read_8_noinc); mov_rr(code, options->gen.scratch1, options->gen.scratch2, SZ_B); @@ -2206,10 +2203,8 @@ void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint3 call(code, options->gen.save_context); //adjust pointer before move and call instructions that got us here sub_ir(code, 11, options->gen.scratch2, SZ_PTR); - mov_rr(code, options->gen.scratch1, RDI, SZ_D); - mov_rr(code, options->gen.scratch2, RDX, SZ_PTR); push_r(code, options->gen.context_reg); - call(code, (code_ptr)z80_retranslate_inst); + call_args(code, (code_ptr)z80_retranslate_inst, 3, options->gen.scratch1, options->gen.context_reg, options->gen.scratch2); pop_r(code, options->gen.context_reg); mov_rr(code, RAX, options->gen.scratch1, SZ_PTR); call(code, options->gen.load_context); @@ -2291,9 +2286,7 @@ void zcreate_stub(z80_context * context) //Save context and call breakpoint handler call(code, opts->gen.save_context); push_r(code, opts->gen.scratch1); - mov_rr(code, opts->gen.context_reg, RDI, SZ_Q); - mov_rr(code, opts->gen.scratch1, RSI, SZ_W); - call(code, context->bp_handler); + call_args_abi(code, context->bp_handler, 2, opts->gen.context_reg, opts->gen.scratch1); mov_rr(code, RAX, opts->gen.context_reg, SZ_Q); //Restore context call(code, opts->gen.load_context); -- cgit v1.2.3 From 983a2089cf49d0f6995fb30ca2327d239f21ebb4 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 1 Jan 2015 20:21:20 -0800 Subject: Use call_args and call_args_abi inside gen_mem_fun --- backend_x86.c | 83 +++++------------------------------------------------------ 1 file changed, 7 insertions(+), 76 deletions(-) diff --git a/backend_x86.c b/backend_x86.c index 71eaf28..925751c 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -91,41 +91,12 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n code_ptr not_null = code->cur + 1; jcc(code, CC_NZ, code->cur + 2); call(code, opts->save_context); -#ifdef X86_64 - if (is_write) { - if (opts->scratch2 != RDI) { - mov_rr(code, opts->scratch2, RDI, opts->address_size); - } - mov_rr(code, opts->scratch1, RDX, size); - } else { - push_r(code, opts->context_reg); - mov_rr(code, opts->scratch1, RDI, opts->address_size); - } - test_ir(code, 8, RSP, opts->address_size); - code_ptr adjust_rsp = code->cur + 1; - jcc(code, CC_NZ, code->cur + 2); - call(code, cfun); - code_ptr no_adjust = code->cur + 1; - jmp(code, code->cur + 2); - *adjust_rsp = code->cur - (adjust_rsp + 1); - sub_ir(code, 8, RSP, SZ_PTR); - call(code, cfun); - add_ir(code, 8, RSP, SZ_PTR); - *no_adjust = code->cur - (no_adjust + 1); -#else - if (is_write) { - push_r(code, opts->scratch1); - } else { - push_r(code, opts->context_reg);//save opts->context_reg for later - } - push_r(code, opts->context_reg); - push_r(code, is_write ? opts->scratch2 : opts->scratch1); - call(code, cfun); - add_ir(code, is_write ? 12 : 8, RSP, opts->address_size); -#endif if (is_write) { + call_args_abi(code, cfun, 3, opts->scratch2, opts->context_reg, opts->scratch1); mov_rr(code, RAX, opts->context_reg, SZ_PTR); } else { + push_r(code, opts->context_reg); + call_args_abi(code, cfun, 2, opts->scratch1, opts->context_reg); pop_r(code, opts->context_reg); mov_rr(code, RAX, opts->scratch1, size); } @@ -206,18 +177,7 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n code_ptr not_code = code->cur + 1; jcc(code, CC_NC, code->cur + 2); call(code, opts->save_context); -#ifdef X86_32 - push_r(code, opts->context_reg); - push_r(code, opts->scratch2); -#else - if (opts->scratch2 != RDI) { - mov_rr(code, opts->scratch2, RDI, opts->address_size); - } -#endif - call(code, opts->handle_code_write); -#ifdef X86_32 - add_ir(code, 8, RSP, SZ_D); -#endif + call_args(code, opts->handle_code_write, 2, opts->scratch2, opts->context_reg); mov_rr(code, RAX, opts->context_reg, SZ_PTR); call(code, opts->load_context); *not_code = code->cur - (not_code+1); @@ -225,41 +185,12 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n retn(code); } else if (cfun) { call(code, opts->save_context); -#ifdef X86_64 - if (is_write) { - if (opts->scratch2 != RDI) { - mov_rr(code, opts->scratch2, RDI, opts->address_size); - } - mov_rr(code, opts->scratch1, RDX, size); - } else { - push_r(code, opts->context_reg); - mov_rr(code, opts->scratch1, RDI, opts->address_size); - } - test_ir(code, 8, RSP, SZ_D); - code_ptr adjust_rsp = code->cur + 1; - jcc(code, CC_NZ, code->cur + 2); - call(code, cfun); - code_ptr no_adjust = code->cur + 1; - jmp(code, code->cur + 2); - *adjust_rsp = code->cur - (adjust_rsp + 1); - sub_ir(code, 8, RSP, SZ_PTR); - call(code, cfun); - add_ir(code, 8, RSP, SZ_PTR); - *no_adjust = code->cur - (no_adjust+1); -#else - if (is_write) { - push_r(code, opts->scratch1); - } else { - push_r(code, opts->context_reg);//save opts->context_reg for later - } - push_r(code, opts->context_reg); - push_r(code, is_write ? opts->scratch2 : opts->scratch1); - call(code, cfun); - add_ir(code, is_write ? 12 : 8, RSP, SZ_D); -#endif if (is_write) { + call_args_abi(code, cfun, 3, opts->scratch2, opts->context_reg, opts->scratch1); mov_rr(code, RAX, opts->context_reg, SZ_PTR); } else { + push_r(code, opts->context_reg); + call_args_abi(code, cfun, 2, opts->scratch1, opts->context_reg); pop_r(code, opts->context_reg); mov_rr(code, RAX, opts->scratch1, size); } -- cgit v1.2.3 From d41ae43228509a1a67446492b844013cf1e68c36 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 1 Jan 2015 20:26:22 -0800 Subject: Minor Z80 core cleanup --- blastem.c | 2 +- transz80.c | 4 ++-- z80_to_x86.c | 14 ++++---------- z80_to_x86.h | 2 +- ztestrun.c | 2 +- 5 files changed, 9 insertions(+), 15 deletions(-) diff --git a/blastem.c b/blastem.c index ddbf8ae..1e396d7 100644 --- a/blastem.c +++ b/blastem.c @@ -1352,7 +1352,7 @@ int main(int argc, char ** argv) z80_context z_context; #ifndef NO_Z80 z80_options z_opts; - init_x86_z80_opts(&z_opts, z80_map, 5); + init_z80_opts(&z_opts, z80_map, 5); init_z80_context(&z_context, &z_opts); #endif diff --git a/transz80.c b/transz80.c index a006a92..eec1736 100644 --- a/transz80.c +++ b/transz80.c @@ -38,7 +38,7 @@ int main(int argc, char ** argv) { long filesize; uint8_t *filebuf; - x86_z80_options opts; + z80_options opts; z80_context context; if (argc < 2) { fputs("usage: transz80 zrom [cartrom]\n", stderr); @@ -70,7 +70,7 @@ int main(int argc, char ** argv) *cur = (*cur >> 8) | (*cur << 8); } } - init_x86_z80_opts(&opts); + init_z80_opts(&opts); init_z80_context(&context, &opts); //Z80 RAM context.mem_pointers[0] = z80_ram; diff --git a/z80_to_x86.c b/z80_to_x86.c index 1912b89..a30adde 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -14,12 +14,6 @@ #define MODE_UNUSED (MODE_IMMED-1) -#define ZCYCLES RBP -#define ZLIMIT RDI -#define SCRATCH1 R13 -#define SCRATCH2 R14 -#define CONTEXT RSI - //#define DO_DEBUG_PRINT #ifdef DO_DEBUG_PRINT @@ -138,7 +132,7 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t } } else { ea->mode = MODE_REG_DISPLACE8; - ea->base = CONTEXT; + ea->base = opts->gen.context_reg; ea->disp = offsetof(z80_context, regs) + inst->ea_reg; } break; @@ -368,7 +362,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B);; - mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), SCRATCH1, SZ_B); + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, iff2), opts->gen.scratch1, SZ_B); mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zf_off(ZF_PV), SZ_B); } z80_save_reg(inst, opts); @@ -1926,7 +1920,7 @@ void translate_z80_stream(z80_context * context, uint32_t address) } while (opts->gen.deferred); } -void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks) +void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks) { memset(options, 0, sizeof(*options)); @@ -2263,7 +2257,7 @@ void z80_reset(z80_context * context) uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst) { code_info code = {dst, dst+16}; - mov_ir(&code, address, SCRATCH1, SZ_W); + mov_ir(&code, address, context->options->gen.scratch1, SZ_W); call(&code, context->bp_stub); return code.cur-dst; } diff --git a/z80_to_x86.h b/z80_to_x86.h index 71d6f10..0c035c6 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -84,7 +84,7 @@ typedef struct { } z80_context; void translate_z80_stream(z80_context * context, uint32_t address); -void init_x86_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks); +void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks); void init_z80_context(z80_context * context, z80_options * options); code_ptr z80_get_native_address(z80_context * context, uint32_t address); code_ptr z80_get_native_address_trans(z80_context * context, uint32_t address); diff --git a/ztestrun.c b/ztestrun.c index 1c7c6d8..ef042b5 100644 --- a/ztestrun.c +++ b/ztestrun.c @@ -53,7 +53,7 @@ int main(int argc, char ** argv) fseek(f, 0, SEEK_SET); fread(z80_ram, 1, filesize < sizeof(z80_ram) ? filesize : sizeof(z80_ram), f); fclose(f); - init_x86_z80_opts(&opts, z80_map, 2); + init_z80_opts(&opts, z80_map, 2); init_z80_context(&context, &opts); //Z80 RAM context.mem_pointers[0] = z80_ram; -- cgit v1.2.3 From 758586c1b7feec3c4fa3761ed17d1a6ea3cbab00 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 1 Jan 2015 22:18:32 -0800 Subject: Add the 3 cycle delay back in to Z80 bank area access --- blastem.c | 30 +++++++++++++++++++++++------- z80_to_x86.c | 7 ------- z80_to_x86.h | 1 - 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/blastem.c b/blastem.c index 1e396d7..46dbdc9 100644 --- a/blastem.c +++ b/blastem.c @@ -419,6 +419,7 @@ void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value) { z80_context * context = vcontext; genesis_context * gen = context->system; + vdp_port &= 0xFF; if (vdp_port & 0xE0) { printf("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port); exit(1); @@ -761,11 +762,20 @@ uint8_t z80_read_ym(uint32_t location, void * vcontext) uint8_t z80_read_bank(uint32_t location, void * vcontext) { z80_context * context = vcontext; + //typical delay from bus arbitration + context->current_cycle += 3; + + location &= 0x7FFF; + //TODO: add cycle for an access right after a previous one + //TODO: block Z80 if VDP has the bus or the 68K is blocked on a VDP access + if (context->mem_pointers[1]) { + return context->mem_pointers[1][location ^ 1]; + } uint32_t address = context->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\n", address); + fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area (%X)\n", address, context->bank_reg << 15); } return 0; } @@ -773,6 +783,11 @@ uint8_t z80_read_bank(uint32_t location, void * vcontext) void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value) { z80_context * context = vcontext; + //typical delay from bus arbitration + context->current_cycle += 3; + location &= 0x7FFF; + //TODO: add cycle for an access right after a previous one + //TODO: block Z80 if VDP has the bus or the 68K is blocked on a VDP access uint32_t address = context->bank_reg << 15 | location; if (address >= 0xE00000) { address &= 0xFFFF; @@ -791,7 +806,8 @@ void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value) context->bank_reg = (context->bank_reg >> 1 | value << 8) & 0x1FF; if (context->bank_reg < 0x80) { - context->mem_pointers[1] = context->mem_pointers[2] + (context->bank_reg << 15); + genesis_context *gen = context->system; + context->mem_pointers[1] = get_native_pointer(context->bank_reg << 15, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen); } else { context->mem_pointers[1] = NULL; } @@ -1178,11 +1194,11 @@ void detect_region() } #ifndef NO_Z80 const memmap_chunk z80_map[] = { - { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL }, - { 0x8000, 0x10000, 0x7FFF, 1, MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL | MMAP_BYTESWAP, NULL, NULL, NULL, z80_read_bank, z80_write_bank}, - { 0x4000, 0x6000, 0x0003, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, - { 0x6000, 0x6100, 0xFFFF, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg}, - { 0x7F00, 0x8000, 0x00FF, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} + { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL }, + { 0x8000, 0x10000, 0x7FFF, 0, 0, NULL, NULL, NULL, z80_read_bank, z80_write_bank}, + { 0x4000, 0x6000, 0x0003, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, + { 0x6000, 0x6100, 0xFFFF, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg}, + { 0x7F00, 0x8000, 0x00FF, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} }; #endif diff --git a/z80_to_x86.c b/z80_to_x86.c index a30adde..5f028b6 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -2223,13 +2223,6 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t jmp_rind(code, options->gen.context_reg); } -void * z80_gen_bank_write(uint32_t start_address, void * voptions) -{ - z80_options * options = voptions; - //TODO: Handle writes to bank register - return options; -} - void init_z80_context(z80_context * context, z80_options * options) { memset(context, 0, sizeof(*context)); diff --git a/z80_to_x86.h b/z80_to_x86.h index 0c035c6..9b29852 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -93,7 +93,6 @@ void z80_run(z80_context * context); void z80_reset(z80_context * context); void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler); void zremove_breakpoint(z80_context * context, uint16_t address); -void * z80_gen_bank_write(uint32_t start_address, void * voptions); #endif //Z80_TO_X86_H_ -- cgit v1.2.3 From 0611fe0f3eec53148200fc8575bfab7d09a9e6db Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 1 Jan 2015 22:52:18 -0800 Subject: Adjust 68K sync cycle when mclk_target gets adjusted --- blastem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/blastem.c b/blastem.c index 46dbdc9..8c375ad 100644 --- a/blastem.c +++ b/blastem.c @@ -307,6 +307,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) vdp_run_context(v_context, mclks); } mclk_target = vdp_cycles_to_frame_end(v_context); + context->sync_cycle = mclk_target/MCLKS_PER_68K; } else { //printf("running VDP for %d cycles\n", mclks - v_context->cycles); vdp_run_context(v_context, mclks); -- cgit v1.2.3 From 32c7399651b886128f9cbd7d185684f84d392a1a Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 1 Jan 2015 23:37:24 -0800 Subject: Remove dedicated registers for Z80 bank reg and Z80 bank pointer as they are no longer used --- z80_to_x86.c | 7 ------- z80_to_x86.h | 2 -- 2 files changed, 9 deletions(-) diff --git a/z80_to_x86.c b/z80_to_x86.c index 5f028b6..c1869b9 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -1956,9 +1956,6 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t options->regs[Z80_IX] = RDX; options->regs[Z80_IY] = R8; - options->bank_reg = R15; - options->bank_pointer = R12; - options->gen.context_reg = RSI; options->gen.cycles = RBP; options->gen.limit = RDI; @@ -2003,8 +2000,6 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t } mov_rrdisp(code, options->gen.limit, options->gen.context_reg, offsetof(z80_context, target_cycle), SZ_D); mov_rrdisp(code, options->gen.cycles, options->gen.context_reg, offsetof(z80_context, current_cycle), SZ_D); - mov_rrdisp(code, options->bank_reg, options->gen.context_reg, offsetof(z80_context, bank_reg), SZ_W); - mov_rrdisp(code, options->bank_pointer, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, SZ_PTR); retn(code); options->load_context_scratch = code->cur; @@ -2034,8 +2029,6 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t } mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, target_cycle), options->gen.limit, SZ_D); mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, current_cycle), options->gen.cycles, SZ_D); - mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, bank_reg), options->bank_reg, SZ_W); - mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, mem_pointers) + sizeof(uint8_t *) * 1, options->bank_pointer, SZ_PTR); retn(code); options->native_addr = code->cur; diff --git a/z80_to_x86.h b/z80_to_x86.h index 9b29852..d3e7b89 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -42,8 +42,6 @@ typedef struct { uint32_t flags; int8_t regs[Z80_UNUSED]; - int8_t bank_reg; - int8_t bank_pointer; z80_run_fun run; } z80_options; -- cgit v1.2.3 From 7d7892a23668855bb93b979e34a1d89440eb6e7e Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 2 Jan 2015 00:19:10 -0800 Subject: Sync Z80 when taking an interrupt so that int_cycle gets updated --- z80_to_x86.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/z80_to_x86.c b/z80_to_x86.c index c1869b9..f13ef16 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -2103,7 +2103,16 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t //TODO: Support interrupt mode 0 and 2 mov_ir(code, 0x38, options->gen.scratch1, SZ_W); call(code, options->native_addr); - jmp_r(code, options->gen.scratch1); + mov_rrind(code, options->gen.scratch1, options->gen.context_reg, SZ_PTR); + //restore callee saved registers + pop_r(code, R15); + pop_r(code, R14); + pop_r(code, R13); + pop_r(code, R12); + pop_r(code, RBP); + pop_r(code, RBX); + //return to caller of z80_run to sync + retn(code); *skip_int = code->cur - (skip_int+1); cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D); code_ptr skip_sync = code->cur + 1; -- cgit v1.2.3 From f92dd42cd257aba22ce4076d1cab2876babe3471 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 2 Jan 2015 12:04:58 -0800 Subject: Use SZ_PTR instead of SZ_Q in Z80 core for 32-bit compat --- z80_to_x86.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/z80_to_x86.c b/z80_to_x86.c index f13ef16..83237ca 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -1671,7 +1671,7 @@ code_info z80_make_interp_stub(z80_context * context, uint16_t address) mov_irdisp(code, address, opts->gen.context_reg, offsetof(z80_context, pc), SZ_W); push_r(code, opts->gen.context_reg); call_args(code, (code_ptr)z80_interp_handler, 2, opts->gen.scratch1, opts->gen.scratch2); - mov_rr(code, RAX, opts->gen.scratch1, SZ_Q); + mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); pop_r(code, opts->gen.context_reg); call(code, opts->gen.load_context); jmp_r(code, opts->gen.scratch1); @@ -2276,7 +2276,7 @@ void zcreate_stub(z80_context * context) call(code, opts->gen.save_context); push_r(code, opts->gen.scratch1); call_args_abi(code, context->bp_handler, 2, opts->gen.context_reg, opts->gen.scratch1); - mov_rr(code, RAX, opts->gen.context_reg, SZ_Q); + mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); //Restore context call(code, opts->gen.load_context); pop_r(code, opts->gen.scratch1); @@ -2285,13 +2285,13 @@ void zcreate_stub(z80_context * context) uint8_t * jmp_off = code->cur+1; jcc(code, CC_NC, code->cur + 7); pop_r(code, opts->gen.scratch1); - add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_Q); + add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_PTR); push_r(code, opts->gen.scratch1); jmp(code, opts->gen.handle_cycle_limit_int); *jmp_off = code->cur - (jmp_off+1); //jump back to body of translated instruction pop_r(code, opts->gen.scratch1); - add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_Q); + add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_PTR); jmp_r(code, opts->gen.scratch1); } -- cgit v1.2.3 From af8bf7f7f18861ef1235e85a72ca100e755d9859 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 2 Jan 2015 13:14:09 -0800 Subject: Added functions to gen_x86 for saving and restoring callee save registers to better abstract over ABI differences between x86 and x86-64 --- gen.h | 2 ++ gen_x86.c | 30 ++++++++++++++++++++++++++++++ m68k_core_x86.c | 27 ++------------------------- z80_to_x86.c | 31 ++++--------------------------- 4 files changed, 38 insertions(+), 52 deletions(-) diff --git a/gen.h b/gen.h index e6ed928..5087b57 100644 --- a/gen.h +++ b/gen.h @@ -27,5 +27,7 @@ void jmp_r(code_info *code, uint8_t dst); void call_args(code_info *code, code_ptr fun, uint32_t num_args, ...); //like the above, but follows other aspects of the ABI like stack alignment void call_args_abi(code_info *code, code_ptr fun, uint32_t num_args, ...); +void save_callee_save_regs(code_info *code); +void restore_callee_save_regs(code_info *code); #endif //GEN_H_ diff --git a/gen_x86.c b/gen_x86.c index b0e209c..1af0061 100644 --- a/gen_x86.c +++ b/gen_x86.c @@ -2039,3 +2039,33 @@ void call_args_abi(code_info *code, code_ptr fun, uint32_t num_args, ...) *no_adjust_rsp = code->cur - (no_adjust_rsp+1); #endif } + +void save_callee_save_regs(code_info *code) +{ + push_r(code, RBX); + push_r(code, RBP); +#ifdef X86_64 + push_r(code, R12); + push_r(code, R13); + push_r(code, R14); + push_r(code, R15); +#else + push_r(code, RDI); + push_r(code, RSI); +#endif +} + +void restore_callee_save_regs(code_info *code) +{ +#ifdef X86_64 + pop_r(code, R15); + pop_r(code, R14); + pop_r(code, R13); + pop_r(code, R12); +#else + pop_r(code, RSI); + pop_r(code, RDI); +#endif + pop_r(code, RBP); + pop_r(code, RBX); +} diff --git a/m68k_core_x86.c b/m68k_core_x86.c index aed617f..44f8c3e 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -2281,42 +2281,19 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu retn(code); opts->start_context = (start_fun)code->cur; + save_callee_save_regs(code); #ifdef X86_64 if (opts->gen.scratch2 != RDI) { mov_rr(code, RDI, opts->gen.scratch2, SZ_PTR); } - //save callee save registers - push_r(code, RBP); - push_r(code, R12); - push_r(code, R13); - push_r(code, R14); - push_r(code, R15); #else - //save callee save registers - push_r(code, RBP); - push_r(code, RBX); - push_r(code, RSI); - push_r(code, RDI); - mov_rdispr(code, RSP, 20, opts->gen.scratch2, SZ_D); mov_rdispr(code, RSP, 24, opts->gen.context_reg, SZ_D); #endif call(code, opts->gen.load_context); call_r(code, opts->gen.scratch2); call(code, opts->gen.save_context); -#ifdef X86_64 - //restore callee save registers - pop_r(code, R15); - pop_r(code, R14); - pop_r(code, R13); - pop_r(code, R12); - pop_r(code, RBP); -#else - pop_r(code, RDI); - pop_r(code, RSI); - pop_r(code, RBX); - pop_r(code, RBP); -#endif + restore_callee_save_regs(code); retn(code); opts->native_addr = code->cur; diff --git a/z80_to_x86.c b/z80_to_x86.c index 83237ca..aac1ceb 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -2052,13 +2052,7 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t sub_ir(code, 5, RAX, SZ_PTR); //adjust return address to point to the call that got us here mov_rrdisp(code, RBX, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR); mov_rrind(code, RAX, options->gen.context_reg, SZ_PTR); - //restore callee saved registers - pop_r(code, R15); - pop_r(code, R14); - pop_r(code, R13); - pop_r(code, R12); - pop_r(code, RBP); - pop_r(code, RBX); + restore_callee_save_regs(code); *no_sync = code->cur - (no_sync + 1); //return to caller of z80_run retn(code); @@ -2104,13 +2098,7 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t mov_ir(code, 0x38, options->gen.scratch1, SZ_W); call(code, options->native_addr); mov_rrind(code, options->gen.scratch1, options->gen.context_reg, SZ_PTR); - //restore callee saved registers - pop_r(code, R15); - pop_r(code, R14); - pop_r(code, R13); - pop_r(code, R12); - pop_r(code, RBP); - pop_r(code, RBX); + restore_callee_save_regs(code); //return to caller of z80_run to sync retn(code); *skip_int = code->cur - (skip_int+1); @@ -2121,12 +2109,7 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t call(code, options->gen.save_context); pop_rind(code, options->gen.context_reg); //restore callee saved registers - pop_r(code, R15); - pop_r(code, R14); - pop_r(code, R13); - pop_r(code, R12); - pop_r(code, RBP); - pop_r(code, RBX); + restore_callee_save_regs(code); //return to caller of z80_run *skip_sync = code->cur - (skip_sync+1); retn(code); @@ -2207,13 +2190,7 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t jmp_r(code, options->gen.scratch1); options->run = (z80_run_fun)code->cur; - //save callee save registers - push_r(code, RBX); - push_r(code, RBP); - push_r(code, R12); - push_r(code, R13); - push_r(code, R14); - push_r(code, R15); + save_callee_save_regs(code); mov_rr(code, RDI, options->gen.context_reg, SZ_PTR); call(code, options->load_context_scratch); cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR); -- cgit v1.2.3 From 172a8961d9ebb577668dcb150c56b3f2c6da0419 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 2 Jan 2015 13:47:34 -0800 Subject: In theory, the Z80 core should work on 32-bit builds now; however, I suspect there is some code that cannot deal with most of the Z80 registers not having a native register so more work will be needed --- Makefile | 1 - z80_to_x86.c | 28 +++++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index c81b86d..f4b1e23 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,6 @@ else ifeq ($(CPU),i686) M68KOBJS+= runtime_32.o m68k_core_x86.o TRANSOBJS+= gen_x86.o backend_x86.o -NOZ80:=1 endif endif diff --git a/z80_to_x86.c b/z80_to_x86.c index aac1ceb..15e42b5 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -124,11 +124,13 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t ea->base = opts->regs[inst->ea_reg]; if (ea->base >= AH && ea->base <= BH && inst->reg != Z80_UNUSED && inst->reg != Z80_USE_IMMED) { uint8_t other_reg = opts->regs[inst->reg]; +#ifdef X86_64 if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) { //we can't mix an *H reg with a register that requires the REX prefix ea->base = opts->regs[z80_low_reg(inst->ea_reg)]; ror_ir(code, 8, ea->base, SZ_W); } +#endif } } else { ea->mode = MODE_REG_DISPLACE8; @@ -224,10 +226,12 @@ void z80_save_ea(code_info *code, z80inst * inst, z80_options * opts) } } else if (inst->reg != Z80_UNUSED && inst->reg != Z80_USE_IMMED && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { uint8_t other_reg = opts->regs[inst->reg]; +#ifdef X86_64 if (other_reg >= R8 || (other_reg >= RSP && other_reg <= RDI)) { //we can't mix an *H reg with a register that requires the REX prefix ror_ir(code, 8, opts->regs[z80_low_reg(inst->ea_reg)], SZ_W); } +#endif } } } @@ -1255,13 +1259,17 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, bts_ir(code, bit, src_op.base, size); if (inst->reg != Z80_USE_IMMED) { if (size == SZ_W) { +#ifdef X86_64 if (dst_op.base >= R8) { ror_ir(code, 8, src_op.base, SZ_W); mov_rr(code, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B); ror_ir(code, 8, src_op.base, SZ_W); } else { +#endif mov_rr(code, opts->regs[inst->ea_reg], dst_op.base, SZ_B); +#ifdef X86_64 } +#endif } else { mov_rr(code, src_op.base, dst_op.base, SZ_B); } @@ -1297,13 +1305,17 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, btr_ir(code, bit, src_op.base, size); if (inst->reg != Z80_USE_IMMED) { if (size == SZ_W) { +#ifdef X86_64 if (dst_op.base >= R8) { ror_ir(code, 8, src_op.base, SZ_W); mov_rr(code, opts->regs[z80_low_reg(inst->ea_reg)], dst_op.base, SZ_B); ror_ir(code, 8, src_op.base, SZ_W); } else { +#endif mov_rr(code, opts->regs[inst->ea_reg], dst_op.base, SZ_B); +#ifdef X86_64 } +#endif } else { mov_rr(code, src_op.base, dst_op.base, SZ_B); } @@ -1935,6 +1947,7 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t options->gen.ram_flags_shift = 7; options->flags = 0; +#ifdef X86_64 options->regs[Z80_B] = BH; options->regs[Z80_C] = RBX; options->regs[Z80_D] = CH; @@ -1955,12 +1968,21 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t options->regs[Z80_AF] = -1; options->regs[Z80_IX] = RDX; options->regs[Z80_IY] = R8; - + + options->gen.scratch1 = R13; + options->gen.scratch2 = R14; +#else + memset(options->regs, -1, sizeof(options->regs)); + options->regs[Z80_A] = RAX; + options->regx[Z80_SP] = RBX; + + options->gen.scratch1 = RCX; + options->gen.scratch2 = RDX; +#endif + options->gen.context_reg = RSI; options->gen.cycles = RBP; options->gen.limit = RDI; - options->gen.scratch1 = R13; - options->gen.scratch2 = R14; options->gen.native_code_map = malloc(sizeof(native_map_slot)); memset(options->gen.native_code_map, 0, sizeof(native_map_slot)); -- cgit v1.2.3 From 8ac1e753e1af481b2090a4c1b7395853f30b5e8f Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 3 Jan 2015 16:08:23 -0800 Subject: All cycle counters are now based off the master clock. This seems to have messed up Z80 interrupt timing (music in Sonic 2 is too slow for instance), but things are generally working --- backend.h | 1 + backend_x86.c | 2 +- blastem.c | 121 ++++++++++++++++++++++++++------------------------------ m68k_core.h | 2 +- m68k_core_x86.c | 19 +++++---- z80_to_x86.c | 28 +++++-------- z80_to_x86.h | 4 +- 7 files changed, 84 insertions(+), 93 deletions(-) diff --git a/backend.h b/backend.h index c3e0c76..7b255f1 100644 --- a/backend.h +++ b/backend.h @@ -89,6 +89,7 @@ typedef struct { uint32_t address_mask; uint32_t max_address; uint32_t bus_cycles; + uint32_t clock_divider; int32_t mem_ptr_off; int32_t ram_flags_off; uint8_t ram_flags_shift; diff --git a/backend_x86.c b/backend_x86.c index 925751c..7c289de 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -3,7 +3,7 @@ void cycles(cpu_options *opts, uint32_t num) { - add_ir(&opts->code, num, opts->cycles, SZ_D); + add_ir(&opts->code, num*opts->clock_divider, opts->cycles, SZ_D); } void check_cycles_int(cpu_options *opts, uint32_t address) diff --git a/blastem.c b/blastem.c index 8c375ad..bf82f3e 100644 --- a/blastem.c +++ b/blastem.c @@ -125,26 +125,18 @@ uint16_t read_dma_value(uint32_t address) return 0; } -//TODO: Make these dependent on the video mode -//#define VINT_CYCLE ((MCLKS_LINE * 225 + (148 + 40) * 4)/MCLKS_PER_68K) -#define ZVINT_CYCLE ((MCLKS_LINE * 225 + (148 + 40) * 4)/MCLKS_PER_Z80) -//#define VINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_68K) -//#define ZVINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_Z80) - void adjust_int_cycle(m68k_context * context, vdp_context * v_context) { context->int_cycle = CYCLE_NEVER; if ((context->status & 0x7) < 6) { uint32_t next_vint = vdp_next_vint(v_context); if (next_vint != CYCLE_NEVER) { - next_vint /= MCLKS_PER_68K; context->int_cycle = next_vint; context->int_num = 6; } if ((context->status & 0x7) < 4) { uint32_t next_hint = vdp_next_hint(v_context); if (next_hint != CYCLE_NEVER) { - next_hint /= MCLKS_PER_68K; if (next_hint < context->int_cycle) { context->int_cycle = next_hint; context->int_num = 4; @@ -185,7 +177,7 @@ void sync_z80(z80_context * z_context, uint32_t mclks) #ifndef NO_Z80 if (z80_enabled && !reset && !busreq) { genesis_context * gen = z_context->system; - z_context->sync_cycle = mclks / MCLKS_PER_Z80; + z_context->sync_cycle = mclks; if (z_context->current_cycle < z_context->sync_cycle) { if (need_reset) { z80_reset(z_context); @@ -194,7 +186,7 @@ void sync_z80(z80_context * z_context, uint32_t mclks) while (z_context->current_cycle < z_context->sync_cycle) { if (z_context->int_pulse_end < z_context->current_cycle || z_context->int_pulse_end == CYCLE_NEVER) { - z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp) / MCLKS_PER_Z80; + z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp); z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION; } if (z_context->iff1) { @@ -211,7 +203,7 @@ void sync_z80(z80_context * z_context, uint32_t mclks) } else #endif { - z_context->current_cycle = mclks / MCLKS_PER_Z80; + z_context->current_cycle = mclks; } } @@ -238,14 +230,14 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) genesis_context * gen = context->system; vdp_context * v_context = gen->vdp; z80_context * z_context = gen->z80; - uint32_t mclks = context->current_cycle * MCLKS_PER_68K; + uint32_t mclks = context->current_cycle; sync_z80(z_context, mclks); if (mclks >= mclk_target) { sync_sound(gen, mclks); gen->ym->current_cycle -= mclk_target; gen->psg->cycles -= mclk_target; if (gen->ym->write_cycle != CYCLE_NEVER) { - gen->ym->write_cycle = gen->ym->write_cycle >= mclk_target/MCLKS_PER_68K ? gen->ym->write_cycle - mclk_target/MCLKS_PER_68K : 0; + gen->ym->write_cycle = gen->ym->write_cycle >= mclk_target ? gen->ym->write_cycle - mclk_target : 0; } //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); vdp_run_context(v_context, mclk_target); @@ -261,35 +253,35 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) frame++; mclks -= mclk_target; vdp_adjust_cycles(v_context, mclk_target); - io_adjust_cycles(gen->ports, context->current_cycle, mclk_target/MCLKS_PER_68K); - io_adjust_cycles(gen->ports+1, context->current_cycle, mclk_target/MCLKS_PER_68K); - io_adjust_cycles(gen->ports+2, context->current_cycle, mclk_target/MCLKS_PER_68K); + io_adjust_cycles(gen->ports, context->current_cycle, mclk_target); + io_adjust_cycles(gen->ports+1, context->current_cycle, mclk_target); + io_adjust_cycles(gen->ports+2, context->current_cycle, mclk_target); if (busack_cycle != CYCLE_NEVER) { - if (busack_cycle > mclk_target/MCLKS_PER_68K) { - busack_cycle -= mclk_target/MCLKS_PER_68K; + if (busack_cycle > mclk_target) { + busack_cycle -= mclk_target; } else { busack_cycle = CYCLE_NEVER; busack = new_busack; } } - context->current_cycle -= mclk_target/MCLKS_PER_68K; - if (z_context->current_cycle >= mclk_target/MCLKS_PER_Z80) { - z_context->current_cycle -= mclk_target/MCLKS_PER_Z80; + context->current_cycle -= mclk_target; + if (z_context->current_cycle >= mclk_target) { + z_context->current_cycle -= mclk_target; } else { z_context->current_cycle = 0; } if (z_context->int_cycle != CYCLE_NEVER) { - if (z_context->int_cycle >= mclk_target/MCLKS_PER_Z80) { - z_context->int_cycle -= mclk_target/MCLKS_PER_Z80; + if (z_context->int_cycle >= mclk_target) { + z_context->int_cycle -= mclk_target; } else { z_context->int_cycle = 0; } } if (z_context->int_pulse_start != CYCLE_NEVER) { - if (z_context->int_pulse_end >= mclk_target/MCLKS_PER_Z80) { - z_context->int_pulse_end -= mclk_target/MCLKS_PER_Z80; - if (z_context->int_pulse_start >= mclk_target/MCLKS_PER_Z80) { - z_context->int_pulse_start -= mclk_target/MCLKS_PER_Z80; + if (z_context->int_pulse_end >= mclk_target) { + z_context->int_pulse_end -= mclk_target; + if (z_context->int_pulse_start >= mclk_target) { + z_context->int_pulse_start -= mclk_target; } else { z_context->int_pulse_start = 0; } @@ -298,8 +290,8 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) z_context->int_pulse_start = CYCLE_NEVER; z_context->int_pulse_end = CYCLE_NEVER; } - if (z_context->int_enable_cycle >= mclk_target/MCLKS_PER_Z80) { - z_context->int_enable_cycle -= mclk_target/MCLKS_PER_Z80; + if (z_context->int_enable_cycle >= mclk_target) { + z_context->int_enable_cycle -= mclk_target; } else { z_context->int_enable_cycle = 0; } @@ -307,7 +299,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) vdp_run_context(v_context, mclks); } mclk_target = vdp_cycles_to_frame_end(v_context); - context->sync_cycle = mclk_target/MCLKS_PER_68K; + context->sync_cycle = mclk_target; } else { //printf("running VDP for %d cycles\n", mclks - v_context->cycles); vdp_run_context(v_context, mclks); @@ -325,9 +317,10 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) } if (save_state) { save_state = 0; + //advance Z80 core to the start of an instruction while (!z_context->pc) { - sync_z80(z_context, z_context->current_cycle * MCLKS_PER_Z80 + MCLKS_PER_Z80); + sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80); } save_gst(gen, "savestate.gst", address); } @@ -355,14 +348,14 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ while(v_context->flags & FLAG_DMA_RUN) { vdp_run_dma_done(v_context, mclk_target); if (v_context->cycles >= mclk_target) { - context->current_cycle = v_context->cycles / MCLKS_PER_68K; - if (context->current_cycle * MCLKS_PER_68K < mclk_target) { - ++context->current_cycle; + context->current_cycle = v_context->cycles; + if (context->current_cycle < mclk_target) { + context->current_cycle += MCLKS_PER_68K; } sync_components(context, 0); } } - //context->current_cycle = v_context->cycles / MCLKS_PER_68K; + //context->current_cycle = v_context->cycles; } } else if(vdp_port < 8) { gen->bus_busy = 1; @@ -372,9 +365,9 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ while(v_context->flags & FLAG_DMA_RUN) { vdp_run_dma_done(v_context, mclk_target); if (v_context->cycles >= mclk_target) { - context->current_cycle = v_context->cycles / MCLKS_PER_68K; - if (context->current_cycle * MCLKS_PER_68K < mclk_target) { - ++context->current_cycle; + context->current_cycle = v_context->cycles; + if (context->current_cycle < mclk_target) { + context->current_cycle += MCLKS_PER_68K; } sync_components(context, 0); } @@ -393,11 +386,11 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ exit(1); } if (v_context->cycles != before_cycle) { - //printf("68K paused for %d (%d) cycles at cycle %d (%d) for write\n", v_context->cycles / MCLKS_PER_68K - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); - context->current_cycle = v_context->cycles / MCLKS_PER_68K; + //printf("68K paused for %d (%d) cycles at cycle %d (%d) for write\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); + context->current_cycle = v_context->cycles; } } else if (vdp_port < 0x18) { - sync_sound(gen, context->current_cycle * MCLKS_PER_68K); + sync_sound(gen, context->current_cycle); psg_write(gen->psg, value); } else { //TODO: Implement undocumented test register(s) @@ -427,7 +420,7 @@ void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value) } 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 * MCLKS_PER_Z80); + vdp_run_context(gen->vdp, context->current_cycle); if (vdp_port < 4) { vdp_data_port_write(gen->vdp, value << 8 | value); } else if (vdp_port < 8) { @@ -437,7 +430,7 @@ void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value) exit(1); } } else if (vdp_port < 0x18) { - sync_sound(gen, context->current_cycle * MCLKS_PER_Z80); + sync_sound(gen, context->current_cycle); psg_write(gen->psg, value); } else { vdp_test_port_write(gen->vdp, value); @@ -472,8 +465,8 @@ uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) value = vdp_test_port_read(v_context); } if (v_context->cycles != before_cycle) { - //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles / MCLKS_PER_68K - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); - context->current_cycle = v_context->cycles / MCLKS_PER_68K; + //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); + context->current_cycle = v_context->cycles; } return value; } @@ -500,7 +493,7 @@ 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 * MCLKS_PER_Z80); + vdp_run_context(gen->vdp, context->current_cycle); if (vdp_port < 4) { ret = vdp_data_port_read(gen->vdp); } else if (vdp_port < 8) { @@ -539,7 +532,7 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value z80_handle_code_write(location & 0x1FFF, gen->z80); #endif } else if (location < 0x6000) { - sync_sound(gen, context->current_cycle * MCLKS_PER_68K); + sync_sound(gen, context->current_cycle); if (location & 1) { ym_data_write(gen->ym, value); } else if(location & 2) { @@ -593,13 +586,13 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value dputs("bus requesting Z80"); if(!reset && !busreq) { - sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K + Z80_ACK_DELAY*MCLKS_PER_Z80); - busack_cycle = (gen->z80->current_cycle * MCLKS_PER_Z80) / MCLKS_PER_68K;//context->current_cycle + Z80_ACK_DELAY; + sync_z80(gen->z80, context->current_cycle + Z80_ACK_DELAY*MCLKS_PER_Z80); + busack_cycle = gen->z80->current_cycle;//context->current_cycle + Z80_ACK_DELAY; new_busack = Z80_REQ_ACK; } busreq = 1; } else { - sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K); + sync_z80(gen->z80, context->current_cycle); if (busreq) { dputs("releasing z80 bus"); #ifdef DO_DEBUG_PRINT @@ -609,7 +602,7 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value fwrite(z80_ram, 1, sizeof(z80_ram), f); fclose(f); #endif - busack_cycle = ((gen->z80->current_cycle + Z80_BUSY_DELAY) * MCLKS_PER_Z80) / MCLKS_PER_68K; + busack_cycle = gen->z80->current_cycle + Z80_BUSY_DELAY; new_busack = Z80_REQ_BUSY; busreq = 0; } @@ -618,17 +611,17 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value } } else if (location == 0x1200) { - sync_z80(gen->z80, context->current_cycle * MCLKS_PER_68K); + sync_z80(gen->z80, context->current_cycle); if (value & 1) { if (reset && busreq) { new_busack = 0; - busack_cycle = ((gen->z80->current_cycle + Z80_ACK_DELAY) * MCLKS_PER_Z80) / MCLKS_PER_68K;//context->current_cycle + Z80_ACK_DELAY; + busack_cycle = gen->z80->current_cycle + Z80_ACK_DELAY;//context->current_cycle + Z80_ACK_DELAY; } //TODO: Deal with the scenario in which reset is not asserted long enough if (reset) { need_reset = 1; //TODO: Add necessary delay between release of reset and start of execution - gen->z80->current_cycle = (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_Z80 + 16; + gen->z80->current_cycle = context->current_cycle + 16 * MCLKS_PER_Z80; } reset = 0; } else { @@ -669,7 +662,7 @@ uint8_t io_read(uint32_t location, m68k_context * context) if (location < 0x4000) { value = z80_ram[location & 0x1FFF]; } else if (location < 0x6000) { - sync_sound(gen, context->current_cycle * MCLKS_PER_68K); + sync_sound(gen, context->current_cycle); value = ym_read_status(gen->ym); } else { value = 0xFF; @@ -741,7 +734,7 @@ 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 * MCLKS_PER_Z80); + sync_sound(gen, context->current_cycle); if (location & 1) { ym_data_write(gen->ym, value); } else if (location & 2) { @@ -756,7 +749,7 @@ 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 * MCLKS_PER_Z80); + sync_sound(gen, context->current_cycle); return ym_read_status(gen->ym); } @@ -765,7 +758,7 @@ uint8_t z80_read_bank(uint32_t location, void * vcontext) z80_context * context = vcontext; //typical delay from bus arbitration context->current_cycle += 3; - + location &= 0x7FFF; //TODO: add cycle for an access right after a previous one //TODO: block Z80 if VDP has the bus or the 68K is blocked on a VDP access @@ -804,7 +797,7 @@ void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value) void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value) { z80_context * context = vcontext; - + context->bank_reg = (context->bank_reg >> 1 | value << 8) & 0x1FF; if (context->bank_reg < 0x80) { genesis_context *gen = context->system; @@ -812,7 +805,7 @@ void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value) } else { context->mem_pointers[1] = NULL; } - + return context; } @@ -1084,7 +1077,7 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u } atexit(save_sram); } - init_m68k_opts(&opts, memmap, num_chunks); + init_m68k_opts(&opts, memmap, num_chunks, MCLKS_PER_68K); opts.address_log = address_log; init_68k_context(&context, opts.gen.native_code_map, &opts); @@ -1092,7 +1085,7 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u context.system = gen; //cartridge ROM context.mem_pointers[0] = cart; - context.target_cycle = context.sync_cycle = mclk_target/MCLKS_PER_68K; + context.target_cycle = context.sync_cycle = mclk_target; //work RAM context.mem_pointers[1] = ram; //save RAM/map @@ -1369,13 +1362,13 @@ int main(int argc, char ** argv) z80_context z_context; #ifndef NO_Z80 z80_options z_opts; - init_z80_opts(&z_opts, z80_map, 5); + init_z80_opts(&z_opts, z80_map, 5, MCLKS_PER_Z80); init_z80_context(&z_context, &z_opts); #endif z_context.system = &gen; z_context.mem_pointers[0] = z80_ram; - z_context.sync_cycle = z_context.target_cycle = mclk_target/MCLKS_PER_Z80; + z_context.sync_cycle = z_context.target_cycle = mclk_target; z_context.int_cycle = CYCLE_NEVER; z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; diff --git a/m68k_core.h b/m68k_core.h index 31ca320..cf43864 100644 --- a/m68k_core.h +++ b/m68k_core.h @@ -67,7 +67,7 @@ typedef struct { void translate_m68k(m68k_options * opts, struct m68kinst * inst); void translate_m68k_stream(uint32_t address, m68k_context * context); void start_68k_context(m68k_context * context, uint32_t address); -void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks); +void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider); void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts); void m68k_reset(m68k_context * context); void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_handler); diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 44f8c3e..dea55f4 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -1012,8 +1012,8 @@ void translate_shift(m68k_options * opts, m68kinst * inst, host_ea *src_op, host //Memory shift shift_ir(code, 1, dst_op->base, SZ_W); } else { - cycles(&opts->gen, inst->extra.size == OPSIZE_LONG ? 8 : 6); if (src_op->mode == MODE_IMMED) { + cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + 2 * src_op->disp); if (src_op->disp != 1 && inst->op == M68K_ASL) { set_flag(opts, 0, FLAG_V); for (int i = 0; i < src_op->disp; i++) { @@ -1037,6 +1037,7 @@ void translate_shift(m68k_options * opts, m68kinst * inst, host_ea *src_op, host set_flag_cond(opts, CC_O, FLAG_V); } } else { + cycles(&opts->gen, inst->extra.size == OPSIZE_LONG ? 8 : 6); if (src_op->base != RCX) { if (src_op->mode == MODE_REG_DIRECT) { mov_rr(code, src_op->base, RCX, SZ_B); @@ -1066,8 +1067,9 @@ void translate_shift(m68k_options * opts, m68kinst * inst, host_ea *src_op, host jmp(code, code->cur + 2); *nz_off = code->cur - (nz_off + 1); //add 2 cycles for every bit shifted - add_rr(code, RCX, opts->gen.cycles, SZ_D); - add_rr(code, RCX, opts->gen.cycles, SZ_D); + mov_ir(code, 2 * opts->gen.clock_divider, opts->gen.scratch2, SZ_D); + imul_rr(code, RCX, opts->gen.scratch2, SZ_D); + add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D); if (inst->op == M68K_ASL) { //ASL has Overflow flag behavior that depends on all of the bits shifted through the MSB //Easiest way to deal with this is to shift one bit at a time @@ -1865,8 +1867,10 @@ void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos and_ir(code, 63, opts->gen.scratch1, SZ_D); code_ptr zero_off = code->cur + 1; jcc(code, CC_Z, code->cur + 2); - add_rr(code, opts->gen.scratch1, opts->gen.cycles, SZ_D); - add_rr(code, opts->gen.scratch1, opts->gen.cycles, SZ_D); + //add 2 cycles for every bit shifted + mov_ir(code, 2 * opts->gen.clock_divider, opts->gen.scratch2, SZ_D); + imul_rr(code, RCX, opts->gen.scratch2, SZ_D); + add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D); cmp_ir(code, 32, opts->gen.scratch1, SZ_B); code_ptr norm_off = code->cur + 1; jcc(code, CC_L, code->cur + 2); @@ -2186,7 +2190,7 @@ void insert_breakpoint(m68k_context * context, uint32_t address, code_ptr bp_han } } -void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks) +void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider) { memset(opts, 0, sizeof(*opts)); opts->gen.memmap = memmap; @@ -2196,6 +2200,7 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu opts->gen.byte_swap = 1; opts->gen.max_address = 0x1000000; opts->gen.bus_cycles = BUS; + opts->gen.clock_divider = clock_divider; opts->gen.mem_ptr_off = offsetof(m68k_context, mem_pointers); opts->gen.ram_flags_off = offsetof(m68k_context, ram_code_flags); opts->gen.ram_flags_shift = 11; @@ -2308,7 +2313,7 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu opts->native_addr_and_sync = code->cur; call(code, opts->gen.save_context); push_r(code, opts->gen.scratch1); - + xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D); call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1); pop_r(code, RSI); //restore saved address from opts->gen.scratch1 diff --git a/z80_to_x86.c b/z80_to_x86.c index 15e42b5..13f952a 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -879,20 +879,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, } break; case Z80_HALT: { + code_ptr loop_top = code->cur; + //this isn't terribly efficient, but it's good enough for now cycles(&opts->gen, 4); - mov_ir(code, address, opts->gen.scratch1, SZ_W); - uint8_t * call_inst = code->cur; - mov_rr(code, opts->gen.limit, opts->gen.scratch2, SZ_D); - sub_rr(code, opts->gen.cycles, opts->gen.scratch2, SZ_D); - and_ir(code, 0xFFFFFFFC, opts->gen.scratch2, SZ_D); - add_rr(code, opts->gen.scratch2, opts->gen.cycles, SZ_D); - cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); - code_ptr skip_last = code->cur+1; - jcc(code, CC_NB, code->cur+2); - cycles(&opts->gen, 4); - *skip_last = code->cur - (skip_last+1); - call(code, opts->gen.handle_cycle_limit_int); - jmp(code, call_inst); + check_cycles_int(&opts->gen, address); + jmp(code, loop_top); break; } case Z80_DI: @@ -908,7 +899,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff1), SZ_B); mov_irdisp(code, 1, opts->gen.context_reg, offsetof(z80_context, iff2), SZ_B); //interrupt enable has a one-instruction latency, minimum instruction duration is 4 cycles - add_irdisp(code, 4, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); + add_irdisp(code, 4*opts->gen.clock_divider, opts->gen.context_reg, offsetof(z80_context, int_enable_cycle), SZ_D); call(code, opts->do_sync); break; case Z80_IM: @@ -1932,7 +1923,7 @@ void translate_z80_stream(z80_context * context, uint32_t address) } while (opts->gen.deferred); } -void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks) +void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks, uint32_t clock_divider) { memset(options, 0, sizeof(*options)); @@ -1942,6 +1933,7 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t options->gen.address_mask = 0xFFFF; options->gen.max_address = 0x10000; options->gen.bus_cycles = 3; + options->gen.clock_divider = clock_divider; options->gen.mem_ptr_off = offsetof(z80_context, mem_pointers); options->gen.ram_flags_off = offsetof(z80_context, ram_code_flags); options->gen.ram_flags_shift = 7; @@ -1968,18 +1960,18 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t options->regs[Z80_AF] = -1; options->regs[Z80_IX] = RDX; options->regs[Z80_IY] = R8; - + options->gen.scratch1 = R13; options->gen.scratch2 = R14; #else memset(options->regs, -1, sizeof(options->regs)); options->regs[Z80_A] = RAX; options->regx[Z80_SP] = RBX; - + options->gen.scratch1 = RCX; options->gen.scratch2 = RDX; #endif - + options->gen.context_reg = RSI; options->gen.cycles = RBP; options->gen.limit = RDI; diff --git a/z80_to_x86.h b/z80_to_x86.h index d3e7b89..792d7b5 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -1,6 +1,6 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #ifndef Z80_TO_X86_H_ @@ -82,7 +82,7 @@ typedef struct { } z80_context; void translate_z80_stream(z80_context * context, uint32_t address); -void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks); +void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t num_chunks, uint32_t clock_divider); void init_z80_context(z80_context * context, z80_options * options); code_ptr z80_get_native_address(z80_context * context, uint32_t address); code_ptr z80_get_native_address_trans(z80_context * context, uint32_t address); -- cgit v1.2.3 From e6216d5d0a9f8cdb700124558d38cd47e63fbdda Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 3 Jan 2015 18:23:04 -0800 Subject: Made the Z80 core more contained by refactoring some code in blastem.c into z80_to_x86.c --- backend.h | 1 + blastem.c | 155 +++++++++++++---------------------------------------------- blastem.h | 4 -- gst.c | 10 ++-- z80_to_x86.c | 114 +++++++++++++++++++++++++++++++++++++++---- z80_to_x86.h | 17 +++++-- 6 files changed, 157 insertions(+), 144 deletions(-) diff --git a/backend.h b/backend.h index 7b255f1..c3ae875 100644 --- a/backend.h +++ b/backend.h @@ -12,6 +12,7 @@ #define INVALID_OFFSET 0xFFFFFFFF #define EXTENSION_WORD 0xFFFFFFFE +#define CYCLE_NEVER 0xFFFFFFFF #if defined(X86_32) || defined(X86_64) typedef struct { diff --git a/blastem.c b/blastem.c index bf82f3e..1ee89aa 100644 --- a/blastem.c +++ b/blastem.c @@ -155,12 +155,6 @@ 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; -uint8_t busreq = 0; -uint8_t busack = 0; -uint32_t busack_cycle = CYCLE_NEVER; -uint8_t new_busack = 0; //#define DO_DEBUG_PRINT #ifdef DO_DEBUG_PRINT #define dprintf printf @@ -172,34 +166,18 @@ uint8_t new_busack = 0; #define Z80_VINT_DURATION 128 +void z80_next_int_pulse(z80_context * z_context) +{ + genesis_context * gen = z_context->system; + z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp); + z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION; +} + void sync_z80(z80_context * z_context, uint32_t mclks) { #ifndef NO_Z80 - if (z80_enabled && !reset && !busreq) { - genesis_context * gen = z_context->system; - z_context->sync_cycle = mclks; - if (z_context->current_cycle < z_context->sync_cycle) { - if (need_reset) { - z80_reset(z_context); - need_reset = 0; - } - - while (z_context->current_cycle < z_context->sync_cycle) { - if (z_context->int_pulse_end < z_context->current_cycle || z_context->int_pulse_end == CYCLE_NEVER) { - z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp); - z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION; - } - if (z_context->iff1) { - z_context->int_cycle = z_context->int_pulse_start < z_context->int_enable_cycle ? z_context->int_enable_cycle : z_context->int_pulse_start; - } else { - z_context->int_cycle = CYCLE_NEVER; - } - z_context->target_cycle = z_context->sync_cycle < z_context->int_cycle ? z_context->sync_cycle : z_context->int_cycle; - dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d\n", z_context->current_cycle, z_context->sync_cycle, z_context->int_cycle); - z_context->run(z_context); - dprintf("Z80 ran to cycle %d\n", z_context->current_cycle); - } - } + if (z80_enabled) { + z80_run(z_context, mclks); } else #endif { @@ -256,45 +234,8 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) io_adjust_cycles(gen->ports, context->current_cycle, mclk_target); io_adjust_cycles(gen->ports+1, context->current_cycle, mclk_target); io_adjust_cycles(gen->ports+2, context->current_cycle, mclk_target); - if (busack_cycle != CYCLE_NEVER) { - if (busack_cycle > mclk_target) { - busack_cycle -= mclk_target; - } else { - busack_cycle = CYCLE_NEVER; - busack = new_busack; - } - } context->current_cycle -= mclk_target; - if (z_context->current_cycle >= mclk_target) { - z_context->current_cycle -= mclk_target; - } else { - z_context->current_cycle = 0; - } - if (z_context->int_cycle != CYCLE_NEVER) { - if (z_context->int_cycle >= mclk_target) { - z_context->int_cycle -= mclk_target; - } else { - z_context->int_cycle = 0; - } - } - if (z_context->int_pulse_start != CYCLE_NEVER) { - if (z_context->int_pulse_end >= mclk_target) { - z_context->int_pulse_end -= mclk_target; - if (z_context->int_pulse_start >= mclk_target) { - z_context->int_pulse_start -= mclk_target; - } else { - z_context->int_pulse_start = 0; - } - } - } else { - z_context->int_pulse_start = CYCLE_NEVER; - z_context->int_pulse_end = CYCLE_NEVER; - } - if (z_context->int_enable_cycle >= mclk_target) { - z_context->int_enable_cycle -= mclk_target; - } else { - z_context->int_enable_cycle = 0; - } + z80_adjust_cycles(z_context, mclk_target); if (mclks) { vdp_run_context(v_context, mclks); } @@ -458,7 +399,7 @@ uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) value = vdp_hv_counter_read(v_context); //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles); } - } else if (vdp_port < 0x18){ + } else if (vdp_port < 0x18) { printf("Illegal read from PSG port %X\n", vdp_port); exit(1); } else { @@ -520,11 +461,7 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value { genesis_context * gen = context->system; if (location < 0x10000) { - if (busack_cycle <= context->current_cycle) { - busack = new_busack; - busack_cycle = CYCLE_NEVER; - } - if (!(busack || reset)) { + if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) { location &= 0x7FFF; if (location < 0x4000) { z80_ram[location & 0x1FFF] = value; @@ -578,54 +515,40 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value } } else { if (location == 0x1100) { - if (busack_cycle <= context->current_cycle) { - busack = new_busack; - busack_cycle = CYCLE_NEVER; - } if (value & 1) { dputs("bus requesting Z80"); - - if(!reset && !busreq) { - sync_z80(gen->z80, context->current_cycle + Z80_ACK_DELAY*MCLKS_PER_Z80); - busack_cycle = gen->z80->current_cycle;//context->current_cycle + Z80_ACK_DELAY; - new_busack = Z80_REQ_ACK; + if (z80_enabled) { + z80_assert_busreq(gen->z80, context->current_cycle); } - busreq = 1; } else { - sync_z80(gen->z80, context->current_cycle); - if (busreq) { + if (gen->z80->busreq) { dputs("releasing z80 bus"); - #ifdef DO_DEBUG_PRINT +#ifdef DO_DEBUG_PRINT char fname[20]; sprintf(fname, "zram-%d", zram_counter++); FILE * f = fopen(fname, "wb"); fwrite(z80_ram, 1, sizeof(z80_ram), f); fclose(f); - #endif - busack_cycle = gen->z80->current_cycle + Z80_BUSY_DELAY; - new_busack = Z80_REQ_BUSY; - busreq = 0; +#endif + } + if (z80_enabled) { + z80_clear_busreq(gen->z80, context->current_cycle); } - //busack_cycle = CYCLE_NEVER; - //busack = Z80_REQ_BUSY; - } } else if (location == 0x1200) { sync_z80(gen->z80, context->current_cycle); if (value & 1) { - if (reset && busreq) { - new_busack = 0; - busack_cycle = gen->z80->current_cycle + Z80_ACK_DELAY;//context->current_cycle + Z80_ACK_DELAY; - } - //TODO: Deal with the scenario in which reset is not asserted long enough - if (reset) { - need_reset = 1; - //TODO: Add necessary delay between release of reset and start of execution - gen->z80->current_cycle = context->current_cycle + 16 * MCLKS_PER_Z80; + if (z80_enabled) { + z80_clear_reset(gen->z80, context->current_cycle); + } else { + gen->z80->reset = 0; } - reset = 0; } else { - reset = 1; + if (z80_enabled) { + z80_assert_reset(gen->z80, context->current_cycle); + } else { + gen->z80->reset = 1; + } } } } @@ -653,11 +576,7 @@ uint8_t io_read(uint32_t location, m68k_context * context) uint8_t value; genesis_context *gen = context->system; if (location < 0x10000) { - if (busack_cycle <= context->current_cycle) { - busack = new_busack; - busack_cycle = CYCLE_NEVER; - } - if (!(busack==Z80_REQ_BUSY || reset)) { + if (!z80_enabled || z80_get_busack(gen->z80, context->current_cycle)) { location &= 0x7FFF; if (location < 0x4000) { value = z80_ram[location & 0x1FFF]; @@ -702,14 +621,10 @@ uint8_t io_read(uint32_t location, m68k_context * context) } } else { if (location == 0x1100) { - if (busack_cycle <= context->current_cycle) { - busack = new_busack; - busack_cycle = CYCLE_NEVER; - } - value = Z80_RES_BUSACK || busack; - dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d, busack: %d, busack_cycle %d)\n", value, context->current_cycle, reset, busack, busack_cycle); + value = z80_enabled ? !z80_get_busack(gen->z80, context->current_cycle) : 0; + dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d)\n", value, context->current_cycle, gen->z80->reset); } else if (location == 0x1200) { - value = !reset; + value = !gen->z80->reset; } else { value = 0xFF; printf("Byte read of unknown IO location: %X\n", location); @@ -1105,9 +1020,6 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u insert_breakpoint(&context, pc, debugger); } adjust_int_cycle(gen->m68k, gen->vdp); -#ifndef NO_Z80 - gen->z80->native_pc = z80_get_native_address_trans(gen->z80, gen->z80->pc); -#endif start_68k_context(&context, pc); } else { if (debugger) { @@ -1364,6 +1276,7 @@ int main(int argc, char ** argv) z80_options z_opts; init_z80_opts(&z_opts, z80_map, 5, MCLKS_PER_Z80); init_z80_context(&z_context, &z_opts); + z80_assert_reset(&z_context, 0); #endif z_context.system = &gen; diff --git a/blastem.h b/blastem.h index 46d0b1b..cd75b64 100644 --- a/blastem.h +++ b/blastem.h @@ -19,8 +19,6 @@ #define RAM_FLAG_EVEN 0x1000 #define RAM_FLAG_BOTH 0x0000 -#define CYCLE_NEVER 0xFFFFFFFF - typedef struct { m68k_context *m68k; z80_context *z80; @@ -42,8 +40,6 @@ extern int headless; extern int break_on_sync; extern int save_state; extern tern_node * config; -extern uint8_t busreq; -extern uint8_t reset; #define CARTRIDGE_WORDS 0x200000 #define RAM_WORDS 32 * 1024 diff --git a/gst.c b/gst.c index adf034d..a901858 100644 --- a/gst.c +++ b/gst.c @@ -1,6 +1,6 @@ /* Copyright 2013 Michael Pavone - This file is part of BlastEm. + This file is part of BlastEm. BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #include "gst.h" @@ -207,8 +207,8 @@ uint8_t z80_load_gst(z80_context * context, FILE * gstfile) curpos += 2; context->iff1 = context->iff2 = *curpos; curpos += 2; - reset = !*(curpos++); - busreq = *curpos; + context->reset = !*(curpos++); + context->busreq = *curpos; curpos += 3; uint32_t bank = read_le_32(curpos); if (bank < 0x400000) { @@ -350,8 +350,8 @@ uint8_t z80_save_gst(z80_context * context, FILE * gstfile) curpos += 2; *curpos = context->iff1; curpos += 2; - *(curpos++) = !reset; - *curpos = busreq; + *(curpos++) = !context->reset; + *curpos = context->busreq; curpos += 3; uint32_t bank = context->bank_reg << 15; write_le_32(curpos, bank); diff --git a/z80_to_x86.c b/z80_to_x86.c index 13f952a..9ae1a7c 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -1777,7 +1777,7 @@ z80_context * z80_handle_code_write(uint32_t address, z80_context * context) code_ptr dst = z80_get_native_address(context, inst_start); code_info code = {dst, dst+16}; z80_options * opts = context->options; - dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code, inst_start, address); + dprintf("patching code at %p for Z80 instruction at %X due to write to %X\n", code.cur, inst_start, address); mov_ir(&code, inst_start, opts->gen.scratch1, SZ_D); call(&code, opts->retrans_stub); } @@ -2226,18 +2226,112 @@ void init_z80_context(z80_context * context, z80_options * options) context->banked_code_map = malloc(sizeof(native_map_slot)); memset(context->banked_code_map, 0, sizeof(native_map_slot)); context->options = options; - context->int_cycle = 0xFFFFFFFF; - context->int_pulse_start = 0xFFFFFFFF; - context->int_pulse_end = 0xFFFFFFFF; - context->run = options->run; + context->int_cycle = CYCLE_NEVER; + context->int_pulse_start = CYCLE_NEVER; + context->int_pulse_end = CYCLE_NEVER; } -void z80_reset(z80_context * context) +void z80_run(z80_context * context, uint32_t target_cycle) { - context->im = 0; - context->iff1 = context->iff2 = 0; - context->native_pc = z80_get_native_address_trans(context, 0); - context->extra_pc = NULL; + if (context->reset || context->busack) { + context->current_cycle = target_cycle; + } else { + if (context->current_cycle < target_cycle) { + //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 + context->sync_cycle = context->busreq ? context->current_cycle + 3*context->options->gen.clock_divider : target_cycle; + if (!context->native_pc) { + context->native_pc = z80_get_native_address_trans(context, context->pc); + } + while (context->current_cycle < context->sync_cycle) + { + if (context->int_pulse_end < context->current_cycle || context->int_pulse_end == CYCLE_NEVER) { + z80_next_int_pulse(context); + } + if (context->iff1) { + context->int_cycle = context->int_pulse_start < context->int_enable_cycle ? context->int_enable_cycle : context->int_pulse_start; + } else { + context->int_cycle = CYCLE_NEVER; + } + context->target_cycle = context->sync_cycle < context->int_cycle ? context->sync_cycle : context->int_cycle; + dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d\n", context->current_cycle, context->sync_cycle, context->int_cycle); + context->options->run(context); + dprintf("Z80 ran to cycle %d\n", context->current_cycle); + } + if (context->busreq) { + context->busack = 1; + context->current_cycle = target_cycle; + } + } + } +} + +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) { + //TODO: Handle case where reset is not asserted long enough + context->im = 0; + context->iff1 = context->iff2 = 0; + context->native_pc = NULL; + context->extra_pc = NULL; + context->pc = 0; + context->reset = 0; + } +} + +void z80_assert_busreq(z80_context * context, uint32_t cycle) +{ + z80_run(context, cycle); + context->busreq = 1; +} + +void z80_clear_busreq(z80_context * context, uint32_t cycle) +{ + z80_run(context, cycle); + context->busreq = 0; + context->busack = 0; +} + +uint8_t z80_get_busack(z80_context * context, uint32_t cycle) +{ + z80_run(context, cycle); + return context->busack; +} + +void z80_adjust_cycles(z80_context * context, uint32_t deduction) +{ + if (context->current_cycle < deduction) { + fprintf(stderr, "WARNING: Deduction of %u cycles when Z80 cycle counter is only %u\n", deduction, context->current_cycle); + context->current_cycle = 0; + } else { + context->current_cycle -= deduction; + } + if (context->int_enable_cycle != CYCLE_NEVER) { + if (context->int_enable_cycle < deduction) { + context->int_enable_cycle = 0; + } else { + context->int_enable_cycle -= deduction; + } + } + if (context->int_pulse_start != CYCLE_NEVER) { + if (context->int_pulse_end < deduction) { + context->int_pulse_start = context->int_pulse_end = CYCLE_NEVER; + } else { + context->int_pulse_end -= deduction; + if (context->int_pulse_start < deduction) { + context->int_pulse_start = 0; + } else { + context->int_pulse_start -= deduction; + } + } + } } uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst) diff --git a/z80_to_x86.h b/z80_to_x86.h index 792d7b5..7a77636 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -70,15 +70,16 @@ typedef struct { void * system; uint8_t ram_code_flags[(8 * 1024)/128/8]; uint32_t int_enable_cycle; - z80_run_fun run; - uint16_t pc; + uint16_t pc; uint32_t int_pulse_start; uint32_t int_pulse_end; uint8_t breakpoint_flags[(16 * 1024)/sizeof(uint8_t)]; uint8_t * bp_handler; uint8_t * bp_stub; uint8_t * interp_code[256]; - + uint8_t reset; + uint8_t busreq; + uint8_t busack; } z80_context; void translate_z80_stream(z80_context * context, uint32_t address); @@ -87,10 +88,18 @@ void init_z80_context(z80_context * context, z80_options * options); code_ptr z80_get_native_address(z80_context * context, uint32_t address); code_ptr z80_get_native_address_trans(z80_context * context, uint32_t address); z80_context * z80_handle_code_write(uint32_t address, z80_context * context); -void z80_run(z80_context * context); void z80_reset(z80_context * context); void zinsert_breakpoint(z80_context * context, uint16_t address, uint8_t * bp_handler); void zremove_breakpoint(z80_context * context, uint16_t address); +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); +uint8_t z80_get_busack(z80_context * context, uint32_t cycle); +void z80_adjust_cycles(z80_context * context, uint32_t deduction); +//to be provided by system code +void z80_next_int_pulse(z80_context * z_context); #endif //Z80_TO_X86_H_ -- cgit v1.2.3 From 102d10b6f2892826ba5c7efd901052e543886816 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 3 Jan 2015 18:27:29 -0800 Subject: Removed some obsolete defines --- blastem.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/blastem.c b/blastem.c index 1ee89aa..3bc2752 100644 --- a/blastem.c +++ b/blastem.c @@ -451,11 +451,6 @@ uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext) } uint32_t zram_counter = 0; -#define Z80_ACK_DELAY 3 -#define Z80_BUSY_DELAY 1//TODO: Find the actual value for this -#define Z80_REQ_BUSY 1 -#define Z80_REQ_ACK 0 -#define Z80_RES_BUSACK reset m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value) { @@ -1281,8 +1276,6 @@ int main(int argc, char ** argv) z_context.system = &gen; z_context.mem_pointers[0] = z80_ram; - z_context.sync_cycle = z_context.target_cycle = mclk_target; - z_context.int_cycle = CYCLE_NEVER; z_context.mem_pointers[1] = z_context.mem_pointers[2] = (uint8_t *)cart; gen.z80 = &z_context; -- cgit v1.2.3 From d57873760390a393e784d1339b1d64564fe83234 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 3 Jan 2015 18:49:07 -0800 Subject: Restore Z80 interrupt pulse duration and make a small improvement to debug print output --- blastem.c | 2 +- z80_to_x86.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/blastem.c b/blastem.c index 3bc2752..b06ccc3 100644 --- a/blastem.c +++ b/blastem.c @@ -170,7 +170,7 @@ void z80_next_int_pulse(z80_context * z_context) { genesis_context * gen = z_context->system; z_context->int_pulse_start = vdp_next_vint_z80(gen->vdp); - z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION; + z_context->int_pulse_end = z_context->int_pulse_start + Z80_VINT_DURATION * MCLKS_PER_Z80; } void sync_z80(z80_context * z_context, uint32_t mclks) diff --git a/z80_to_x86.c b/z80_to_x86.c index 9ae1a7c..68f3b4f 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -2254,7 +2254,7 @@ void z80_run(z80_context * context, uint32_t target_cycle) context->int_cycle = CYCLE_NEVER; } context->target_cycle = context->sync_cycle < context->int_cycle ? context->sync_cycle : context->int_cycle; - dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d\n", context->current_cycle, context->sync_cycle, context->int_cycle); + dprintf("Running Z80 from cycle %d to cycle %d. Int cycle: %d (%d - %d)\n", context->current_cycle, context->sync_cycle, context->int_cycle, context->int_pulse_start, context->int_pulse_end); context->options->run(context); dprintf("Z80 ran to cycle %d\n", context->current_cycle); } -- cgit v1.2.3 From ba230802d2dc53066d94a70cc27c0ca6cf1502b6 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 3 Jan 2015 20:13:51 -0800 Subject: Fix bank area access delay for master clock change --- blastem.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/blastem.c b/blastem.c index b06ccc3..3b02567 100644 --- a/blastem.c +++ b/blastem.c @@ -667,7 +667,7 @@ uint8_t z80_read_bank(uint32_t location, void * vcontext) { z80_context * context = vcontext; //typical delay from bus arbitration - context->current_cycle += 3; + context->current_cycle += 3 * MCLKS_PER_Z80; location &= 0x7FFF; //TODO: add cycle for an access right after a previous one @@ -688,7 +688,7 @@ void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value) { z80_context * context = vcontext; //typical delay from bus arbitration - context->current_cycle += 3; + context->current_cycle += 3 * MCLKS_PER_Z80; location &= 0x7FFF; //TODO: add cycle for an access right after a previous one //TODO: block Z80 if VDP has the bus or the 68K is blocked on a VDP access -- cgit v1.2.3 From 64168b8e1d6d46e3569d190ea79aa372b5c86fc2 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 3 Jan 2015 20:20:15 -0800 Subject: Restore emulation of Z80 being locked out of the 68K bus during DMA and the like --- blastem.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/blastem.c b/blastem.c index 3b02567..2c83075 100644 --- a/blastem.c +++ b/blastem.c @@ -666,12 +666,15 @@ uint8_t z80_read_ym(uint32_t location, void * vcontext) 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; + } //typical delay from bus arbitration context->current_cycle += 3 * MCLKS_PER_Z80; + //TODO: add cycle for an access right after a previous one location &= 0x7FFF; - //TODO: add cycle for an access right after a previous one - //TODO: block Z80 if VDP has the bus or the 68K is blocked on a VDP access if (context->mem_pointers[1]) { return context->mem_pointers[1][location ^ 1]; } @@ -687,11 +690,15 @@ uint8_t z80_read_bank(uint32_t location, void * vcontext) 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; + } //typical delay from bus arbitration context->current_cycle += 3 * MCLKS_PER_Z80; - location &= 0x7FFF; //TODO: add cycle for an access right after a previous one - //TODO: block Z80 if VDP has the bus or the 68K is blocked on a VDP access + + location &= 0x7FFF; uint32_t address = context->bank_reg << 15 | location; if (address >= 0xE00000) { address &= 0xFFFF; -- cgit v1.2.3 From aaffee9fef3cf5506649b6e5e9ef95f271d14b25 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 3 Jan 2015 20:46:25 -0800 Subject: Fix 68K remove_breakpoint --- m68k_core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/m68k_core.c b/m68k_core.c index fd2f406..46c4950 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -889,7 +889,11 @@ code_ptr get_native_address_trans(m68k_context * context, uint32_t address) void remove_breakpoint(m68k_context * context, uint32_t address) { code_ptr native = get_native_address(context->native_code_map, address); + code_info tmp = context->options->gen.code; + context->options->gen.code.cur = native; + context->options->gen.code.last = native + 16; check_cycles_int(&context->options->gen, address); + context->options->gen.code = tmp; } void start_68k_context(m68k_context * context, uint32_t address) -- cgit v1.2.3 From b50d8fcdaf4fd846d34f3bf07d7e6fd8675b7178 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 3 Jan 2015 20:46:45 -0800 Subject: Fix ztestrun --- ztestrun.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/ztestrun.c b/ztestrun.c index ef042b5..e9b8bf5 100644 --- a/ztestrun.c +++ b/ztestrun.c @@ -12,12 +12,6 @@ uint8_t z80_ram[0x2000]; -#define MCLKS_PER_Z80 15 -//TODO: Figure out the exact value for this -#define MCLKS_PER_FRAME (MCLKS_LINE*262) -#define VINT_CYCLE ((MCLKS_LINE * 226)/MCLKS_PER_Z80) -#define CYCLE_NEVER 0xFFFFFFFF - uint8_t z80_unmapped_read(uint32_t location, void * context) { return 0xFF; @@ -33,6 +27,11 @@ const memmap_chunk z80_map[] = { { 0x4000, 0x10000, 0xFFFF, 0, 0, NULL, NULL, NULL, z80_unmapped_read, z80_unmapped_write} }; +void z80_next_int_pulse(z80_context * context) +{ + context->int_pulse_start = context->int_pulse_end = CYCLE_NEVER; +} + int main(int argc, char ** argv) { long filesize; @@ -40,7 +39,7 @@ int main(int argc, char ** argv) z80_options opts; z80_context context; if (argc < 2) { - fputs("usage: transz80 zrom [cartrom]\n", stderr); + fputs("usage: ztestrun zrom [cartrom]\n", stderr); exit(1); } FILE * f = fopen(argv[1], "rb"); @@ -53,16 +52,12 @@ int main(int argc, char ** argv) fseek(f, 0, SEEK_SET); fread(z80_ram, 1, filesize < sizeof(z80_ram) ? filesize : sizeof(z80_ram), f); fclose(f); - init_z80_opts(&opts, z80_map, 2); + init_z80_opts(&opts, z80_map, 2, 1); init_z80_context(&context, &opts); //Z80 RAM context.mem_pointers[0] = z80_ram; - context.sync_cycle = context.target_cycle = 1000; context.int_cycle = CYCLE_NEVER; - z80_reset(&context); - while (context.current_cycle < 1000) { - context.run(&context); - } + z80_run(&context, 1000); printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n", context.regs[Z80_A], context.regs[Z80_B], context.regs[Z80_C], context.regs[Z80_D], context.regs[Z80_E], -- cgit v1.2.3 From bacdb22a02104be7b3bd32dad05c52ce706f069f Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 3 Jan 2015 21:20:18 -0800 Subject: Added a -r flag to ztestrun that force instruction retranslation to allow a quick sanity test of that feature --- ztestrun.c | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/ztestrun.c b/ztestrun.c index e9b8bf5..0e262d3 100644 --- a/ztestrun.c +++ b/ztestrun.c @@ -9,6 +9,7 @@ #include "vdp.h" #include #include +#include uint8_t z80_ram[0x2000]; @@ -38,25 +39,57 @@ int main(int argc, char ** argv) uint8_t *filebuf; z80_options opts; z80_context context; - if (argc < 2) { + char *fname = NULL; + uint8_t retranslate = 0; + for (int i = 1; i < argc; i++) + { + if (argv[i][0] == '-') { + switch(argv[i][1]) + { + case 'r': + retranslate = 1; + break; + default: + fprintf(stderr, "Unrecognized switch -%c\n", argv[i][1]); + exit(1); + } + } else if (!fname) { + fname = argv[i]; + } + } + if (!fname) { fputs("usage: ztestrun zrom [cartrom]\n", stderr); exit(1); } - FILE * f = fopen(argv[1], "rb"); + FILE * f = fopen(fname, "rb"); if (!f) { - fprintf(stderr, "unable to open file %s\n", argv[2]); + fprintf(stderr, "unable to open file %s\n", fname); exit(1); } fseek(f, 0, SEEK_END); filesize = ftell(f); fseek(f, 0, SEEK_SET); - fread(z80_ram, 1, filesize < sizeof(z80_ram) ? filesize : sizeof(z80_ram), f); + filesize = filesize < sizeof(z80_ram) ? filesize : sizeof(z80_ram); + if (fread(z80_ram, 1, filesize, f) != filesize) { + fprintf(stderr, "error reading %s\n",fname); + exit(1); + } fclose(f); init_z80_opts(&opts, z80_map, 2, 1); init_z80_context(&context, &opts); //Z80 RAM context.mem_pointers[0] = z80_ram; - context.int_cycle = CYCLE_NEVER; + if (retranslate) { + //run core long enough to translate code + z80_run(&context, 1); + for (int i = 0; i < filesize; i++) + { + z80_handle_code_write(i, &context); + } + z80_assert_reset(&context, context.current_cycle); + z80_clear_reset(&context, context.current_cycle + 3); + z80_adjust_cycles(&context, context.current_cycle); + } z80_run(&context, 1000); printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n", context.regs[Z80_A], context.regs[Z80_B], context.regs[Z80_C], -- cgit v1.2.3 From 78a4b6f68e5e53c42fdd62c0269fe5862ce73a32 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 3 Jan 2015 21:35:23 -0800 Subject: When going directly from reset to busreq, do not allow the Z80 to run --- z80_to_x86.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/z80_to_x86.c b/z80_to_x86.c index 68f3b4f..13716ff 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -2283,6 +2283,10 @@ void z80_clear_reset(z80_context * context, uint32_t cycle) context->extra_pc = NULL; context->pc = 0; context->reset = 0; + if (context->busreq) { + //TODO: Figure out appropriate delay + context->busack = 1; + } } } -- cgit v1.2.3 From bb5e4d5126fb6c6b64ef84615ec9e5e15848575d Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 3 Jan 2015 21:54:41 -0800 Subject: Fake busack when Z80 is disabled --- blastem.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/blastem.c b/blastem.c index 2c83075..bf8a333 100644 --- a/blastem.c +++ b/blastem.c @@ -514,6 +514,8 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value dputs("bus requesting Z80"); if (z80_enabled) { z80_assert_busreq(gen->z80, context->current_cycle); + } else { + gen->z80->busack = 1; } } else { if (gen->z80->busreq) { @@ -528,6 +530,8 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value } if (z80_enabled) { z80_clear_busreq(gen->z80, context->current_cycle); + } else { + gen->z80->busack = 0; } } } else if (location == 0x1200) { @@ -616,7 +620,7 @@ uint8_t io_read(uint32_t location, m68k_context * context) } } else { if (location == 0x1100) { - value = z80_enabled ? !z80_get_busack(gen->z80, context->current_cycle) : 0; + value = z80_enabled ? !z80_get_busack(gen->z80, context->current_cycle) : !gen->z80->busack; dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d)\n", value, context->current_cycle, gen->z80->reset); } else if (location == 0x1200) { value = !gen->z80->reset; -- cgit v1.2.3 From 5517b4f5712f49a04ab2f43365991b14e286065a Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 4 Jan 2015 12:24:34 -0800 Subject: Adjusted h40_hsync_cycles so that lines actually take 3420 mclks. Fixed vdp_cycles_next_line to take h40_sync_cycles into account --- vdp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/vdp.c b/vdp.c index 6250e0e..d6dc899 100644 --- a/vdp.c +++ b/vdp.c @@ -1420,7 +1420,7 @@ void check_render_bg(vdp_context * context, int32_t line, uint32_t slot) } } -uint32_t h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19}; +uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 19, 20, 20, 20, 19, 20, 20, 20, 19, 20, 20, 20, 19}; void vdp_run_context(vdp_context * context, uint32_t target_cycles) { @@ -1827,6 +1827,15 @@ uint32_t vdp_cycles_next_line(vdp_context * context) return (HBLANK_START_H40 - context->hslot) * MCLKS_SLOT_H40; } else if (context->hslot < 183) { return MCLKS_LINE - (context->hslot - LINE_CHANGE_H40) * MCLKS_SLOT_H40; + } else if (context->hslot < HSYNC_END_H40){ + uint32_t before_hsync = context->hslot < HSYNC_SLOT_H40 ? (HSYNC_SLOT_H40 - context->hslot) * MCLKS_SLOT_H40 : 0; + uint32_t hsync = 0; + for (int i = context->hslot <= HSYNC_SLOT_H40 ? 0 : context->hslot - HSYNC_SLOT_H40; i < sizeof(h40_hsync_cycles)/sizeof(uint32_t); i++) + { + hsync += h40_hsync_cycles[i]; + } + uint32_t after_hsync = (256- HSYNC_END_H40 + LINE_CHANGE_H40) * MCLKS_SLOT_H40; + return before_hsync + hsync + after_hsync; } else { return (256-context->hslot + LINE_CHANGE_H40) * MCLKS_SLOT_H40; } -- cgit v1.2.3 From 52fb42428540e149d7ae6b53bdb52603b8e1947f Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 4 Jan 2015 12:25:33 -0800 Subject: Removed some code that tried to deal with the 68K not using master clocks that is no longer necessary --- blastem.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/blastem.c b/blastem.c index bf8a333..21e59ab 100644 --- a/blastem.c +++ b/blastem.c @@ -217,8 +217,8 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) if (gen->ym->write_cycle != CYCLE_NEVER) { gen->ym->write_cycle = gen->ym->write_cycle >= mclk_target ? gen->ym->write_cycle - mclk_target : 0; } - //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); vdp_run_context(v_context, mclk_target); + //printf("reached frame end | MCLK Cycles: %d, Target: %d, VDP cycles: %d\n", mclks, mclk_target, v_context->cycles); if (!headless) { break_on_sync |= wait_render_frame(v_context, frame_limit); @@ -290,9 +290,6 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ vdp_run_dma_done(v_context, mclk_target); if (v_context->cycles >= mclk_target) { context->current_cycle = v_context->cycles; - if (context->current_cycle < mclk_target) { - context->current_cycle += MCLKS_PER_68K; - } sync_components(context, 0); } } @@ -307,9 +304,6 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ vdp_run_dma_done(v_context, mclk_target); if (v_context->cycles >= mclk_target) { context->current_cycle = v_context->cycles; - if (context->current_cycle < mclk_target) { - context->current_cycle += MCLKS_PER_68K; - } sync_components(context, 0); } } -- cgit v1.2.3 From d8bb1db03b5f3c3beb86dce633f89872d05318a5 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 4 Jan 2015 23:05:37 -0800 Subject: Some small synchronization improvements that do not seem to fix anything --- blastem.c | 76 +++++++++++++++++++++++++++++++++------------------------------ vdp.c | 17 +++++++++++--- vdp.h | 1 + 3 files changed, 55 insertions(+), 39 deletions(-) diff --git a/blastem.c b/blastem.c index 21e59ab..bbb9c51 100644 --- a/blastem.c +++ b/blastem.c @@ -210,41 +210,45 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) z80_context * z_context = gen->z80; uint32_t mclks = context->current_cycle; sync_z80(z_context, mclks); + sync_sound(gen, mclks); if (mclks >= mclk_target) { - sync_sound(gen, mclks); - gen->ym->current_cycle -= mclk_target; - gen->psg->cycles -= mclk_target; - if (gen->ym->write_cycle != CYCLE_NEVER) { - gen->ym->write_cycle = gen->ym->write_cycle >= mclk_target ? gen->ym->write_cycle - mclk_target : 0; - } vdp_run_context(v_context, mclk_target); - //printf("reached frame end | MCLK Cycles: %d, Target: %d, VDP cycles: %d\n", mclks, mclk_target, v_context->cycles); - - if (!headless) { - break_on_sync |= wait_render_frame(v_context, frame_limit); - } else if(exit_after){ - --exit_after; - if (!exit_after) { - exit(0); + if (vdp_is_frame_over(v_context)) { + //printf("reached frame end | MCLK Cycles: %d, Target: %d, VDP cycles: %d\n", mclks, mclk_target, v_context->cycles); + + if (!headless) { + break_on_sync |= wait_render_frame(v_context, frame_limit); + } else if(exit_after){ + --exit_after; + if (!exit_after) { + exit(0); + } } - } - frame++; - mclks -= mclk_target; - vdp_adjust_cycles(v_context, mclk_target); - io_adjust_cycles(gen->ports, context->current_cycle, mclk_target); - io_adjust_cycles(gen->ports+1, context->current_cycle, mclk_target); - io_adjust_cycles(gen->ports+2, context->current_cycle, mclk_target); - context->current_cycle -= mclk_target; - z80_adjust_cycles(z_context, mclk_target); - if (mclks) { + frame++; + mclks -= mclk_target; + vdp_adjust_cycles(v_context, mclk_target); + io_adjust_cycles(gen->ports, context->current_cycle, mclk_target); + io_adjust_cycles(gen->ports+1, context->current_cycle, mclk_target); + io_adjust_cycles(gen->ports+2, context->current_cycle, mclk_target); + context->current_cycle -= mclk_target; + z80_adjust_cycles(z_context, mclk_target); + gen->ym->current_cycle -= mclk_target; + gen->psg->cycles -= mclk_target; + if (gen->ym->write_cycle != CYCLE_NEVER) { + gen->ym->write_cycle = gen->ym->write_cycle >= mclk_target ? gen->ym->write_cycle - mclk_target : 0; + } + if (mclks) { + vdp_run_context(v_context, mclks); + } + mclk_target = vdp_cycles_to_frame_end(v_context); + context->sync_cycle = mclk_target; + } else { vdp_run_context(v_context, mclks); + mclk_target = vdp_cycles_to_frame_end(v_context); } - mclk_target = vdp_cycles_to_frame_end(v_context); - context->sync_cycle = mclk_target; } else { //printf("running VDP for %d cycles\n", mclks - v_context->cycles); vdp_run_context(v_context, mclks); - sync_sound(gen, mclks); } if (context->int_ack) { vdp_int_ack(v_context, context->int_ack); @@ -284,7 +288,6 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ int blocked; uint32_t before_cycle = v_context->cycles; if (vdp_port < 4) { - gen->bus_busy = 1; while (vdp_data_port_write(v_context, value) < 0) { while(v_context->flags & FLAG_DMA_RUN) { vdp_run_dma_done(v_context, mclk_target); @@ -296,7 +299,6 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ //context->current_cycle = v_context->cycles; } } else if(vdp_port < 8) { - gen->bus_busy = 1; blocked = vdp_control_port_write(v_context, value); if (blocked) { while (blocked) { @@ -323,19 +325,16 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ if (v_context->cycles != before_cycle) { //printf("68K paused for %d (%d) cycles at cycle %d (%d) for write\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); context->current_cycle = v_context->cycles; + //Lock the Z80 out of the bus until the VDP access is complete + gen->bus_busy = 1; + sync_z80(gen->z80, v_context->cycles); + gen->bus_busy = 0; } } else if (vdp_port < 0x18) { - sync_sound(gen, context->current_cycle); psg_write(gen->psg, value); } else { //TODO: Implement undocumented test register(s) } - if (gen->bus_busy) - { - //Lock the Z80 out of the bus until the VDP access is complete - sync_z80(gen->z80, v_context->cycles); - gen->bus_busy = 0; - } return context; } @@ -402,6 +401,11 @@ uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) if (v_context->cycles != before_cycle) { //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); context->current_cycle = v_context->cycles; + //Lock the Z80 out of the bus until the VDP access is complete + genesis_context *gen = context->system; + gen->bus_busy = 1; + sync_z80(gen->z80, v_context->cycles); + gen->bus_busy = 0; } return value; } diff --git a/vdp.c b/vdp.c index d6dc899..710d2ab 100644 --- a/vdp.c +++ b/vdp.c @@ -1627,7 +1627,7 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) if (!context->double_res) { context->framebuf = context->oddbuf; } - } + } context->cd &= 0x3C; } } else { @@ -1892,7 +1892,7 @@ uint32_t vdp_cycles_to_line(vdp_context * context, uint32_t target) return MCLKS_LINE * (lines - 1) + vdp_cycles_next_line(context); } -uint32_t vdp_cycles_to_frame_end(vdp_context * context) +uint32_t vdp_frame_end_line(vdp_context * context) { uint32_t frame_end; if (context->flags2 & FLAG2_REGION_PAL) { @@ -1908,7 +1908,18 @@ uint32_t vdp_cycles_to_frame_end(vdp_context * context) frame_end = NTSC_INACTIVE_START + 8; } } - return context->cycles + vdp_cycles_to_line(context, frame_end); + return frame_end; +} + +uint32_t vdp_cycles_to_frame_end(vdp_context * context) +{ + return context->cycles + vdp_cycles_to_line(context, vdp_frame_end_line(context)); +} + +uint8_t vdp_is_frame_over(vdp_context * context) +{ + uint32_t frame_end = vdp_frame_end_line(context); + return context->vcounter >= frame_end && context->vcounter < (frame_end + 8); } uint32_t vdp_next_hint(vdp_context * context) diff --git a/vdp.h b/vdp.h index 184521a..70c0953 100644 --- a/vdp.h +++ b/vdp.h @@ -194,6 +194,7 @@ void vdp_print_sprite_table(vdp_context * context); void vdp_print_reg_explain(vdp_context * context); void latch_mode(vdp_context * context); uint32_t vdp_cycles_to_frame_end(vdp_context * context); +uint8_t vdp_is_frame_over(vdp_context * context); extern int32_t color_map[1 << 12]; -- cgit v1.2.3 From a788b768cdaffb4bcc62a0f45c1ac0d005db9aa6 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 4 Jan 2015 23:21:56 -0800 Subject: Prevent an infinite loop when handling out of bounds addresses in translate_m68k_stream --- m68k_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/m68k_core.c b/m68k_core.c index 46c4950..fbd8923 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -766,6 +766,7 @@ void translate_m68k_stream(uint32_t address, m68k_context * context) do { encoded = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen); if (!encoded) { + map_native_address(context, address, code->cur, 2, 1); translate_out_of_bounds(code); break; } -- cgit v1.2.3 From bd14f5b08583c050e8e23af5814908b99ba8d547 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 6 Jan 2015 19:09:00 -0800 Subject: Move detect_region down so that it once again occurs after load_rom since it won't work before the ROM is loaded --- blastem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/blastem.c b/blastem.c index e41f550..684f644 100644 --- a/blastem.c +++ b/blastem.c @@ -1120,7 +1120,6 @@ int main(int argc, char ** argv) } set_exe_str(argv[0]); config = load_config(); - detect_region(); int width = -1; int height = -1; int debug = 0; @@ -1242,6 +1241,8 @@ int main(int argc, char ** argv) } if (force_version) { version_reg = force_version; + } else { + detect_region(); } update_title(); int def_width = 0; -- cgit v1.2.3 From f1ad0a3e376b1103b48689fc48ed9443641a038f Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 7 Jan 2015 22:42:35 -0800 Subject: Added ldr and str instructions to gen_arm --- gen_arm.c | 36 ++++++++++++++++++++++++++++++++++++ gen_arm.h | 4 ++++ 2 files changed, 40 insertions(+) diff --git a/gen_arm.c b/gen_arm.c index 5d9fab6..1534ee2 100644 --- a/gen_arm.c +++ b/gen_arm.c @@ -548,3 +548,39 @@ uint32_t popm_cc(code_info *code, uint32_t reglist, uint32_t cc) *(code->cur++) = cc | POPM | reglist; return CODE_OK; } + +uint32_t load_store_immoff(code_info *code, uint32_t op, uint32_t dst, uint32_t base, int32_t offset, uint32_t cc) +{ + if (offset >= 0x1000 || offset <= -0x1000) { + return INVALID_IMMED; + } + check_alloc_code(code); + uint32_t instruction = cc | op | POST_IND | OFF_IMM | SZ_W | base << 16 | dst << 12; + if (offset >= 0) { + instruction |= offset | DIR_UP; + } else { + instruction |= (-offset) | DIR_DOWN; + } + *(code->cur++) = instruction; + return CODE_OK; +} + +uint32_t ldr_cc(code_info *code, uint32_t dst, uint32_t base, int32_t offset, uint32_t cc) +{ + return load_store_immoff(code, OP_LDR, dst, base, offset, cc); +} + +uint32_t ldr(code_info *code, uint32_t dst, uint32_t base, int32_t offset) +{ + return ldr_cc(code, dst, base, offset, CC_AL); +} + +uint32_t str_cc(code_info *code, uint32_t src, uint32_t base, int32_t offset, uint32_t cc) +{ + return load_store_immoff(code, OP_STR, src, base, offset, cc); +} + +uint32_t str(code_info *code, uint32_t src, uint32_t base, int32_t offset) +{ + return str_cc(code, src, base, offset, CC_AL); +} diff --git a/gen_arm.h b/gen_arm.h index 749f78c..191a80f 100644 --- a/gen_arm.h +++ b/gen_arm.h @@ -149,5 +149,9 @@ uint32_t pop(code_info *code, uint32_t reg); uint32_t pop_cc(code_info *code, uint32_t reg, uint32_t cc); uint32_t popm(code_info *code, uint32_t reglist); uint32_t popm_cc(code_info *code, uint32_t reglist, uint32_t cc); +uint32_t ldr_cc(code_info *code, uint32_t dst, uint32_t base, int32_t offset, uint32_t cc); +uint32_t ldr(code_info *code, uint32_t rst, uint32_t base, int32_t offset); +uint32_t str_cc(code_info *code, uint32_t src, uint32_t base, int32_t offset, uint32_t cc); +uint32_t str(code_info *code, uint32_t src, uint32_t base, int32_t offset); #endif //GEN_ARM_H_ -- cgit v1.2.3 From 1a8489d67d209986951adb84eef3fc36dbe3b548 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 8 Jan 2015 09:36:54 -0800 Subject: Fix indentation that presumably got messed up in a merge --- m68k_core_x86.c | 544 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 272 insertions(+), 272 deletions(-) diff --git a/m68k_core_x86.c b/m68k_core_x86.c index f8a323d..285a1dd 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -216,42 +216,42 @@ void dreg_to_native_sx(m68k_options *opts, uint8_t reg, uint8_t native_reg) { if (opts->dregs[reg] >= 0) { movsx_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_W, SZ_D); - } else { + } else { movsx_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_W, SZ_D); - } } +} void native_to_areg(m68k_options *opts, uint8_t native_reg, uint8_t reg) { if (opts->aregs[reg] >= 0) { mov_rr(&opts->gen.code, native_reg, opts->aregs[reg], SZ_D); - } else { + } else { mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, areg_offset(reg), SZ_D); - } - } + } +} void native_to_dreg(m68k_options *opts, uint8_t native_reg, uint8_t reg) { if (opts->dregs[reg] >= 0) { mov_rr(&opts->gen.code, native_reg, opts->dregs[reg], SZ_D); - } else { + } else { mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, dreg_offset(reg), SZ_D); - } + } } void ldi_areg(m68k_options *opts, int32_t value, uint8_t reg) { if (opts->aregs[reg] >= 0) { mov_ir(&opts->gen.code, value, opts->aregs[reg], SZ_D); - } else { + } else { mov_irdisp(&opts->gen.code, value, opts->gen.context_reg, areg_offset(reg), SZ_D); - } + } } void ldi_native(m68k_options *opts, int32_t value, uint8_t reg) - { +{ mov_ir(&opts->gen.code, value, reg, SZ_D); - } +} void addi_native(m68k_options *opts, int32_t value, uint8_t reg) { @@ -261,90 +261,90 @@ void addi_native(m68k_options *opts, int32_t value, uint8_t reg) void subi_native(m68k_options *opts, int32_t value, uint8_t reg) { sub_ir(&opts->gen.code, value, reg, SZ_D); - } +} void push_native(m68k_options *opts, uint8_t reg) { push_r(&opts->gen.code, reg); - } +} void pop_native(m68k_options *opts, uint8_t reg) - { +{ pop_r(&opts->gen.code, reg); - } +} void sign_extend16_native(m68k_options *opts, uint8_t reg) { movsx_rr(&opts->gen.code, reg, reg, SZ_W, SZ_D); - } +} void addi_areg(m68k_options *opts, int32_t val, uint8_t reg) { if (opts->aregs[reg] >= 0) { add_ir(&opts->gen.code, val, opts->aregs[reg], SZ_D); - } else { + } else { add_irdisp(&opts->gen.code, val, opts->gen.context_reg, areg_offset(reg), SZ_D); - } + } } void subi_areg(m68k_options *opts, int32_t val, uint8_t reg) { if (opts->aregs[reg] >= 0) { sub_ir(&opts->gen.code, val, opts->aregs[reg], SZ_D); - } else { + } else { sub_irdisp(&opts->gen.code, val, opts->gen.context_reg, areg_offset(reg), SZ_D); - } - } + } +} void add_areg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg) { if (opts->aregs[reg] >= 0) { add_rr(&opts->gen.code, opts->aregs[reg], native_reg, SZ_D); - } else { + } else { add_rdispr(&opts->gen.code, opts->gen.context_reg, areg_offset(reg), native_reg, SZ_D); - } + } } void add_dreg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg) { if (opts->dregs[reg] >= 0) { add_rr(&opts->gen.code, opts->dregs[reg], native_reg, SZ_D); - } else { + } else { add_rdispr(&opts->gen.code, opts->gen.context_reg, dreg_offset(reg), native_reg, SZ_D); - } - } + } +} void calc_areg_displace(m68k_options *opts, m68k_op_info *op, uint8_t native_reg) - { +{ areg_to_native(opts, op->params.regs.pri, native_reg); add_ir(&opts->gen.code, op->params.regs.displacement, native_reg, SZ_D); - } +} void calc_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg) - { +{ uint8_t sec_reg = (op->params.regs.sec >> 1) & 0x7; if (op->params.regs.sec & 1) { if (op->params.regs.sec & 0x10) { add_areg_native(opts, sec_reg, native_reg); - } else { + } else { add_dreg_native(opts, sec_reg, native_reg); - } - } else { + } + } else { uint8_t other_reg = native_reg == opts->gen.scratch1 ? opts->gen.scratch2 : opts->gen.scratch1; if (op->params.regs.sec & 0x10) { areg_to_native_sx(opts, sec_reg, other_reg); - } else { + } else { dreg_to_native_sx(opts, sec_reg, other_reg); - } + } add_rr(&opts->gen.code, other_reg, native_reg, SZ_D); - } + } if (op->params.regs.displacement) { add_ir(&opts->gen.code, op->params.regs.displacement, native_reg, SZ_D); - } - } + } +} void calc_areg_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg) - { +{ areg_to_native(opts, op->params.regs.pri, native_reg); calc_index_disp8(opts, op, native_reg); } @@ -362,8 +362,8 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8 movsx_rr(code, reg, opts->gen.scratch1, SZ_W, SZ_D); ea->base = opts->gen.scratch1; } else { - ea->base = reg; - } + ea->base = reg; + } return; } switch (op->addr_mode) @@ -375,7 +375,7 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8 if (dst || native_reg(&(inst->dst), opts) >= 0 || inst->dst.addr_mode == MODE_UNUSED || !(inst->dst.addr_mode == MODE_REG || inst->dst.addr_mode == MODE_AREG) || inst->op == M68K_EXG) { - ea->mode = MODE_REG_DISPLACE8; + ea->mode = MODE_REG_DISPLACE8; ea->base = opts->gen.context_reg; ea->disp = reg_offset(op); } else { @@ -405,10 +405,10 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8 m68k_read_size(opts, inst->extra.size); if (dst) { - if (inst->src.addr_mode == MODE_AREG_PREDEC) { + if (inst->src.addr_mode == MODE_AREG_PREDEC) { //restore src operand to opts->gen.scratch2 pop_r(code, opts->gen.scratch2); - } else { + } else { //save reg value in opts->gen.scratch2 so we can use it to save the result in memory later areg_to_native(opts, op->params.regs.pri, opts->gen.scratch2); } @@ -430,7 +430,7 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8 m68k_read_size(opts, inst->extra.size); if (dst) { pop_r(code, opts->gen.scratch2); - } + } ea->mode = MODE_REG_DIRECT; ea->base = opts->gen.scratch1; @@ -444,7 +444,7 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8 m68k_read_size(opts, inst->extra.size); if (dst) { pop_r(code, opts->gen.scratch2); - } + } ea->mode = MODE_REG_DIRECT; ea->base = opts->gen.scratch1; @@ -454,7 +454,7 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8 mov_ir(code, op->params.regs.displacement + inst->address+2, opts->gen.scratch1, SZ_D); if (dst) { push_r(code, opts->gen.scratch1); - } + } m68k_read_size(opts, inst->extra.size); if (dst) { pop_r(code, opts->gen.scratch2); @@ -469,11 +469,11 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8 calc_index_disp8(opts, op, opts->gen.scratch1); if (dst) { push_r(code, opts->gen.scratch1); - } + } m68k_read_size(opts, inst->extra.size); if (dst) { pop_r(code, opts->gen.scratch2); - } + } ea->mode = MODE_REG_DIRECT; ea->base = opts->gen.scratch1; @@ -484,7 +484,7 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8 mov_ir(code, op->params.immed, opts->gen.scratch1, SZ_D); if (dst) { push_r(code, opts->gen.scratch1); - } + } m68k_read_size(opts, inst->extra.size); if (dst) { pop_r(code, opts->gen.scratch2); @@ -708,8 +708,8 @@ void translate_m68k_move(m68k_options * opts, m68kinst * inst) if (inst->dst.addr_mode == MODE_AREG_POSTINC) { inc_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (inst->dst.params.regs.pri == 7 ? 2 : 1)); addi_areg(opts, inc_amount, inst->dst.params.regs.pri); - } - } + } + } //add cycles for prefetch cycles(&opts->gen, BUS); @@ -758,48 +758,48 @@ void translate_m68k_ext(m68k_options * opts, m68kinst * inst) uint8_t m68k_eval_cond(m68k_options * opts, uint8_t cc) { - uint8_t cond = CC_NZ; + uint8_t cond = CC_NZ; switch (cc) - { - case COND_HIGH: - cond = CC_Z; - case COND_LOW_SAME: + { + case COND_HIGH: + cond = CC_Z; + case COND_LOW_SAME: flag_to_reg(opts, FLAG_Z, opts->gen.scratch1); or_flag_to_reg(opts, FLAG_C, opts->gen.scratch1); - break; - case COND_CARRY_CLR: - cond = CC_Z; - case COND_CARRY_SET: + break; + case COND_CARRY_CLR: + cond = CC_Z; + case COND_CARRY_SET: check_flag(opts, FLAG_C); - break; - case COND_NOT_EQ: - cond = CC_Z; - case COND_EQ: + break; + case COND_NOT_EQ: + cond = CC_Z; + case COND_EQ: check_flag(opts, FLAG_Z); - break; - case COND_OVERF_CLR: - cond = CC_Z; - case COND_OVERF_SET: + break; + case COND_OVERF_CLR: + cond = CC_Z; + case COND_OVERF_SET: check_flag(opts, FLAG_V); - break; - case COND_PLUS: - cond = CC_Z; - case COND_MINUS: + break; + case COND_PLUS: + cond = CC_Z; + case COND_MINUS: check_flag(opts, FLAG_N); - break; - case COND_GREATER_EQ: - cond = CC_Z; - case COND_LESS: + break; + case COND_GREATER_EQ: + cond = CC_Z; + case COND_LESS: cmp_flags(opts, FLAG_N, FLAG_V); - break; - case COND_GREATER: - cond = CC_Z; - case COND_LESS_EQ: + break; + case COND_GREATER: + cond = CC_Z; + case COND_LESS_EQ: flag_to_reg(opts, FLAG_V, opts->gen.scratch1); xor_flag_to_reg(opts, FLAG_N, opts->gen.scratch1); or_flag_to_reg(opts, FLAG_Z, opts->gen.scratch1); - break; - } + break; + } return cond; } @@ -1210,8 +1210,8 @@ void op_irdisp(code_info *code, m68kinst *inst, int32_t val, uint8_t dst, int32_ case M68K_ROXR: rcr_irdisp(code, val, dst, disp, size); break; case M68K_SUB: sub_irdisp(code, val, dst, disp, size); break; case M68K_SUBX: sbb_irdisp(code, val, dst, disp, size); break; - } } +} void op_rr(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, uint8_t size) { @@ -1230,7 +1230,7 @@ void op_rr(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, uint8_t si case M68K_SUB: sub_rr(code, src, dst, size); break; case M68K_SUBX: sbb_rr(code, src, dst, size); break; } - } +} void op_rrdisp(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, int32_t disp, uint8_t size) { @@ -1248,8 +1248,8 @@ void op_rrdisp(code_info *code, m68kinst *inst, uint8_t src, uint8_t dst, int32_ case M68K_OR: or_rrdisp(code, src, dst, disp, size); break; case M68K_SUB: sub_rrdisp(code, src, dst, disp, size); break; case M68K_SUBX: sbb_rrdisp(code, src, dst, disp, size); break; - } - } + } +} void op_rdispr(code_info *code, m68kinst *inst, uint8_t src, int32_t disp, uint8_t dst, uint8_t size) { @@ -1263,8 +1263,8 @@ void op_rdispr(code_info *code, m68kinst *inst, uint8_t src, int32_t disp, uint8 case M68K_OR: or_rdispr(code, src, disp, dst, size); break; case M68K_SUB: sub_rdispr(code, src, disp, dst, size); break; case M68K_SUBX: sbb_rdispr(code, src, disp, dst, size); break; - } - } + } +} void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mask, host_ea *src_op, host_ea *dst_op) { @@ -1272,23 +1272,23 @@ void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mas cycles(&opts->gen, BUS); if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) { flag_to_carry(opts, FLAG_X); - } + } uint8_t size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size; if (src_op->mode == MODE_REG_DIRECT) { if (dst_op->mode == MODE_REG_DIRECT) { op_rr(code, inst, src_op->base, dst_op->base, size); - } else { + } else { op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size); - } + } } else if (src_op->mode == MODE_REG_DISPLACE8) { op_rdispr(code, inst, src_op->base, src_op->disp, dst_op->base, size); - } else { + } else { if (dst_op->mode == MODE_REG_DIRECT) { op_ir(code, inst, src_op->disp, dst_op->base, size); - } else { + } else { op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, size); - } } + } if (inst->dst.addr_mode != MODE_AREG || inst->op == M68K_CMP) { update_flags(opts, flag_mask); if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) { @@ -1297,8 +1297,8 @@ void translate_m68k_arith(m68k_options *opts, m68kinst * inst, uint32_t flag_mas jcc(code, CC_Z, code->cur + 2); set_flag(opts, 0, FLAG_Z); *after_flag_set = code->cur - (after_flag_set+1); - } } + } if (inst->op != M68K_CMP) { m68k_save_result(inst, opts); } @@ -1315,11 +1315,11 @@ void translate_m68k_cmp(m68k_options * opts, m68kinst * inst) translate_m68k_op(inst, &dst_op, opts, 1); pop_r(code, opts->gen.scratch2); src_op.base = opts->gen.scratch2; - } else { + } else { translate_m68k_op(inst, &dst_op, opts, 1); if (inst->dst.addr_mode == MODE_AREG && size == OPSIZE_WORD) { size = OPSIZE_LONG; - } + } } translate_m68k_arith(opts, inst, N|Z|V|C, &src_op, &dst_op); } @@ -1360,12 +1360,12 @@ void translate_m68k_unary(m68k_options *opts, m68kinst *inst, uint32_t flag_mask cycles(&opts->gen, BUS); if (dst_op->mode == MODE_REG_DIRECT) { op_r(code, inst, dst_op->base, inst->extra.size); - } else { + } else { op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size); - } + } update_flags(opts, flag_mask); m68k_save_result(inst, opts); - } +} void translate_m68k_invalid(m68k_options *opts, m68kinst *inst) { @@ -1391,16 +1391,16 @@ void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_o if (dst_op->base != opts->gen.scratch1) { if (dst_op->mode == MODE_REG_DIRECT) { mov_rr(code, dst_op->base, opts->gen.scratch1, SZ_B); - } else { + } else { mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, SZ_B); - } + } } uint8_t other_reg; //WARNING: This may need adjustment if register assignments change if (opts->gen.scratch2 > RBX) { other_reg = RAX; xchg_rr(code, opts->gen.scratch2, RAX, SZ_D); - } else { + } else { other_reg = opts->gen.scratch2; } mov_rr(code, opts->gen.scratch1, opts->gen.scratch1 + (AH-RAX), SZ_B); @@ -1413,9 +1413,9 @@ void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_o flag_to_carry(opts, FLAG_X); if (inst->op == M68K_ABCD) { adc_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B); - } else { + } else { sbb_rr(code, other_reg + (AH-RAX), opts->gen.scratch1 + (AH-RAX), SZ_B); - } + } cmp_ir(code, 0xA, opts->gen.scratch1 + (AH-RAX), SZ_B); code_ptr no_adjust = code->cur+1; //add correction factor if necessary @@ -1424,7 +1424,7 @@ void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_o add_ir(code, 6, opts->gen.scratch1 + (AH-RAX), SZ_B); } else { sub_ir(code, 6, opts->gen.scratch1 + (AH-RAX), SZ_B); - } + } *no_adjust = code->cur - (no_adjust+1); //add low nibble result to one of the high nibble operands add_rr(code, opts->gen.scratch1 + (AH-RAX), opts->gen.scratch1, SZ_B); @@ -1432,10 +1432,10 @@ void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_o add_rr(code, other_reg, opts->gen.scratch1, SZ_B); } else { sub_rr(code, other_reg, opts->gen.scratch1, SZ_B); - } + } if (opts->gen.scratch2 > RBX) { mov_rr(code, opts->gen.scratch2, RAX, SZ_D); - } + } set_flag(opts, 0, FLAG_C); set_flag(opts, 0, FLAG_V); code_ptr def_adjust = code->cur+1; @@ -1449,7 +1449,7 @@ void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_o add_ir(code, 0x60, opts->gen.scratch1, SZ_B); } else { sub_ir(code, 0x60, opts->gen.scratch1, SZ_B); - } + } //V flag is set based on the result of the addition of the //result and the correction factor set_flag_cond(opts, CC_O, FLAG_V); @@ -1466,19 +1466,19 @@ void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_o } else { mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_B); } - } + } m68k_save_result(inst, opts); - } +} void translate_m68k_sl(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) { translate_shift(opts, inst, src_op, dst_op, shl_ir, shl_irdisp, shl_clr, shl_clrdisp, shr_ir, shr_irdisp); - } +} void translate_m68k_asr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) { translate_shift(opts, inst, src_op, dst_op, sar_ir, sar_irdisp, sar_clr, sar_clrdisp, NULL, NULL); - } +} void translate_m68k_lsr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) { @@ -1490,17 +1490,17 @@ void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos code_info *code = &opts->gen.code; cycles(&opts->gen, inst->extra.size == OPSIZE_BYTE ? 4 : ( inst->op == M68K_BTST ? 6 : (inst->op == M68K_BCLR ? 10 : 8)) - ); + ); if (src_op->mode == MODE_IMMED) { - if (inst->extra.size == OPSIZE_BYTE) { + if (inst->extra.size == OPSIZE_BYTE) { src_op->disp &= 0x7; - } + } if (dst_op->mode == MODE_REG_DIRECT) { op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size); - } else { + } else { op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); - } - } else { + } + } else { if (src_op->mode == MODE_REG_DISPLACE8 || (inst->dst.addr_mode != MODE_REG && src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2)) { if (dst_op->base == opts->gen.scratch1) { push_r(code, opts->gen.scratch2); @@ -1524,38 +1524,38 @@ void translate_m68k_bit(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos if (src_op->base != opts->gen.scratch1 && src_op->base != opts->gen.scratch2) { if (src_op->mode == MODE_REG_DIRECT) { mov_rr(code, src_op->base, opts->gen.scratch1, SZ_D); - } else { + } else { mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D); src_op->mode = MODE_REG_DIRECT; - } - src_op->base = opts->gen.scratch1; } - //b### with register destination is modulo 32 - //x86 with a memory destination isn't modulo anything - //so use an and here to force the value to be modulo 32 + src_op->base = opts->gen.scratch1; + } + //b### with register destination is modulo 32 + //x86 with a memory destination isn't modulo anything + //so use an and here to force the value to be modulo 32 and_ir(code, 31, opts->gen.scratch1, SZ_D); - } else if(inst->dst.addr_mode != MODE_REG) { - //b### with memory destination is modulo 8 - //x86-64 doesn't support 8-bit bit operations - //so we fake it by forcing the bit number to be modulo 8 + } else if(inst->dst.addr_mode != MODE_REG) { + //b### with memory destination is modulo 8 + //x86-64 doesn't support 8-bit bit operations + //so we fake it by forcing the bit number to be modulo 8 and_ir(code, 7, src_op->base, SZ_D); - size = SZ_D; - } + size = SZ_D; + } if (dst_op->mode == MODE_REG_DIRECT) { op_rr(code, inst, src_op->base, dst_op->base, size); - } else { + } else { op_rrdisp(code, inst, src_op->base, dst_op->base, dst_op->disp, size); - } + } if (src_op->base == opts->gen.scratch2) { pop_r(code, opts->gen.scratch2); - } } - //x86 sets the carry flag to the value of the bit tested - //68K sets the zero flag to the complement of the bit tested + } + //x86 sets the carry flag to the value of the bit tested + //68K sets the zero flag to the complement of the bit tested set_flag_cond(opts, CC_NC, FLAG_Z); - if (inst->op != M68K_BTST) { + if (inst->op != M68K_BTST) { m68k_save_result(inst, opts); - } + } } void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) @@ -1564,26 +1564,26 @@ void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos cycles(&opts->gen, 6); if (dst_op->mode == MODE_REG_DIRECT) { cmp_ir(code, 0, dst_op->base, inst->extra.size); - } else { + } else { cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size); - } - uint32_t isize; - switch(inst->src.addr_mode) - { - case MODE_AREG_DISPLACE: - case MODE_AREG_INDEX_DISP8: - case MODE_ABSOLUTE_SHORT: - case MODE_PC_INDEX_DISP8: - case MODE_PC_DISPLACE: - case MODE_IMMEDIATE: - isize = 4; - break; - case MODE_ABSOLUTE: - isize = 6; - break; - default: - isize = 2; - } + } + uint32_t isize; + switch(inst->src.addr_mode) + { + case MODE_AREG_DISPLACE: + case MODE_AREG_INDEX_DISP8: + case MODE_ABSOLUTE_SHORT: + case MODE_PC_INDEX_DISP8: + case MODE_PC_DISPLACE: + case MODE_IMMEDIATE: + isize = 4; + break; + case MODE_ABSOLUTE: + isize = 6; + break; + default: + isize = 2; + } //make sure we won't start a new chunk in the middle of these branches check_alloc_code(code, MAX_INST_LEN * 11); code_ptr passed = code->cur + 1; @@ -1598,16 +1598,16 @@ void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos cmp_rr(code, src_op->base, dst_op->base, inst->extra.size); } else if(src_op->mode == MODE_REG_DISPLACE8) { cmp_rdispr(code, src_op->base, src_op->disp, dst_op->base, inst->extra.size); - } else { + } else { cmp_ir(code, src_op->disp, dst_op->base, inst->extra.size); - } + } } else if(dst_op->mode == MODE_REG_DISPLACE8) { if (src_op->mode == MODE_REG_DIRECT) { cmp_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, inst->extra.size); - } else { + } else { cmp_irdisp(code, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); - } } + } passed = code->cur + 1; jcc(code, CC_LE, code->cur + 2); set_flag(opts, 0, FLAG_N); @@ -1616,37 +1616,37 @@ void translate_m68k_chk(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos jmp(code, opts->trap); *passed = code->cur - (passed+1); cycles(&opts->gen, 4); - } +} void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) - { +{ code_info *code = &opts->gen.code; check_alloc_code(code, MAX_NATIVE_SIZE); - //TODO: cycle exact division + //TODO: cycle exact division cycles(&opts->gen, inst->op == M68K_DIVS ? 158 : 140); set_flag(opts, 0, FLAG_C); push_r(code, RDX); push_r(code, RAX); if (dst_op->mode == MODE_REG_DIRECT) { mov_rr(code, dst_op->base, RAX, SZ_D); - } else { + } else { mov_rdispr(code, dst_op->base, dst_op->disp, RAX, SZ_D); - } + } if (src_op->mode == MODE_IMMED) { mov_ir(code, (src_op->disp & 0x8000) && inst->op == M68K_DIVS ? src_op->disp | 0xFFFF0000 : src_op->disp, opts->gen.scratch2, SZ_D); } else if (src_op->mode == MODE_REG_DIRECT) { - if (inst->op == M68K_DIVS) { + if (inst->op == M68K_DIVS) { movsx_rr(code, src_op->base, opts->gen.scratch2, SZ_W, SZ_D); - } else { + } else { movzx_rr(code, src_op->base, opts->gen.scratch2, SZ_W, SZ_D); - } + } } else if (src_op->mode == MODE_REG_DISPLACE8) { - if (inst->op == M68K_DIVS) { + if (inst->op == M68K_DIVS) { movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D); - } else { + } else { movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch2, SZ_W, SZ_D); - } } + } uint32_t isize = 2; switch(inst->src.addr_mode) { @@ -1671,38 +1671,38 @@ void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); jmp(code, opts->trap); *not_zero = code->cur - (not_zero+1); - if (inst->op == M68K_DIVS) { + if (inst->op == M68K_DIVS) { cdq(code); - } else { + } else { xor_rr(code, RDX, RDX, SZ_D); - } - if (inst->op == M68K_DIVS) { + } + if (inst->op == M68K_DIVS) { idiv_r(code, opts->gen.scratch2, SZ_D); - } else { + } else { div_r(code, opts->gen.scratch2, SZ_D); - } + } code_ptr skip_sec_check, norm_off; - if (inst->op == M68K_DIVS) { + if (inst->op == M68K_DIVS) { cmp_ir(code, 0x8000, RAX, SZ_D); skip_sec_check = code->cur + 1; jcc(code, CC_GE, code->cur + 2); cmp_ir(code, -0x8000, RAX, SZ_D); norm_off = code->cur + 1; jcc(code, CC_L, code->cur + 2); - } else { + } else { cmp_ir(code, 0x10000, RAX, SZ_D); norm_off = code->cur + 1; jcc(code, CC_NC, code->cur + 2); - } + } if (dst_op->mode == MODE_REG_DIRECT) { mov_rr(code, RDX, dst_op->base, SZ_W); shl_ir(code, 16, dst_op->base, SZ_D); mov_rr(code, RAX, dst_op->base, SZ_W); - } else { + } else { mov_rrdisp(code, RDX, dst_op->base, dst_op->disp, SZ_W); shl_irdisp(code, 16, dst_op->base, dst_op->disp, SZ_D); mov_rrdisp(code, RAX, dst_op->base, dst_op->disp, SZ_W); - } + } cmp_ir(code, 0, RAX, SZ_W); pop_r(code, RAX); pop_r(code, RDX); @@ -1710,14 +1710,14 @@ void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos code_ptr end_off = code->cur + 1; jmp(code, code->cur + 2); *norm_off = code->cur - (norm_off + 1); - if (inst->op == M68K_DIVS) { + if (inst->op == M68K_DIVS) { *skip_sec_check = code->cur - (skip_sec_check+1); - } + } pop_r(code, RAX); pop_r(code, RDX); set_flag(opts, 1, FLAG_V); *end_off = code->cur - (end_off + 1); - } +} void translate_m68k_exg(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) { @@ -1728,22 +1728,22 @@ void translate_m68k_exg(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos if (src_op->mode == MODE_REG_DIRECT) { mov_rr(code, src_op->base, dst_op->base, SZ_D); mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D); - } else { + } else { mov_rdispr(code, src_op->base, src_op->disp, dst_op->base, SZ_D); mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D); - } - } else { + } + } else { mov_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_D); if (src_op->mode == MODE_REG_DIRECT) { mov_rrdisp(code, src_op->base, dst_op->base, dst_op->disp, SZ_D); mov_rr(code, opts->gen.scratch2, src_op->base, SZ_D); - } else { + } else { mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_D); mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_D); mov_rrdisp(code, opts->gen.scratch2, src_op->base, src_op->disp, SZ_D); - } - } } + } +} void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) { @@ -1752,41 +1752,41 @@ void translate_m68k_mul(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos if (src_op->mode == MODE_IMMED) { mov_ir(code, inst->op == M68K_MULU ? (src_op->disp & 0xFFFF) : ((src_op->disp & 0x8000) ? src_op->disp | 0xFFFF0000 : src_op->disp), opts->gen.scratch1, SZ_D); } else if (src_op->mode == MODE_REG_DIRECT) { - if (inst->op == M68K_MULS) { + if (inst->op == M68K_MULS) { movsx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D); - } else { - movzx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D); - } } else { - if (inst->op == M68K_MULS) { + movzx_rr(code, src_op->base, opts->gen.scratch1, SZ_W, SZ_D); + } + } else { + if (inst->op == M68K_MULS) { movsx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D); - } else { + } else { movzx_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W, SZ_D); - } } + } uint8_t dst_reg; if (dst_op->mode == MODE_REG_DIRECT) { dst_reg = dst_op->base; - if (inst->op == M68K_MULS) { + if (inst->op == M68K_MULS) { movsx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); - } else { - movzx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); - } } else { + movzx_rr(code, dst_reg, dst_reg, SZ_W, SZ_D); + } + } else { dst_reg = opts->gen.scratch2; - if (inst->op == M68K_MULS) { + if (inst->op == M68K_MULS) { movsx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D); - } else { + } else { movzx_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch2, SZ_W, SZ_D); - } } + } imul_rr(code, opts->gen.scratch1, dst_reg, SZ_D); if (dst_op->mode == MODE_REG_DISPLACE8) { mov_rrdisp(code, dst_reg, dst_op->base, dst_op->disp, SZ_D); - } + } cmp_ir(code, 0, dst_reg, SZ_D); update_flags(opts, N|Z|V0|C0); - } +} void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) { @@ -1806,12 +1806,12 @@ void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, ho sbb_rr(code, dst_op->base, opts->gen.scratch1, inst->extra.size); mov_rr(code, opts->gen.scratch1, dst_op->base, inst->extra.size); } - } else { + } else { xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, inst->extra.size); flag_to_carry(opts, FLAG_X); sbb_rdispr(code, dst_op->base, dst_op->disp, opts->gen.scratch1, inst->extra.size); mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, inst->extra.size); - } + } set_flag_cond(opts, CC_C, FLAG_C); code_ptr after_flag_set = code->cur + 1; jcc(code, CC_Z, code->cur + 2); @@ -1819,21 +1819,21 @@ void translate_m68k_negx(m68k_options *opts, m68kinst *inst, host_ea *src_op, ho *after_flag_set = code->cur - (after_flag_set+1); set_flag_cond(opts, CC_S, FLAG_N); set_flag_cond(opts, CC_O, FLAG_V); - if (opts->flag_regs[FLAG_C] >= 0) { + if (opts->flag_regs[FLAG_C] >= 0) { flag_to_flag(opts, FLAG_C, FLAG_X); - } else { + } else { set_flag_cond(opts, CC_C, FLAG_X); - } + } m68k_save_result(inst, opts); - } +} void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) { code_info *code = &opts->gen.code; int32_t init_flags = C|V0; - if (inst->src.addr_mode == MODE_UNUSED) { + if (inst->src.addr_mode == MODE_UNUSED) { cycles(&opts->gen, BUS); - //Memory rotate + //Memory rotate if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { flag_to_carry(opts, FLAG_X); init_flags |= X; @@ -1843,7 +1843,7 @@ void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos cmp_ir(code, 0, dst_op->base, inst->extra.size); update_flags(opts, Z|N); m68k_save_result(inst, opts); - } else { + } else { if (src_op->mode == MODE_IMMED) { cycles(&opts->gen, (inst->extra.size == OPSIZE_LONG ? 8 : 6) + src_op->disp*2); if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { @@ -1852,18 +1852,18 @@ void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos } if (dst_op->mode == MODE_REG_DIRECT) { op_ir(code, inst, src_op->disp, dst_op->base, inst->extra.size); - } else { + } else { op_irdisp(code, inst, src_op->disp, dst_op->base, dst_op->disp, inst->extra.size); - } + } update_flags(opts, init_flags); - } else { + } else { if (src_op->mode == MODE_REG_DIRECT) { if (src_op->base != opts->gen.scratch1) { mov_rr(code, src_op->base, opts->gen.scratch1, SZ_B); - } + } } else { mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_B); - } + } and_ir(code, 63, opts->gen.scratch1, SZ_D); code_ptr zero_off = code->cur + 1; jcc(code, CC_Z, code->cur + 2); @@ -1877,30 +1877,30 @@ void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { flag_to_carry(opts, FLAG_X); init_flags |= X; - } else { + } else { sub_ir(code, 32, opts->gen.scratch1, SZ_B); - } + } if (dst_op->mode == MODE_REG_DIRECT) { op_ir(code, inst, 31, dst_op->base, inst->extra.size); op_ir(code, inst, 1, dst_op->base, inst->extra.size); - } else { + } else { op_irdisp(code, inst, 31, dst_op->base, dst_op->disp, inst->extra.size); op_irdisp(code, inst, 1, dst_op->base, dst_op->disp, inst->extra.size); - } + } if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { set_flag_cond(opts, CC_C, FLAG_X); sub_ir(code, 32, opts->gen.scratch1, SZ_B); *norm_off = code->cur - (norm_off+1); flag_to_carry(opts, FLAG_X); - } else { + } else { *norm_off = code->cur - (norm_off+1); - } + } if (dst_op->mode == MODE_REG_DIRECT) { op_r(code, inst, dst_op->base, inst->extra.size); - } else { + } else { op_rdisp(code, inst, dst_op->base, dst_op->disp, inst->extra.size); - } + } update_flags(opts, init_flags); code_ptr end_off = code->cur + 1; jmp(code, code->cur + 2); @@ -1908,26 +1908,26 @@ void translate_m68k_rot(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos if (inst->op == M68K_ROXR || inst->op == M68K_ROXL) { //Carry flag is set to X flag when count is 0, this is different from ROR/ROL flag_to_flag(opts, FLAG_X, FLAG_C); - } else { + } else { set_flag(opts, 0, FLAG_C); - } + } *end_off = code->cur - (end_off+1); - } + } if (dst_op->mode == MODE_REG_DIRECT) { cmp_ir(code, 0, dst_op->base, inst->extra.size); - } else { + } else { cmp_irdisp(code, 0, dst_op->base, dst_op->disp, inst->extra.size); - } - update_flags(opts, Z|N); } - } + update_flags(opts, Z|N); + } +} void translate_m68k_illegal(m68k_options *opts, m68kinst *inst) { code_info *code = &opts->gen.code; call(code, opts->gen.save_context); call_args(code, (code_ptr)print_regs_exit, 1, opts->gen.context_reg); - } +} #define BIT_SUPERVISOR 5 @@ -1943,25 +1943,25 @@ void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst) if ((base_flag == X0) ^ (inst->src.params.immed & 1 << i) > 0) { flag_mask |= base_flag << ((4 - i) * 3); - } - } + } + } update_flags(opts, flag_mask); if (inst->op == M68K_ANDI_SR || inst->op == M68K_ORI_SR) { if (inst->op == M68K_ANDI_SR) { and_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); - } else { + } else { or_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); - } + } if (inst->op == M68K_ANDI_SR && !(inst->src.params.immed & (1 << (BIT_SUPERVISOR + 8)))) { //leave supervisor mode swap_ssp_usp(opts); - } + } if ((inst->op == M68K_ANDI_SR && (inst->src.params.immed & 0x700) != 0x700) || (inst->op == M68K_ORI_SR && inst->src.params.immed & 0x700)) { call(code, opts->do_sync); - } - } - } + } + } +} void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst) { @@ -1970,26 +1970,26 @@ void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst) //TODO: If ANDI to SR, trap if not in supervisor mode if (inst->src.params.immed & 0x1) { xor_flag(opts, 1, FLAG_C); - } + } if (inst->src.params.immed & 0x2) { xor_flag(opts, 1, FLAG_V); - } + } if (inst->src.params.immed & 0x4) { xor_flag(opts, 1, FLAG_Z); - } + } if (inst->src.params.immed & 0x8) { xor_flag(opts, 1, FLAG_N); - } + } if (inst->src.params.immed & 0x10) { xor_flag(opts, 1, FLAG_X); - } + } if (inst->op == M68K_ORI_SR) { xor_irdisp(code, inst->src.params.immed >> 8, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); if (inst->src.params.immed & 0x700) { call(code, opts->do_sync); - } - } - } + } + } +} void set_all_flags(m68k_options *opts, uint8_t flags) { @@ -1999,7 +1999,7 @@ void set_all_flags(m68k_options *opts, uint8_t flags) flag_mask |= flags & 0x2 ? V1 : V0; flag_mask |= flags & 0x1 ? C1 : C0; update_flags(opts, flag_mask); - } +} void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) { @@ -2012,11 +2012,11 @@ void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { //leave supervisor mode swap_ssp_usp(opts); - } - call(code, opts->do_sync); } + call(code, opts->do_sync); + } cycles(&opts->gen, 12); - } else { + } else { if (src_op->base != opts->gen.scratch1) { if (src_op->mode == MODE_REG_DIRECT) { mov_rr(code, src_op->base, opts->gen.scratch1, SZ_W); @@ -2026,24 +2026,24 @@ void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src } call(code, inst->op == M68K_MOVE_SR ? opts->set_sr : opts->set_ccr); cycles(&opts->gen, 12); - } - } + } +} void translate_m68k_stop(m68k_options *opts, m68kinst *inst) { - //TODO: Trap if not in system mode - //manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction - //possibly even 12 since that's how long MOVE to SR takes + //TODO: Trap if not in system mode + //manual says 4 cycles, but it has to be at least 8 since it's a 2-word instruction + //possibly even 12 since that's how long MOVE to SR takes //On further thought prefetch + the fact that this stops the CPU may make //Motorola's accounting make sense here code_info *code = &opts->gen.code; cycles(&opts->gen, BUS*2); set_all_flags(opts, inst->src.params.immed); mov_irdisp(code, (inst->src.params.immed >> 8), opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); - if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { - //leave supervisor mode + if (!((inst->src.params.immed >> 8) & (1 << BIT_SUPERVISOR))) { + //leave supervisor mode swap_ssp_usp(opts); - } + } code_ptr loop_top = code->cur; call(code, opts->do_sync); cmp_rr(code, opts->gen.limit, opts->gen.cycles, SZ_D); @@ -2057,7 +2057,7 @@ void translate_m68k_stop(m68k_options *opts, m68kinst *inst) *after_cycle_up = code->cur - (after_cycle_up+1); cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D); jcc(code, CC_C, loop_top); - } +} void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) { @@ -2066,9 +2066,9 @@ void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *sr call(code, opts->get_sr); if (dst_op->mode == MODE_REG_DIRECT) { mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_W); - } else { + } else { mov_rrdisp(code, opts->gen.scratch1, dst_op->base, dst_op->disp, SZ_W); - } + } m68k_save_result(inst, opts); } @@ -2114,8 +2114,8 @@ void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst) if (next_inst == old_end && next_inst - code->cur < 2) { while (code->cur < old_end) { *(code->cur++) = 0x90; //NOP - } - } else { + } + } else { jmp(code, next_inst); } } @@ -2141,7 +2141,7 @@ m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context) mov_rr(code, RAX, options->gen.scratch1, SZ_PTR); call(code, options->gen.load_context); jmp_r(code, options->gen.scratch1); - } + } jmp(&orig, options->retrans_stub); } return context; -- cgit v1.2.3 From 882b6ddf738a529c15f45f9d058dc753bc354b50 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 8 Jan 2015 19:11:56 -0800 Subject: Moved translate_m68k_rte and translate_m68k_reset to m68k_core.c --- m68k_core.c | 26 ++++++++++++++++++++++++++ m68k_core_x86.c | 54 +++++++++++++----------------------------------------- m68k_internal.h | 3 +-- 3 files changed, 40 insertions(+), 43 deletions(-) diff --git a/m68k_core.c b/m68k_core.c index fbd8923..6b0484a 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -503,6 +503,32 @@ void swap_ssp_usp(m68k_options * opts) native_to_areg(opts, opts->gen.scratch2, 8); } +void translate_m68k_reset(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + call(code, opts->gen.save_context); + call_args(code, (code_ptr)print_regs_exit, 1, opts->gen.context_reg); +} + +void translate_m68k_rte(m68k_options *opts, m68kinst *inst) +{ + code_info *code = &opts->gen.code; + //TODO: Trap if not in system mode + //Read saved SR + areg_to_native(opts, 7, opts->gen.scratch1); + call(code, opts->read_16); + addi_areg(opts, 2, 7); + call(code, opts->set_sr); + //Read saved PC + areg_to_native(opts, 7, opts->gen.scratch1); + call(code, opts->read_32); + addi_areg(opts, 4, 7); + check_user_mode_swap_ssp_usp(opts); + //Get native address, sync components, recalculate integer points and jump to returned address + call(code, opts->native_addr_and_sync); + jmp_r(code, opts->gen.scratch1); +} + code_ptr get_native_address(native_map_slot * native_code_map, uint32_t address) { address &= 0xFFFFFF; diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 285a1dd..d59b9bd 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -543,6 +543,17 @@ void m68k_save_result(m68kinst * inst, m68k_options * opts) } } +void check_user_mode_swap_ssp_usp(m68k_options *opts) +{ + code_info * code = &opts->gen.code; + //Check if we've switched to user mode and swap stack pointers if needed + bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); + code_ptr end_off = code->cur + 1; + jcc(code, CC_C, code->cur + 2); + swap_ssp_usp(opts); + *end_off = code->cur - (end_off + 1); +} + void translate_m68k_move(m68k_options * opts, m68kinst * inst) { code_info *code = &opts->gen.code; @@ -2072,37 +2083,6 @@ void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *sr m68k_save_result(inst, opts); } -void translate_m68k_reset(m68k_options *opts, m68kinst *inst) -{ - code_info *code = &opts->gen.code; - call(code, opts->gen.save_context); - call_args(code, (code_ptr)print_regs_exit, 1, opts->gen.context_reg); -} - -void translate_m68k_rte(m68k_options *opts, m68kinst *inst) -{ - code_info *code = &opts->gen.code; - //TODO: Trap if not in system mode - //Read saved SR - areg_to_native(opts, 7, opts->gen.scratch1); - call(code, opts->read_16); - addi_areg(opts, 2, 7); - call(code, opts->set_sr); - //Read saved PC - areg_to_native(opts, 7, opts->gen.scratch1); - call(code, opts->read_32); - addi_areg(opts, 4, 7); - //Check if we've switched to user mode and swap stack pointers if needed - bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); - code_ptr end_off = code->cur + 1; - jcc(code, CC_C, code->cur + 2); - swap_ssp_usp(opts); - *end_off = code->cur - (end_off+1); - //Get native address, sync components, recalculate integer points and jump to returned address - call(code, opts->native_addr_and_sync); - jmp_r(code, opts->gen.scratch1); -} - void translate_out_of_bounds(code_info *code) { xor_rr(code, RDI, RDI, SZ_D); @@ -2459,11 +2439,7 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu //set target cycle to sync cycle mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.limit, SZ_D); //swap USP and SSP if not already in supervisor mode - bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); - code_ptr already_supervisor = code->cur + 1; - jcc(code, CC_C, code->cur + 2); - swap_ssp_usp(opts); - *already_supervisor = code->cur - (already_supervisor+1); + check_user_mode_swap_ssp_usp(opts); //save PC subi_areg(opts, 4, 7); areg_to_native(opts, 7, opts->gen.scratch2); @@ -2493,11 +2469,7 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu opts->trap = code->cur; push_r(code, opts->gen.scratch2); //swap USP and SSP if not already in supervisor mode - bt_irdisp(code, 5, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); - already_supervisor = code->cur + 1; - jcc(code, CC_C, code->cur + 2); - swap_ssp_usp(opts); - *already_supervisor = code->cur - (already_supervisor+1); + check_user_mode_swap_ssp_usp(opts); //save PC subi_areg(opts, 4, 7); areg_to_native(opts, 7, opts->gen.scratch2); diff --git a/m68k_internal.h b/m68k_internal.h index a556505..fe77e78 100644 --- a/m68k_internal.h +++ b/m68k_internal.h @@ -31,6 +31,7 @@ void calc_areg_displace(m68k_options *opts, m68k_op_info *op, uint8_t native_reg void calc_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg); void calc_areg_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg); void nop_fill_or_jmp_next(code_info *code, code_ptr old_end, code_ptr next_inst); +void check_user_mode_swap_ssp_usp(m68k_options *opts); //functions implemented in m68k_core.c int8_t native_reg(m68k_op_info * op, m68k_options * opts); @@ -83,8 +84,6 @@ void translate_m68k_eori_ccr_sr(m68k_options *opts, m68kinst *inst); void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); void translate_m68k_stop(m68k_options *opts, m68kinst *inst); void translate_m68k_move_from_sr(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op); -void translate_m68k_reset(m68k_options *opts, m68kinst *inst); -void translate_m68k_rte(m68k_options *opts, m68kinst *inst); //flag update bits #define X0 0x0001 -- cgit v1.2.3 From 7565848dd7a5d4dd1f762aeebd31d5835fe14835 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 8 Jan 2015 21:00:21 -0800 Subject: Moved m68k_save_result to m68k_core.c --- m68k_core.c | 22 ++++++++++++++++++++++ m68k_core_x86.c | 22 ---------------------- m68k_internal.h | 1 + 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/m68k_core.c b/m68k_core.c index 6b0484a..63133a1 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -86,6 +86,28 @@ void m68k_write_size(m68k_options *opts, uint8_t size) } } +void m68k_save_result(m68kinst * inst, m68k_options * opts) +{ + code_info *code = &opts->gen.code; + if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_UNUSED) { + if (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->src.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) { + areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2); + } + switch (inst->extra.size) + { + case OPSIZE_BYTE: + call(code, opts->write_8); + break; + case OPSIZE_WORD: + call(code, opts->write_16); + break; + case OPSIZE_LONG: + call(code, opts->write_32_lowfirst); + break; + } + } +} + void translate_m68k_lea_pea(m68k_options * opts, m68kinst * inst) { code_info *code = &opts->gen.code; diff --git a/m68k_core_x86.c b/m68k_core_x86.c index d59b9bd..938b071 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -521,28 +521,6 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8 } } -void m68k_save_result(m68kinst * inst, m68k_options * opts) -{ - code_info *code = &opts->gen.code; - if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_UNUSED) { - if (inst->dst.addr_mode == MODE_AREG_PREDEC && inst->src.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) { - areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2); - } - switch (inst->extra.size) - { - case OPSIZE_BYTE: - call(code, opts->write_8); - break; - case OPSIZE_WORD: - call(code, opts->write_16); - break; - case OPSIZE_LONG: - call(code, opts->write_32_lowfirst); - break; - } - } -} - void check_user_mode_swap_ssp_usp(m68k_options *opts) { code_info * code = &opts->gen.code; diff --git a/m68k_internal.h b/m68k_internal.h index fe77e78..755fd99 100644 --- a/m68k_internal.h +++ b/m68k_internal.h @@ -42,6 +42,7 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8 void print_regs_exit(m68k_context * context); void m68k_read_size(m68k_options *opts, uint8_t size); void m68k_write_size(m68k_options *opts, uint8_t size); +void m68k_save_result(m68kinst * inst, m68k_options * opts); void push_const(m68k_options *opts, int32_t value); void jump_m68k_abs(m68k_options * opts, uint32_t address); void swap_ssp_usp(m68k_options * opts); -- cgit v1.2.3 From d42234e4af41481a3db6f6ea5173bb1623b30d22 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 8 Jan 2015 23:20:41 -0800 Subject: A couple more indentation fixes --- m68k_core_x86.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 938b071..9787b9c 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -649,7 +649,7 @@ void translate_m68k_move(m68k_options * opts, m68kinst * inst) mov_ir(code, inst->address, opts->gen.scratch2, SZ_D); if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) { push_r(code, opts->gen.scratch1); - } + } calc_index_disp8(opts, &inst->dst, opts->gen.scratch2); if (src.base == opts->gen.scratch1 && !(inst->dst.params.regs.sec & 1)) { pop_r(code, opts->gen.scratch1); @@ -691,7 +691,7 @@ void translate_m68k_move(m68k_options * opts, m68kinst * inst) if (inst->dst.addr_mode != MODE_AREG) { cmp_ir(code, 0, flags_reg, inst->extra.size); update_flags(opts, N|Z|V0|C0); -} + } if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG) { m68k_write_size(opts, inst->extra.size); if (inst->dst.addr_mode == MODE_AREG_POSTINC) { -- cgit v1.2.3 From f439d8688758710b74d4909e77ebce6444b8a448 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 14 Jan 2015 09:38:54 -0800 Subject: Removed hardcoded assumptions in M68K core about which parts of the memory map are RAM --- backend.c | 25 +++++++++++++++++++++ backend.h | 2 ++ backend_x86.c | 8 ++++++- blastem.c | 29 ++++++++++++------------- m68k_core.c | 67 ++++++++++++++++++++++++++++++++++++++++++--------------- m68k_core.h | 4 ++-- m68k_core_x86.c | 8 +++++-- 7 files changed, 106 insertions(+), 37 deletions(-) diff --git a/backend.c b/backend.c index 8f65f25..1f9e718 100644 --- a/backend.c +++ b/backend.c @@ -72,3 +72,28 @@ void * get_native_pointer(uint32_t address, void ** mem_pointers, cpu_options * } return NULL; } + +uint32_t chunk_size(cpu_options *opts, memmap_chunk const *chunk) +{ + if (chunk->mask == opts->address_mask) { + return chunk->end - chunk->start; + } else { + return chunk->mask + 1; + } +} + +uint32_t ram_size(cpu_options *opts) +{ + uint32_t size = 0; + for (int i = 0; i < opts->memmap_chunks; i++) + { + if ((opts->memmap[i].flags & (MMAP_WRITE | MMAP_CODE)) == (MMAP_WRITE | MMAP_CODE)) { + if (opts->memmap[i].mask == opts->address_mask) { + size += opts->memmap[i].end - opts->memmap[i].start; + } else { + size += opts->memmap[i].mask + 1; + } + } + } + return size; +} diff --git a/backend.h b/backend.h index c3ae875..2b95d06 100644 --- a/backend.h +++ b/backend.h @@ -116,6 +116,8 @@ void check_code_prologue(code_info *code); code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc); void * get_native_pointer(uint32_t address, void ** mem_pointers, cpu_options * opts); +uint32_t chunk_size(cpu_options *opts, memmap_chunk const *chunk); +uint32_t ram_size(cpu_options *opts); #endif //BACKEND_H_ diff --git a/backend_x86.c b/backend_x86.c index 7c289de..5a1f5d5 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -50,6 +50,7 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n uint8_t adr_reg = is_write ? opts->scratch2 : opts->scratch1; uint16_t access_flag = is_write ? MMAP_WRITE : MMAP_READ; uint8_t size = (fun_type == READ_16 || fun_type == WRITE_16) ? SZ_W : SZ_B; + uint32_t ram_flags_off = opts->ram_flags_off; for (uint32_t chunk = 0; chunk < num_chunks; chunk++) { if (memmap[chunk].start > 0) { @@ -173,7 +174,12 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n if (is_write && (memmap[chunk].flags & MMAP_CODE)) { mov_rr(code, opts->scratch2, opts->scratch1, opts->address_size); shr_ir(code, opts->ram_flags_shift, opts->scratch1, opts->address_size); - bt_rrdisp(code, opts->scratch1, opts->context_reg, opts->ram_flags_off, opts->address_size); + bt_rrdisp(code, opts->scratch1, opts->context_reg, ram_flags_off, opts->address_size); + if (memmap[chunk].mask == opts->address_mask) { + ram_flags_off += memmap[chunk].end - memmap[chunk].start; + } else { + ram_flags_off += memmap[chunk].mask + 1; + } code_ptr not_code = code->cur + 1; jcc(code, CC_NC, code->cur + 2); call(code, opts->save_context); diff --git a/blastem.c b/blastem.c index 684f644..27b9d07 100644 --- a/blastem.c +++ b/blastem.c @@ -901,9 +901,7 @@ void save_sram() void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, uint8_t * debugger) { - m68k_context context; m68k_options opts; - gen->m68k = &context; memmap_chunk memmap[MAX_MAP_CHUNKS]; uint32_t num_chunks; void * initial_mapped = NULL; @@ -998,21 +996,22 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u } init_m68k_opts(&opts, memmap, num_chunks, MCLKS_PER_68K); opts.address_log = address_log; - init_68k_context(&context, opts.gen.native_code_map, &opts); + m68k_context *context = init_68k_context(&opts); + gen->m68k = context; - context.video_context = gen->vdp; - context.system = gen; + context->video_context = gen->vdp; + context->system = gen; //cartridge ROM - context.mem_pointers[0] = cart; - context.target_cycle = context.sync_cycle = mclk_target; + context->mem_pointers[0] = cart; + context->target_cycle = context->sync_cycle = mclk_target; //work RAM - context.mem_pointers[1] = ram; + context->mem_pointers[1] = ram; //save RAM/map - context.mem_pointers[2] = initial_mapped; - context.mem_pointers[3] = (uint16_t *)gen->save_ram; + context->mem_pointers[2] = initial_mapped; + context->mem_pointers[3] = (uint16_t *)gen->save_ram; uint32_t address; address = cart[2] << 16 | cart[3]; - translate_m68k_stream(address, &context); + translate_m68k_stream(address, context); if (statefile) { uint32_t pc = load_gst(gen, statefile); if (!pc) { @@ -1021,15 +1020,15 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u } printf("Loaded %s\n", statefile); if (debugger) { - insert_breakpoint(&context, pc, debugger); + insert_breakpoint(context, pc, debugger); } adjust_int_cycle(gen->m68k, gen->vdp); - start_68k_context(&context, pc); + start_68k_context(context, pc); } else { if (debugger) { - insert_breakpoint(&context, address, debugger); + insert_breakpoint(context, address, debugger); } - m68k_reset(&context); + m68k_reset(context); } } diff --git a/m68k_core.c b/m68k_core.c index 63133a1..ff6278c 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -553,6 +553,7 @@ void translate_m68k_rte(m68k_options *opts, m68kinst *inst) code_ptr get_native_address(native_map_slot * native_code_map, uint32_t address) { + //FIXME: Use opts->gen.address_mask address &= 0xFFFFFF; address /= 2; uint32_t chunk = address / NATIVE_CHUNK_SIZE; @@ -573,6 +574,7 @@ code_ptr get_native_from_context(m68k_context * context, uint32_t address) uint32_t get_instruction_start(native_map_slot * native_code_map, uint32_t address) { + //FIXME: Use opts->gen.address_mask address &= 0xFFFFFF; address /= 2; uint32_t chunk = address / NATIVE_CHUNK_SIZE; @@ -595,17 +597,34 @@ void map_native_address(m68k_context * context, uint32_t address, code_ptr nativ { native_map_slot * native_code_map = context->native_code_map; m68k_options * opts = context->options; - address &= 0xFFFFFF; - if (address > 0xE00000) { - context->ram_code_flags[(address & 0xC000) >> 14] |= 1 << ((address & 0x3800) >> 11); - if (((address & 0x3FFF) + size) & 0xC000) { - context->ram_code_flags[((address+size) & 0xC000) >> 14] |= 1 << (((address+size) & 0x3800) >> 11); - } - uint32_t slot = (address & 0xFFFF)/1024; - if (!opts->gen.ram_inst_sizes[slot]) { - opts->gen.ram_inst_sizes[slot] = malloc(sizeof(uint8_t) * 512); + address &= opts->gen.address_mask; + uint32_t meta_off = 0; + //TODO: Refactor part of this loop into some kind of get_ram_chunk function + for (int i = 0; i < opts->gen.memmap_chunks; i++) { + if (address >= opts->gen.memmap[i].start && address < opts->gen.memmap[i].end) { + if ((opts->gen.memmap[i].flags & (MMAP_WRITE | MMAP_CODE)) == (MMAP_WRITE | MMAP_CODE)) { + uint32_t masked = (address & opts->gen.memmap[i].mask); + uint32_t final_off = masked + meta_off; + uint32_t ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3); + context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 3); + + uint32_t slot = final_off / 1024; + if (!opts->gen.ram_inst_sizes[slot]) { + opts->gen.ram_inst_sizes[slot] = malloc(sizeof(uint8_t) * 512); + } + opts->gen.ram_inst_sizes[slot][(final_off/2) & 511] = native_size; + + //TODO: Deal with case in which end of instruction is in a different memory chunk + masked = (address + size - 1) & opts->gen.memmap[i].mask; + final_off = masked + meta_off; + ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3); + context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 3); + } + break; + } else if ((opts->gen.memmap[i].flags & (MMAP_WRITE | MMAP_CODE)) == (MMAP_WRITE | MMAP_CODE)) { + uint32_t size = chunk_size(&opts->gen, opts->gen.memmap + i); + meta_off += size; } - opts->gen.ram_inst_sizes[slot][((address & 0xFFFF)/2)%512] = native_size; } address/= 2; uint32_t chunk = address / NATIVE_CHUNK_SIZE; @@ -630,11 +649,22 @@ void map_native_address(m68k_context * context, uint32_t address, code_ptr nativ uint8_t get_native_inst_size(m68k_options * opts, uint32_t address) { - if (address < 0xE00000) { - return 0; + address &= opts->gen.address_mask; + uint32_t meta_off = 0; + for (int i = 0; i < opts->gen.memmap_chunks; i++) { + if (address >= opts->gen.memmap[i].start && address < opts->gen.memmap[i].end) { + if ((opts->gen.memmap[i].flags & (MMAP_WRITE | MMAP_CODE)) != (MMAP_WRITE | MMAP_CODE)) { + return 0; + } + meta_off += address & opts->gen.memmap[i].mask; + break; + } else if ((opts->gen.memmap[i].flags & (MMAP_WRITE | MMAP_CODE)) == (MMAP_WRITE | MMAP_CODE)) { + uint32_t size = chunk_size(&opts->gen, opts->gen.memmap + i); + meta_off += size; + } } - uint32_t slot = (address & 0xFFFF)/1024; - return opts->gen.ram_inst_sizes[slot][((address & 0xFFFF)/2)%512]; + uint32_t slot = meta_off/1024; + return opts->gen.ram_inst_sizes[slot][(meta_off/2)%512]; } uint8_t m68k_is_terminal(m68kinst * inst) @@ -926,6 +956,7 @@ void * m68k_retranslate_inst(uint32_t address, m68k_context * context) code_ptr get_native_address_trans(m68k_context * context, uint32_t address) { + //FIXME: Use opts->gen.address_mask address &= 0xFFFFFF; code_ptr ret = get_native_address(context->native_code_map, address); if (!ret) { @@ -962,11 +993,13 @@ void m68k_reset(m68k_context * context) } -void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts) +m68k_context * init_68k_context(m68k_options * opts) { + m68k_context * context = malloc(sizeof(m68k_context) + ram_size(&opts->gen) / (1 << opts->gen.ram_flags_shift) / 8); memset(context, 0, sizeof(m68k_context)); - context->native_code_map = native_code_map; + context->native_code_map = opts->gen.native_code_map; context->options = opts; - context->int_cycle = 0xFFFFFFFF; + context->int_cycle = CYCLE_NEVER; context->status = 0x27; + return context; } diff --git a/m68k_core.h b/m68k_core.h index cf43864..2635a09 100644 --- a/m68k_core.h +++ b/m68k_core.h @@ -60,15 +60,15 @@ typedef struct { native_map_slot *native_code_map; m68k_options *options; - uint8_t ram_code_flags[32/8]; void *system; + uint8_t ram_code_flags[]; } m68k_context; void translate_m68k(m68k_options * opts, struct m68kinst * inst); void translate_m68k_stream(uint32_t address, m68k_context * context); void start_68k_context(m68k_context * context, uint32_t address); void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider); -void init_68k_context(m68k_context * context, native_map_slot * native_code_map, void * opts); +m68k_context * init_68k_context(m68k_options * opts); void m68k_reset(m68k_context * context); void insert_breakpoint(m68k_context * context, uint32_t address, uint8_t * bp_handler); void remove_breakpoint(m68k_context * context, uint32_t address); diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 9787b9c..167c740 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -2202,8 +2202,10 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu opts->gen.native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS); memset(opts->gen.native_code_map, 0, sizeof(native_map_slot) * NATIVE_MAP_CHUNKS); opts->gen.deferred = NULL; - opts->gen.ram_inst_sizes = malloc(sizeof(uint8_t *) * 64); - memset(opts->gen.ram_inst_sizes, 0, sizeof(uint8_t *) * 64); + + uint32_t inst_size_size = sizeof(uint8_t *) * ram_size(&opts->gen) / 1024; + opts->gen.ram_inst_sizes = malloc(inst_size_size); + memset(opts->gen.ram_inst_sizes, 0, inst_size_size); code_info *code = &opts->gen.code; init_code_info(code); @@ -2227,9 +2229,11 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu opts->gen.load_context = code->cur; for (int i = 0; i < 5; i++) + { if (opts->flag_regs[i] >= 0) { mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, flags) + i, opts->flag_regs[i], SZ_B); } + } for (int i = 0; i < 8; i++) { if (opts->dregs[i] >= 0) { -- cgit v1.2.3 From 543e7e93904092da8c12149c83304c0d64a5e789 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 14 Mar 2015 12:05:03 -0700 Subject: WIP of functions to determine size of x86 instruction to allow patching of arbitrary pieces of code --- gen_x86.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/gen_x86.c b/gen_x86.c index cbae264..7531cd9 100644 --- a/gen_x86.c +++ b/gen_x86.c @@ -2069,3 +2069,78 @@ void restore_callee_save_regs(code_info *code) pop_r(code, RBP); pop_r(code, RBX); } + +uint8_t has_modrm(uint8_t prefix, uint8_t opcode) +{ + if (!prefix) { + switch (opcode) + { + case OP_JMP: + case OP_JMP_BYTE: + case OP_JCC: + case OP_CALL: + case OP_RETN: + case OP_LOOP: + case OP_MOV_I8R: + case OP_MOV_IR: + case OP_PUSHF: + case OP_POPF: + case OP_PUSH: + case OP_POP: + case OP_CDQ: + return 0; + } + } else if (prefix == PRE_2BYTE) { + switch (opcode) + { + case OP2_JCC: + return 0; + } + } + return 1; +} + +uint8_t has_sib(uint8_t mod_rm) +{ + uint8_t mode = mod_rm & 0xC0; + uint8_t rm = mod_rm & 3; + + return mode != MODE_REG_DIRECT && rm == RSP; +} + +uint32_t x86_inst_size(code_ptr start) +{ + code_ptr code = start; + uint8_t cont = 1; + uint8_t prefix = 0; + uint8_t op_size = SZ_B; + uint8_t main_op; + + while (cont) + { + if (*code == PRE_SIZE) { + op_size = SZ_W; + } else if (*code == PRE_REX) { + if (*code & REX_QUAD) { + op_size = SZ_Q; + } + } else if(*code == PRE_2BYTE || PRE_XOP) { + prefix = *code; + } else { + main_op = *code; + cont = 0; + } + code++; + } + if (has_modrm(prefix, main_op)) { + uint8_t mod_rm = *(code++); + if (has_sib(mod_rm)) { + uint8_t sib = *(code++); + } else { + + } + } else { + } + + return code-start; +} -- cgit v1.2.3 From 46b4c104c2447d9081122696a43094d0cb987de3 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 28 Apr 2015 19:04:36 -0700 Subject: Fix bug in map_native_address that was breaking some self-modifying code in Gunstar Heroes --- backend_x86.c | 1 + gen_x86.c | 12 +++++++++--- m68k_core.c | 4 ++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/backend_x86.c b/backend_x86.c index 5a1f5d5..d606886 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -175,6 +175,7 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n mov_rr(code, opts->scratch2, opts->scratch1, opts->address_size); shr_ir(code, opts->ram_flags_shift, opts->scratch1, opts->address_size); bt_rrdisp(code, opts->scratch1, opts->context_reg, ram_flags_off, opts->address_size); + //FIXME: These adjustments to ram_flags_off need to take into account bits vs bytes and ram_flags_shift if (memmap[chunk].mask == opts->address_mask) { ram_flags_off += memmap[chunk].end - memmap[chunk].start; } else { diff --git a/gen_x86.c b/gen_x86.c index 7531cd9..ef5fbe5 100644 --- a/gen_x86.c +++ b/gen_x86.c @@ -2135,9 +2135,15 @@ uint32_t x86_inst_size(code_ptr start) if (has_modrm(prefix, main_op)) { uint8_t mod_rm = *(code++); if (has_sib(mod_rm)) { - uint8_t sib = *(code++); - } else { - + //sib takes up a byte, but can't add any additional ones beyond that + code++; + } + uint8_t mode = mod_rm & 0xC0; + uint8_t rm = mod_rm & 3; + if (mode == MODE_REG_DISPLACE8) { + code++; + } else if (mode == MODE_REG_DISPLACE32 || (mode == MODE_REG_INDIRECT && rm == RBP)) { + code += 4; } } else { } diff --git a/m68k_core.c b/m68k_core.c index ff6278c..d3125a9 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -606,7 +606,7 @@ void map_native_address(m68k_context * context, uint32_t address, code_ptr nativ uint32_t masked = (address & opts->gen.memmap[i].mask); uint32_t final_off = masked + meta_off; uint32_t ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3); - context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 3); + context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 7); uint32_t slot = final_off / 1024; if (!opts->gen.ram_inst_sizes[slot]) { @@ -618,7 +618,7 @@ void map_native_address(m68k_context * context, uint32_t address, code_ptr nativ masked = (address + size - 1) & opts->gen.memmap[i].mask; final_off = masked + meta_off; ram_flags_off = final_off >> (opts->gen.ram_flags_shift + 3); - context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 3); + context->ram_code_flags[ram_flags_off] |= 1 << ((final_off >> opts->gen.ram_flags_shift) & 7); } break; } else if ((opts->gen.memmap[i].flags & (MMAP_WRITE | MMAP_CODE)) == (MMAP_WRITE | MMAP_CODE)) { -- cgit v1.2.3 From d11ec6908700a7eb34c326159826fcfbd04c1ab6 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 30 Apr 2015 19:28:01 -0700 Subject: Fix missing call to setup_io_devices --- blastem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/blastem.c b/blastem.c index 27b9d07..e278488 100644 --- a/blastem.c +++ b/blastem.c @@ -1292,6 +1292,7 @@ int main(int argc, char ** argv) gen.ym = &y_context; gen.psg = &p_context; genesis = &gen; + setup_io_devices(config, gen.ports); int fname_size = strlen(romfname); sram_filename = malloc(fname_size+6); -- cgit v1.2.3 From 63a7a70313c8915f79904a99367e3b7d21a98220 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 30 Apr 2015 19:28:18 -0700 Subject: Adjust TH timeout value to take into account the move to master clock cycles --- io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io.c b/io.c index 3ec8672..3f76d90 100644 --- a/io.c +++ b/io.c @@ -750,7 +750,7 @@ void set_keybindings(io_port *ports) } #define TH 0x40 -#define TH_TIMEOUT 8000 +#define TH_TIMEOUT 56000 void io_adjust_cycles(io_port * port, uint32_t current_cycle, uint32_t deduction) { -- cgit v1.2.3 From d9ede1d212bee27df782abffdc1817203358f621 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 4 May 2015 08:48:10 -0700 Subject: Indentation fixup --- blastem.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/blastem.c b/blastem.c index e278488..fe2ba8b 100644 --- a/blastem.c +++ b/blastem.c @@ -210,21 +210,21 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) z80_context * z_context = gen->z80; uint32_t mclks = context->current_cycle; sync_z80(z_context, mclks); - sync_sound(gen, mclks); + sync_sound(gen, mclks); if (mclks >= mclk_target) { vdp_run_context(v_context, mclk_target); if (vdp_is_frame_over(v_context)) { //printf("reached frame end | MCLK Cycles: %d, Target: %d, VDP cycles: %d\n", mclks, mclk_target, v_context->cycles); - if (!headless) { - break_on_sync |= wait_render_frame(v_context, frame_limit); - } else if(exit_after){ - --exit_after; - if (!exit_after) { - exit(0); + if (!headless) { + break_on_sync |= wait_render_frame(v_context, frame_limit); + } else if(exit_after){ + --exit_after; + if (!exit_after) { + exit(0); + } } - } - frame++; + frame++; mclks -= mclk_target; vdp_adjust_cycles(v_context, mclk_target); io_adjust_cycles(gen->ports, context->current_cycle, mclk_target); @@ -239,7 +239,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) } if (mclks) { vdp_run_context(v_context, mclks); - } + } mclk_target = vdp_cycles_to_frame_end(v_context); context->sync_cycle = mclk_target; } else { @@ -257,9 +257,9 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) adjust_int_cycle(context, v_context); if (address) { if (break_on_sync) { - break_on_sync = 0; - debugger(context, address); - } + break_on_sync = 0; + debugger(context, address); + } if (save_state) { save_state = 0; //advance Z80 core to the start of an instruction -- cgit v1.2.3 From 89ca3bce585f06927569ed1f18ad433d33e320e9 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 5 May 2015 08:42:27 -0700 Subject: Added config option to allow specifying a max sync cycle smaller than the end of frame --- blastem.c | 53 ++++++++++++++++++++++++++++------------------------- blastem.h | 2 ++ 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/blastem.c b/blastem.c index fe2ba8b..51a39b1 100644 --- a/blastem.c +++ b/blastem.c @@ -33,8 +33,6 @@ #define MAX_SOUND_CYCLES 100000 -uint32_t mclk_target = 0; - uint16_t cart[CARTRIDGE_WORDS]; uint16_t ram[RAM_WORDS]; uint8_t z80_ram[Z80_RAM_BYTES]; @@ -127,6 +125,10 @@ uint16_t read_dma_value(uint32_t address) void adjust_int_cycle(m68k_context * context, vdp_context * v_context) { + genesis_context *gen = context->system; + if (context->sync_cycle - context->current_cycle > gen->max_cycles) { + context->sync_cycle = context->current_cycle + gen->max_cycles; + } context->int_cycle = CYCLE_NEVER; if ((context->status & 0x7) < 6) { uint32_t next_vint = vdp_next_vint(v_context); @@ -204,17 +206,16 @@ void sync_sound(genesis_context * gen, uint32_t target) uint32_t frame=0; m68k_context * sync_components(m68k_context * context, uint32_t address) { - //TODO: Handle sync targets smaller than a single frame genesis_context * gen = context->system; vdp_context * v_context = gen->vdp; z80_context * z_context = gen->z80; uint32_t mclks = context->current_cycle; sync_z80(z_context, mclks); sync_sound(gen, mclks); - if (mclks >= mclk_target) { - vdp_run_context(v_context, mclk_target); + if (mclks >= gen->frame_end) { + vdp_run_context(v_context, gen->frame_end); if (vdp_is_frame_over(v_context)) { - //printf("reached frame end | MCLK Cycles: %d, Target: %d, VDP cycles: %d\n", mclks, mclk_target, v_context->cycles); + //printf("reached frame end | MCLK Cycles: %d, Target: %d, VDP cycles: %d\n", mclks, gen->frame_end, v_context->cycles); if (!headless) { break_on_sync |= wait_render_frame(v_context, frame_limit); @@ -225,27 +226,27 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) } } frame++; - mclks -= mclk_target; - vdp_adjust_cycles(v_context, mclk_target); - io_adjust_cycles(gen->ports, context->current_cycle, mclk_target); - io_adjust_cycles(gen->ports+1, context->current_cycle, mclk_target); - io_adjust_cycles(gen->ports+2, context->current_cycle, mclk_target); - context->current_cycle -= mclk_target; - z80_adjust_cycles(z_context, mclk_target); - gen->ym->current_cycle -= mclk_target; - gen->psg->cycles -= mclk_target; + mclks -= gen->frame_end; + vdp_adjust_cycles(v_context, gen->frame_end); + io_adjust_cycles(gen->ports, context->current_cycle, gen->frame_end); + io_adjust_cycles(gen->ports+1, context->current_cycle, gen->frame_end); + io_adjust_cycles(gen->ports+2, context->current_cycle, gen->frame_end); + context->current_cycle -= gen->frame_end; + z80_adjust_cycles(z_context, gen->frame_end); + gen->ym->current_cycle -= gen->frame_end; + gen->psg->cycles -= gen->frame_end; if (gen->ym->write_cycle != CYCLE_NEVER) { - gen->ym->write_cycle = gen->ym->write_cycle >= mclk_target ? gen->ym->write_cycle - mclk_target : 0; + gen->ym->write_cycle = gen->ym->write_cycle >= gen->frame_end ? gen->ym->write_cycle - gen->frame_end : 0; } if (mclks) { vdp_run_context(v_context, mclks); } - mclk_target = vdp_cycles_to_frame_end(v_context); - context->sync_cycle = mclk_target; + gen->frame_end = vdp_cycles_to_frame_end(v_context); } else { vdp_run_context(v_context, mclks); - mclk_target = vdp_cycles_to_frame_end(v_context); + gen->frame_end = vdp_cycles_to_frame_end(v_context); } + context->sync_cycle = gen->frame_end; } else { //printf("running VDP for %d cycles\n", mclks - v_context->cycles); vdp_run_context(v_context, mclks); @@ -290,8 +291,8 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ if (vdp_port < 4) { while (vdp_data_port_write(v_context, value) < 0) { while(v_context->flags & FLAG_DMA_RUN) { - vdp_run_dma_done(v_context, mclk_target); - if (v_context->cycles >= mclk_target) { + vdp_run_dma_done(v_context, gen->frame_end); + if (v_context->cycles >= gen->frame_end) { context->current_cycle = v_context->cycles; sync_components(context, 0); } @@ -303,8 +304,8 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ if (blocked) { while (blocked) { while(v_context->flags & FLAG_DMA_RUN) { - vdp_run_dma_done(v_context, mclk_target); - if (v_context->cycles >= mclk_target) { + vdp_run_dma_done(v_context, gen->frame_end); + if (v_context->cycles >= gen->frame_end) { context->current_cycle = v_context->cycles; sync_components(context, 0); } @@ -1003,7 +1004,7 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u context->system = gen; //cartridge ROM context->mem_pointers[0] = cart; - context->target_cycle = context->sync_cycle = mclk_target; + context->target_cycle = context->sync_cycle = gen->frame_end > gen->max_cycles ? gen->frame_end : gen->max_cycles; //work RAM context->mem_pointers[1] = ram; //save RAM/map @@ -1267,7 +1268,9 @@ int main(int argc, char ** argv) gen.master_clock = gen.normal_clock = fps == 60 ? MCLKS_NTSC : MCLKS_PAL; init_vdp_context(&v_context, version_reg & 0x40); - mclk_target = vdp_cycles_to_frame_end(&v_context); + gen.frame_end = vdp_cycles_to_frame_end(&v_context); + char * config_cycles = tern_find_ptr(config, "clocksmax_cycles"); + gen.max_cycles = config_cycles ? atoi(config_cycles) : 10000000; ym2612_context y_context; ym_init(&y_context, render_sample_rate(), gen.master_clock, MCLKS_PER_YM, render_audio_buffer(), ym_log ? YM_OPT_WAVE_LOG : 0); diff --git a/blastem.h b/blastem.h index cd75b64..680fc73 100644 --- a/blastem.h +++ b/blastem.h @@ -30,6 +30,8 @@ typedef struct { uint32_t save_flags; uint32_t master_clock; //Current master clock value uint32_t normal_clock; //Normal master clock (used to restore master clock after turbo mode) + uint32_t frame_end; + uint32_t max_cycles; uint8_t bank_regs[8]; io_port ports[3]; uint8_t bus_busy; -- cgit v1.2.3 From b3e40bd29176e1c4cf53f8542628e48e1eb5dcb0 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 11 May 2015 00:28:47 -0700 Subject: Sync fixes and logging to fix more sync issues --- backend.h | 1 + backend_x86.c | 17 ++++++++++++-- blastem.c | 71 +++++++++++++++++++++++++++++------------------------------ m68k_core.c | 1 + vdp.c | 22 +++++++++--------- vdp.h | 3 ++- z80_to_x86.c | 3 +++ 7 files changed, 67 insertions(+), 51 deletions(-) diff --git a/backend.h b/backend.h index 2b95d06..6c18675 100644 --- a/backend.h +++ b/backend.h @@ -113,6 +113,7 @@ void cycles(cpu_options *opts, uint32_t num); void check_cycles_int(cpu_options *opts, uint32_t address); void check_cycles(cpu_options * opts); void check_code_prologue(code_info *code); +void log_address(cpu_options *opts, uint32_t address, char * format); code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t num_chunks, ftype fun_type, code_ptr *after_inc); void * get_native_pointer(uint32_t address, void ** mem_pointers, cpu_options * opts); diff --git a/backend_x86.c b/backend_x86.c index d606886..75eece9 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -11,7 +11,7 @@ void check_cycles_int(cpu_options *opts, uint32_t address) code_info *code = &opts->code; cmp_rr(code, opts->cycles, opts->limit, SZ_D); code_ptr jmp_off = code->cur+1; - jcc(code, CC_NC, jmp_off+1); + jcc(code, CC_A, jmp_off+1); mov_ir(code, address, opts->scratch1, SZ_D); call(code, opts->handle_cycle_limit_int); *jmp_off = code->cur - (jmp_off+1); @@ -23,11 +23,24 @@ void check_cycles(cpu_options * opts) cmp_rr(code, opts->cycles, opts->limit, SZ_D); check_alloc_code(code, MAX_INST_LEN*2); code_ptr jmp_off = code->cur+1; - jcc(code, CC_NC, jmp_off+1); + jcc(code, CC_A, jmp_off+1); call(code, opts->handle_cycle_limit); *jmp_off = code->cur - (jmp_off+1); } +void log_address(cpu_options *opts, uint32_t address, char * format) +{ + code_info *code = &opts->code; + call(code, opts->save_context); + push_r(code, opts->context_reg); + mov_rr(code, opts->cycles, RDX, SZ_D); + mov_ir(code, (int64_t)format, RDI, SZ_PTR); + mov_ir(code, address, RSI, SZ_D); + call_args_abi(code, (code_ptr)printf, 3, RDI, RSI, RDX); + pop_r(code, opts->context_reg); + call(code, opts->load_context); +} + void check_code_prologue(code_info *code) { check_alloc_code(code, MAX_INST_LEN*4); diff --git a/blastem.c b/blastem.c index 51a39b1..9a26e4b 100644 --- a/blastem.c +++ b/blastem.c @@ -203,7 +203,7 @@ void sync_sound(genesis_context * gen, uint32_t target) //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2); } -uint32_t frame=0; +uint32_t last_frame_num; m68k_context * sync_components(m68k_context * context, uint32_t address) { genesis_context * gen = context->system; @@ -212,45 +212,37 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) uint32_t mclks = context->current_cycle; sync_z80(z_context, mclks); sync_sound(gen, mclks); - if (mclks >= gen->frame_end) { - vdp_run_context(v_context, gen->frame_end); - if (vdp_is_frame_over(v_context)) { - //printf("reached frame end | MCLK Cycles: %d, Target: %d, VDP cycles: %d\n", mclks, gen->frame_end, v_context->cycles); - - if (!headless) { - break_on_sync |= wait_render_frame(v_context, frame_limit); - } else if(exit_after){ - --exit_after; - if (!exit_after) { - exit(0); - } - } - frame++; - mclks -= gen->frame_end; - vdp_adjust_cycles(v_context, gen->frame_end); - io_adjust_cycles(gen->ports, context->current_cycle, gen->frame_end); - io_adjust_cycles(gen->ports+1, context->current_cycle, gen->frame_end); - io_adjust_cycles(gen->ports+2, context->current_cycle, gen->frame_end); - context->current_cycle -= gen->frame_end; - z80_adjust_cycles(z_context, gen->frame_end); - gen->ym->current_cycle -= gen->frame_end; - gen->psg->cycles -= gen->frame_end; - if (gen->ym->write_cycle != CYCLE_NEVER) { - gen->ym->write_cycle = gen->ym->write_cycle >= gen->frame_end ? gen->ym->write_cycle - gen->frame_end : 0; - } - if (mclks) { - vdp_run_context(v_context, mclks); + vdp_run_context(v_context, mclks); + if (v_context->frame != last_frame_num) { + //printf("reached frame end %d | MCLK Cycles: %d, Target: %d, VDP cycles: %d, vcounter: %d, hslot: %d\n", last_frame_num, mclks, gen->frame_end, v_context->cycles, v_context->vcounter, v_context->hslot); + last_frame_num = v_context->frame; + + if (!headless) { + break_on_sync |= wait_render_frame(v_context, frame_limit); + } else if(exit_after){ + --exit_after; + if (!exit_after) { + exit(0); } - gen->frame_end = vdp_cycles_to_frame_end(v_context); - } else { - vdp_run_context(v_context, mclks); - gen->frame_end = vdp_cycles_to_frame_end(v_context); } - context->sync_cycle = gen->frame_end; + + vdp_adjust_cycles(v_context, mclks); + io_adjust_cycles(gen->ports, context->current_cycle, mclks); + io_adjust_cycles(gen->ports+1, context->current_cycle, mclks); + io_adjust_cycles(gen->ports+2, context->current_cycle, mclks); + context->current_cycle -= mclks; + z80_adjust_cycles(z_context, mclks); + gen->ym->current_cycle -= mclks; + gen->psg->cycles -= mclks; + if (gen->ym->write_cycle != CYCLE_NEVER) { + gen->ym->write_cycle = gen->ym->write_cycle >= mclks ? gen->ym->write_cycle - mclks : 0; + } + gen->frame_end = vdp_cycles_to_frame_end(v_context); } else { - //printf("running VDP for %d cycles\n", mclks - v_context->cycles); - vdp_run_context(v_context, mclks); + gen->frame_end = vdp_cycles_to_frame_end(v_context); } + context->sync_cycle = gen->frame_end; + //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot); if (context->int_ack) { vdp_int_ack(v_context, context->int_ack); context->int_ack = 0; @@ -289,12 +281,15 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ int blocked; uint32_t before_cycle = v_context->cycles; if (vdp_port < 4) { + while (vdp_data_port_write(v_context, value) < 0) { while(v_context->flags & FLAG_DMA_RUN) { vdp_run_dma_done(v_context, gen->frame_end); if (v_context->cycles >= gen->frame_end) { context->current_cycle = v_context->cycles; + gen->bus_busy = 1; sync_components(context, 0); + gen->bus_busy = 0; } } //context->current_cycle = v_context->cycles; @@ -307,7 +302,9 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ vdp_run_dma_done(v_context, gen->frame_end); if (v_context->cycles >= gen->frame_end) { context->current_cycle = v_context->cycles; + gen->bus_busy = 1; sync_components(context, 0); + gen->bus_busy = 0; } } if (blocked < 0) { @@ -317,6 +314,8 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ } } } else { + context->sync_cycle = gen->frame_end = vdp_cycles_to_frame_end(v_context); + //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot); adjust_int_cycle(context, v_context); } } else { diff --git a/m68k_core.c b/m68k_core.c index d3125a9..b56b58b 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -801,6 +801,7 @@ impl_info m68k_impls[] = { void translate_m68k(m68k_options * opts, m68kinst * inst) { check_cycles_int(&opts->gen, inst->address); + log_address(&opts->gen, inst->address, "M68K: %X @ %d\n"); impl_info * info = m68k_impls + inst->op; if (info->itype == RAW_FUNC) { info->impl.raw(opts, inst); diff --git a/vdp.c b/vdp.c index 710d2ab..c760529 100644 --- a/vdp.c +++ b/vdp.c @@ -24,8 +24,8 @@ #define MCLKS_SLOT_H32 20 #define VINT_SLOT_H40 4 //21 slots before HSYNC, 16 during, 10 after #define VINT_SLOT_H32 23 //33 slots before HSYNC, 20 during, 7 after TODO: confirm final number -#define HSYNC_SLOT_H40 240 -#define HSYNC_END_H40 (240+17) +#define HSYNC_SLOT_H40 234 +#define HSYNC_END_H40 (HSYNC_SLOT_H40+17) #define HSYNC_END_H32 (33 * MCLKS_SLOT_H32) #define HBLANK_START_H40 178 //should be 179 according to Nemesis, but 178 seems to fit slightly better with my test ROM results #define HBLANK_END_H40 0 //should be 5.5 according to Nemesis, but 0 seems to fit better with my test ROM results @@ -1420,7 +1420,7 @@ void check_render_bg(vdp_context * context, int32_t line, uint32_t slot) } } -uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 19, 20, 20, 20, 19, 20, 20, 20, 19, 20, 20, 20, 19}; +uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19}; void vdp_run_context(vdp_context * context, uint32_t target_cycles) { @@ -1428,12 +1428,13 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) { context->flags &= ~FLAG_UNUSED_SLOT; uint32_t line = context->vcounter; - uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; uint32_t slot = context->hslot; - //TODO: Figure out when this actually happens + if (!line && !slot) { + //TODO: Figure out when this actually happens latch_mode(context); } + uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; if (is_h40) { @@ -1455,6 +1456,9 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) } if (is_h40 && slot == LINE_CHANGE_H40 || !is_h40 && slot == LINE_CHANGE_H32) { if (line >= inactive_start) { + if (line == (inactive_start + 8)) { + context->frame++; + } context->hint_counter = context->regs[REG_HINT]; } else if (context->hint_counter) { context->hint_counter--; @@ -1824,7 +1828,7 @@ uint32_t vdp_cycles_next_line(vdp_context * context) { if (context->regs[REG_MODE_4] & BIT_H40) { if (context->hslot < LINE_CHANGE_H40) { - return (HBLANK_START_H40 - context->hslot) * MCLKS_SLOT_H40; + return (LINE_CHANGE_H40 - context->hslot) * MCLKS_SLOT_H40; } else if (context->hslot < 183) { return MCLKS_LINE - (context->hslot - LINE_CHANGE_H40) * MCLKS_SLOT_H40; } else if (context->hslot < HSYNC_END_H40){ @@ -1916,12 +1920,6 @@ uint32_t vdp_cycles_to_frame_end(vdp_context * context) return context->cycles + vdp_cycles_to_line(context, vdp_frame_end_line(context)); } -uint8_t vdp_is_frame_over(vdp_context * context) -{ - uint32_t frame_end = vdp_frame_end_line(context); - return context->vcounter >= frame_end && context->vcounter < (frame_end + 8); -} - uint32_t vdp_next_hint(vdp_context * context) { if (!(context->regs[REG_MODE_1] & BIT_HINT_EN)) { diff --git a/vdp.h b/vdp.h index 70c0953..31bd4e7 100644 --- a/vdp.h +++ b/vdp.h @@ -143,6 +143,7 @@ typedef struct { uint32_t colors[CRAM_SIZE*3]; uint32_t debugcolors[1 << (3 + 1 + 1 + 1)];//3 bits for source, 1 bit for priority, 1 bit for shadow, 1 bit for hilight uint16_t vsram[VSRAM_SIZE]; + uint32_t frame; uint16_t vcounter; uint16_t hslot; //hcounter/2 uint16_t hscroll_a; @@ -194,7 +195,7 @@ void vdp_print_sprite_table(vdp_context * context); void vdp_print_reg_explain(vdp_context * context); void latch_mode(vdp_context * context); uint32_t vdp_cycles_to_frame_end(vdp_context * context); -uint8_t vdp_is_frame_over(vdp_context * context); +uint32_t vdp_frame_end_line(vdp_context *context); extern int32_t color_map[1 << 12]; diff --git a/z80_to_x86.c b/z80_to_x86.c index fab31da..6b498f5 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -309,6 +309,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, if (context->breakpoint_flags[address / sizeof(uint8_t)] & (1 << (address % sizeof(uint8_t)))) { zbreakpoint_patch(context, address, start); } + //log_address(&opts->gen, address, "Z80: %X @ %d\n"); } switch(inst->op) { @@ -2293,7 +2294,9 @@ void z80_clear_reset(z80_context * context, uint32_t cycle) void z80_assert_busreq(z80_context * context, uint32_t cycle) { + printf("bus requested at %d\n", cycle); z80_run(context, cycle); + printf("asserted busreq at %d\n", context->current_cycle); context->busreq = 1; } -- cgit v1.2.3 From 705e3ec64b1c659f400f96536dcb8c5c930e4bda Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 11 May 2015 20:30:13 -0700 Subject: Fixed a missed call to do_sync when updating SR in 68K core --- m68k_core_x86.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 167c740..2792bc6 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -2013,7 +2013,12 @@ void translate_m68k_move_ccr_sr(m68k_options *opts, m68kinst *inst, host_ea *src mov_rdispr(code, src_op->base, src_op->disp, opts->gen.scratch1, SZ_W); } } - call(code, inst->op == M68K_MOVE_SR ? opts->set_sr : opts->set_ccr); + if (inst->op == M68K_MOVE_SR) { + call(code, opts->set_sr); + call(code, opts->do_sync); + } else { + call(code, opts->set_ccr); + } cycles(&opts->gen, 12); } } -- cgit v1.2.3 From f44c90756358ab4b6582b69d0ebca4f7fce6c74e Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 11 May 2015 20:30:35 -0700 Subject: Fix frame counter increment and VINT cycle time calculation --- vdp.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/vdp.c b/vdp.c index c760529..8e7d739 100644 --- a/vdp.c +++ b/vdp.c @@ -1456,9 +1456,6 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) } if (is_h40 && slot == LINE_CHANGE_H40 || !is_h40 && slot == LINE_CHANGE_H32) { if (line >= inactive_start) { - if (line == (inactive_start + 8)) { - context->frame++; - } context->hint_counter = context->regs[REG_HINT]; } else if (context->hint_counter) { context->hint_counter--; @@ -1524,12 +1521,18 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) if (is_h40) { if (context->hslot == LINE_CHANGE_H40) { context->vcounter++; + if (context->vcounter == (inactive_start + 8)) { + context->frame++; + } } else if (context->hslot == 183) { context->hslot = 229; } } else { if (context->hslot == LINE_CHANGE_H32) { context->vcounter++; + if (context->vcounter == (inactive_start + 8)) { + context->frame++; + } } else if (context->hslot == 148) { context->hslot = 233; } @@ -1957,7 +1960,7 @@ uint32_t vdp_next_vint_z80(vdp_context * context) uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; if (context->vcounter == inactive_start) { if (context->regs[REG_MODE_4] & BIT_H40) { - if (context->hslot >= HBLANK_START_H40) { + if (context->hslot >= LINE_CHANGE_H40) { if (context->hslot < 183) { return context->cycles + (VINT_SLOT_H40 + 183 - context->hslot + 256 - 229) * MCLKS_SLOT_H40; } else { @@ -1967,7 +1970,7 @@ uint32_t vdp_next_vint_z80(vdp_context * context) return context->cycles + (VINT_SLOT_H40 - context->hslot) * MCLKS_SLOT_H40; } } else { - if (context->hslot >= HBLANK_START_H32) { + if (context->hslot >= LINE_CHANGE_H32) { if (context->hslot < 148) { return context->cycles + (VINT_SLOT_H32 + 148 - context->hslot + 256 - 233) * MCLKS_SLOT_H32; } else { @@ -1980,9 +1983,9 @@ uint32_t vdp_next_vint_z80(vdp_context * context) } int32_t cycles_to_vint = vdp_cycles_to_line(context, inactive_start); if (context->regs[REG_MODE_4] & BIT_H40) { - cycles_to_vint += (VINT_SLOT_H40 + 183 - HBLANK_START_H40 + 256 - 229) * MCLKS_SLOT_H40; + cycles_to_vint += (VINT_SLOT_H40 + 183 - LINE_CHANGE_H40 + 256 - 229) * MCLKS_SLOT_H40; } else { - cycles_to_vint += (VINT_SLOT_H32 + 148 - HBLANK_START_H32 + 256 - 233) * MCLKS_SLOT_H32; + cycles_to_vint += (VINT_SLOT_H32 + 148 - LINE_CHANGE_H32 + 256 - 233) * MCLKS_SLOT_H32; } return context->cycles + cycles_to_vint; } -- cgit v1.2.3 From 92699df4cb844ec29bcb2c55e5d68d747aabb6a8 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 11 May 2015 20:31:59 -0700 Subject: Tiny cleanup --- blastem.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/blastem.c b/blastem.c index 9a26e4b..56f3ca9 100644 --- a/blastem.c +++ b/blastem.c @@ -237,10 +237,8 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) if (gen->ym->write_cycle != CYCLE_NEVER) { gen->ym->write_cycle = gen->ym->write_cycle >= mclks ? gen->ym->write_cycle - mclks : 0; } - gen->frame_end = vdp_cycles_to_frame_end(v_context); - } else { - gen->frame_end = vdp_cycles_to_frame_end(v_context); } + gen->frame_end = vdp_cycles_to_frame_end(v_context); context->sync_cycle = gen->frame_end; //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot); if (context->int_ack) { -- cgit v1.2.3 From 9eadca47ed6f00e7a00ac25b6b85ba4426104950 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 11 May 2015 20:34:33 -0700 Subject: Remove/comment verbose logging added for tracking down sync bug --- m68k_core.c | 2 +- z80_to_x86.c | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/m68k_core.c b/m68k_core.c index b56b58b..c58b906 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -801,7 +801,7 @@ impl_info m68k_impls[] = { void translate_m68k(m68k_options * opts, m68kinst * inst) { check_cycles_int(&opts->gen, inst->address); - log_address(&opts->gen, inst->address, "M68K: %X @ %d\n"); + //log_address(&opts->gen, inst->address, "M68K: %X @ %d\n"); impl_info * info = m68k_impls + inst->op; if (info->itype == RAW_FUNC) { info->impl.raw(opts, inst); diff --git a/z80_to_x86.c b/z80_to_x86.c index 6b498f5..17eb40a 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -2279,10 +2279,10 @@ void z80_clear_reset(z80_context * context, uint32_t cycle) z80_run(context, cycle); if (context->reset) { //TODO: Handle case where reset is not asserted long enough - context->im = 0; - context->iff1 = context->iff2 = 0; + context->im = 0; + context->iff1 = context->iff2 = 0; context->native_pc = NULL; - context->extra_pc = NULL; + context->extra_pc = NULL; context->pc = 0; context->reset = 0; if (context->busreq) { @@ -2294,11 +2294,9 @@ void z80_clear_reset(z80_context * context, uint32_t cycle) void z80_assert_busreq(z80_context * context, uint32_t cycle) { - printf("bus requested at %d\n", cycle); z80_run(context, cycle); - printf("asserted busreq at %d\n", context->current_cycle); context->busreq = 1; - } +} void z80_clear_busreq(z80_context * context, uint32_t cycle) { -- cgit v1.2.3 From 42c1cb8c7c5369c88a8e94c083731b1e93b6119a Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 12 May 2015 19:14:09 -0700 Subject: Save PC to context struct when syncing Z80 at instruction start. This fixes saving savestates and probably the Z80 debugger as well --- z80_to_x86.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/z80_to_x86.c b/z80_to_x86.c index 17eb40a..313a8bb 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -2121,6 +2121,8 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t cmp_rdispr(code, options->gen.context_reg, offsetof(z80_context, sync_cycle), options->gen.cycles, SZ_D); code_ptr skip_sync = code->cur + 1; jcc(code, CC_B, skip_sync); + //save PC + mov_rrdisp(code, options->gen.scratch1, options->gen.context_reg, offsetof(z80_context, pc), SZ_D); options->do_sync = code->cur; call(code, options->gen.save_context); pop_rind(code, options->gen.context_reg); -- cgit v1.2.3 From f27e8413fb547c3201329915f0231a533ab2bb33 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 13 May 2015 19:13:15 -0700 Subject: Get save state viewer compiling again --- stateview.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stateview.c b/stateview.c index ee34407..713c390 100644 --- a/stateview.c +++ b/stateview.c @@ -53,6 +53,7 @@ void handle_joy_dpad(int joystick, int dpadnum, uint8_t value) } tern_node * config; +int headless = 0; int main(int argc, char ** argv) { @@ -86,8 +87,8 @@ int main(int argc, char ** argv) height = height < 240 ? (width/320) * 240 : height; vdp_context context; - render_init(width, height, "GST State Viewer", 60, 0); - init_vdp_context(&context); + render_init(width, height, "GST State Viewer", 60, 0, 0); + init_vdp_context(&context, 0); vdp_load_gst(&context, state_file); vdp_run_to_vblank(&context); vdp_print_sprite_table(&context); -- cgit v1.2.3 From 2a1a7e2d02bfc68048eab0d02efa81b152d78c8c Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 13 May 2015 19:13:49 -0700 Subject: Properly print equ for named labels that point outside the cartridge area in disassembler --- dis.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dis.c b/dis.c index 17dbc56..53c1d51 100644 --- a/dis.c +++ b/dis.c @@ -317,7 +317,15 @@ int main(int argc, char ** argv) } } for (address = filesize; address < (16*1024*1024); address++) { - if (is_label(address)) { + char key[MAX_INT_KEY_SIZE]; + tern_int_key(address, key); + label_names *names = tern_find_ptr(named_labels, key); + if (names) { + for (int i = 0; i < names->num_labels; i++) + { + printf("%s equ $%X\n", names->labels[i], address); + } + } else if (is_label(address)) { printf("ADR_%X equ $%X\n", address, address); } } -- cgit v1.2.3 From f62e6e2704a06ceba1e89656146c69272a71e3ba Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 13 May 2015 19:19:43 -0700 Subject: Add description of cd register value to vr debugger command --- vdp.c | 61 +++++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/vdp.c b/vdp.c index 8e7d739..e6d5aea 100644 --- a/vdp.c +++ b/vdp.c @@ -209,6 +209,45 @@ void vdp_print_sprite_table(vdp_context * context) } while (current_index != 0 && count < 80); } +#define VRAM_READ 0 //0000 +#define VRAM_WRITE 1 //0001 +//2 would trigger register write 0010 +#define CRAM_WRITE 3 //0011 +#define VSRAM_READ 4 //0100 +#define VSRAM_WRITE 5//0101 +//6 would trigger regsiter write 0110 +//7 is a mystery +#define CRAM_READ 8 //1000 +//9 is also a mystery //1001 +//A would trigger register write 1010 +//B is a mystery 1011 +#define VRAM_READ8 0xC //1100 +//D is a mystery 1101 +//E would trigger register write 1110 +//F is a mystery 1111 +#define DMA_START 0x20 + +const char * cd_name(uint8_t cd) +{ + switch (cd & 0xF) + { + case VRAM_READ: + return "VRAM read"; + case VRAM_WRITE: + return "VRAM write"; + case CRAM_WRITE: + return "CRAM write"; + case VSRAM_READ: + return "VSRAM read"; + case VSRAM_WRITE: + return "VSRAM write"; + case VRAM_READ8: + return "VRAM read (undocumented 8-bit mode)"; + default: + return "invalid"; + } +} + void vdp_print_reg_explain(vdp_context * context) { char * hscroll[] = {"full", "7-line", "cell", "line"}; @@ -261,11 +300,11 @@ void vdp_print_reg_explain(vdp_context * context) src_types[context->regs[REG_DMASRC_H] >> 6 & 3]); printf("\n**Internal Group**\n" "Address: %X\n" - "CD: %X\n" + "CD: %X - %s\n" "Pending: %s\n" "VCounter: %d\n" "HCounter: %d\n", - context->address, context->cd, (context->flags & FLAG_PENDING) ? "true" : "false", + context->address, context->cd, cd_name(context->cd), (context->flags & FLAG_PENDING) ? "true" : "false", context->vcounter, context->hslot*2); //TODO: Window Group, DMA Group @@ -416,24 +455,6 @@ void write_cram(vdp_context * context, uint16_t address, uint16_t value) context->colors[addr + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT]; } -#define VRAM_READ 0 //0000 -#define VRAM_WRITE 1 //0001 -//2 would trigger register write 0010 -#define CRAM_WRITE 3 //0011 -#define VSRAM_READ 4 //0100 -#define VSRAM_WRITE 5//0101 -//6 would trigger regsiter write 0110 -//7 is a mystery -#define CRAM_READ 8 //1000 -//9 is also a mystery //1001 -//A would trigger register write 1010 -//B is a mystery 1011 -#define VRAM_READ8 0xC //1100 -//D is a mystery 1101 -//E would trigger register write 1110 -//F is a mystery 1111 -#define DMA_START 0x20 - void external_slot(vdp_context * context) { fifo_entry * start = context->fifo + context->fifo_read; -- cgit v1.2.3 From 9ad6463d0b731c4afda4fceb9a9683e2f65e14f5 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 13 May 2015 23:55:02 -0700 Subject: Fix problem with removing breakpoints --- m68k_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/m68k_core.c b/m68k_core.c index c58b906..31f536b 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -972,7 +972,7 @@ void remove_breakpoint(m68k_context * context, uint32_t address) code_ptr native = get_native_address(context->native_code_map, address); code_info tmp = context->options->gen.code; context->options->gen.code.cur = native; - context->options->gen.code.last = native + 16; + context->options->gen.code.last = native + MAX_NATIVE_SIZE; check_cycles_int(&context->options->gen, address); context->options->gen.code = tmp; } -- cgit v1.2.3 From b88dc02ba056c2b5891b1bb062a2ad44df5df544 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 14 May 2015 00:04:22 -0700 Subject: Sync machine state before entering debugger --- blastem.h | 1 + debug.c | 1 + 2 files changed, 2 insertions(+) diff --git a/blastem.h b/blastem.h index 680fc73..23c62dd 100644 --- a/blastem.h +++ b/blastem.h @@ -52,6 +52,7 @@ extern uint16_t ram[RAM_WORDS]; extern uint8_t z80_ram[Z80_RAM_BYTES]; uint16_t read_dma_value(uint32_t address); +m68k_context * sync_components(m68k_context *context, uint32_t address); m68k_context * debugger(m68k_context * context, uint32_t address); void set_speed_percent(genesis_context * context, uint32_t percent); diff --git a/debug.c b/debug.c index fa0e26e..11ec9ad 100644 --- a/debug.c +++ b/debug.c @@ -471,6 +471,7 @@ m68k_context * debugger(m68k_context * context, uint32_t address) static uint32_t branch_t; static uint32_t branch_f; m68kinst inst; + sync_components(context, 0); //probably not necessary, but let's play it safe address &= 0xFFFFFF; if (address == branch_t) { -- cgit v1.2.3 From 7d1aa2ab5e1b839f8cd15425f1004c7d1e952400 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 14 May 2015 23:17:55 -0700 Subject: Small horizontal interrupt fixes --- gst.c | 2 +- vdp.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gst.c b/gst.c index a901858..28cc4ca 100644 --- a/gst.c +++ b/gst.c @@ -423,7 +423,7 @@ uint32_t load_gst(genesis_context * gen, char * fname) fprintf(stderr, "Could not read ident code from %s\n", fname); goto error_close; } - if (memcmp(ident, "GST\x40\xE0", 5) != 0) { + if (memcmp(ident, "GST\x40\xE0", 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\\x40\\xE0.\n", fname, ident[0], ident[1], ident[2], ident[3], ident[4]); goto error_close; } diff --git a/vdp.c b/vdp.c index e6d5aea..a7f9d1b 100644 --- a/vdp.c +++ b/vdp.c @@ -1476,7 +1476,7 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) } } if (is_h40 && slot == LINE_CHANGE_H40 || !is_h40 && slot == LINE_CHANGE_H32) { - if (line >= inactive_start) { + if (line > inactive_start) { context->hint_counter = context->regs[REG_HINT]; } else if (context->hint_counter) { context->hint_counter--; @@ -1954,7 +1954,7 @@ uint32_t vdp_next_hint(vdp_context * context) } uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; uint32_t hint_line; - if (context->vcounter >= inactive_start) { + if (context->vcounter + context->hint_counter >= inactive_start) { hint_line = context->regs[REG_HINT]; } else { hint_line = context->vcounter + context->hint_counter + 1; -- cgit v1.2.3 From b31d70dcda706dbf8a3a34ea27ff614617c1c9c1 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 16 May 2015 22:42:26 -0700 Subject: Fix trans so it compiles again --- trans.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/trans.c b/trans.c index 2f98e91..7251cb9 100644 --- a/trans.c +++ b/trans.c @@ -25,7 +25,6 @@ int main(int argc, char ** argv) char disbuf[1024]; unsigned short * cur; m68k_options opts; - m68k_context context; FILE * f = fopen(argv[1], "rb"); fseek(f, 0, SEEK_END); filesize = ftell(f); @@ -51,15 +50,15 @@ int main(int argc, char ** argv) memmap[1].flags = MMAP_READ | MMAP_WRITE | MMAP_CODE; memmap[1].buffer = malloc(64 * 1024); memset(memmap[1].buffer, 0, 64 * 1024); - init_m68k_opts(&opts, memmap, 2); - init_68k_context(&context, opts.gen.native_code_map, &opts); - context.mem_pointers[0] = memmap[0].buffer; - context.mem_pointers[1] = memmap[1].buffer; - context.target_cycle = context.sync_cycle = 0x80000000; + init_m68k_opts(&opts, memmap, 2, 1); + m68k_context * context = init_68k_context(&opts); + context->mem_pointers[0] = memmap[0].buffer; + context->mem_pointers[1] = memmap[1].buffer; + context->target_cycle = context->sync_cycle = 0x80000000; uint32_t address; address = filebuf[2] << 16 | filebuf[3]; - translate_m68k_stream(address, &context); - m68k_reset(&context); + translate_m68k_stream(address, context); + m68k_reset(context); return 0; } -- cgit v1.2.3 From 7e2fdcb2f3378827b1286e8d7ee5290303e71d6b Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 16 May 2015 23:04:57 -0700 Subject: First pass at emulating a vscroll latch. Titan's Overdrive demo seems to depend on the scroll value being latched early in the line before the HINT gets a chance to change it --- vdp.c | 7 ++++++- vdp.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/vdp.c b/vdp.c index a7f9d1b..0c016f0 100644 --- a/vdp.c +++ b/vdp.c @@ -657,7 +657,12 @@ void read_map_scroll(uint16_t column, uint16_t vsram_off, uint32_t line, uint16_ vscroll <<= 1; vscroll |= 1; } - vscroll &= (context->vsram[(context->regs[REG_MODE_3] & BIT_VSCROLL ? (column-2)&63 : 0) + vsram_off] + line); + //TODO: Further research on vscroll latch behavior and the "first column bug" seen in Gynoug + //this should be close, but won't match the exact behavior Eke-Eke has written about + if (column == 2 || (column && (context->regs[REG_MODE_3] & BIT_VSCROLL))) { + context->vscroll_latch[vsram_off] = context->vsram[column - 2 + vsram_off]; + } + vscroll &= context->vscroll_latch[vsram_off] + line; context->v_offset = vscroll & v_offset_mask; //printf("%s | line %d, vsram: %d, vscroll: %d, v_offset: %d\n",(vsram_off ? "B" : "A"), line, context->vsram[context->regs[REG_MODE_3] & 0x4 ? column : 0], vscroll, context->v_offset); vscroll >>= vscroll_shift; diff --git a/vdp.h b/vdp.h index 31bd4e7..7950c38 100644 --- a/vdp.h +++ b/vdp.h @@ -143,6 +143,7 @@ typedef struct { uint32_t colors[CRAM_SIZE*3]; uint32_t debugcolors[1 << (3 + 1 + 1 + 1)];//3 bits for source, 1 bit for priority, 1 bit for shadow, 1 bit for hilight uint16_t vsram[VSRAM_SIZE]; + uint16_t vscroll_latch[2]; uint32_t frame; uint16_t vcounter; uint16_t hslot; //hcounter/2 -- cgit v1.2.3 From 247d94aefe4260638e35bc13b006e0b9330c5fe7 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 16 May 2015 23:08:07 -0700 Subject: Adjust H32 vint slot in response to latest test ROM data --- vdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vdp.c b/vdp.c index 0c016f0..73ca200 100644 --- a/vdp.c +++ b/vdp.c @@ -23,7 +23,7 @@ #define MCLKS_SLOT_H40 16 #define MCLKS_SLOT_H32 20 #define VINT_SLOT_H40 4 //21 slots before HSYNC, 16 during, 10 after -#define VINT_SLOT_H32 23 //33 slots before HSYNC, 20 during, 7 after TODO: confirm final number +#define VINT_SLOT_H32 4 //old value was 23, but recent tests suggest the actual value is close to the H40 one #define HSYNC_SLOT_H40 234 #define HSYNC_END_H40 (HSYNC_SLOT_H40+17) #define HSYNC_END_H32 (33 * MCLKS_SLOT_H32) -- cgit v1.2.3 From fabfa5cb07a4d407146f22afdb5349cdde8016b2 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 17 May 2015 15:40:31 -0700 Subject: Fix crash bug in Z80 interpreter --- z80_to_x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/z80_to_x86.c b/z80_to_x86.c index 313a8bb..1f8d477 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -1674,7 +1674,7 @@ code_info z80_make_interp_stub(z80_context * context, uint16_t address) call(code, opts->gen.save_context); mov_irdisp(code, address, opts->gen.context_reg, offsetof(z80_context, pc), SZ_W); push_r(code, opts->gen.context_reg); - call_args(code, (code_ptr)z80_interp_handler, 2, opts->gen.scratch1, opts->gen.scratch2); + call_args(code, (code_ptr)z80_interp_handler, 2, opts->gen.scratch1, opts->gen.context_reg); mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); pop_r(code, opts->gen.context_reg); call(code, opts->gen.load_context); -- cgit v1.2.3 From a629ad5a0a5f1325d528f335501922dc423acf03 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 17 May 2015 15:41:15 -0700 Subject: Don't overwrite an instruction offset mapping with an extension word value. I really need the ability for a word to be mapped to more than one instruction, but this will be more correct for now --- m68k_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/m68k_core.c b/m68k_core.c index 31f536b..1ac4ca2 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -643,7 +643,10 @@ void map_native_address(m68k_context * context, uint32_t address, code_ptr nativ native_code_map[chunk].offsets = malloc(sizeof(int32_t) * NATIVE_CHUNK_SIZE); memset(native_code_map[chunk].offsets, 0xFF, sizeof(int32_t) * NATIVE_CHUNK_SIZE); } - native_code_map[chunk].offsets[offset] = EXTENSION_WORD; + if (native_code_map[chunk].offsets[offset] == INVALID_OFFSET) { + //TODO: Better handling of overlapping instructions + native_code_map[chunk].offsets[offset] = EXTENSION_WORD; + } } } -- cgit v1.2.3 From 66e9ade3dc32f118d6d9229b709c4cd389f9162e Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 17 May 2015 15:43:20 -0700 Subject: Fix VDP status register PAL bit based on observations of the Titan Overdrive demo --- vdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vdp.c b/vdp.c index 73ca200..70784dc 100644 --- a/vdp.c +++ b/vdp.c @@ -1757,7 +1757,7 @@ uint16_t vdp_control_port_read(vdp_context * context) if (context->flags & FLAG_DMA_RUN) { value |= 0x2; } - if (context->latched_mode & BIT_PAL) {//Not sure about this, need to verify + if (context->flags2 & FLAG2_REGION_PAL) { value |= 0x1; } //printf("status read at cycle %d returned %X\n", context->cycles, value); -- cgit v1.2.3 From e51040f08071327061219caa1c54d3dcb346b1c7 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 17 May 2015 19:14:41 -0700 Subject: Call z80_handle_deferred after generating an insruction handler so that instructions like rst work correctly --- z80_to_x86.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/z80_to_x86.c b/z80_to_x86.c index 1f8d477..bef749f 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -23,6 +23,7 @@ #endif uint32_t zbreakpoint_patch(z80_context * context, uint16_t address, code_ptr dst); +void z80_handle_deferred(z80_context * context); uint8_t z80_size(z80inst * inst) { @@ -1653,6 +1654,7 @@ uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context) add_ir(code, after - codebuf, opts->gen.scratch1, SZ_W); call(code, opts->native_addr); jmp_r(code, opts->gen.scratch1); + z80_handle_deferred(context); } return context->interp_code[opcode]; } -- cgit v1.2.3 From 9c11d06c90e3d1f8e1c7bfbd5478b5852fcae876 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 17 May 2015 20:03:27 -0700 Subject: Make sure z80_save_reg does nothing when there is no register in the reg field of the instruction. This fixes a bug that corrupted SP in the MDEM 2011 demo --- z80_to_x86.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/z80_to_x86.c b/z80_to_x86.c index bef749f..6d33c14 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -81,6 +81,9 @@ void translate_z80_reg(z80inst * inst, host_ea * ea, z80_options * opts) void z80_save_reg(z80inst * inst, z80_options * opts) { code_info *code = &opts->gen.code; + if (inst->reg == Z80_USE_IMMED || inst->reg == Z80_UNUSED) { + return; + } if (inst->reg == Z80_IYH) { if ((inst->addr_mode & 0x1F) == Z80_REG && inst->ea_reg == Z80_IYL) { ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); -- cgit v1.2.3 From b06a76dab4014a5ea1046eee6e4fdd819dbe7cbb Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 19 May 2015 23:23:53 -0700 Subject: Small correction to VBLANK flag timing. Fixed some inconsistencies in interrupt timing calculation. --- blastem.c | 6 ++++ vdp.c | 118 ++++++++++++++++++++++++++++++++++++++++---------------------- vdp.h | 2 ++ 3 files changed, 85 insertions(+), 41 deletions(-) diff --git a/blastem.c b/blastem.c index 56f3ca9..48f1883 100644 --- a/blastem.c +++ b/blastem.c @@ -125,6 +125,7 @@ uint16_t read_dma_value(uint32_t address) void adjust_int_cycle(m68k_context * context, vdp_context * v_context) { + //static int old_int_cycle = CYCLE_NEVER; genesis_context *gen = context->system; if (context->sync_cycle - context->current_cycle > gen->max_cycles) { context->sync_cycle = context->current_cycle + gen->max_cycles; @@ -147,6 +148,10 @@ void adjust_int_cycle(m68k_context * context, vdp_context * v_context) } } } + /*if (context->int_cycle != old_int_cycle) { + printf("int cycle changed to: %d, level: %d @ %d(%d), frame: %d, vcounter: %d, hslot: %d, mask: %d, hint_counter: %d\n", context->int_cycle, context->int_num, v_context->cycles, context->current_cycle, v_context->frame, v_context->vcounter, v_context->hslot, context->status & 0x7, v_context->hint_counter); + old_int_cycle = context->int_cycle; + }*/ context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle; /*printf("Cyc: %d, Trgt: %d, Int Cyc: %d, Int: %d, Mask: %X, V: %d, H: %d, HICount: %d, HReg: %d, Line: %d\n", @@ -242,6 +247,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) context->sync_cycle = gen->frame_end; //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot); if (context->int_ack) { + printf("acknowledging %d @ %d:%d, vcounter: %d, hslot: %d\n", context->int_ack, context->current_cycle, v_context->cycles, v_context->vcounter, v_context->hslot); vdp_int_ack(v_context, context->int_ack); context->int_ack = 0; } diff --git a/vdp.c b/vdp.c index 70784dc..eb85194 100644 --- a/vdp.c +++ b/vdp.c @@ -33,6 +33,8 @@ #define HBLANK_END_H32 0 //should be 5 according to Nemesis, but 0 seems to fit better with my test ROM results #define LINE_CHANGE_H40 165 #define LINE_CHANGE_H32 132 +#define VBLANK_START_H40 (LINE_CHANGE_H40+2) +#define VBLANK_START_H32 (LINE_CHANGE_H32+2) #define FIFO_LATENCY 3 int32_t color_map[1 << 12]; @@ -562,7 +564,7 @@ void run_dma_src(vdp_context * context, uint32_t slot) context->regs[REG_DMALEN_H] = dma_len >> 8; context->regs[REG_DMALEN_L] = dma_len; if (!dma_len) { - //printf("DMA end at cycle %d\n", context->cycles); + //printf("DMA end at cycle %d, frame: %d, vcounter: %d, hslot: %d\n", context->cycles, context->frame, context->vcounter, context->hslot); context->flags &= ~FLAG_DMA_RUN; context->cd &= 0xF; } @@ -1448,6 +1450,20 @@ void check_render_bg(vdp_context * context, int32_t line, uint32_t slot) uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19}; +void vdp_advance_line(vdp_context *context) +{ + context->vcounter++; + if (context->vcounter > (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) { + context->hint_counter = context->regs[REG_HINT]; + } else if (context->hint_counter) { + context->hint_counter--; + } else { + context->flags2 |= FLAG2_HINT_PENDING; + context->pending_hint_start = context->cycles; + context->hint_counter = context->regs[REG_HINT]; + } +} + void vdp_run_context(vdp_context * context, uint32_t target_cycles) { while(context->cycles < target_cycles) @@ -1480,19 +1496,11 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) context->slot_counter = MAX_SPRITES_LINE_H32; } } - if (is_h40 && slot == LINE_CHANGE_H40 || !is_h40 && slot == LINE_CHANGE_H32) { - if (line > inactive_start) { - context->hint_counter = context->regs[REG_HINT]; - } else if (context->hint_counter) { - context->hint_counter--; - } else { - context->flags2 |= FLAG2_HINT_PENDING; - context->hint_counter = context->regs[REG_HINT]; - } - } else if(line == inactive_start) { + if(line == inactive_start) { uint32_t intslot = context->regs[REG_MODE_4] & BIT_H40 ? VINT_SLOT_H40 : VINT_SLOT_H32; if (slot == intslot) { context->flags2 |= FLAG2_VINT_PENDING; + context->pending_vint_start = context->cycles; } } uint32_t inccycles; @@ -1522,7 +1530,6 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) if (slot == LINE_CHANGE_H40 && line < inactive_start && (target_cycles - context->cycles) >= MCLKS_LINE) { vdp_h40_line(line, context); inccycles = MCLKS_LINE; - context->vcounter++; inc_slot = 0; } else { vdp_h40(line, slot, context); @@ -1541,12 +1548,13 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) if (context->flags & FLAG_DMA_RUN && !is_refresh(context, slot)) { run_dma_src(context, slot); } + context->cycles += inccycles; if (inc_slot) { context->hslot++; context->hslot &= 0xFF; if (is_h40) { if (context->hslot == LINE_CHANGE_H40) { - context->vcounter++; + vdp_advance_line(context); if (context->vcounter == (inactive_start + 8)) { context->frame++; } @@ -1555,7 +1563,7 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) } } else { if (context->hslot == LINE_CHANGE_H32) { - context->vcounter++; + vdp_advance_line(context); if (context->vcounter == (inactive_start + 8)) { context->frame++; } @@ -1564,6 +1572,8 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) } } + } else { + vdp_advance_line(context); } context->vcounter &= 0x1FF; if (context->flags2 & FLAG2_REGION_PAL) { @@ -1577,7 +1587,7 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) } else if (!(context->latched_mode & BIT_PAL) && context->vcounter == 0xEB) { context->vcounter = 0x1E5; } - context->cycles += inccycles; + } } @@ -1631,7 +1641,7 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) //DMA copy or 68K -> VDP, transfer starts immediately context->flags |= FLAG_DMA_RUN; context->dma_cd = context->cd; - //printf("DMA start at cycle %d\n", context->cycles); + //printf("DMA start (length: %X) at cycle %d, frame: %d, vcounter: %d, hslot: %d\n", (context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L], context->cycles, context->frame, context->vcounter, context->hslot); if (!(context->regs[REG_DMASRC_H] & 0x80)) { //printf("DMA Address: %X, New CD: %X, Source: %X, Length: %X\n", context->address, context->cd, (context->regs[REG_DMASRC_H] << 17) | (context->regs[REG_DMASRC_M] << 9) | (context->regs[REG_DMASRC_L] << 1), context->regs[REG_DMALEN_H] << 8 | context->regs[REG_DMALEN_L]); return 1; @@ -1654,6 +1664,9 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) if (reg == REG_BG_COLOR) { value &= 0x3F; } + if (reg == REG_MODE_4 && ((value ^ context->regs[reg]) & BIT_H40)) { + printf("Mode changed from H%d to H%d @ %d, frame: %d\n", context->regs[reg] & BIT_H40 ? 40 : 32, value & BIT_H40 ? 40 : 32, context->cycles, context->frame); + } context->regs[reg] = value; if (reg == REG_MODE_4) { context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); @@ -1736,11 +1749,21 @@ uint16_t vdp_control_port_read(vdp_context * context) } uint32_t line= context->vcounter; uint32_t slot = context->hslot; + uint32_t inactive_start = (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START); if ( ( - line >= (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START) + line > inactive_start && line < 0x1FF ) + || (line == inactive_start + && ( + slot >= (context->regs[REG_MODE_4] & BIT_H40 ? VBLANK_START_H40 : VBLANK_START_H32) + || slot < (context->regs[REG_MODE_4] & BIT_H40 ? LINE_CHANGE_H40 : LINE_CHANGE_H32) + ) + ) + || (line == 0x1FF + && slot < (context->regs[REG_MODE_4] & BIT_H40 ? VBLANK_START_H40 : VBLANK_START_H32)) + && slot >= (context->regs[REG_MODE_4] & BIT_H40 ? LINE_CHANGE_H40 : LINE_CHANGE_H32) || !(context->regs[REG_MODE_2] & BIT_DISP_EN) ) { value |= 0x8; @@ -1840,6 +1863,16 @@ uint16_t vdp_test_port_read(vdp_context * context) void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) { context->cycles -= deduction; + if (context->pending_vint_start >= deduction) { + context->pending_vint_start -= deduction; + } else { + context->pending_vint_start = 0; + } + if (context->pending_hint_start >= deduction) { + context->pending_hint_start -= deduction; + } else { + context->pending_hint_start = 0; + } if (context->fifo_read >= 0) { int32_t idx = context->fifo_read; do { @@ -1853,24 +1886,31 @@ void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) } } +uint32_t vdp_cycles_hslot_wrap_h40(vdp_context * context) +{ + if (context->hslot < 183) { + return MCLKS_LINE - context->hslot * MCLKS_SLOT_H40; + } else if (context->hslot < HSYNC_END_H40) { + uint32_t before_hsync = context->hslot < HSYNC_SLOT_H40 ? (HSYNC_SLOT_H40 - context->hslot) * MCLKS_SLOT_H40 : 0; + uint32_t hsync = 0; + for (int i = context->hslot <= HSYNC_SLOT_H40 ? 0 : context->hslot - HSYNC_SLOT_H40; i < sizeof(h40_hsync_cycles)/sizeof(uint32_t); i++) + { + hsync += h40_hsync_cycles[i]; + } + uint32_t after_hsync = (256- HSYNC_END_H40) * MCLKS_SLOT_H40; + return before_hsync + hsync + after_hsync; + } else { + return (256-context->hslot) * MCLKS_SLOT_H40; + } +} + uint32_t vdp_cycles_next_line(vdp_context * context) { if (context->regs[REG_MODE_4] & BIT_H40) { if (context->hslot < LINE_CHANGE_H40) { return (LINE_CHANGE_H40 - context->hslot) * MCLKS_SLOT_H40; - } else if (context->hslot < 183) { - return MCLKS_LINE - (context->hslot - LINE_CHANGE_H40) * MCLKS_SLOT_H40; - } else if (context->hslot < HSYNC_END_H40){ - uint32_t before_hsync = context->hslot < HSYNC_SLOT_H40 ? (HSYNC_SLOT_H40 - context->hslot) * MCLKS_SLOT_H40 : 0; - uint32_t hsync = 0; - for (int i = context->hslot <= HSYNC_SLOT_H40 ? 0 : context->hslot - HSYNC_SLOT_H40; i < sizeof(h40_hsync_cycles)/sizeof(uint32_t); i++) - { - hsync += h40_hsync_cycles[i]; - } - uint32_t after_hsync = (256- HSYNC_END_H40 + LINE_CHANGE_H40) * MCLKS_SLOT_H40; - return before_hsync + hsync + after_hsync; } else { - return (256-context->hslot + LINE_CHANGE_H40) * MCLKS_SLOT_H40; + return vdp_cycles_hslot_wrap_h40(context) + LINE_CHANGE_H40 * MCLKS_SLOT_H40; } } else { if (context->hslot < LINE_CHANGE_H32) { @@ -1912,9 +1952,9 @@ uint32_t vdp_cycles_to_line(vdp_context * context, uint32_t target) } } else { if (context->vcounter < jump_start) { - lines = jump_start - context->vcounter + 512 - jump_dst; + lines = jump_start - context->vcounter + 512 - jump_dst + 1; } else { - lines = 512 - context->vcounter; + lines = 512 - context->vcounter + 1; } if (target < jump_start) { lines += target; @@ -1955,7 +1995,7 @@ uint32_t vdp_next_hint(vdp_context * context) return 0xFFFFFFFF; } if (context->flags2 & FLAG2_HINT_PENDING) { - return context->cycles; + return context->pending_hint_start; } uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; uint32_t hint_line; @@ -1974,7 +2014,7 @@ uint32_t vdp_next_vint(vdp_context * context) return 0xFFFFFFFF; } if (context->flags2 & FLAG2_VINT_PENDING) { - return context->cycles; + return context->pending_vint_start; } @@ -1987,12 +2027,8 @@ uint32_t vdp_next_vint_z80(vdp_context * context) if (context->vcounter == inactive_start) { if (context->regs[REG_MODE_4] & BIT_H40) { if (context->hslot >= LINE_CHANGE_H40) { - if (context->hslot < 183) { - return context->cycles + (VINT_SLOT_H40 + 183 - context->hslot + 256 - 229) * MCLKS_SLOT_H40; - } else { - return context->cycles + (VINT_SLOT_H40 + 256 - context->hslot) * MCLKS_SLOT_H40; - } - } else if (context->hslot < VINT_SLOT_H40) { + return context->cycles + vdp_cycles_hslot_wrap_h40(context) + VINT_SLOT_H40 * MCLKS_SLOT_H40; + } else if (context->hslot <= VINT_SLOT_H40) { return context->cycles + (VINT_SLOT_H40 - context->hslot) * MCLKS_SLOT_H40; } } else { @@ -2002,14 +2038,14 @@ uint32_t vdp_next_vint_z80(vdp_context * context) } else { return context->cycles + (VINT_SLOT_H32 + 256 - context->hslot) * MCLKS_SLOT_H32; } - } else if (context->hslot < VINT_SLOT_H32) { + } else if (context->hslot <= VINT_SLOT_H32) { return context->cycles + (VINT_SLOT_H32 - context->hslot) * MCLKS_SLOT_H32; } } } int32_t cycles_to_vint = vdp_cycles_to_line(context, inactive_start); if (context->regs[REG_MODE_4] & BIT_H40) { - cycles_to_vint += (VINT_SLOT_H40 + 183 - LINE_CHANGE_H40 + 256 - 229) * MCLKS_SLOT_H40; + cycles_to_vint += MCLKS_LINE - (LINE_CHANGE_H40 - VINT_SLOT_H40) * MCLKS_SLOT_H40; } else { cycles_to_vint += (VINT_SLOT_H32 + 148 - LINE_CHANGE_H32 + 256 - 233) * MCLKS_SLOT_H32; } diff --git a/vdp.h b/vdp.h index 7950c38..a05501c 100644 --- a/vdp.h +++ b/vdp.h @@ -132,6 +132,8 @@ typedef struct { uint8_t regs[VDP_REGS]; //cycle count in MCLKs uint32_t cycles; + uint32_t pending_vint_start; + uint32_t pending_hint_start; uint8_t *vdpmem; //stores 2-bit palette + 4-bit palette index + priority for current sprite line uint8_t *linebuf; -- cgit v1.2.3 From 265a11e776d9708483024f48a9e0eaaf6686d00b Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 20 May 2015 10:35:03 -0700 Subject: Update vscroll latch implementation to be more in line with what Eke-Eke has observed. Revert the change to vdp_cycles_to_line because it breaks hints on line 0. H-Int timing is still a little messed up, but the previous change made things worse. --- blastem.c | 2 +- vdp.c | 31 +++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/blastem.c b/blastem.c index 48f1883..c11c4a4 100644 --- a/blastem.c +++ b/blastem.c @@ -247,7 +247,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) context->sync_cycle = gen->frame_end; //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot); if (context->int_ack) { - printf("acknowledging %d @ %d:%d, vcounter: %d, hslot: %d\n", context->int_ack, context->current_cycle, v_context->cycles, v_context->vcounter, v_context->hslot); + //printf("acknowledging %d @ %d:%d, vcounter: %d, hslot: %d\n", context->int_ack, context->current_cycle, v_context->cycles, v_context->vcounter, v_context->hslot); vdp_int_ack(v_context, context->int_ack); context->int_ack = 0; } diff --git a/vdp.c b/vdp.c index eb85194..8c6405e 100644 --- a/vdp.c +++ b/vdp.c @@ -487,7 +487,7 @@ void external_slot(vdp_context * context) } case VSRAM_WRITE: if (((start->address/2) & 63) < VSRAM_SIZE) { - //printf("VSRAM Write: %X to %X\n", start->value, context->address); + //printf("VSRAM Write: %X to %X @ vcounter: %d, hslot: %d, cycle: %d\n", start->value, context->address, context->vcounter, context->hslot, context->cycles); context->vsram[(start->address/2) & 63] = start->partial == 2 ? context->fifo[context->fifo_write].value : start->value; } @@ -659,9 +659,24 @@ void read_map_scroll(uint16_t column, uint16_t vsram_off, uint32_t line, uint16_ vscroll <<= 1; vscroll |= 1; } - //TODO: Further research on vscroll latch behavior and the "first column bug" seen in Gynoug - //this should be close, but won't match the exact behavior Eke-Eke has written about - if (column == 2 || (column && (context->regs[REG_MODE_3] & BIT_VSCROLL))) { + //TODO: Further research on vscroll latch behavior and the "first column bug" + if (!column) { + if (context->regs[REG_MODE_3] & BIT_VSCROLL) { + if (context->regs[REG_MODE_4] & BIT_H40) { + //Based on observed behavior documented by Eke-Eke, I'm guessing the VDP + //ends up fetching the last value on the VSRAM bus in the H40 case + //getting the last latched value should be close enough for now + if (!vsram_off) { + context->vscroll_latch[0] = context->vscroll_latch[1]; + } + } else { + //supposedly it's always forced to 0 in the H32 case + context->vscroll_latch[0] = context->vscroll_latch[1] = 0; + } + } else { + context->vscroll_latch[vsram_off] = context->vsram[vsram_off]; + } + } else if (context->regs[REG_MODE_3] & BIT_VSCROLL) { context->vscroll_latch[vsram_off] = context->vsram[column - 2 + vsram_off]; } vscroll &= context->vscroll_latch[vsram_off] + line; @@ -1664,9 +1679,9 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) if (reg == REG_BG_COLOR) { value &= 0x3F; } - if (reg == REG_MODE_4 && ((value ^ context->regs[reg]) & BIT_H40)) { + /*if (reg == REG_MODE_4 && ((value ^ context->regs[reg]) & BIT_H40)) { printf("Mode changed from H%d to H%d @ %d, frame: %d\n", context->regs[reg] & BIT_H40 ? 40 : 32, value & BIT_H40 ? 40 : 32, context->cycles, context->frame); - } + }*/ context->regs[reg] = value; if (reg == REG_MODE_4) { context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); @@ -1952,9 +1967,9 @@ uint32_t vdp_cycles_to_line(vdp_context * context, uint32_t target) } } else { if (context->vcounter < jump_start) { - lines = jump_start - context->vcounter + 512 - jump_dst + 1; + lines = jump_start - context->vcounter + 512 - jump_dst; } else { - lines = 512 - context->vcounter + 1; + lines = 512 - context->vcounter; } if (target < jump_start) { lines += target; -- cgit v1.2.3 From 863ea0b3f8b8879ac3092f391a68dc95d0d04de2 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 20 May 2015 19:05:11 -0700 Subject: Upgrade to SDL 2.0 and drop support for the non-OpenGL render path --- Makefile | 8 +- blastem.c | 2 +- render.h | 3 +- render_sdl.c | 287 ++++++++++++++++++----------------------------------------- stateview.c | 2 +- vdp.c | 45 +++------- vgmplay.c | 2 +- 7 files changed, 103 insertions(+), 246 deletions(-) diff --git a/Makefile b/Makefile index 784ac8f..6ddcd52 100644 --- a/Makefile +++ b/Makefile @@ -2,14 +2,10 @@ ifndef OS OS:=$(shell uname -s) endif -ifdef NOGL -LIBS=sdl -else ifeq ($(OS),Darwin) -LIBS=sdl glew +LIBS=sdl2 glew else -LIBS=sdl glew gl -endif +LIBS=sdl2 glew gl endif ifdef DEBUG diff --git a/blastem.c b/blastem.c index c11c4a4..60a5fa6 100644 --- a/blastem.c +++ b/blastem.c @@ -1263,7 +1263,7 @@ int main(int argc, char ** argv) fps = 50; } if (!headless) { - render_init(width, height, title, fps, fullscreen, use_gl); + render_init(width, height, title, fps, fullscreen); } vdp_context v_context; genesis_context gen; diff --git a/render.h b/render.h index ccc556d..90ebf9d 100644 --- a/render.h +++ b/render.h @@ -18,8 +18,7 @@ typedef struct { uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b); void render_alloc_surfaces(vdp_context * context); -uint8_t render_depth(); -void render_init(int width, int height, char * title, uint32_t fps, uint8_t fullscreen, uint8_t use_gl); +void render_init(int width, int height, char * title, uint32_t fps, uint8_t fullscreen); void render_context(vdp_context * context); void render_wait_quit(vdp_context * context); void render_wait_psg(psg_context * context); diff --git a/render_sdl.c b/render_sdl.c index f50c476..53a0e2f 100644 --- a/render_sdl.c +++ b/render_sdl.c @@ -11,14 +11,12 @@ #include "io.h" #include "util.h" -#ifndef DISABLE_OPENGL #include -#endif -SDL_Surface *screen; +SDL_Window *main_window; +SDL_GLContext *main_context; uint8_t render_dbg = 0; uint8_t debug_pal = 0; -uint8_t render_gl = 1; uint32_t last_frame = 0; @@ -92,14 +90,9 @@ int render_num_joysticks() uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) { - if (render_gl) { - return 255 << 24 | r << 16 | g << 8 | b; - } else { - return SDL_MapRGB(screen->format, r, g, b); - } + return 255 << 24 | r << 16 | g << 8 | b; } -#ifndef DISABLE_OPENGL GLuint textures[3], buffers[2], vshader, fshader, program, un_textures[2], un_width, at_pos; GLfloat vertex_data[] = { @@ -153,139 +146,108 @@ GLuint load_shader(char * fname, GLenum shader_type) } return ret; } -#endif void render_alloc_surfaces(vdp_context * context) { -#ifndef DISABLE_OPENGL - if (render_gl) { - context->oddbuf = context->framebuf = malloc(512 * 256 * 4 * 2); - memset(context->oddbuf, 0, 512 * 256 * 4 * 2); - context->evenbuf = ((char *)context->oddbuf) + 512 * 256 * 4; - glGenTextures(3, textures); - for (int i = 0; i < 3; i++) - { - glBindTexture(GL_TEXTURE_2D, textures[i]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (i < 2) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, i ? context->evenbuf : context->oddbuf); - } else { - uint32_t blank = 255 << 24; - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank); - } - } - glGenBuffers(2, buffers); - glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW); - vshader = load_shader(tern_find_ptr_default(config, "videovertex_shader", "default.v.glsl"), GL_VERTEX_SHADER); - fshader = load_shader(tern_find_ptr_default(config, "videofragment_shader", "default.f.glsl"), GL_FRAGMENT_SHADER); - program = glCreateProgram(); - glAttachShader(program, vshader); - glAttachShader(program, fshader); - glLinkProgram(program); - GLint link_status; - glGetProgramiv(program, GL_LINK_STATUS, &link_status); - if (!link_status) { - fputs("Failed to link shader program\n", stderr); - exit(1); + context->oddbuf = context->framebuf = malloc(512 * 256 * 4 * 2); + memset(context->oddbuf, 0, 512 * 256 * 4 * 2); + context->evenbuf = ((char *)context->oddbuf) + 512 * 256 * 4; + glGenTextures(3, textures); + for (int i = 0; i < 3; i++) + { + glBindTexture(GL_TEXTURE_2D, textures[i]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (i < 2) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, i ? context->evenbuf : context->oddbuf); + } else { + uint32_t blank = 255 << 24; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_BGRA, GL_UNSIGNED_BYTE, &blank); } - un_textures[0] = glGetUniformLocation(program, "textures[0]"); - un_textures[1] = glGetUniformLocation(program, "textures[1]"); - un_width = glGetUniformLocation(program, "width"); - at_pos = glGetAttribLocation(program, "pos"); - } else { -#endif - context->oddbuf = context->framebuf = malloc(320 * 240 * screen->format->BytesPerPixel * 2); - context->evenbuf = ((char *)context->oddbuf) + 320 * 240 * screen->format->BytesPerPixel; -#ifndef DISABLE_OPENGL } -#endif -} - -uint8_t render_depth() -{ - return screen->format->BytesPerPixel * 8; + glGenBuffers(2, buffers); + glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data), vertex_data, GL_STATIC_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(element_data), element_data, GL_STATIC_DRAW); + vshader = load_shader(tern_find_ptr_default(config, "videovertex_shader", "default.v.glsl"), GL_VERTEX_SHADER); + fshader = load_shader(tern_find_ptr_default(config, "videofragment_shader", "default.f.glsl"), GL_FRAGMENT_SHADER); + program = glCreateProgram(); + glAttachShader(program, vshader); + glAttachShader(program, fshader); + glLinkProgram(program); + GLint link_status; + glGetProgramiv(program, GL_LINK_STATUS, &link_status); + if (!link_status) { + fputs("Failed to link shader program\n", stderr); + exit(1); + } + un_textures[0] = glGetUniformLocation(program, "textures[0]"); + un_textures[1] = glGetUniformLocation(program, "textures[1]"); + un_width = glGetUniformLocation(program, "width"); + at_pos = glGetAttribLocation(program, "pos"); } char * caption = NULL; -void render_init(int width, int height, char * title, uint32_t fps, uint8_t fullscreen, uint8_t use_gl) +void render_init(int width, int height, char * title, uint32_t fps, uint8_t fullscreen) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK) < 0) { fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); exit(1); } printf("width: %d, height: %d\n", width, height); - uint32_t flags = SDL_ANYFORMAT; - -#ifndef DISABLE_OPENGL - if (use_gl) - { - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - flags = SDL_OPENGL; - if (fullscreen) { - flags |= SDL_FULLSCREEN; - } - } else { -#else - { -#endif - if (fullscreen) { - flags |= SDL_FULLSCREEN | SDL_HWSURFACE | SDL_DOUBLEBUF; - } else { - flags |= SDL_SWSURFACE; - } + uint32_t flags = SDL_WINDOW_OPENGL; + + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + if (fullscreen) { + flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + SDL_DisplayMode mode; + //TODO: Multiple monitor support + SDL_GetCurrentDisplayMode(0, &mode); + //the SDL2 migration guide suggests setting width and height to 0 when using SDL_WINDOW_FULLSCREEN_DESKTOP + //but that doesn't seem to work right when using OpenGL, at least on Linux anyway + width = mode.w; + height = mode.h; + } + main_window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, flags); + if (!main_window) { + fprintf(stderr, "Unable to create SDL window: %s\n", SDL_GetError()); + SDL_Quit(); + exit(1); } - screen = SDL_SetVideoMode(width, height, 32, flags); - if (!screen) { - fprintf(stderr, "Unable to get SDL surface: %s\n", SDL_GetError()); + SDL_GetWindowSize(main_window, &width, &height); + printf("Window created with size: %d x %d\n", width, height); + main_context = SDL_GL_CreateContext(main_window); + GLenum res = glewInit(); + if (res != GLEW_OK) { + fprintf(stderr, "Initialization of GLEW failed with code %d\n", res); SDL_Quit(); exit(1); } - if (!use_gl && screen->format->BytesPerPixel != 2 && screen->format->BytesPerPixel != 4) { - fprintf(stderr, "BlastEm requires a 16-bit or 32-bit surface, SDL returned a %d-bit surface\n", screen->format->BytesPerPixel * 8); + if (!GLEW_VERSION_2_0) { + fputs("BlastEm requires at least OpenGL 2.0, but it is unavailable\n", stderr); SDL_Quit(); exit(1); } -#ifndef DISABLE_OPENGL - //TODO: fallback on standard rendering if OpenGL 2.0 is unavailable or if init fails - if (use_gl) - { - GLenum res = glewInit(); - if (res != GLEW_OK) { - fprintf(stderr, "Initialization of GLEW failed with code %d\n", res); - SDL_Quit(); - exit(1); - } - if (!GLEW_VERSION_2_0) { - fputs("OpenGL 2.0 is unable, falling back to standard SDL rendering\n", stderr); - SDL_Quit(); - exit(1); - } - float aspect = (float)width / height; - if (fabs(aspect - 4.0/3.0) > 0.01 && strcmp(tern_find_ptr_default(config, "videoaspect", "normal"), "stretch")) { - for (int i = 0; i < 4; i++) - { - if (aspect > 4.0/3.0) { - vertex_data[i*2] *= (4.0/3.0)/aspect; - } else { - vertex_data[i*2+1] *= aspect/(4.0/3.0); - } + float aspect = (float)width / height; + if (fabs(aspect - 4.0/3.0) > 0.01 && strcmp(tern_find_ptr_default(config, "videoaspect", "normal"), "stretch")) { + for (int i = 0; i < 4; i++) + { + if (aspect > 4.0/3.0) { + vertex_data[i*2] *= (4.0/3.0)/aspect; + } else { + vertex_data[i*2+1] *= aspect/(4.0/3.0); } } } - render_gl = use_gl; -#endif - SDL_WM_SetCaption(title, title); caption = title; min_delay = 0; for (int i = 0; i < 100; i++) { @@ -341,8 +303,8 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full num_joysticks = MAX_JOYSTICKS; } for (int i = 0; i < num_joysticks; i++) { - printf("Joystick %d: %s\n", i, SDL_JoystickName(i)); SDL_Joystick * joy = joysticks[i] = SDL_JoystickOpen(i); + printf("Joystick %d: %s\n", i, SDL_JoystickName(joy)); if (joy) { printf("\tNum Axes: %d\n\tNum Buttons: %d\n\tNum Hats: %d\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy)); } @@ -352,9 +314,11 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full atexit(SDL_Quit); atexit(render_close_audio); } -#ifndef DISABLE_OPENGL -void render_context_gl(vdp_context * context) + +void render_context(vdp_context * context) { + last_frame = SDL_GetTicks(); + glBindTexture(GL_TEXTURE_2D, textures[context->framebuf == context->oddbuf ? 0 : 1]); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 320, 240, GL_BGRA, GL_UNSIGNED_BYTE, context->framebuf);; @@ -381,81 +345,7 @@ void render_context_gl(vdp_context * context) glDisableVertexAttribArray(at_pos); - SDL_GL_SwapBuffers(); - if (context->regs[REG_MODE_4] & BIT_INTERLACE) - { - context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; - } -} -#endif - -uint32_t blankbuf[320*240]; - -void render_context(vdp_context * context) -{ - uint16_t *buf_16; - uint32_t *buf_32; - uint8_t b,g,r; - last_frame = SDL_GetTicks(); -#ifndef DISABLE_OPENGL - if (render_gl) - { - render_context_gl(context); - return; - } -#endif - if (SDL_MUSTLOCK(screen)) { - if (SDL_LockSurface(screen) < 0) { - return; - } - } - uint16_t repeat_x = screen->clip_rect.w / 320; - uint16_t repeat_y = screen->clip_rect.h / 240; - if (repeat_x > repeat_y) { - repeat_x = repeat_y; - } else { - repeat_y = repeat_x; - } - int othermask = repeat_y >> 1; - - if (screen->format->BytesPerPixel == 2) { - uint16_t *otherbuf = (context->regs[REG_MODE_4] & BIT_INTERLACE) ? context->evenbuf : (uint16_t *)blankbuf; - uint16_t * oddbuf = context->oddbuf; - buf_16 = (uint16_t *)screen->pixels; - for (int y = 0; y < 240; y++) { - for (int i = 0; i < repeat_y; i++,buf_16 += screen->pitch/2) { - uint16_t *line = buf_16; - uint16_t *src_line = (i & othermask ? otherbuf : oddbuf) + y * 320; - for (int x = 0; x < 320; x++) { - uint16_t color = *(src_line++); - for (int j = 0; j < repeat_x; j++) { - *(line++) = color; - } - } - } - } - } else { - uint32_t *otherbuf = (context->regs[REG_MODE_4] & BIT_INTERLACE) ? context->evenbuf : (uint32_t *)blankbuf; - uint32_t * oddbuf = context->oddbuf; - buf_32 = (uint32_t *)screen->pixels; - for (int y = 0; y < 240; y++) { - for (int i = 0; i < repeat_y; i++,buf_32 += screen->pitch/4) { - uint32_t *line = buf_32; - uint32_t *src_line = (i & othermask ? otherbuf : oddbuf) + y * 320; - for (int x = 0; x < 320; x++) { - uint32_t color = *(src_line++); - for (int j = 0; j < repeat_x; j++) { - *(line++) = color; - } - } - } - } - } - if ( SDL_MUSTLOCK(screen) ) { - SDL_UnlockSurface(screen); - } - //SDL_UpdateRect(screen, 0, 0, screen->clip_rect.w, screen->clip_rect.h); - SDL_Flip(screen); + SDL_GL_SwapWindow(main_window); if (context->regs[REG_MODE_4] & BIT_INTERLACE) { context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; @@ -568,8 +458,6 @@ int wait_render_frame(vdp_context * context, int frame_limit) } render_context(context); - - //TODO: Figure out why this causes segfaults frame_counter++; if ((last_frame - start) > 1000) { if (start && (last_frame-start)) { @@ -577,8 +465,7 @@ int wait_render_frame(vdp_context * context, int frame_limit) fps_caption = malloc(strlen(caption) + strlen(" - 1000.1 fps") + 1); } sprintf(fps_caption, "%s - %.1f fps", caption, ((float)frame_counter) / (((float)(last_frame-start)) / 1000.0)); - SDL_WM_SetCaption(fps_caption, caption); - fflush(stdout); + SDL_SetWindowTitle(main_window, fps_caption); } start = last_frame; frame_counter = 0; diff --git a/stateview.c b/stateview.c index 713c390..0d2286d 100644 --- a/stateview.c +++ b/stateview.c @@ -87,7 +87,7 @@ int main(int argc, char ** argv) height = height < 240 ? (width/320) * 240 : height; vdp_context context; - render_init(width, height, "GST State Viewer", 60, 0, 0); + render_init(width, height, "GST State Viewer", 60, 0); init_vdp_context(&context, 0); vdp_load_gst(&context, state_file); vdp_run_to_vblank(&context); diff --git a/vdp.c b/vdp.c index 8c6405e..c7240d4 100644 --- a/vdp.c +++ b/vdp.c @@ -62,10 +62,8 @@ void init_vdp_context(vdp_context * context, uint8_t region_pal) memset(context->framebuf, 0, FRAMEBUF_ENTRIES * (32 / 8)); context->evenbuf = malloc(FRAMEBUF_ENTRIES * (32 / 8)); memset(context->evenbuf, 0, FRAMEBUF_ENTRIES * (32 / 8)); - context->b32 = 1; } else { render_alloc_surfaces(context); - context->b32 = render_depth() == 32; } context->framebuf = context->oddbuf; context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); @@ -788,20 +786,14 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context) return; } render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context); - uint16_t *dst; - uint32_t *dst32; + uint32_t *dst; uint8_t *sprite_buf, *plane_a, *plane_b; int plane_a_off, plane_b_off; if (col) { col-=2; - if (context->b32) { - dst32 = context->framebuf; - dst32 += line * 320 + col * 8; - } else { - dst = context->framebuf; - dst += line * 320 + col * 8; - } + dst = context->framebuf; + dst += line * 320 + col * 8; sprite_buf = context->linebuf + col * 8; uint8_t a_src, src; if (context->flags & FLAG_WINDOW) { @@ -859,11 +851,7 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context) } else { outpixel = colors[pixel]; } - if (context->b32) { - *(dst32++) = outpixel; - } else { - *(dst++) = outpixel; - } + *(dst++) = outpixel; //*dst = (context->cram[pixel & 0x3F] & 0xEEE) | ((pixel & BUF_BIT_PRIORITY) ? FBUF_BIT_PRIORITY : 0) | src; } } else { @@ -890,11 +878,7 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context) } else { outpixel = context->colors[pixel & 0x3F]; } - if (context->b32) { - *(dst32++) = outpixel; - } else { - *(dst++) = outpixel; - } + *(dst++) = outpixel; } } } @@ -1445,20 +1429,11 @@ void check_render_bg(vdp_context * context, int32_t line, uint32_t slot) } } if (starti >= 0) { - if (context->b32) { - uint32_t color = context->colors[context->regs[REG_BG_COLOR]]; - uint32_t * start = context->framebuf; - start += starti; - for (int i = 0; i < 2; i++) { - *(start++) = color; - } - } else { - uint16_t color = context->colors[context->regs[REG_BG_COLOR]]; - uint16_t * start = context->framebuf; - start += starti; - for (int i = 0; i < 2; i++) { - *(start++) = color; - } + uint32_t color = context->colors[context->regs[REG_BG_COLOR]]; + uint32_t * start = context->framebuf; + start += starti; + for (int i = 0; i < 2; i++) { + *(start++) = color; } } } diff --git a/vgmplay.c b/vgmplay.c index f29a9a5..879a399 100644 --- a/vgmplay.c +++ b/vgmplay.c @@ -142,7 +142,7 @@ int main(int argc, char ** argv) uint32_t fps = 60; config = load_config(argv[0]); - render_init(320, 240, "vgm play", 60, 0, 0); + render_init(320, 240, "vgm play", 60, 0); uint32_t opts = 0; if (argc >= 3 && !strcmp(argv[2], "-y")) { -- cgit v1.2.3 From 73ffeecaebbc313eb5713d779622b6e91cc72675 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 20 May 2015 22:27:51 -0700 Subject: Add some tests for hint timing and fix it properly this time. --- Makefile | 3 +++ test.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ vdp.c | 26 +++++++++++----------- 3 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 test.c diff --git a/Makefile b/Makefile index 6ddcd52..ae61100 100644 --- a/Makefile +++ b/Makefile @@ -106,6 +106,9 @@ stateview : stateview.o vdp.o render_sdl.o $(CONFIGOBJS) gst.o vgmplay : vgmplay.o render_sdl.o $(CONFIGOBJS) $(AUDIOOBJS) $(CC) -o vgmplay vgmplay.o render_sdl.o $(CONFIGOBJS) $(AUDIOOBJS) $(LDFLAGS) + +test : test.o vdp.o + $(CC) -o test test.o vdp.o testgst : testgst.o gst.o $(CC) -o testgst testgst.o gst.o diff --git a/test.c b/test.c new file mode 100644 index 0000000..d06a26b --- /dev/null +++ b/test.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include +#include "vdp.h" + +int headless = 1; +uint16_t read_dma_value(uint32_t address) +{ + return 0; +} + +uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t b) +{ + return 0; +} + +void render_alloc_surfaces(vdp_context * context) +{ + context->oddbuf = context->framebuf = malloc(512 * 256 * 4 * 2); + memset(context->oddbuf, 0, 512 * 256 * 4 * 2); + context->evenbuf = ((char *)context->oddbuf) + 512 * 256 * 4; +} + +int check_hint_time(vdp_context * v_context) +{ + uint32_t orig_hint_cycle = vdp_next_hint(v_context); + uint32_t cur_hint_cycle; + printf("hint cycle is %d at vcounter: %d, hslot: %d\n", orig_hint_cycle, v_context->vcounter, v_context->hslot); + int res = 1; + while ((cur_hint_cycle = vdp_next_hint(v_context)) > v_context->cycles) + { + if (cur_hint_cycle != orig_hint_cycle) { + fprintf(stderr, "ERROR: hint cycle changed to %d at vcounter: %d, hslot: %d\n", cur_hint_cycle, v_context->vcounter, v_context->hslot); + orig_hint_cycle = cur_hint_cycle; + res = 0; + } + vdp_run_context(v_context, v_context->cycles + 1); + } + printf("hint fired at cycle: %d, vcounter: %d, hslot: %d\n", cur_hint_cycle, v_context->vcounter, v_context->hslot); + vdp_int_ack(v_context, 4); + return res; +} + + +int main(int argc, char ** argv) +{ + vdp_context v_context; + init_vdp_context(&v_context, 0); + vdp_control_port_write(&v_context, 0x8144); + vdp_control_port_write(&v_context, 0x8C81); + vdp_control_port_write(&v_context, 0x8A7F); + vdp_control_port_write(&v_context, 0x8014); + v_context.hint_counter = 0x7F; + v_context.vcounter = 128; + v_context.hslot = 165; + //check single shot behavior + int res = check_hint_time(&v_context); + //check every line behavior + while (v_context.vcounter < 225) + { + vdp_run_context(&v_context, v_context.cycles + 1); + } + vdp_control_port_write(&v_context, 0x8A00); + int hint_count = 0; + while (res && v_context.vcounter != 224) + { + res = res && check_hint_time(&v_context); + hint_count++; + } + if (res && hint_count != 225) { + fprintf(stderr, "ERROR: hint count should be 225 but was %d instead\n", hint_count); + res = 0; + } + return 0; +} diff --git a/vdp.c b/vdp.c index c7240d4..afd5087 100644 --- a/vdp.c +++ b/vdp.c @@ -1443,6 +1443,19 @@ uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, void vdp_advance_line(vdp_context *context) { context->vcounter++; + context->vcounter &= 0x1FF; + if (context->flags2 & FLAG2_REGION_PAL) { + if (context->latched_mode & BIT_PAL) { + if (context->vcounter == 0x10B) { + context->vcounter = 0x1D2; + } + } else if (context->vcounter == 0x103){ + context->vcounter = 0x1CA; + } + } else if (!(context->latched_mode & BIT_PAL) && context->vcounter == 0xEB) { + context->vcounter = 0x1E5; + } + if (context->vcounter > (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) { context->hint_counter = context->regs[REG_HINT]; } else if (context->hint_counter) { @@ -1565,19 +1578,6 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) } else { vdp_advance_line(context); } - context->vcounter &= 0x1FF; - if (context->flags2 & FLAG2_REGION_PAL) { - if (context->latched_mode & BIT_PAL) { - if (context->vcounter == 0x10B) { - context->vcounter = 0x1D2; - } - } else if (context->vcounter == 0x103){ - context->vcounter = 0x1CA; - } - } else if (!(context->latched_mode & BIT_PAL) && context->vcounter == 0xEB) { - context->vcounter = 0x1E5; - } - } } -- cgit v1.2.3 From c16bdc99580a5867127efb1fad51c79f7c0804a7 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 20 May 2015 23:34:12 -0700 Subject: Better handling of savestate and debug break events with "uncooperative" games/demos --- blastem.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/blastem.c b/blastem.c index 60a5fa6..148b6c4 100644 --- a/blastem.c +++ b/blastem.c @@ -251,6 +251,9 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) vdp_int_ack(v_context, context->int_ack); context->int_ack = 0; } + if (!address && (break_on_sync || save_state)) { + context->sync_cycle = context->current_cycle + 1; + } adjust_int_cycle(context, v_context); if (address) { if (break_on_sync) { @@ -265,6 +268,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80); } save_gst(gen, "savestate.gst", address); + puts("Saved state to savestate.gst"); } } return context; -- cgit v1.2.3 From da1788598fe5f71295b6086ed8ef54fa39bbbd22 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 21 May 2015 00:55:46 -0700 Subject: Restore the other 2 debug display modes --- io.c | 2 +- vdp.c | 196 ++++++++++++++++++++++++++++++++++++++++-------------------------- vdp.h | 1 + 3 files changed, 122 insertions(+), 77 deletions(-) diff --git a/io.c b/io.c index 3f76d90..d50133d 100644 --- a/io.c +++ b/io.c @@ -255,7 +255,7 @@ void handle_binding_up(keybinding * binding) if (ui_debug_pal == 4) { ui_debug_pal = 0; } - render_debug_pal(ui_debug_pal); + genesis->vdp->debug_pal = ui_debug_pal; break; case UI_ENTER_DEBUGGER: break_on_sync = 1; diff --git a/vdp.c b/vdp.c index afd5087..065d719 100644 --- a/vdp.c +++ b/vdp.c @@ -794,91 +794,135 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context) col-=2; dst = context->framebuf; dst += line * 320 + col * 8; - sprite_buf = context->linebuf + col * 8; - uint8_t a_src, src; - if (context->flags & FLAG_WINDOW) { - plane_a_off = context->buf_a_off; - a_src = DBG_SRC_W; - } else { - plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF); - a_src = DBG_SRC_A; - } - 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; - plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); - plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); - uint32_t * colors = context->colors; - src = 0; - pixel = context->regs[REG_BG_COLOR]; - src = DBG_SRC_BG; - if (*plane_b & 0xF) { - pixel = *plane_b; - src = DBG_SRC_B; - } - if (*plane_a & 0xF && (*plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { - pixel = *plane_a; - src = DBG_SRC_A; - } - if (*sprite_buf & 0xF) { - uint8_t sprite_color = *sprite_buf & 0x3F; - if (sprite_color == 0x3E) { - colors += CRAM_SIZE*2; - src |= DBG_HILIGHT; - } else if (sprite_color == 0x3F) { + if (context->debug < 2) { + sprite_buf = context->linebuf + col * 8; + uint8_t a_src, src; + if (context->flags & FLAG_WINDOW) { + plane_a_off = context->buf_a_off; + a_src = DBG_SRC_W; + } else { + plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF); + a_src = DBG_SRC_A; + } + 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; + plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); + plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); + uint32_t * colors = context->colors; + src = 0; + pixel = context->regs[REG_BG_COLOR]; + src = DBG_SRC_BG; + if (*plane_b & 0xF) { + pixel = *plane_b; + src = DBG_SRC_B; + } + if (*plane_a & 0xF && (*plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { + pixel = *plane_a; + src = DBG_SRC_A; + } + if (*sprite_buf & 0xF) { + uint8_t sprite_color = *sprite_buf & 0x3F; + if (sprite_color == 0x3E) { + colors += CRAM_SIZE*2; + src |= DBG_HILIGHT; + } else if (sprite_color == 0x3F) { + colors += CRAM_SIZE; + src |= DBG_SHADOW; + } else if ((*sprite_buf & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { + pixel = *sprite_buf; + src = DBG_SRC_S; + if ((pixel & 0xF) == 0xE) { + src |= DBG_SHADOW; + colors += CRAM_SIZE; + } + + } + } else if (!((*plane_a | *plane_b) & BUF_BIT_PRIORITY)) { colors += CRAM_SIZE; src |= DBG_SHADOW; - } else if ((*sprite_buf & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { + } + pixel &= 0x3F; + uint32_t outpixel; + if (context->debug) { + outpixel = context->debugcolors[src]; + } else { + outpixel = colors[pixel]; + } + *(dst++) = outpixel; + //*dst = (context->cram[pixel & 0x3F] & 0xEEE) | ((pixel & BUF_BIT_PRIORITY) ? FBUF_BIT_PRIORITY : 0) | src; + } + } else { + for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { + plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); + plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); + uint8_t pixel = context->regs[REG_BG_COLOR]; + src = DBG_SRC_BG; + if (*plane_b & 0xF) { + pixel = *plane_b; + src = DBG_SRC_B; + } + if (*plane_a & 0xF && (*plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { + pixel = *plane_a; + src = DBG_SRC_A; + } + if (*sprite_buf & 0xF && (*sprite_buf & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { pixel = *sprite_buf; src = DBG_SRC_S; - if ((pixel & 0xF) == 0xE) { - src |= DBG_SHADOW; - colors += CRAM_SIZE; - } - } - } else if (!((*plane_a | *plane_b) & BUF_BIT_PRIORITY)) { - colors += CRAM_SIZE; - src |= DBG_SHADOW; - } - pixel &= 0x3F; - uint32_t outpixel; - if (context->debug) { - outpixel = context->debugcolors[src]; - } else { - outpixel = colors[pixel]; + uint32_t outpixel; + if (context->debug) { + outpixel = context->debugcolors[src]; + } else { + outpixel = context->colors[pixel & 0x3F]; + } + *(dst++) = outpixel; } - *(dst++) = outpixel; - //*dst = (context->cram[pixel & 0x3F] & 0xEEE) | ((pixel & BUF_BIT_PRIORITY) ? FBUF_BIT_PRIORITY : 0) | src; } - } else { - for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { - plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); - plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); - uint8_t pixel = context->regs[REG_BG_COLOR]; - src = DBG_SRC_BG; - if (*plane_b & 0xF) { - pixel = *plane_b; - src = DBG_SRC_B; - } - if (*plane_a & 0xF && (*plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { - pixel = *plane_a; - src = DBG_SRC_A; + } else if (context->debug == 2) { + if (col < 32) { + *(dst++) = context->colors[col * 2]; + *(dst++) = context->colors[col * 2]; + *(dst++) = context->colors[col * 2]; + *(dst++) = context->colors[col * 2]; + *(dst++) = context->colors[col * 2 + 1]; + *(dst++) = context->colors[col * 2 + 1]; + *(dst++) = context->colors[col * 2 + 1]; + *(dst++) = context->colors[col * 2 + 1]; + *(dst++) = context->colors[col * 2 + 2]; + *(dst++) = context->colors[col * 2 + 2]; + *(dst++) = context->colors[col * 2 + 2]; + *(dst++) = context->colors[col * 2 + 2]; + *(dst++) = context->colors[col * 2 + 3]; + *(dst++) = context->colors[col * 2 + 3]; + *(dst++) = context->colors[col * 2 + 3]; + *(dst++) = context->colors[col * 2 + 3]; + } else if (col == 32 || line >= 192) { + for (int32_t i = 0; i < 16; i ++) { + *(dst++) = 0; } - if (*sprite_buf & 0xF && (*sprite_buf & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { - pixel = *sprite_buf; - src = DBG_SRC_S; - } - uint32_t outpixel; - if (context->debug) { - outpixel = context->debugcolors[src]; - } else { - outpixel = context->colors[pixel & 0x3F]; + } else { + for (int32_t i = 0; i < 16; i ++) { + *(dst++) = context->colors[line / 3 + (col - 34) * 0x20]; } - *(dst++) = outpixel; + } + } else { + uint32_t cell = (line / 8) * (context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32) + col; + uint32_t address = cell * 32 + (line % 8) * 4; + for (int32_t i = 0; i < 4; i ++) { + *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] >> 4)]; + *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] & 0xF)]; + address++; + } + cell++; + address = cell * 32 + (line % 8) * 4; + for (int32_t i = 0; i < 4; i ++) { + *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] >> 4)]; + *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] & 0xF)]; + address++; } } } diff --git a/vdp.h b/vdp.h index a05501c..5627057 100644 --- a/vdp.h +++ b/vdp.h @@ -170,6 +170,7 @@ typedef struct { uint8_t buf_a_off; uint8_t buf_b_off; uint8_t debug; + uint8_t debug_pal; uint8_t *tmp_buf_a; uint8_t *tmp_buf_b; } vdp_context; -- cgit v1.2.3 From 68f82c7735196d65a2d57ce8d36cac01a402c3a2 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 21 May 2015 18:37:41 -0700 Subject: Process events while waiting for 68K debugger input. This prevents "not responsive" dialogs when sitting in the debugger --- debug.c | 21 ++++++++++++++++++++- render.h | 1 + 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/debug.c b/debug.c index 11ec9ad..ac5c34d 100644 --- a/debug.c +++ b/debug.c @@ -3,6 +3,8 @@ #include "68kinst.h" #include #include +#include +#include "render.h" static bp_def * breakpoints = NULL; static bp_def * zbreakpoints = NULL; @@ -508,8 +510,25 @@ m68k_context * debugger(m68k_context * context, uint32_t address) printf("%X: %s\n", address, input_buf); uint32_t after = address + (after_pc-pc)*2; int debugging = 1; + int prompt = 1; + fd_set read_fds; + FD_ZERO(&read_fds); + struct timeval timeout; while (debugging) { - fputs(">", stdout); + if (prompt) { + fputs(">", stdout); + fflush(stdout); + } + process_events(); + timeout.tv_sec = 0; + timeout.tv_usec = 16667; + FD_SET(fileno(stdin), &read_fds); + if(select(fileno(stdin) + 1, &read_fds, NULL, NULL, &timeout) < 1) { + prompt = 0; + continue; + } else { + prompt = 1; + } if (!fgets(input_buf, sizeof(input_buf), stdin)) { fputs("fgets failed", stderr); break; diff --git a/render.h b/render.h index 90ebf9d..79f05ca 100644 --- a/render.h +++ b/render.h @@ -33,6 +33,7 @@ void process_events(); int render_joystick_num_buttons(int joystick); int render_joystick_num_hats(int joystick); int render_num_joysticks(); +void process_events(); //TODO: Throw an ifdef in here once there's more than one renderer #include -- cgit v1.2.3 From 808e9ca1a04cf5c5a6077e5f3a11f289db2093b6 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 22 May 2015 18:38:44 -0700 Subject: Fix bug in vdp_next_hint that was causing HINTs to fire repeatedly when they should not have fired at all based on an HINT interval that was larger than the number of active lines in the display --- vdp.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vdp.c b/vdp.c index 065d719..5bbe50a 100644 --- a/vdp.c +++ b/vdp.c @@ -2034,6 +2034,9 @@ uint32_t vdp_next_hint(vdp_context * context) uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; uint32_t hint_line; if (context->vcounter + context->hint_counter >= inactive_start) { + if (context->regs[REG_HINT] > inactive_start) { + return 0xFFFFFFFF; + } hint_line = context->regs[REG_HINT]; } else { hint_line = context->vcounter + context->hint_counter + 1; -- cgit v1.2.3 From eb8ad570f140b57480ba8ce28819d7cd68d6548e Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 22 May 2015 21:11:41 -0700 Subject: Fix out of bounds memory access when an instruction wraps around the end of memory --- m68k_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/m68k_core.c b/m68k_core.c index 1ac4ca2..8bf9582 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -636,6 +636,7 @@ void map_native_address(m68k_context * context, uint32_t address, code_ptr nativ uint32_t offset = address % NATIVE_CHUNK_SIZE; native_code_map[chunk].offsets[offset] = native_addr-native_code_map[chunk].base; for(address++,size-=2; size; address++,size-=2) { + address &= opts->gen.address_mask >> 1; chunk = address / NATIVE_CHUNK_SIZE; offset = address % NATIVE_CHUNK_SIZE; if (!native_code_map[chunk].base) { -- cgit v1.2.3 From 057e8fb32092e1c1c642791cf915c2522b5662e0 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 22 May 2015 23:49:32 -0700 Subject: Don't attempt to translate or map code at odd addresses. This fixes a bug that shows up when playing College Footbal USA 96 --- m68k_core.c | 30 +++++++++++++++++------------- m68k_core.h | 1 + m68k_core_x86.c | 11 +++++++++-- m68k_internal.h | 2 +- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/m68k_core.c b/m68k_core.c index 8bf9582..5d88a2d 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -195,7 +195,7 @@ void push_const(m68k_options *opts, int32_t value) void jump_m68k_abs(m68k_options * opts, uint32_t address) { code_info *code = &opts->gen.code; - code_ptr dest_addr = get_native_address(opts->gen.native_code_map, address); + code_ptr dest_addr = get_native_address(opts, address); if (!dest_addr) { opts->gen.deferred = defer_address(opts->gen.deferred, address, code->cur + 1); //dummy address to be replaced later, make sure it generates a 4-byte displacement @@ -551,10 +551,13 @@ void translate_m68k_rte(m68k_options *opts, m68kinst *inst) jmp_r(code, opts->gen.scratch1); } -code_ptr get_native_address(native_map_slot * native_code_map, uint32_t address) +code_ptr get_native_address(m68k_options *opts, uint32_t address) { - //FIXME: Use opts->gen.address_mask - address &= 0xFFFFFF; + native_map_slot * native_code_map = opts->gen.native_code_map; + address &= opts->gen.address_mask; + if (address & 1) { + return opts->odd_address; + } address /= 2; uint32_t chunk = address / NATIVE_CHUNK_SIZE; if (!native_code_map[chunk].base) { @@ -569,7 +572,7 @@ code_ptr get_native_address(native_map_slot * native_code_map, uint32_t address) code_ptr get_native_from_context(m68k_context * context, uint32_t address) { - return get_native_address(context->native_code_map, address); + return get_native_address(context->options, address); } uint32_t get_instruction_start(native_map_slot * native_code_map, uint32_t address) @@ -837,7 +840,7 @@ void translate_m68k_stream(uint32_t address, m68k_context * context) m68kinst instbuf; m68k_options * opts = context->options; code_info *code = &opts->gen.code; - if(get_native_address(opts->gen.native_code_map, address)) { + if(get_native_address(opts, address)) { return; } uint16_t *encoded, *next; @@ -847,13 +850,16 @@ void translate_m68k_stream(uint32_t address, m68k_context * context) fflush(opts->address_log); } do { + if (address & 1) { + break; + } encoded = get_native_pointer(address, (void **)context->mem_pointers, &opts->gen); if (!encoded) { map_native_address(context, address, code->cur, 2, 1); translate_out_of_bounds(code); break; } - code_ptr existing = get_native_address(opts->gen.native_code_map, address); + code_ptr existing = get_native_address(opts, address); if (existing) { jmp(code, existing); break; @@ -887,7 +893,7 @@ void * m68k_retranslate_inst(uint32_t address, m68k_context * context) m68k_options * opts = context->options; code_info *code = &opts->gen.code; uint8_t orig_size = get_native_inst_size(opts, address); - code_ptr orig_start = get_native_address(context->native_code_map, address); + code_ptr orig_start = get_native_address(context->options, address); uint32_t orig = address; code_info orig_code; orig_code.cur = orig_start; @@ -961,19 +967,17 @@ void * m68k_retranslate_inst(uint32_t address, m68k_context * context) code_ptr get_native_address_trans(m68k_context * context, uint32_t address) { - //FIXME: Use opts->gen.address_mask - address &= 0xFFFFFF; - code_ptr ret = get_native_address(context->native_code_map, address); + code_ptr ret = get_native_address(context->options, address); if (!ret) { translate_m68k_stream(address, context); - ret = get_native_address(context->native_code_map, address); + ret = get_native_address(context->options, address); } return ret; } void remove_breakpoint(m68k_context * context, uint32_t address) { - code_ptr native = get_native_address(context->native_code_map, address); + code_ptr native = get_native_address(context->options, address); code_info tmp = context->options->gen.code; context->options->gen.code.cur = native; context->options->gen.code.last = native + MAX_NATIVE_SIZE; diff --git a/m68k_core.h b/m68k_core.h index 2635a09..b91a37b 100644 --- a/m68k_core.h +++ b/m68k_core.h @@ -34,6 +34,7 @@ typedef struct { code_ptr write_32_highfirst; code_ptr do_sync; code_ptr trap; + code_ptr odd_address; start_fun start_context; code_ptr retrans_stub; code_ptr native_addr; diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 2792bc6..62588b7 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -801,7 +801,7 @@ void translate_m68k_bcc(m68k_options * opts, m68kinst * inst) if (inst->extra.cond == COND_TRUE) { jump_m68k_abs(opts, after + disp); } else { - code_ptr dest_addr = get_native_address(opts->gen.native_code_map, after + disp); + code_ptr dest_addr = get_native_address(opts, after + disp); uint8_t cond = m68k_eval_cond(opts, inst->extra.cond); if (!dest_addr) { opts->gen.deferred = defer_address(opts->gen.deferred, after + disp, code->cur + 2); @@ -2089,7 +2089,7 @@ m68k_context * m68k_handle_code_write(uint32_t address, m68k_context * context) if (inst_start) { m68k_options * options = context->options; code_info *code = &options->gen.code; - code_ptr dst = get_native_address(context->native_code_map, inst_start); + code_ptr dst = get_native_address(context->options, inst_start); code_info orig; orig.cur = dst; orig.last = dst + 128; @@ -2475,4 +2475,11 @@ void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chu call(code, opts->native_addr_and_sync); cycles(&opts->gen, 18); jmp_r(code, opts->gen.scratch1); + + opts->odd_address = code->cur; + mov_ir(code, (int64_t)stderr, RDI, SZ_PTR); + mov_ir(code, (int64_t)"Attempt to execute code at odd address\n", RSI, SZ_PTR); + call_args_abi(code, (code_ptr)fprintf, 2, RDI, RSI, RDX); + xor_rr(code, RDI, RDI, SZ_D); + call_args(code, (code_ptr)exit, 1, RDI); } diff --git a/m68k_internal.h b/m68k_internal.h index 755fd99..13b7c15 100644 --- a/m68k_internal.h +++ b/m68k_internal.h @@ -46,7 +46,7 @@ void m68k_save_result(m68kinst * inst, m68k_options * opts); void push_const(m68k_options *opts, int32_t value); void jump_m68k_abs(m68k_options * opts, uint32_t address); void swap_ssp_usp(m68k_options * opts); -code_ptr get_native_address(native_map_slot * native_code_map, uint32_t address); +code_ptr get_native_address(m68k_options *opts, uint32_t address); void map_native_address(m68k_context * context, uint32_t address, code_ptr native_addr, uint8_t size, uint8_t native_size); uint8_t get_native_inst_size(m68k_options * opts, uint32_t address); uint8_t m68k_is_terminal(m68kinst * inst); -- cgit v1.2.3 From a68ca32cfe9156b40952894ff09f1991f073486e Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 23 May 2015 20:24:27 -0700 Subject: Eliminate runtime.S/runtime_32.S. --- Makefile | 10 ++++++---- m68k_core_x86.c | 8 ++++++-- runtime.S | 16 ---------------- runtime_32.S | 17 ----------------- 4 files changed, 12 insertions(+), 39 deletions(-) delete mode 100644 runtime.S delete mode 100644 runtime_32.S diff --git a/Makefile b/Makefile index ae61100..f5ff1d3 100644 --- a/Makefile +++ b/Makefile @@ -45,11 +45,11 @@ endif TRANSOBJS=gen.o backend.o mem.o M68KOBJS=68kinst.o m68k_core.o ifeq ($(CPU),x86_64) -M68KOBJS+= runtime.o m68k_core_x86.o +M68KOBJS+= m68k_core_x86.o TRANSOBJS+= gen_x86.o backend_x86.o else ifeq ($(CPU),i686) -M68KOBJS+= runtime_32.o m68k_core_x86.o +M68KOBJS+= m68k_core_x86.o TRANSOBJS+= gen_x86.o backend_x86.o endif endif @@ -61,10 +61,12 @@ CONFIGOBJS=config.o tern.o util.o MAINOBJS=blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) ifeq ($(CPU),x86_64) -CFLAGS+=-DX86_64 +CFLAGS+=-DX86_64 -m64 +LDFLAGS+=-m64 else ifeq ($(CPU),i686) -CFLAGS+=-DX86_32 +CFLAGS+=-DX86_32 -m32 +LDFLAGS+=-m32 endif endif diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 62588b7..5c459b0 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -1363,8 +1363,12 @@ void translate_m68k_invalid(m68k_options *opts, m68kinst *inst) retn(code); return; } - mov_ir(code, inst->address, opts->gen.scratch1, SZ_D); - call(code, (code_ptr)m68k_invalid); + mov_ir(code, (int64_t)stderr, RDI, SZ_PTR); + mov_ir(code, (int64_t)"Invalid instruction at %X\n", RSI, SZ_PTR); + mov_ir(code, inst->address, RDX, SZ_D); + call_args_abi(code, (code_ptr)fprintf, 3, RDI, RSI, RDX); + mov_ir(code, 1, RDI, SZ_D); + call_args(code, (code_ptr)exit, 1, RDI); } void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_op, host_ea *dst_op) diff --git a/runtime.S b/runtime.S deleted file mode 100644 index 5595eb1..0000000 --- a/runtime.S +++ /dev/null @@ -1,16 +0,0 @@ - - -invalid_msg: - .asciz "Invalid instruction at %X\n" - - .global m68k_invalid -m68k_invalid: - lea invalid_msg(%rip), %rdi - mov %ecx, %esi - xor %rax, %rax - call printf - mov $1, %rdi - call exit - - - diff --git a/runtime_32.S b/runtime_32.S deleted file mode 100644 index 50117f1..0000000 --- a/runtime_32.S +++ /dev/null @@ -1,17 +0,0 @@ - - -invalid_msg: - .asciz "Invalid instruction at %X\n" - - .global m68k_invalid -m68k_invalid: - push %ecx - push invalid_msg - xor %eax, %eax - call printf - push $1 - call exit - - - - -- cgit v1.2.3 From 6b6598401eb4b16585718f69097be63137c3e111 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 23 May 2015 20:25:16 -0700 Subject: Generate an error in x86-32 builds for most cases when a REX prefix would be generated --- gen_x86.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/gen_x86.c b/gen_x86.c index ef5fbe5..ed46e6c 100644 --- a/gen_x86.c +++ b/gen_x86.c @@ -130,6 +130,44 @@ enum { X86_R15 } x86_regs_enc; +char * x86_reg_names[] = { +#ifdef X86_64 + "rax", + "rcx", + "rdx", + "rbx", + "rsp", + "rbp", + "rsi", + "rdi", +#else + "eax", + "ecx", + "edx", + "ebx", + "esp", + "ebp", + "esi", + "edi", +#endif + "ah", + "ch", + "dh", + "bh", + "r8", + "r9", + "r10", + "r11", + "r12", + "r13", + "r14", + "r15", +}; + +char * x86_sizes[] = { + "b", "w", "d", "q" +}; + void jmp_nocheck(code_info *code, code_ptr dest) { code_ptr out = code->cur; @@ -190,6 +228,7 @@ void x86_rr_sizedir(code_info *code, uint16_t opcode, uint8_t src, uint8_t dst, src = tmp; } if (size == SZ_Q || src >= R8 || dst >= R8 || (size == SZ_B && src >= RSP && src <= RDI)) { +#ifdef X86_64 *out = PRE_REX; if (src >= AH && src <= BH || dst >= AH && dst <= BH) { fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); @@ -207,6 +246,10 @@ void x86_rr_sizedir(code_info *code, uint16_t opcode, uint8_t src, uint8_t dst, dst -= (R8 - X86_R8); } out++; +#else + fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X, src: %s, dst: %s, size: %s\n", opcode, x86_reg_names[src], x86_reg_names[dst], x86_sizes[size]); + exit(1); +#endif } if (size == SZ_B) { if (src >= AH && src <= BH) { @@ -238,6 +281,7 @@ void x86_rrdisp_sizedir(code_info *code, uint16_t opcode, uint8_t reg, uint8_t b *(out++) = PRE_SIZE; } if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) { +#ifdef X86_64 *out = PRE_REX; if (reg >= AH && reg <= BH) { fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); @@ -255,6 +299,10 @@ void x86_rrdisp_sizedir(code_info *code, uint16_t opcode, uint8_t reg, uint8_t b base -= (R8 - X86_R8); } out++; +#else + fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]); + exit(1); +#endif } if (size == SZ_B) { if (reg >= AH && reg <= BH) { @@ -298,6 +346,7 @@ void x86_rrind_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t bas *(out++) = PRE_SIZE; } if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) { +#ifdef X86_64 *out = PRE_REX; if (reg >= AH && reg <= BH) { fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); @@ -315,6 +364,10 @@ void x86_rrind_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t bas base -= (R8 - X86_R8); } out++; +#else + fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]); + exit(1); +#endif } if (size == SZ_B) { if (reg >= AH && reg <= BH) { @@ -349,6 +402,7 @@ void x86_rrindex_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t b *(out++) = PRE_SIZE; } if (size == SZ_Q || reg >= R8 || base >= R8 || (size == SZ_B && reg >= RSP && reg <= RDI)) { +#ifdef X86_64 *out = PRE_REX; if (reg >= AH && reg <= BH) { fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); @@ -370,6 +424,10 @@ void x86_rrindex_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t b index -= (R8 - X86_R8); } out++; +#else + fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, base: %s, size: %s\n", opcode, x86_reg_names[reg], x86_reg_names[base], x86_sizes[size]); + exit(1); +#endif } if (size == SZ_B) { if (reg >= AH && reg <= BH) { @@ -400,6 +458,7 @@ void x86_r_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, uint *(out++) = PRE_SIZE; } if (size == SZ_Q || dst >= R8) { +#ifdef X86_64 *out = PRE_REX; if (dst >= AH && dst <= BH) { fprintf(stderr, "attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); @@ -413,6 +472,10 @@ void x86_r_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, uint dst -= (R8 - X86_R8); } out++; +#else + fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, opex, x86_reg_names[dst], x86_sizes[size]); + exit(1); +#endif } if (size == SZ_B) { if (dst >= AH && dst <= BH) { @@ -435,6 +498,7 @@ void x86_rdisp_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, *(out++) = PRE_SIZE; } if (size == SZ_Q || dst >= R8) { +#ifdef X86_64 *out = PRE_REX; if (size == SZ_Q) { *out |= REX_QUAD; @@ -444,6 +508,10 @@ void x86_rdisp_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, dst -= (R8 - X86_R8); } out++; +#else + fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, opex, x86_reg_names[dst], x86_sizes[size]); + exit(1); +#endif } if (size != SZ_B) { opcode |= BIT_SIZE; @@ -478,12 +546,18 @@ void x86_ir(code_info *code, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, i if (size != SZ_B) { al_opcode |= BIT_SIZE; if (size == SZ_Q) { +#ifdef X86_64 *out = PRE_REX | REX_QUAD; +#else + fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X, reg: %s, size: %s\n", al_opcode, x86_reg_names[dst], x86_sizes[size]); + exit(1); +#endif } } *(out++) = al_opcode | BIT_IMMED_RAX; } else { if (size == SZ_Q || dst >= R8 || (size == SZ_B && dst >= RSP && dst <= RDI)) { +#ifdef X86_64 *out = PRE_REX; if (size == SZ_Q) { *out |= REX_QUAD; @@ -493,6 +567,10 @@ void x86_ir(code_info *code, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, i dst -= (R8 - X86_R8); } out++; +#else + fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, op_ex, x86_reg_names[dst], x86_sizes[size]); + exit(1); +#endif } if (dst >= AH && dst <= BH) { dst -= (AH-X86_AH); @@ -531,6 +609,7 @@ void x86_irdisp(code_info *code, uint8_t opcode, uint8_t op_ex, int32_t val, uin } if (size == SZ_Q || dst >= R8) { +#ifdef X86_64 *out = PRE_REX; if (size == SZ_Q) { *out |= REX_QUAD; @@ -540,6 +619,10 @@ void x86_irdisp(code_info *code, uint8_t opcode, uint8_t op_ex, int32_t val, uin dst -= (R8 - X86_R8); } out++; +#else + fprintf(stderr, "Instruction requires REX prefix but this is a 32-bit build | opcode: %X:%X, reg: %s, size: %s\n", opcode, op_ex, x86_reg_names[dst], x86_sizes[size]); + exit(1); +#endif } if (size != SZ_B) { opcode |= BIT_SIZE; -- cgit v1.2.3 From e010a3570b866e225a269f1e2fc2d0dbb3b26ddc Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 23 May 2015 20:26:20 -0700 Subject: Fix a bunch of assumptions about which Z80 registers are stored in native registers to make the x86-32 build less broken --- z80_to_x86.c | 213 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 162 insertions(+), 51 deletions(-) diff --git a/z80_to_x86.c b/z80_to_x86.c index 6d33c14..a005369 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -115,7 +115,7 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t switch(inst->addr_mode & 0x1F) { case Z80_REG: - if (inst->ea_reg == Z80_IYH) { + if (inst->ea_reg == Z80_IYH && opts->regs[Z80_IY] >= 0) { if (inst->reg == Z80_IYL) { mov_rr(code, opts->regs[Z80_IY], opts->gen.scratch1, SZ_W); ror_ir(code, 8, opts->gen.scratch1, SZ_W); @@ -143,7 +143,11 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t } break; case Z80_REG_INDIRECT: - mov_rr(code, opts->regs[inst->ea_reg], areg, SZ_W); + if (opts->regs[inst->ea_reg] >= 0) { + mov_rr(code, opts->regs[inst->ea_reg], areg, SZ_W); + } else { + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, regs) + z80_low_reg(inst->ea_reg), areg, SZ_W); + } size = z80_size(inst); if (read) { if (modify) { @@ -188,7 +192,11 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t case Z80_IX_DISPLACE: case Z80_IY_DISPLACE: reg = opts->regs[(inst->addr_mode & 0x1F) == Z80_IX_DISPLACE ? Z80_IX : Z80_IY]; - mov_rr(code, reg, areg, SZ_W); + if (reg >= 0) { + mov_rr(code, reg, areg, SZ_W); + } else { + mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, regs) + (inst->addr_mode & 0x1F) == Z80_IX_DISPLACE ? Z80_IXL : Z80_IYL, areg, SZ_W); + } add_ir(code, inst->ea_reg & 0x80 ? inst->ea_reg - 256 : inst->ea_reg, areg, SZ_W); size = z80_size(inst); if (read) { @@ -276,11 +284,40 @@ uint8_t zaf_off(uint8_t flag) return offsetof(z80_context, alt_flags) + flag; } +uint8_t zr_off(uint8_t reg) +{ + if (reg > Z80_A) { + reg = z80_low_reg(reg); + } + return offsetof(z80_context, regs) + reg; +} + uint8_t zar_off(uint8_t reg) { + if (reg > Z80_A) { + reg = z80_low_reg(reg); + } return offsetof(z80_context, alt_regs) + reg; } +void zreg_to_native(z80_options *opts, uint8_t reg, uint8_t native_reg) +{ + if (opts->regs[reg] >= 0) { + mov_rr(&opts->gen.code, opts->regs[reg], native_reg, reg > Z80_A ? SZ_W : SZ_B); + } else { + mov_rdispr(&opts->gen.code, opts->gen.context_reg, zr_off(reg), native_reg, reg > Z80_A ? SZ_W : SZ_B); + } +} + +void native_to_zreg(z80_options *opts, uint8_t native_reg, uint8_t reg) +{ + if (opts->regs[reg] >= 0) { + mov_rr(&opts->gen.code, native_reg, opts->regs[reg], reg > Z80_A ? SZ_W : SZ_B); + } else { + mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, zr_off(reg), reg > Z80_A ? SZ_W : SZ_B); + } +} + void z80_print_regs_exit(z80_context * context) { printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n", @@ -384,7 +421,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, cycles(&opts->gen, (inst->reg == Z80_IX || inst->reg == Z80_IY) ? 9 : 5); sub_ir(code, 2, opts->regs[Z80_SP], SZ_W); if (inst->reg == Z80_AF) { - mov_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B); + zreg_to_native(opts, Z80_A, opts->gen.scratch1); shl_ir(code, 8, opts->gen.scratch1, SZ_W); mov_rdispr(code, opts->gen.context_reg, zf_off(ZF_S), opts->gen.scratch1, SZ_B); shl_ir(code, 1, opts->gen.scratch1, SZ_B); @@ -426,7 +463,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, bt_ir(code, 7, opts->gen.scratch1, SZ_W); setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_S)); shr_ir(code, 8, opts->gen.scratch1, SZ_W); - mov_rr(code, opts->gen.scratch1, opts->regs[Z80_A], SZ_B); + native_to_zreg(opts, opts->gen.scratch1, Z80_A); } else { translate_z80_reg(inst, &src_op, opts); mov_rr(code, opts->gen.scratch1, src_op.base, SZ_W); @@ -443,9 +480,10 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, cycles(&opts->gen, num_cycles); if (inst->addr_mode == Z80_REG) { if(inst->reg == Z80_AF) { - mov_rr(code, opts->regs[Z80_A], opts->gen.scratch1, SZ_B); - mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_A), opts->regs[Z80_A], SZ_B); + zreg_to_native(opts, Z80_A, opts->gen.scratch1); + mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_A), opts->gen.scratch2, SZ_B); mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_A), SZ_B); + native_to_zreg(opts, opts->gen.scratch2, Z80_A); //Flags are currently word aligned, so we can move //them efficiently a word at a time @@ -456,56 +494,91 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zf_off(f), SZ_W); } } else { - xchg_rr(code, opts->regs[Z80_DE], opts->regs[Z80_HL], SZ_W); + if (opts->regs[Z80_DE] >= 0 && opts->regs[Z80_HL] >= 0) { + xchg_rr(code, opts->regs[Z80_DE], opts->regs[Z80_HL], SZ_W); + } else { + zreg_to_native(opts, Z80_DE, opts->gen.scratch1); + zreg_to_native(opts, Z80_HL, opts->gen.scratch2); + native_to_zreg(opts, opts->gen.scratch1, Z80_HL); + native_to_zreg(opts, opts->gen.scratch2, Z80_DE); + } } } else { mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); call(code, opts->read_8); - xchg_rr(code, opts->regs[inst->reg], opts->gen.scratch1, SZ_B); + if (opts->regs[inst->reg] >= 0) { + xchg_rr(code, opts->regs[inst->reg], opts->gen.scratch1, SZ_B); + } else { + zreg_to_native(opts, inst->reg, opts->gen.scratch2); + xchg_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B); + native_to_zreg(opts, opts->gen.scratch2, inst->reg); + } mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); call(code, opts->write_8); cycles(&opts->gen, 1); uint8_t high_reg = z80_high_reg(inst->reg); - uint8_t use_reg; - //even though some of the upper halves can be used directly - //the limitations on mixing *H regs with the REX prefix - //prevent us from taking advantage of it - use_reg = opts->regs[inst->reg]; - ror_ir(code, 8, use_reg, SZ_W); mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch1, SZ_W); add_ir(code, 1, opts->gen.scratch1, SZ_W); call(code, opts->read_8); - xchg_rr(code, use_reg, opts->gen.scratch1, SZ_B); + if (opts->regs[inst->reg] >= 0) { + //even though some of the upper halves can be used directly + //the limitations on mixing *H regs with the REX prefix + //prevent us from taking advantage of it + uint8_t use_reg = opts->regs[inst->reg]; + ror_ir(code, 8, use_reg, SZ_W); + xchg_rr(code, use_reg, opts->gen.scratch1, SZ_B); + //restore reg to normal rotation + ror_ir(code, 8, use_reg, SZ_W); + } else { + zreg_to_native(opts, high_reg, opts->gen.scratch2); + xchg_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_B); + native_to_zreg(opts, opts->gen.scratch2, high_reg); + } mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); add_ir(code, 1, opts->gen.scratch2, SZ_W); call(code, opts->write_8); - //restore reg to normal rotation - ror_ir(code, 8, use_reg, SZ_W); cycles(&opts->gen, 2); } break; case Z80_EXX: cycles(&opts->gen, 4); - mov_rr(code, opts->regs[Z80_BC], opts->gen.scratch1, SZ_W); - mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); - mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_C), opts->regs[Z80_BC], SZ_W); - mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_L), opts->regs[Z80_HL], SZ_W); - mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_C), SZ_W); - mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, zar_off(Z80_L), SZ_W); - mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch1, SZ_W); - mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_E), opts->regs[Z80_DE], SZ_W); - mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_E), SZ_W); + zreg_to_native(opts, Z80_BC, opts->gen.scratch1); + mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_BC), opts->gen.scratch2, SZ_W); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_BC), SZ_W); + native_to_zreg(opts, opts->gen.scratch2, Z80_BC); + + zreg_to_native(opts, Z80_HL, opts->gen.scratch1); + mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_HL), opts->gen.scratch2, SZ_W); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_HL), SZ_W); + native_to_zreg(opts, opts->gen.scratch2, Z80_HL); + + zreg_to_native(opts, Z80_DE, opts->gen.scratch1); + mov_rdispr(code, opts->gen.context_reg, zar_off(Z80_DE), opts->gen.scratch2, SZ_W); + mov_rrdisp(code, opts->gen.scratch1, opts->gen.context_reg, zar_off(Z80_DE), SZ_W); + native_to_zreg(opts, opts->gen.scratch2, Z80_DE); break; case Z80_LDI: { cycles(&opts->gen, 8); - mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + zreg_to_native(opts, Z80_HL, opts->gen.scratch1); call(code, opts->read_8); - mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); + zreg_to_native(opts, Z80_DE, opts->gen.scratch2); call(code, opts->write_8); cycles(&opts->gen, 2); - add_ir(code, 1, opts->regs[Z80_DE], SZ_W); - add_ir(code, 1, opts->regs[Z80_HL], SZ_W); - sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); + if (opts->regs[Z80_DE] >= 0) { + add_ir(code, 1, opts->regs[Z80_DE], SZ_W); + } else { + add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_DE), SZ_W); + } + if (opts->regs[Z80_HL] >= 0) { + add_ir(code, 1, opts->regs[Z80_HL], SZ_W); + } else { + add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W); + } + if (opts->regs[Z80_BC] >= 0) { + sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); + } else { + sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W); + } //TODO: Implement half-carry mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV)); @@ -513,14 +586,25 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, } case Z80_LDIR: { cycles(&opts->gen, 8); - mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + zreg_to_native(opts, Z80_HL, opts->gen.scratch1); call(code, opts->read_8); - mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); + zreg_to_native(opts, Z80_DE, opts->gen.scratch2); call(code, opts->write_8); - add_ir(code, 1, opts->regs[Z80_DE], SZ_W); - add_ir(code, 1, opts->regs[Z80_HL], SZ_W); - - sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); + if (opts->regs[Z80_DE] >= 0) { + add_ir(code, 1, opts->regs[Z80_DE], SZ_W); + } else { + add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_DE), SZ_W); + } + if (opts->regs[Z80_HL] >= 0) { + add_ir(code, 1, opts->regs[Z80_HL], SZ_W); + } else { + add_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W); + } + if (opts->regs[Z80_BC] >= 0) { + sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); + } else { + sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W); + } uint8_t * cont = code->cur+1; jcc(code, CC_Z, code->cur+2); cycles(&opts->gen, 7); @@ -536,14 +620,26 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, } case Z80_LDD: { cycles(&opts->gen, 8); - mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + zreg_to_native(opts, Z80_HL, opts->gen.scratch1); call(code, opts->read_8); - mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); + zreg_to_native(opts, Z80_DE, opts->gen.scratch2); call(code, opts->write_8); cycles(&opts->gen, 2); - sub_ir(code, 1, opts->regs[Z80_DE], SZ_W); - sub_ir(code, 1, opts->regs[Z80_HL], SZ_W); - sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); + if (opts->regs[Z80_DE] >= 0) { + sub_ir(code, 1, opts->regs[Z80_DE], SZ_W); + } else { + sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_DE), SZ_W); + } + if (opts->regs[Z80_HL] >= 0) { + add_ir(code, 1, opts->regs[Z80_HL], SZ_W); + } else { + sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W); + } + if (opts->regs[Z80_BC] >= 0) { + sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); + } else { + sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W); + } //TODO: Implement half-carry mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); setcc_rdisp(code, CC_NZ, opts->gen.context_reg, zf_off(ZF_PV)); @@ -551,14 +647,25 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, } case Z80_LDDR: { cycles(&opts->gen, 8); - mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + zreg_to_native(opts, Z80_HL, opts->gen.scratch1); call(code, opts->read_8); - mov_rr(code, opts->regs[Z80_DE], opts->gen.scratch2, SZ_W); + zreg_to_native(opts, Z80_DE, opts->gen.scratch2); call(code, opts->write_8); - sub_ir(code, 1, opts->regs[Z80_DE], SZ_W); - sub_ir(code, 1, opts->regs[Z80_HL], SZ_W); - - sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); + if (opts->regs[Z80_DE] >= 0) { + sub_ir(code, 1, opts->regs[Z80_DE], SZ_W); + } else { + sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_DE), SZ_W); + } + if (opts->regs[Z80_HL] >= 0) { + add_ir(code, 1, opts->regs[Z80_HL], SZ_W); + } else { + sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_HL), SZ_W); + } + if (opts->regs[Z80_BC] >= 0) { + sub_ir(code, 1, opts->regs[Z80_BC], SZ_W); + } else { + sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_BC), SZ_W); + } uint8_t * cont = code->cur+1; jcc(code, CC_Z, code->cur+2); cycles(&opts->gen, 7); @@ -1342,7 +1449,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, jmp(code, call_dst); } else { if (inst->addr_mode == Z80_REG_INDIRECT) { - mov_rr(code, opts->regs[inst->ea_reg], opts->gen.scratch1, SZ_W); + zreg_to_native(opts, inst->ea_reg, opts->gen.scratch1); } else { mov_ir(code, inst->immed, opts->gen.scratch1, SZ_W); } @@ -1973,7 +2080,7 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t #else memset(options->regs, -1, sizeof(options->regs)); options->regs[Z80_A] = RAX; - options->regx[Z80_SP] = RBX; + options->regs[Z80_SP] = RBX; options->gen.scratch1 = RCX; options->gen.scratch2 = RDX; @@ -2214,7 +2321,11 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t options->run = (z80_run_fun)code->cur; save_callee_save_regs(code); +#ifdef X86_64 mov_rr(code, RDI, options->gen.context_reg, SZ_PTR); +#else + mov_rdispr(code, RSP, 5 * sizeof(int32_t), options->gen.context_reg, SZ_PTR); +#endif call(code, options->load_context_scratch); cmp_irdisp(code, 0, options->gen.context_reg, offsetof(z80_context, extra_pc), SZ_PTR); code_ptr no_extra = code->cur+1; -- cgit v1.2.3 From b2aeff4d9434393ca621bd424d435f0fb98c8a3c Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 24 May 2015 15:05:18 -0700 Subject: More bugfixes for the 32-bit build of the Z80 core --- z80_to_x86.c | 231 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 178 insertions(+), 53 deletions(-) diff --git a/z80_to_x86.c b/z80_to_x86.c index a005369..98b6f49 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -109,7 +109,8 @@ void z80_save_reg(z80inst * inst, z80_options * opts) void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t read, uint8_t modify) { code_info *code = &opts->gen.code; - uint8_t size, reg, areg; + uint8_t size, areg; + int8_t reg; ea->mode = MODE_REG_DIRECT; areg = read ? opts->gen.scratch1 : opts->gen.scratch2; switch(inst->addr_mode & 0x1F) @@ -397,9 +398,18 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, mov_rr(code, src_op.base, dst_op.base, size); } } else if(src_op.mode == MODE_IMMED) { - mov_ir(code, src_op.disp, dst_op.base, size); + if(dst_op.mode == MODE_REG_DISPLACE8) { + mov_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, size); + } else { + mov_ir(code, src_op.disp, dst_op.base, size); + } } else { - mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, size); + if(dst_op.mode == MODE_REG_DISPLACE8) { + mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, size); + mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, size); + } else { + mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, size); + } } if (inst->ea_reg == Z80_I && inst->addr_mode == Z80_REG) { //ld a, i sets some flags @@ -696,10 +706,23 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, cycles(&opts->gen, num_cycles); translate_z80_reg(inst, &dst_op, opts); translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); - if (src_op.mode == MODE_REG_DIRECT) { - add_rr(code, src_op.base, dst_op.base, z80_size(inst)); + if (dst_op.mode == MODE_REG_DIRECT) { + if (src_op.mode == MODE_REG_DIRECT) { + add_rr(code, src_op.base, dst_op.base, z80_size(inst)); + } else if (src_op.mode == MODE_IMMED) { + add_ir(code, src_op.disp, dst_op.base, z80_size(inst)); + } else { + add_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst)); + } } else { - add_ir(code, src_op.disp, dst_op.base, z80_size(inst)); + if (src_op.mode == MODE_REG_DIRECT) { + add_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, z80_size(inst)); + } else if (src_op.mode == MODE_IMMED) { + add_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, z80_size(inst)); + } else { + mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, z80_size(inst)); + add_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, z80_size(inst)); + } } setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); @@ -725,10 +748,23 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, translate_z80_reg(inst, &dst_op, opts); translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); - if (src_op.mode == MODE_REG_DIRECT) { - adc_rr(code, src_op.base, dst_op.base, z80_size(inst)); + if (dst_op.mode == MODE_REG_DIRECT) { + if (src_op.mode == MODE_REG_DIRECT) { + adc_rr(code, src_op.base, dst_op.base, z80_size(inst)); + } else if (src_op.mode == MODE_IMMED) { + adc_ir(code, src_op.disp, dst_op.base, z80_size(inst)); + } else { + adc_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst)); + } } else { - adc_ir(code, src_op.disp, dst_op.base, z80_size(inst)); + if (src_op.mode == MODE_REG_DIRECT) { + adc_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, z80_size(inst)); + } else if (src_op.mode == MODE_IMMED) { + adc_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, z80_size(inst)); + } else { + mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, z80_size(inst)); + adc_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, z80_size(inst)); + } } setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); @@ -749,10 +785,23 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, cycles(&opts->gen, num_cycles); translate_z80_reg(inst, &dst_op, opts); translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); - if (src_op.mode == MODE_REG_DIRECT) { - sub_rr(code, src_op.base, dst_op.base, z80_size(inst)); + if (dst_op.mode == MODE_REG_DIRECT) { + if (src_op.mode == MODE_REG_DIRECT) { + sub_rr(code, src_op.base, dst_op.base, z80_size(inst)); + } else if (src_op.mode == MODE_IMMED) { + sub_ir(code, src_op.disp, dst_op.base, z80_size(inst)); + } else { + sub_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst)); + } } else { - sub_ir(code, src_op.disp, dst_op.base, z80_size(inst)); + if (src_op.mode == MODE_REG_DIRECT) { + sub_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, z80_size(inst)); + } else if (src_op.mode == MODE_IMMED) { + sub_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, z80_size(inst)); + } else { + mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, z80_size(inst)); + sub_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, z80_size(inst)); + } } setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); @@ -776,10 +825,23 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, translate_z80_reg(inst, &dst_op, opts); translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); - if (src_op.mode == MODE_REG_DIRECT) { - sbb_rr(code, src_op.base, dst_op.base, z80_size(inst)); + if (dst_op.mode == MODE_REG_DIRECT) { + if (src_op.mode == MODE_REG_DIRECT) { + sbb_rr(code, src_op.base, dst_op.base, z80_size(inst)); + } else if (src_op.mode == MODE_IMMED) { + sbb_ir(code, src_op.disp, dst_op.base, z80_size(inst)); + } else { + sbb_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst)); + } } else { - sbb_ir(code, src_op.disp, dst_op.base, z80_size(inst)); + if (src_op.mode == MODE_REG_DIRECT) { + sbb_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, z80_size(inst)); + } else if (src_op.mode == MODE_IMMED) { + sbb_irdisp(code, src_op.disp, dst_op.base, dst_op.disp, z80_size(inst)); + } else { + mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, z80_size(inst)); + sbb_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, z80_size(inst)); + } } setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); @@ -804,8 +866,10 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { and_rr(code, src_op.base, dst_op.base, z80_size(inst)); - } else { + } else if (src_op.mode == MODE_IMMED) { and_ir(code, src_op.disp, dst_op.base, z80_size(inst)); + } else { + and_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst)); } //TODO: Cleanup flags setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); @@ -833,8 +897,10 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { or_rr(code, src_op.base, dst_op.base, z80_size(inst)); - } else { + } else if (src_op.mode == MODE_IMMED) { or_ir(code, src_op.disp, dst_op.base, z80_size(inst)); + } else { + or_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst)); } //TODO: Cleanup flags setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); @@ -862,8 +928,10 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { xor_rr(code, src_op.base, dst_op.base, z80_size(inst)); - } else { + } else if (src_op.mode == MODE_IMMED) { xor_ir(code, src_op.disp, dst_op.base, z80_size(inst)); + } else { + xor_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst)); } //TODO: Cleanup flags setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); @@ -889,8 +957,10 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, translate_z80_ea(inst, &src_op, opts, READ, DONT_MODIFY); if (src_op.mode == MODE_REG_DIRECT) { cmp_rr(code, src_op.base, dst_op.base, z80_size(inst)); - } else { + } else if (src_op.mode == MODE_IMMED) { cmp_ir(code, src_op.disp, dst_op.base, z80_size(inst)); + } else { + cmp_rdispr(code, src_op.base, src_op.disp, dst_op.base, z80_size(inst)); } setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); @@ -915,7 +985,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, if (dst_op.mode == MODE_UNUSED) { translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); } - add_ir(code, 1, dst_op.base, z80_size(inst)); + if (dst_op.mode == MODE_REG_DIRECT) { + add_ir(code, 1, dst_op.base, z80_size(inst)); + } else { + add_irdisp(code, 1, dst_op.base, dst_op.disp, z80_size(inst)); + } if (z80_size(inst) == SZ_B) { mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag @@ -941,7 +1015,12 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, if (dst_op.mode == MODE_UNUSED) { translate_z80_ea(inst, &dst_op, opts, READ, MODIFY); } - sub_ir(code, 1, dst_op.base, z80_size(inst)); + if (dst_op.mode == MODE_REG_DIRECT) { + sub_ir(code, 1, dst_op.base, z80_size(inst)); + } else { + sub_irdisp(code, 1, dst_op.base, dst_op.disp, z80_size(inst)); + } + if (z80_size(inst) == SZ_B) { mov_irdisp(code, 1, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag @@ -1029,19 +1108,25 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, src_op.mode = MODE_UNUSED; translate_z80_reg(inst, &dst_op, opts); } - rol_ir(code, 1, dst_op.base, SZ_B); - if (src_op.mode != MODE_UNUSED) { + if (dst_op.mode == MODE_REG_DIRECT) { + rol_ir(code, 1, dst_op.base, SZ_B); + } else { + rol_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B); + } + if (src_op.mode == MODE_REG_DIRECT) { mov_rr(code, dst_op.base, src_op.base, SZ_B); + } else if(src_op.mode == MODE_REG_DISPLACE8) { + mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B); } setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (inst->immed) { //rlca does not set these flags - cmp_ir(code, 0, dst_op.base, SZ_B); - setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } if (inst->addr_mode != Z80_UNUSED) { z80_save_result(opts, inst); @@ -1064,19 +1149,25 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, translate_z80_reg(inst, &dst_op, opts); } bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); - rcl_ir(code, 1, dst_op.base, SZ_B); - if (src_op.mode != MODE_UNUSED) { + if (dst_op.mode == MODE_REG_DIRECT) { + rcl_ir(code, 1, dst_op.base, SZ_B); + } else { + rcl_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B); + } + if (src_op.mode == MODE_REG_DIRECT) { mov_rr(code, dst_op.base, src_op.base, SZ_B); + } else if(src_op.mode == MODE_REG_DISPLACE8) { + mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B); } setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (inst->immed) { //rla does not set these flags - cmp_ir(code, 0, dst_op.base, SZ_B); - setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } if (inst->addr_mode != Z80_UNUSED) { z80_save_result(opts, inst); @@ -1098,19 +1189,25 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, src_op.mode = MODE_UNUSED; translate_z80_reg(inst, &dst_op, opts); } - ror_ir(code, 1, dst_op.base, SZ_B); - if (src_op.mode != MODE_UNUSED) { + if (dst_op.mode == MODE_REG_DIRECT) { + ror_ir(code, 1, dst_op.base, SZ_B); + } else { + ror_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B); + } + if (src_op.mode == MODE_REG_DIRECT) { mov_rr(code, dst_op.base, src_op.base, SZ_B); + } else if(src_op.mode == MODE_REG_DISPLACE8) { + mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B); } setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (inst->immed) { //rrca does not set these flags - cmp_ir(code, 0, dst_op.base, SZ_B); - setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } if (inst->addr_mode != Z80_UNUSED) { z80_save_result(opts, inst); @@ -1133,19 +1230,25 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, translate_z80_reg(inst, &dst_op, opts); } bt_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_C), SZ_B); - rcr_ir(code, 1, dst_op.base, SZ_B); - if (src_op.mode != MODE_UNUSED) { + if (dst_op.mode == MODE_REG_DIRECT) { + rcr_ir(code, 1, dst_op.base, SZ_B); + } else { + rcr_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B); + } + if (src_op.mode == MODE_REG_DIRECT) { mov_rr(code, dst_op.base, src_op.base, SZ_B); + } else if(src_op.mode == MODE_REG_DISPLACE8) { + mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B); } setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag if (inst->immed) { //rra does not set these flags - cmp_ir(code, 0, dst_op.base, SZ_B); - setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); - setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); - setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); + cmp_ir(code, 0, dst_op.base, SZ_B); + setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); + setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); + setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } if (inst->addr_mode != Z80_UNUSED) { z80_save_result(opts, inst); @@ -1168,13 +1271,19 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, src_op.mode = MODE_UNUSED; translate_z80_reg(inst, &dst_op, opts); } - shl_ir(code, 1, dst_op.base, SZ_B); + if (dst_op.mode == MODE_REG_DIRECT) { + shl_ir(code, 1, dst_op.base, SZ_B); + } else { + shl_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B); + } setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); if (inst->op == Z80_SLL) { or_ir(code, 1, dst_op.base, SZ_B); } - if (src_op.mode != MODE_UNUSED) { + if (src_op.mode == MODE_REG_DIRECT) { mov_rr(code, dst_op.base, src_op.base, SZ_B); + } else if(src_op.mode == MODE_REG_DISPLACE8) { + mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B); } mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag @@ -1202,9 +1311,15 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, src_op.mode = MODE_UNUSED; translate_z80_reg(inst, &dst_op, opts); } - sar_ir(code, 1, dst_op.base, SZ_B); - if (src_op.mode != MODE_UNUSED) { + if (dst_op.mode == MODE_REG_DIRECT) { + sar_ir(code, 1, dst_op.base, SZ_B); + } else { + sar_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B); + } + if (src_op.mode == MODE_REG_DIRECT) { mov_rr(code, dst_op.base, src_op.base, SZ_B); + } else if(src_op.mode == MODE_REG_DISPLACE8) { + mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B); } setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); @@ -1233,9 +1348,15 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, src_op.mode = MODE_UNUSED; translate_z80_reg(inst, &dst_op, opts); } - shr_ir(code, 1, dst_op.base, SZ_B); - if (src_op.mode != MODE_UNUSED) { + if (dst_op.mode == MODE_REG_DIRECT) { + shr_ir(code, 1, dst_op.base, SZ_B); + } else { + shr_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B); + } + if (src_op.mode == MODE_REG_DIRECT) { mov_rr(code, dst_op.base, src_op.base, SZ_B); + } else if(src_op.mode == MODE_REG_DISPLACE8) { + mov_rrdisp(code, dst_op.base, src_op.base, src_op.disp, SZ_B); } setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); @@ -1542,7 +1663,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, } case Z80_DJNZ: { cycles(&opts->gen, 8);//T States: 5,3 - sub_ir(code, 1, opts->regs[Z80_B], SZ_B); + if (opts->regs[Z80_B] >= 0) { + sub_ir(code, 1, opts->regs[Z80_B], SZ_B); + } else { + sub_irdisp(code, 1, opts->gen.context_reg, zr_off(Z80_B), SZ_B); + } uint8_t *no_jump_off = code->cur+1; jcc(code, CC_Z, code->cur+2); cycles(&opts->gen, 5);//T States: 5 @@ -2311,7 +2436,7 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t pop_r(code, options->gen.scratch2); call(code, options->gen.save_context); //adjust pointer before move and call instructions that got us here - sub_ir(code, 11, options->gen.scratch2, SZ_PTR); + sub_ir(code, options->gen.scratch1 >= R8 ? 11 : 10, options->gen.scratch2, SZ_PTR); push_r(code, options->gen.context_reg); call_args(code, (code_ptr)z80_retranslate_inst, 3, options->gen.scratch1, options->gen.context_reg, options->gen.scratch2); pop_r(code, options->gen.context_reg); -- cgit v1.2.3 From 64a79c95cbbb23079d0da1eca89c3a676725dfae Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 24 May 2015 21:11:18 -0700 Subject: Z80 test cases that passed on 64-bit now pass on 32-bit --- z80_to_x86.c | 231 ++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 150 insertions(+), 81 deletions(-) diff --git a/z80_to_x86.c b/z80_to_x86.c index 98b6f49..51f855a 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -35,6 +35,50 @@ uint8_t z80_size(z80inst * inst) return SZ_B; } +uint8_t zf_off(uint8_t flag) +{ + return offsetof(z80_context, flags) + flag; +} + +uint8_t zaf_off(uint8_t flag) +{ + return offsetof(z80_context, alt_flags) + flag; +} + +uint8_t zr_off(uint8_t reg) +{ + if (reg > Z80_A) { + reg = z80_low_reg(reg); + } + return offsetof(z80_context, regs) + reg; +} + +uint8_t zar_off(uint8_t reg) +{ + if (reg > Z80_A) { + reg = z80_low_reg(reg); + } + return offsetof(z80_context, alt_regs) + reg; +} + +void zreg_to_native(z80_options *opts, uint8_t reg, uint8_t native_reg) +{ + if (opts->regs[reg] >= 0) { + mov_rr(&opts->gen.code, opts->regs[reg], native_reg, reg > Z80_A ? SZ_W : SZ_B); + } else { + mov_rdispr(&opts->gen.code, opts->gen.context_reg, zr_off(reg), native_reg, reg > Z80_A ? SZ_W : SZ_B); + } +} + +void native_to_zreg(z80_options *opts, uint8_t native_reg, uint8_t reg) +{ + if (opts->regs[reg] >= 0) { + mov_rr(&opts->gen.code, native_reg, opts->regs[reg], reg > Z80_A ? SZ_W : SZ_B); + } else { + mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, zr_off(reg), reg > Z80_A ? SZ_W : SZ_B); + } +} + void translate_z80_reg(z80inst * inst, host_ea * ea, z80_options * opts) { code_info *code = &opts->gen.code; @@ -45,7 +89,7 @@ void translate_z80_reg(z80inst * inst, host_ea * ea, z80_options * opts) ea->mode = MODE_UNUSED; } else { ea->mode = MODE_REG_DIRECT; - if (inst->reg == Z80_IYH) { + if (inst->reg == Z80_IYH && opts->regs[Z80_IYL] >= 0) { if ((inst->addr_mode & 0x1F) == Z80_REG && inst->ea_reg == Z80_IYL) { mov_rr(code, opts->regs[Z80_IY], opts->gen.scratch1, SZ_W); ror_ir(code, 8, opts->gen.scratch1, SZ_W); @@ -73,7 +117,7 @@ void translate_z80_reg(z80inst * inst, host_ea * ea, z80_options * opts) } else { ea->mode = MODE_REG_DISPLACE8; ea->base = opts->gen.context_reg; - ea->disp = offsetof(z80_context, regs) + inst->reg; + ea->disp = zr_off(inst->reg); } } } @@ -84,7 +128,7 @@ void z80_save_reg(z80inst * inst, z80_options * opts) if (inst->reg == Z80_USE_IMMED || inst->reg == Z80_UNUSED) { return; } - if (inst->reg == Z80_IYH) { + if (inst->reg == Z80_IYH && opts->regs[Z80_IYL] >= 0) { if ((inst->addr_mode & 0x1F) == Z80_REG && inst->ea_reg == Z80_IYL) { ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); mov_rr(code, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B); @@ -116,7 +160,7 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t switch(inst->addr_mode & 0x1F) { case Z80_REG: - if (inst->ea_reg == Z80_IYH && opts->regs[Z80_IY] >= 0) { + if (inst->ea_reg == Z80_IYH && opts->regs[Z80_IYL] >= 0) { if (inst->reg == Z80_IYL) { mov_rr(code, opts->regs[Z80_IY], opts->gen.scratch1, SZ_W); ror_ir(code, 8, opts->gen.scratch1, SZ_W); @@ -140,15 +184,11 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t } else { ea->mode = MODE_REG_DISPLACE8; ea->base = opts->gen.context_reg; - ea->disp = offsetof(z80_context, regs) + inst->ea_reg; + ea->disp = zr_off(inst->ea_reg); } break; case Z80_REG_INDIRECT: - if (opts->regs[inst->ea_reg] >= 0) { - mov_rr(code, opts->regs[inst->ea_reg], areg, SZ_W); - } else { - mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, regs) + z80_low_reg(inst->ea_reg), areg, SZ_W); - } + zreg_to_native(opts, inst->ea_reg, areg); size = z80_size(inst); if (read) { if (modify) { @@ -192,12 +232,7 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t break; case Z80_IX_DISPLACE: case Z80_IY_DISPLACE: - reg = opts->regs[(inst->addr_mode & 0x1F) == Z80_IX_DISPLACE ? Z80_IX : Z80_IY]; - if (reg >= 0) { - mov_rr(code, reg, areg, SZ_W); - } else { - mov_rdispr(code, opts->gen.context_reg, offsetof(z80_context, regs) + (inst->addr_mode & 0x1F) == Z80_IX_DISPLACE ? Z80_IXL : Z80_IYL, areg, SZ_W); - } + zreg_to_native(opts, (inst->addr_mode & 0x1F) == Z80_IX_DISPLACE ? Z80_IX : Z80_IY, areg); add_ir(code, inst->ea_reg & 0x80 ? inst->ea_reg - 256 : inst->ea_reg, areg, SZ_W); size = z80_size(inst); if (read) { @@ -229,7 +264,7 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t void z80_save_ea(code_info *code, z80inst * inst, z80_options * opts) { if ((inst->addr_mode & 0x1F) == Z80_REG) { - if (inst->ea_reg == Z80_IYH) { + if (inst->ea_reg == Z80_IYH && opts->regs[Z80_IYL] >= 0) { if (inst->reg == Z80_IYL) { ror_ir(code, 8, opts->regs[Z80_IY], SZ_W); mov_rr(code, opts->gen.scratch1, opts->regs[Z80_IYL], SZ_B); @@ -275,50 +310,6 @@ enum { MODIFY }; -uint8_t zf_off(uint8_t flag) -{ - return offsetof(z80_context, flags) + flag; -} - -uint8_t zaf_off(uint8_t flag) -{ - return offsetof(z80_context, alt_flags) + flag; -} - -uint8_t zr_off(uint8_t reg) -{ - if (reg > Z80_A) { - reg = z80_low_reg(reg); - } - return offsetof(z80_context, regs) + reg; -} - -uint8_t zar_off(uint8_t reg) -{ - if (reg > Z80_A) { - reg = z80_low_reg(reg); - } - return offsetof(z80_context, alt_regs) + reg; -} - -void zreg_to_native(z80_options *opts, uint8_t reg, uint8_t native_reg) -{ - if (opts->regs[reg] >= 0) { - mov_rr(&opts->gen.code, opts->regs[reg], native_reg, reg > Z80_A ? SZ_W : SZ_B); - } else { - mov_rdispr(&opts->gen.code, opts->gen.context_reg, zr_off(reg), native_reg, reg > Z80_A ? SZ_W : SZ_B); - } -} - -void native_to_zreg(z80_options *opts, uint8_t native_reg, uint8_t reg) -{ - if (opts->regs[reg] >= 0) { - mov_rr(&opts->gen.code, native_reg, opts->regs[reg], reg > Z80_A ? SZ_W : SZ_B); - } else { - mov_rrdisp(&opts->gen.code, native_reg, opts->gen.context_reg, zr_off(reg), reg > Z80_A ? SZ_W : SZ_B); - } -} - void z80_print_regs_exit(z80_context * context) { printf("A: %X\nB: %X\nC: %X\nD: %X\nE: %X\nHL: %X\nIX: %X\nIY: %X\nSP: %X\n\nIM: %d, IFF1: %d, IFF2: %d\n", @@ -445,8 +436,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, shl_ir(code, 1, opts->gen.scratch1, SZ_B); or_rdispr(code, opts->gen.context_reg, zf_off(ZF_C), opts->gen.scratch1, SZ_B); } else { - translate_z80_reg(inst, &src_op, opts); - mov_rr(code, src_op.base, opts->gen.scratch1, SZ_W); + zreg_to_native(opts, inst->reg, opts->gen.scratch1); } mov_rr(code, opts->regs[Z80_SP], opts->gen.scratch2, SZ_W); call(code, opts->write_16_highfirst); @@ -475,8 +465,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, shr_ir(code, 8, opts->gen.scratch1, SZ_W); native_to_zreg(opts, opts->gen.scratch1, Z80_A); } else { - translate_z80_reg(inst, &src_op, opts); - mov_rr(code, opts->gen.scratch1, src_op.base, SZ_W); + native_to_zreg(opts, opts->gen.scratch1, inst->reg); } //no call to save_z80_reg needed since there's no chance we'll use the only //the upper half of a register pair @@ -1123,7 +1112,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, //TODO: Implement half-carry flag if (inst->immed) { //rlca does not set these flags - cmp_ir(code, 0, dst_op.base, SZ_B); + if (dst_op.mode == MODE_REG_DIRECT) { + cmp_ir(code, 0, dst_op.base, SZ_B); + } else { + cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B); + } setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); @@ -1164,7 +1157,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, //TODO: Implement half-carry flag if (inst->immed) { //rla does not set these flags - cmp_ir(code, 0, dst_op.base, SZ_B); + if (dst_op.mode == MODE_REG_DIRECT) { + cmp_ir(code, 0, dst_op.base, SZ_B); + } else { + cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B); + } setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); @@ -1204,7 +1201,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, //TODO: Implement half-carry flag if (inst->immed) { //rrca does not set these flags - cmp_ir(code, 0, dst_op.base, SZ_B); + if (dst_op.mode == MODE_REG_DIRECT) { + cmp_ir(code, 0, dst_op.base, SZ_B); + } else { + cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B); + } setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); @@ -1245,7 +1246,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, //TODO: Implement half-carry flag if (inst->immed) { //rra does not set these flags - cmp_ir(code, 0, dst_op.base, SZ_B); + if (dst_op.mode == MODE_REG_DIRECT) { + cmp_ir(code, 0, dst_op.base, SZ_B); + } else { + cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B); + } setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); @@ -1278,7 +1283,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, } setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); if (inst->op == Z80_SLL) { - or_ir(code, 1, dst_op.base, SZ_B); + if (dst_op.mode == MODE_REG_DIRECT) { + or_ir(code, 1, dst_op.base, SZ_B); + } else { + or_irdisp(code, 1, dst_op.base, dst_op.disp, SZ_B); + } } if (src_op.mode == MODE_REG_DIRECT) { mov_rr(code, dst_op.base, src_op.base, SZ_B); @@ -1287,7 +1296,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, } mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - cmp_ir(code, 0, dst_op.base, SZ_B); + if (dst_op.mode == MODE_REG_DIRECT) { + cmp_ir(code, 0, dst_op.base, SZ_B); + } else { + cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B); + } setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); @@ -1324,7 +1337,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - cmp_ir(code, 0, dst_op.base, SZ_B); + if (dst_op.mode == MODE_REG_DIRECT) { + cmp_ir(code, 0, dst_op.base, SZ_B); + } else { + cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B); + } setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); @@ -1361,7 +1378,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, setcc_rdisp(code, CC_C, opts->gen.context_reg, zf_off(ZF_C)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); //TODO: Implement half-carry flag - cmp_ir(code, 0, dst_op.base, SZ_B); + if (dst_op.mode == MODE_REG_DIRECT) { + cmp_ir(code, 0, dst_op.base, SZ_B); + } else { + cmp_irdisp(code, 0, dst_op.base, dst_op.disp, SZ_B); + } setcc_rdisp(code, CC_P, opts->gen.context_reg, zf_off(ZF_PV)); setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); @@ -1448,12 +1469,20 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, //Reads normally take 3 cycles, but the read at the end of a bit instruction takes 4 cycles(&opts->gen, 1); } - bt_ir(code, bit, src_op.base, size); + if (src_op.mode == MODE_REG_DIRECT) { + bt_ir(code, bit, src_op.base, size); + } else { + bt_irdisp(code, bit, src_op.base, src_op.disp, size); + } setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_NC, opts->gen.context_reg, zf_off(ZF_PV)); mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_N), SZ_B); if (inst->immed == 7) { - cmp_ir(code, 0, src_op.base, size); + if (src_op.mode == MODE_REG_DIRECT) { + cmp_ir(code, 0, src_op.base, size); + } else { + cmp_irdisp(code, 0, src_op.base, src_op.disp, size); + } setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); } else { mov_irdisp(code, 0, opts->gen.context_reg, zf_off(ZF_S), SZ_B); @@ -1480,7 +1509,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, //Reads normally take 3 cycles, but the read in the middle of a set instruction takes 4 cycles(&opts->gen, 1); } - bts_ir(code, bit, src_op.base, size); + if (src_op.mode == MODE_REG_DIRECT) { + bts_ir(code, bit, src_op.base, size); + } else { + bts_irdisp(code, bit, src_op.base, src_op.disp, size); + } if (inst->reg != Z80_USE_IMMED) { if (size == SZ_W) { #ifdef X86_64 @@ -1490,12 +1523,28 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, ror_ir(code, 8, src_op.base, SZ_W); } else { #endif - mov_rr(code, opts->regs[inst->ea_reg], dst_op.base, SZ_B); + if (dst_op.mode == MODE_REG_DIRECT) { + zreg_to_native(opts, inst->ea_reg, dst_op.base); + } else { + zreg_to_native(opts, inst->ea_reg, opts->gen.scratch1); + mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B); + } #ifdef X86_64 } #endif } else { - mov_rr(code, src_op.base, dst_op.base, SZ_B); + if (dst_op.mode == MODE_REG_DIRECT) { + if (src_op.mode == MODE_REG_DIRECT) { + mov_rr(code, src_op.base, dst_op.base, SZ_B); + } else { + mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, SZ_B); + } + } else if (src_op.mode == MODE_REG_DIRECT) { + mov_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, SZ_B); + } else { + mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B); + mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B); + } } } if ((inst->addr_mode & 0x1F) != Z80_REG) { @@ -1526,7 +1575,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, //Reads normally take 3 cycles, but the read in the middle of a set instruction takes 4 cycles(&opts->gen, 1); } - btr_ir(code, bit, src_op.base, size); + if (src_op.mode == MODE_REG_DIRECT) { + btr_ir(code, bit, src_op.base, size); + } else { + btr_irdisp(code, bit, src_op.base, src_op.disp, size); + } if (inst->reg != Z80_USE_IMMED) { if (size == SZ_W) { #ifdef X86_64 @@ -1536,12 +1589,28 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, ror_ir(code, 8, src_op.base, SZ_W); } else { #endif - mov_rr(code, opts->regs[inst->ea_reg], dst_op.base, SZ_B); + if (dst_op.mode == MODE_REG_DIRECT) { + zreg_to_native(opts, inst->ea_reg, dst_op.base); + } else { + zreg_to_native(opts, inst->ea_reg, opts->gen.scratch1); + mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B); + } #ifdef X86_64 } #endif } else { - mov_rr(code, src_op.base, dst_op.base, SZ_B); + if (dst_op.mode == MODE_REG_DIRECT) { + if (src_op.mode == MODE_REG_DIRECT) { + mov_rr(code, src_op.base, dst_op.base, SZ_B); + } else { + mov_rdispr(code, src_op.base, src_op.disp, dst_op.base, SZ_B); + } + } else if (src_op.mode == MODE_REG_DIRECT) { + mov_rrdisp(code, src_op.base, dst_op.base, dst_op.disp, SZ_B); + } else { + mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B); + mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B); + } } } if (inst->addr_mode != Z80_REG) { -- cgit v1.2.3 From f76857783001f197067e6a8728e76046da8b9e6f Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 25 May 2015 13:21:24 -0700 Subject: Fix div instruction when dest is d0 in 32-bit build --- m68k_core_x86.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 5c459b0..ed0265b 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -1698,8 +1698,13 @@ void translate_m68k_div(m68k_options *opts, m68kinst *inst, host_ea *src_op, hos } cmp_ir(code, 0, RAX, SZ_W); pop_r(code, RAX); - pop_r(code, RDX); - update_flags(opts, V0|Z|N); + if (dst_op->base == RDX) { + update_flags(opts, V0|Z|N); + add_ir(code, sizeof(void *), RSP, SZ_D); + } else { + pop_r(code, RDX); + update_flags(opts, V0|Z|N); + } code_ptr end_off = code->cur + 1; jmp(code, code->cur + 2); *norm_off = code->cur - (norm_off + 1); -- cgit v1.2.3 From b40138532a2345f01538a991ab756fa5e28aa8e0 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 25 May 2015 15:01:38 -0700 Subject: Fix crash bug in 32-bit build for certain secnarios with bcd instructions --- m68k_core_x86.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/m68k_core_x86.c b/m68k_core_x86.c index ed0265b..7b542da 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -1451,8 +1451,10 @@ void translate_m68k_abcd_sbcd(m68k_options *opts, m68kinst *inst, host_ea *src_o cmp_ir(code, 0, opts->gen.scratch1, SZ_B); set_flag_cond(opts, CC_S, FLAG_N); - jcc(code, CC_Z, code->cur + 4); + code_ptr no_setz = code->cur+1; + jcc(code, CC_Z, no_setz); set_flag(opts, 0, FLAG_Z); + *no_setz = code->cur - (no_setz + 1); if (dst_op->base != opts->gen.scratch1) { if (dst_op->mode == MODE_REG_DIRECT) { mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_B); -- cgit v1.2.3 From 86bed7b5415c0f2ceef4a3b043eca445b3b4f0ec Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 25 May 2015 17:08:56 -0700 Subject: Fix RLD and RRD for the case in which HL does not map to a native register --- z80_to_x86.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/z80_to_x86.c b/z80_to_x86.c index 51f855a..4cb7f2a 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -1397,11 +1397,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, break; case Z80_RLD: cycles(&opts->gen, 8); - mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + zreg_to_native(opts, Z80_HL, opts->gen.scratch1); call(code, opts->read_8); //Before: (HL) = 0x12, A = 0x34 //After: (HL) = 0x24, A = 0x31 - mov_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B); + zreg_to_native(opts, Z80_A, opts->gen.scratch2); shl_ir(code, 4, opts->gen.scratch1, SZ_W); and_ir(code, 0xF, opts->gen.scratch2, SZ_W); and_ir(code, 0xFFF, opts->gen.scratch1, SZ_W); @@ -1418,17 +1418,17 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); - mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); + zreg_to_native(opts, Z80_HL, opts->gen.scratch2); ror_ir(code, 8, opts->gen.scratch1, SZ_W); call(code, opts->write_8); break; case Z80_RRD: cycles(&opts->gen, 8); - mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch1, SZ_W); + zreg_to_native(opts, Z80_HL, opts->gen.scratch1); call(code, opts->read_8); //Before: (HL) = 0x12, A = 0x34 //After: (HL) = 0x41, A = 0x32 - movzx_rr(code, opts->regs[Z80_A], opts->gen.scratch2, SZ_B, SZ_W); + zreg_to_native(opts, Z80_A, opts->gen.scratch2); ror_ir(code, 4, opts->gen.scratch1, SZ_W); shl_ir(code, 4, opts->gen.scratch2, SZ_W); and_ir(code, 0xF00F, opts->gen.scratch1, SZ_W); @@ -1448,7 +1448,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, setcc_rdisp(code, CC_Z, opts->gen.context_reg, zf_off(ZF_Z)); setcc_rdisp(code, CC_S, opts->gen.context_reg, zf_off(ZF_S)); - mov_rr(code, opts->regs[Z80_HL], opts->gen.scratch2, SZ_W); + zreg_to_native(opts, Z80_HL, opts->gen.scratch2); ror_ir(code, 8, opts->gen.scratch1, SZ_W); call(code, opts->write_8); break; -- cgit v1.2.3 From a75fc6b803164c251b62a941a4544f71a2e86892 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 25 May 2015 18:56:22 -0700 Subject: Add a define in both the source and Makefile for enabling logging of z80 instruction address/cycle counts. Fix Z80 in/out instructions to eliminate assumptions about which registers are stored in native regs. Fix read_16 to not corrupt the low byte when the read has to call into a C function. --- Makefile | 4 ++++ z80_to_x86.c | 27 ++++++++++++++++++++++++--- z80_to_x86.h | 4 ++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index f5ff1d3..ca09d69 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,10 @@ CFLAGS:=-O2 -flto -std=gnu99 $(shell pkg-config --cflags-only-I $(LIBS)) -Wretu LDFLAGS:=-O2 -flto -lm $(shell pkg-config --libs $(LIBS)) endif +ifdef Z80_LOG_ADDRESS +CFLAGS+= -DZ80_LOG_ADDRESS +endif + ifdef PROFILE CFLAGS+= -pg LDFLAGS+= -pg diff --git a/z80_to_x86.c b/z80_to_x86.c index 4cb7f2a..d1d26a9 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -342,7 +342,9 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, if (context->breakpoint_flags[address / sizeof(uint8_t)] & (1 << (address % sizeof(uint8_t)))) { zbreakpoint_patch(context, address, start); } - //log_address(&opts->gen, address, "Z80: %X @ %d\n"); +#ifdef Z80_LOG_ADDRESS + log_address(&opts->gen, address, "Z80: %X @ %d\n"); +#endif } switch(inst->op) { @@ -1897,7 +1899,11 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, } call(code, opts->read_io); translate_z80_reg(inst, &dst_op, opts); - mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_B); + if (dst_op.mode == MODE_REG_DIRECT) { + mov_rr(code, opts->gen.scratch1, dst_op.base, SZ_B); + } else { + mov_rrdisp(code, opts->gen.scratch1, dst_op.base, dst_op.disp, SZ_B); + } z80_save_reg(inst, opts); break; /*case Z80_INI: @@ -1909,10 +1915,17 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, if ((inst->addr_mode & 0x1F) == Z80_IMMED_INDIRECT) { mov_ir(code, inst->immed, opts->gen.scratch2, SZ_B); } else { + zreg_to_native(opts, Z80_C, opts->gen.scratch2); mov_rr(code, opts->regs[Z80_C], opts->gen.scratch2, SZ_B); } translate_z80_reg(inst, &src_op, opts); - mov_rr(code, dst_op.base, opts->gen.scratch1, SZ_B); + if (src_op.mode == MODE_REG_DIRECT) { + mov_rr(code, src_op.base, opts->gen.scratch1, SZ_B); + } else if (src_op.mode == MODE_IMMED) { + mov_ir(code, src_op.disp, opts->gen.scratch1, SZ_B); + } else { + mov_rdispr(code, src_op.base, src_op.disp, opts->gen.scratch1, SZ_B); + } call(code, opts->write_io); z80_save_reg(inst, opts); break; @@ -2459,13 +2472,21 @@ void init_z80_opts(z80_options * options, memmap_chunk const * chunks, uint32_t push_r(code, options->gen.scratch1); call(code, options->read_8_noinc); mov_rr(code, options->gen.scratch1, options->gen.scratch2, SZ_B); +#ifndef X86_64 + //scratch 2 is a caller save register in 32-bit builds and may be clobbered by something called from the read8 fun + mov_rrdisp(code, options->gen.scratch1, options->gen.context_reg, offsetof(z80_context, scratch2), SZ_B); +#endif pop_r(code, options->gen.scratch1); add_ir(code, 1, options->gen.scratch1, SZ_W); cycles(&options->gen, 3); check_cycles(&options->gen); call(code, options->read_8_noinc); shl_ir(code, 8, options->gen.scratch1, SZ_W); +#ifdef X86_64 mov_rr(code, options->gen.scratch2, options->gen.scratch1, SZ_B); +#else + mov_rdispr(code, options->gen.context_reg, offsetof(z80_context, scratch2), options->gen.scratch1, SZ_B); +#endif retn(code); options->write_16_highfirst = code->cur; diff --git a/z80_to_x86.h b/z80_to_x86.h index fefa836..a940bb7 100644 --- a/z80_to_x86.h +++ b/z80_to_x86.h @@ -9,7 +9,11 @@ #include "backend.h" #define ZNUM_MEM_AREAS 4 +#ifdef Z80_LOG_ADDRESS +#define ZMAX_NATIVE_SIZE 255 +#else #define ZMAX_NATIVE_SIZE 128 +#endif enum { ZF_C = 0, -- cgit v1.2.3 From 09f4bd8615c8c0bec0888fee26093381e4d93477 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 25 May 2015 23:37:13 -0700 Subject: Implement cycles being stolen from 68K when the Z80 accesses the bank area or VDP/PSG. Small fix to code that tries to get system into a consistent state for a savestate --- blastem.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/blastem.c b/blastem.c index 148b6c4..4c1af0d 100644 --- a/blastem.c +++ b/blastem.c @@ -217,6 +217,11 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) uint32_t mclks = context->current_cycle; sync_z80(z_context, mclks); sync_sound(gen, mclks); + while (context->current_cycle > mclks) { + mclks = context->current_cycle; + sync_z80(z_context, mclks); + sync_sound(gen, mclks); + } vdp_run_context(v_context, mclks); if (v_context->frame != last_frame_num) { //printf("reached frame end %d | MCLK Cycles: %d, Target: %d, VDP cycles: %d, vcounter: %d, hslot: %d\n", last_frame_num, mclks, gen->frame_end, v_context->cycles, v_context->vcounter, v_context->hslot); @@ -260,7 +265,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) break_on_sync = 0; debugger(context, address); } - if (save_state) { + if (save_state && (z_context->pc || (!z_context->reset && !z_context->busreq))) { save_state = 0; //advance Z80 core to the start of an instruction while (!z_context->pc) @@ -269,6 +274,8 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) } save_gst(gen, "savestate.gst", address); puts("Saved state to savestate.gst"); + } else if(save_state) { + context->sync_cycle = context->current_cycle + 1; } } return context; @@ -436,6 +443,15 @@ uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext) exit(1); } 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; + //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; + + vdp_port &= 0x1F; uint16_t ret; if (vdp_port < 0x10) { @@ -683,6 +699,9 @@ uint8_t z80_read_bank(uint32_t location, void * vcontext) //typical delay from bus arbitration context->current_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; if (context->mem_pointers[1]) { @@ -707,6 +726,9 @@ void *z80_write_bank(uint32_t location, void * vcontext, uint8_t value) //typical delay from bus arbitration context->current_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; -- cgit v1.2.3 From 81fed3292d80883b76202cf9de913cea60f44627 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 26 May 2015 20:00:50 -0700 Subject: Fixes for the 32-bit build accidentally introduced a bug into the 64-bit build, this commit fixes the regression --- z80_to_x86.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/z80_to_x86.c b/z80_to_x86.c index d1d26a9..1474da9 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -1460,6 +1460,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, uint8_t bit; if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { src_op.base = opts->regs[z80_word_reg(inst->ea_reg)]; + src_op.mode = MODE_REG_DIRECT; size = SZ_W; bit = inst->immed + 8; } else { @@ -1497,6 +1498,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, uint8_t bit; if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { src_op.base = opts->regs[z80_word_reg(inst->ea_reg)]; + src_op.mode = MODE_REG_DIRECT; size = SZ_W; bit = inst->immed + 8; } else { @@ -1563,6 +1565,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, uint8_t bit; if ((inst->addr_mode & 0x1F) == Z80_REG && opts->regs[inst->ea_reg] >= AH && opts->regs[inst->ea_reg] <= BH) { src_op.base = opts->regs[z80_word_reg(inst->ea_reg)]; + src_op.mode = MODE_REG_DIRECT; size = SZ_W; bit = inst->immed + 8; } else { -- cgit v1.2.3 From 6817ef558d165b50a9b08a337dd93c4f1f46304e Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 26 May 2015 22:22:30 -0700 Subject: Fix register to operator mapping for channel 3 special mode --- ym2612.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ym2612.c b/ym2612.c index 2d3404a..cc2fd01 100644 --- a/ym2612.c +++ b/ym2612.c @@ -585,14 +585,16 @@ void ym_update_phase_inc(ym2612_context * context, ym_operator * operator, uint3 ym_channel * channel = context->channels + chan_num; uint32_t inc, detune; if (chan_num == 2 && context->ch3_mode && (op < (2*4 + 3))) { - inc = context->ch3_supp[op-2*4].fnum; - if (!context->ch3_supp[op-2*4].block) { + //supplemental fnum registers are in a different order than normal slot paramters + int index = (op-2*4) ^ 2; + inc = context->ch3_supp[index].fnum; + if (!context->ch3_supp[index].block) { inc >>= 1; } else { - inc <<= (context->ch3_supp[op-2*4].block-1); + inc <<= (context->ch3_supp[index].block-1); } //detune - detune = detune_table[context->ch3_supp[op-2*4].keycode][operator->detune & 0x3]; + detune = detune_table[context->ch3_supp[index].keycode][operator->detune & 0x3]; } else { inc = channel->fnum; if (!channel->block) { -- cgit v1.2.3