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 From 38d85c1c95d0a4152a480baff4974622977dcfce Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 27 May 2015 20:53:21 -0700 Subject: Add a basic YM-2612 command to the debugger. Fix negative detune values and get the correct precision for the multiplication step of phase inc calculation --- debug.c | 17 +++++++++++++++++ ym2612.c | 43 ++++++++++++++++++++++++++++++++++++++++++- ym2612.h | 2 ++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/debug.c b/debug.c index ac5c34d..e121277 100644 --- a/debug.c +++ b/debug.c @@ -760,6 +760,23 @@ m68k_context * debugger(m68k_context * context, uint32_t address) } break; } + case 'y': { + genesis_context * gen = context->system; + //YM-2612 debug commands + switch(input_buf[1]) + { + case 'c': + if (input_buf[2] == ' ') { + int channel = atoi(input_buf+3)-1; + ym_print_channel_info(gen->ym, channel); + } else { + for (int i = 0; i < 6; i++) { + ym_print_channel_info(gen->ym, i); + } + } + } + break; + } #ifndef NO_Z80 case 'z': { genesis_context * gen = context->system; diff --git a/ym2612.c b/ym2612.c index cc2fd01..2e273c0 100644 --- a/ym2612.c +++ b/ym2612.c @@ -605,7 +605,7 @@ void ym_update_phase_inc(ym2612_context * context, ym_operator * operator, uint3 //detune detune = detune_table[channel->keycode][operator->detune & 0x3]; } - if (operator->detune & 0x40) { + if (operator->detune & 0x4) { inc -= detune; //this can underflow, mask to 17-bit result inc &= 0x1FFFF; @@ -615,6 +615,7 @@ void ym_update_phase_inc(ym2612_context * context, ym_operator * operator, uint3 //multiple if (operator->multiple) { inc *= operator->multiple; + inc &= 0xFFFFF; } else { //0.5 inc >>= 1; @@ -748,6 +749,7 @@ void ym_data_write(ym2612_context * context, uint8_t value) break; case REG_DECAY_AM: //TODO: AM flag for LFO + operator->am = value & 0x80; operator->rates[PHASE_DECAY] = value & 0x1F; break; case REG_SUSTAIN_RATE: @@ -821,3 +823,42 @@ uint8_t ym_read_status(ym2612_context * context) return context->status; } +void ym_print_channel_info(ym2612_context *context, int channel) +{ + ym_channel *chan = context->channels + channel; + printf("\n***Channel %d***\n" + "Algorithm: %d\n" + "Feedback: %d\n" + "Pan: %s\n" + "AMS: %d\n" + "PMS: %d\n", + channel+1, chan->algorithm, chan->feedback, + chan->lr == 0xC0 ? "LR" : chan->lr == 0x80 ? "L" : chan->lr == 0x40 ? "R" : "", + chan->ams, chan->pms); + for (int operator = channel * 4; operator < channel * 4+4; operator++) + { + int dispnum = operator - channel * 4 + 1; + if (dispnum == 2) { + dispnum = 3; + } else if (dispnum == 3) { + dispnum = 2; + } + ym_operator *op = context->operators + operator; + printf("\nOperator %d:\n" + " Multiple: %d\n" + " Detune: %d\n" + " Total Level: %d\n" + " Attack Rate: %d\n" + " Key Scaling: %d\n" + " Decay Rate: %d\n" + " Sustain Level: %d\n" + " Sustain Rate: %d\n" + " Release Rate: %d\n" + " Amplitude Modulation %s\n", + dispnum, op->multiple, op->detune, op->total_level, + op->rates[PHASE_ATTACK], op->key_scaling, op->rates[PHASE_DECAY], + op->sustain_level, op->rates[PHASE_SUSTAIN], op->rates[PHASE_RELEASE], + op->am ? "On" : "Off"); + } +} + diff --git a/ym2612.h b/ym2612.h index 88fca1a..c05b073 100644 --- a/ym2612.h +++ b/ym2612.h @@ -26,6 +26,7 @@ typedef struct { uint8_t key_scaling; uint8_t multiple; uint8_t detune; + uint8_t am; uint8_t env_phase; } ym_operator; @@ -105,6 +106,7 @@ void ym_data_write(ym2612_context * context, uint8_t value); uint8_t ym_read_status(ym2612_context * context); uint8_t ym_load_gst(ym2612_context * context, FILE * gstfile); uint8_t ym_save_gst(ym2612_context * context, FILE * gstfile); +void ym_print_channel_info(ym2612_context *context, int channel); #endif //YM2612_H_ -- cgit v1.2.3 From 391656eca9eb35b7e3937b2af1316460d5639306 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 28 May 2015 00:11:15 -0700 Subject: Fix LFO counter update speed and implement amplitude modulation --- ym2612.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/ym2612.c b/ym2612.c index 2e273c0..a560c1a 100644 --- a/ym2612.c +++ b/ym2612.c @@ -108,6 +108,8 @@ uint8_t lfo_pm_base[][8] = { }; int16_t lfo_pm_table[128 * 32 * 8]; +uint16_t ams_shift[] = {8, 3, 1, 0}; + #define MAX_ENVELOPE 0xFFC #define YM_DIVIDER 2 #define CYCLE_NEVER 0xFFFFFFFF @@ -268,16 +270,16 @@ void ym_run(ym2612_context * context, uint32_t to_cycle) context->timer_b = context->timer_b_load; } } - } - //Update LFO - if (context->lfo_enable) { - if (context->lfo_counter) { - context->lfo_counter--; - } else { - context->lfo_counter = lfo_timer_values[context->lfo_freq]; - context->lfo_am_step += 2; - context->lfo_am_step &= 0xFE; - context->lfo_pm_step = context->lfo_am_step / 8; + //Update LFO + if (context->lfo_enable) { + if (context->lfo_counter) { + context->lfo_counter--; + } else { + context->lfo_counter = lfo_timer_values[context->lfo_freq]; + context->lfo_am_step += 2; + context->lfo_am_step &= 0xFE; + context->lfo_pm_step = context->lfo_am_step / 8; + } } } //Update Envelope Generator @@ -427,6 +429,10 @@ void ym_run(ym2612_context * context, uint32_t to_cycle) break; } uint16_t env = operator->envelope + operator->total_level; + if (operator->am) { + uint16_t base_am = (context->lfo_am_step & 0x80 ? context->lfo_am_step : ~context->lfo_am_step) & 0x7E; + env += base_am >> ams_shift[chan->ams]; + } if (env > MAX_ENVELOPE) { env = MAX_ENVELOPE; } -- cgit v1.2.3 From 632c82bd63a13da242c90a5d93dfe7482a0bebe6 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 28 May 2015 21:09:33 -0700 Subject: Adjusted Makefile to support linking against the static glew library from the standard download --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 83f50f1..b7b0eee 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,7 @@ endif ifdef WINDOWS ifndef NOGL -MAINOBJS+= glew.o +MAINOBJS+= glew32s.lib endif endif -- cgit v1.2.3 From 93a29403d334c8dd1253221fd4588209a706f500 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 28 May 2015 22:31:21 -0700 Subject: Get windows build compiling again post-merge --- Makefile | 8 ++++---- debug.c | 8 ++++++++ io.c | 15 +++++++++++++-- render_sdl.c | 1 + 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index b3e966b..fc6a29a 100644 --- a/Makefile +++ b/Makefile @@ -9,8 +9,8 @@ MEM:=mem_win.o BLASTEM:=blastem.exe CC:=wine gcc.exe -CFLAGS:=-O2 -std=gnu99 -Wreturn-type -Werror=return-type -Werror= -LDFLAGS:= -L"C:/MinGW/usr/lib" -lm -lmingw32 -lSDLmain -lSDL -mwindows +CFLAGS:=-g -std=gnu99 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -I"C:/MinGW/usr/include/SDL2" -DGLEW_STATIC +LDFLAGS:= -L"C:/MinGW/usr/lib" -lm -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lglu32 -mwindows CPU:=i686 else @@ -63,7 +63,7 @@ ifeq ($(OS),Darwin) LDFLAGS+= -framework OpenGL endif -TRANSOBJS=gen.o backend.o mem.o +TRANSOBJS=gen.o backend.o $(MEM) M68KOBJS=68kinst.o m68k_core.o ifeq ($(CPU),x86_64) M68KOBJS+= m68k_core_x86.o @@ -97,7 +97,7 @@ else MAINOBJS+= $(Z80OBJS) endif -ifdef WINDOWS +ifeq ($(OS),Windows) MAINOBJS+= glew32s.lib endif diff --git a/debug.c b/debug.c index ac5c34d..6ff8917 100644 --- a/debug.c +++ b/debug.c @@ -3,7 +3,9 @@ #include "68kinst.h" #include #include +#ifndef _WIN32 #include +#endif #include "render.h" static bp_def * breakpoints = NULL; @@ -510,16 +512,21 @@ 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; +#ifdef _WIN32 +#define prompt 1 +#else int prompt = 1; fd_set read_fds; FD_ZERO(&read_fds); struct timeval timeout; +#endif while (debugging) { if (prompt) { fputs(">", stdout); fflush(stdout); } process_events(); +#ifndef _WIN32 timeout.tv_sec = 0; timeout.tv_usec = 16667; FD_SET(fileno(stdin), &read_fds); @@ -529,6 +536,7 @@ m68k_context * debugger(m68k_context * context, uint32_t address) } else { prompt = 1; } +#endif if (!fgets(input_buf, sizeof(input_buf), stdin)) { fputs("fgets failed", stderr); break; diff --git a/io.c b/io.c index d50133d..d6d55c7 100644 --- a/io.c +++ b/io.c @@ -3,6 +3,7 @@ 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 _WIN32 #include #include #include @@ -10,7 +11,9 @@ #include #include #include +#endif #include +#include #include "io.h" #include "blastem.h" @@ -544,7 +547,7 @@ void setup_io_devices(tern_node * config, io_port * ports) for (int i = 0; i < 3; i++) { - +#ifndef _WIN32 if (ports[i].device_type == IO_SEGA_PARALLEL) { char *pipe_name = tern_find_ptr(config, "ioparallel_pipe"); @@ -606,7 +609,9 @@ 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) { + } else +#endif + 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]); @@ -770,6 +775,7 @@ void io_adjust_cycles(io_port * port, uint32_t current_cycle, uint32_t deduction } } +#ifndef _WIN32 static void wait_for_connection(io_port * port) { if (port->device.stream.data_fd == -1) @@ -869,6 +875,7 @@ static void service_socket(io_port *port) } } } +#endif void io_data_write(io_port * port, uint8_t value, uint32_t current_cycle) { @@ -889,12 +896,14 @@ void io_data_write(io_port * port, uint8_t value, uint32_t current_cycle) } port->output = value; break; +#ifndef _WIN32 case IO_GENERIC: wait_for_connection(port); port->input[IO_STATE] = IO_WRITE_PENDING; port->output = value; service_socket(port); break; +#endif default: port->output = value; } @@ -938,6 +947,7 @@ uint8_t io_data_read(io_port * port, uint32_t current_cycle) } break; } +#ifndef _WIN32 case IO_SEGA_PARALLEL: if (!th) { @@ -954,6 +964,7 @@ uint8_t io_data_read(io_port * port, uint32_t current_cycle) service_socket(port); input = ~port->input[IO_TH0]; break; +#endif default: input = 0; break; diff --git a/render_sdl.c b/render_sdl.c index 53a0e2f..38b7ed4 100644 --- a/render_sdl.c +++ b/render_sdl.c @@ -5,6 +5,7 @@ */ #include #include +#include #include #include "render.h" #include "blastem.h" -- cgit v1.2.3 From 66aedc9c1a87c8811be4dba263dbcd7ec026cc70 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 28 May 2015 23:04:49 -0700 Subject: Fix crash bug in windows build --- Makefile | 2 +- render_sdl.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index fc6a29a..eed9d6d 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ MEM:=mem_win.o BLASTEM:=blastem.exe CC:=wine gcc.exe -CFLAGS:=-g -std=gnu99 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -I"C:/MinGW/usr/include/SDL2" -DGLEW_STATIC +CFLAGS:=-O2 -std=gnu99 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -I"C:/MinGW/usr/include/SDL2" -DGLEW_STATIC LDFLAGS:= -L"C:/MinGW/usr/lib" -lm -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lglu32 -mwindows CPU:=i686 diff --git a/render_sdl.c b/render_sdl.c index 38b7ed4..9de86dd 100644 --- a/render_sdl.c +++ b/render_sdl.c @@ -107,7 +107,7 @@ const GLushort element_data[] = {0, 1, 2, 3}; GLuint load_shader(char * fname, GLenum shader_type) { - char * parts[] = {getenv("HOME"), "/.config/blastem/shaders/", fname}; + char * parts[] = {get_home_dir(), "/.config/blastem/shaders/", fname}; char * shader_path = alloc_concat_m(3, parts); FILE * f = fopen(shader_path, "r"); free(shader_path); -- cgit v1.2.3 From 4fbc40d176ff6c872ea39fd743349077dbcbf6fd Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 30 May 2015 15:53:59 -0700 Subject: Fixed shadow/highlight mode --- vdp.c | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/vdp.c b/vdp.c index 5bbe50a..028e882 100644 --- a/vdp.c +++ b/vdp.c @@ -809,51 +809,51 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context) 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]; + uint8_t pixel = context->regs[REG_BG_COLOR]; + uint32_t *colors = context->colors; src = DBG_SRC_BG; if (*plane_b & 0xF) { pixel = *plane_b; src = DBG_SRC_B; } + uint8_t intensity = *plane_b & BUF_BIT_PRIORITY; 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)) { + intensity |= *plane_a & BUF_BIT_PRIORITY; + if (*sprite_buf & 0xF && (*sprite_buf & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { + if ((*sprite_buf & 0x3F) == 0x3E) { + intensity += BUF_BIT_PRIORITY; + } else if ((*sprite_buf & 0x3F) == 0x3F) { + intensity = 0; + } else { pixel = *sprite_buf; src = DBG_SRC_S; if ((pixel & 0xF) == 0xE) { - src |= DBG_SHADOW; - colors += CRAM_SIZE; + intensity = BUF_BIT_PRIORITY; + } else { + intensity |= pixel & BUF_BIT_PRIORITY; } - } - } else if (!((*plane_a | *plane_b) & BUF_BIT_PRIORITY)) { - colors += CRAM_SIZE; + } + if (!intensity) { src |= DBG_SHADOW; + colors += CRAM_SIZE; + } else if (intensity == BUF_BIT_PRIORITY*2) { + src |= DBG_HILIGHT; + colors += CRAM_SIZE*2; } - pixel &= 0x3F; + uint32_t outpixel; if (context->debug) { outpixel = context->debugcolors[src]; } else { - outpixel = colors[pixel]; + outpixel = colors[pixel & 0x3F]; } *(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) { -- cgit v1.2.3 From 130254db3165ed9c34a860f6d340521b45194e0e Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 22 Jun 2015 09:22:05 -0700 Subject: Fix check for DEBUG in Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index eed9d6d..8c51ce8 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ else LIBS=sdl2 glew gl endif #Darwin -ifdef DEBUGW +ifdef DEBUG CFLAGS:=-ggdb -std=gnu99 $(shell pkg-config --cflags-only-I $(LIBS)) -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration LDFLAGS:=-ggdb -lm $(shell pkg-config --libs $(LIBS)) else -- cgit v1.2.3 From 67e7b127d579b5db3d8dffbff045c037569bcd31 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 22 Jun 2015 09:22:18 -0700 Subject: Fix handling of address mask in gen_mem_fun --- backend_x86.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend_x86.c b/backend_x86.c index 75eece9..3e804b2 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -55,12 +55,12 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n 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); - } - code_ptr lb_jcc = NULL, ub_jcc = NULL; uint8_t is_write = fun_type == WRITE_16 || fun_type == WRITE_8; uint8_t adr_reg = is_write ? opts->scratch2 : opts->scratch1; + if (opts->address_size == SZ_D && opts->address_mask != 0xFFFFFFFF) { + and_ir(code, opts->address_mask, adr_reg, SZ_D); + } + code_ptr lb_jcc = NULL, ub_jcc = NULL; 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; -- cgit v1.2.3 From 62f46efe85292831385d27ee80f1220e661cc982 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 22 Jun 2015 22:00:02 -0700 Subject: Fix negative offsets in calc_areg_displace --- 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 7b542da..64e8866 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -317,7 +317,7 @@ void add_dreg_native(m68k_options *opts, uint8_t reg, uint8_t native_reg) 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); + add_ir(&opts->gen.code, op->params.regs.displacement & 0x8000 ? op->params.regs.displacement | 0xFFFF0000 : op->params.regs.displacement, native_reg, SZ_D); } void calc_index_disp8(m68k_options *opts, m68k_op_info *op, uint8_t native_reg) -- cgit v1.2.3 From 4dcb86c4023fef4e0c0d8e66ee1fb345d2537a47 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 22 Jun 2015 22:00:44 -0700 Subject: Minor cleanup in init_run_cpu --- blastem.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/blastem.c b/blastem.c index 4c1af0d..c3d1bd4 100644 --- a/blastem.c +++ b/blastem.c @@ -1039,9 +1039,7 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u //save RAM/map 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); + if (statefile) { uint32_t pc = load_gst(gen, statefile); if (!pc) { @@ -1056,6 +1054,7 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u start_68k_context(context, pc); } else { if (debugger) { + uint32_t address = cart[2] << 16 | cart[3]; insert_breakpoint(context, address, debugger); } m68k_reset(context); -- cgit v1.2.3 From 4802e603569557fbc0e8086703d562ffa52236c7 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 25 Jun 2015 09:02:42 -0700 Subject: Lame placeholder support for floating bus bits of IO hardware. Needs to be replaced with prefetch based values --- blastem.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/blastem.c b/blastem.c index c3d1bd4..fcbcd52 100644 --- a/blastem.c +++ b/blastem.c @@ -643,6 +643,8 @@ 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) : !gen->z80->busack; + //TODO: actual pre-fetch emulation + value |= 0x4E; 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; @@ -662,6 +664,8 @@ uint16_t io_read_w(uint32_t location, m68k_context * context) value = value | (value << 8); } else { value <<= 8; + //TODO: actual pre-fetch emulation + value |= 0x73; } return value; } -- cgit v1.2.3 From 0ce892b31ad6767fc1658d47418b9f7d14faab05 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 27 Jun 2015 11:39:55 -0700 Subject: Handle far calls in call_args and call_args_abi --- gen_x86.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/gen_x86.c b/gen_x86.c index ed46e6c..97c1f3a 100644 --- a/gen_x86.c +++ b/gen_x86.c @@ -2003,6 +2003,27 @@ void call(code_info *code, code_ptr fun) code->cur = out; } +void call_raxfallback(code_info *code, code_ptr fun) +{ + check_alloc_code(code, 5); + code_ptr out = code->cur; + ptrdiff_t disp = fun-(out+5); + if (disp <= 0x7FFFFFFF && disp >= -2147483648) { + *(out++) = OP_CALL; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + disp >>= 8; + *(out++) = disp; + } else { + mov_ir(code, fun, RAX, SZ_PTR); + call_r(code, RAX); + } + code->cur = out; +} + void call_r(code_info *code, uint8_t dst) { check_alloc_code(code, 2); @@ -2091,7 +2112,7 @@ void call_args(code_info *code, code_ptr fun, uint32_t num_args, ...) va_start(args, num_args); uint32_t adjust = prep_args(code, num_args, args); va_end(args); - call(code, fun); + call_raxfallback(code, fun); if (adjust) { add_ir(code, adjust, RSP, SZ_PTR); } @@ -2108,7 +2129,7 @@ void call_args_abi(code_info *code, code_ptr fun, uint32_t num_args, ...) code_ptr do_adjust_rsp = code->cur + 1; jcc(code, CC_NZ, code->cur + 2); #endif - call(code, fun); + call_raxfallback(code, fun); if (adjust) { add_ir(code, adjust, RSP, SZ_PTR); } @@ -2117,7 +2138,7 @@ void call_args_abi(code_info *code, code_ptr fun, uint32_t num_args, ...) jmp(code, code->cur + 2); *do_adjust_rsp = code->cur - (do_adjust_rsp+1); sub_ir(code, 8, RSP, SZ_PTR); - call(code, fun); + call_raxfallback(code, fun); add_ir(code, adjust + 8 , RSP, SZ_PTR); *no_adjust_rsp = code->cur - (no_adjust_rsp+1); #endif -- cgit v1.2.3 From 41427a5cbad6eae33ec644d38227fc7301d7a8c6 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 27 Jun 2015 12:17:18 -0700 Subject: Cleanup some warnings under clang through a combination of code fixes and supressing specific warnings --- Makefile | 4 ++-- gen_x86.c | 4 ++-- z80_to_x86.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 8c51ce8..bbd44f4 100644 --- a/Makefile +++ b/Makefile @@ -25,10 +25,10 @@ LIBS=sdl2 glew gl endif #Darwin ifdef DEBUG -CFLAGS:=-ggdb -std=gnu99 $(shell pkg-config --cflags-only-I $(LIBS)) -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration +CFLAGS:=-ggdb -std=gnu99 $(shell pkg-config --cflags-only-I $(LIBS)) -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -Wno-unused-value -Wno-logical-op-parentheses LDFLAGS:=-ggdb -lm $(shell pkg-config --libs $(LIBS)) else -CFLAGS:=-O2 -flto -std=gnu99 $(shell pkg-config --cflags-only-I $(LIBS)) -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration +CFLAGS:=-O2 -flto -std=gnu99 $(shell pkg-config --cflags-only-I $(LIBS)) -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -Wno-unused-value -Wno-logical-op-parentheses LDFLAGS:=-O2 -flto -lm $(shell pkg-config --libs $(LIBS)) endif #DEBUG endif #Windows diff --git a/gen_x86.c b/gen_x86.c index 97c1f3a..2bec3e8 100644 --- a/gen_x86.c +++ b/gen_x86.c @@ -2018,7 +2018,7 @@ void call_raxfallback(code_info *code, code_ptr fun) disp >>= 8; *(out++) = disp; } else { - mov_ir(code, fun, RAX, SZ_PTR); + mov_ir(code, (int64_t)fun, RAX, SZ_PTR); call_r(code, RAX); } code->cur = out; @@ -2228,7 +2228,7 @@ uint32_t x86_inst_size(code_ptr start) if (*code & REX_QUAD) { op_size = SZ_Q; } - } else if(*code == PRE_2BYTE || PRE_XOP) { + } else if(*code == PRE_2BYTE || *code == PRE_XOP) { prefix = *code; } else { main_op = *code; diff --git a/z80_to_x86.c b/z80_to_x86.c index 1474da9..23b19b8 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -1951,7 +1951,7 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context) { if (!context->interp_code[opcode]) { - if (opcode == 0xCB || (opcode >= 0xDD && opcode & 0xF == 0xD)) { + 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); } -- cgit v1.2.3 From 85a13fa44481d4dafd548ed0e92654a9d6aea62f Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 27 Jun 2015 13:18:55 -0700 Subject: Preserve scratch2 when using it as a temporary in memory read functions. This fixes a bunch of issues with the Z80 core and possibly some issues with the 68K core as well --- backend_x86.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend_x86.c b/backend_x86.c index 3e804b2..f9128ef 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -171,8 +171,10 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n pop_r(code, opts->scratch1); mov_rrind(code, opts->scratch1, opts->scratch2, tmp_size); } else { + push_r(code, opts->scratch2); mov_ir(code, (intptr_t)memmap[chunk].buffer, opts->scratch2, SZ_PTR); mov_rindexr(code, opts->scratch2, opts->scratch1, 1, opts->scratch1, tmp_size); + pop_r(code, opts->scratch2); } } if (size != tmp_size && !is_write) { -- cgit v1.2.3 From de641ad9418c0d95d58d83e5f4f37d24701c4dcf Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 28 Jun 2015 09:53:17 -0700 Subject: More clang warning cleanup --- gdb_remote.c | 4 ++-- m68k_core_x86.c | 2 +- vdp.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/gdb_remote.c b/gdb_remote.c index dd6a98a..764cf83 100644 --- a/gdb_remote.c +++ b/gdb_remote.c @@ -283,8 +283,8 @@ void gdb_run_command(m68k_context * context, uint32_t pc, char * command) char * rest; uint32_t address = strtoul(command+1, &rest, 16); uint32_t size = strtoul(rest+1, NULL, 16); - if (size > sizeof(send_buf-1)/2) { - size = sizeof(send_buf-1)/2; + if (size > (sizeof(send_buf)-1)/2) { + size = (sizeof(send_buf)-1)/2; } char *cur = send_buf; while (size) diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 64e8866..5429bfd 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -1940,7 +1940,7 @@ void translate_m68k_andi_ori_ccr_sr(m68k_options *opts, m68kinst *inst) uint32_t base_flag = inst->op == M68K_ANDI_SR || inst->op == M68K_ANDI_CCR ? X0 : X1; for (int i = 0; i < 5; i++) { - if ((base_flag == X0) ^ (inst->src.params.immed & 1 << i) > 0) + if ((base_flag == X0) ^ ((inst->src.params.immed & 1 << i) > 0)) { flag_mask |= base_flag << ((4 - i) * 3); } diff --git a/vdp.c b/vdp.c index 028e882..bfc301c 100644 --- a/vdp.c +++ b/vdp.c @@ -256,7 +256,7 @@ void vdp_print_reg_explain(vdp_context * context) "01: %.2X | Display %s, V-ints %s, Height: %d, Mode %d\n" "0B: %.2X | E-ints %s, V-Scroll: %s, H-Scroll: %s\n" "0C: %.2X | Width: %d, Shadow/Highlight: %s\n", - context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_PAL_SEL != 0, + context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", (context->regs[REG_MODE_1] & BIT_PAL_SEL) != 0, context->regs[REG_MODE_1] & BIT_HVC_LATCH ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_DISP_DIS ? "disabled" : "enabled", context->regs[REG_MODE_2], context->regs[REG_MODE_2] & BIT_DISP_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_VINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_PAL ? 30 : 28, context->regs[REG_MODE_2] & BIT_MODE_5 ? 5 : 4, -- cgit v1.2.3 From b4ed5b152505ed1dc46d2af083acb19053661787 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 28 Jun 2015 10:12:37 -0700 Subject: Use mmap with a hint rather than sbrk for allocating executable memory within 32-bit displacement range of compiled code --- mem.c | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/mem.c b/mem.c index d019c6f..cb3a047 100644 --- a/mem.c +++ b/mem.c @@ -8,33 +8,20 @@ #include #include #include + #include "mem.h" +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif -/* void * alloc_code(size_t *size) { + //start at the 1GB mark to allow plenty of room for sbrk based malloc implementations + //while still keeping well within 32-bit displacement range for calling code compiled into the executable + static uint8_t *next = (uint8_t *)0x40000000; *size += PAGE_SIZE - (*size & (PAGE_SIZE - 1)); - return mmap(NULL, *size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); -} -*/ - -/* -void * alloc_code(size_t *size) -{ - char * ret = malloc(*size); - char * base = (char *)(((intptr_t)ret) & (~(PAGE_SIZE-1))); - mprotect(base, (ret + *size) - base, PROT_EXEC | PROT_READ | PROT_WRITE); + uint8_t *ret = mmap(NULL, *size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + next = ret + *size; return ret; } -*/ -void * alloc_code(size_t *size) -{ - *size += PAGE_SIZE - (*size & (PAGE_SIZE - 1)); - void * ret = sbrk(*size); - if (ret == ((void *)-1)) { - return NULL; - } - mprotect(ret, *size, PROT_EXEC | PROT_READ | PROT_WRITE); - return ret; -} -- cgit v1.2.3 From f345f5d118a45778f46b478f438eb47fc31d6705 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 28 Jun 2015 10:21:51 -0700 Subject: Use MAP_32BIT on Linux since my hint seems to be ignored --- mem.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mem.c b/mem.c index cb3a047..048f751 100644 --- a/mem.c +++ b/mem.c @@ -14,13 +14,17 @@ #define MAP_ANONYMOUS MAP_ANON #endif +#ifndef MAP_32BIT +#define MAP_32BIT 0 +#endif + void * alloc_code(size_t *size) { //start at the 1GB mark to allow plenty of room for sbrk based malloc implementations //while still keeping well within 32-bit displacement range for calling code compiled into the executable static uint8_t *next = (uint8_t *)0x40000000; *size += PAGE_SIZE - (*size & (PAGE_SIZE - 1)); - uint8_t *ret = mmap(NULL, *size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + uint8_t *ret = mmap(NULL, *size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0); next = ret + *size; return ret; } -- cgit v1.2.3 From fb8f8c12d3188a85f57a7f9e3a67ec167868cfe4 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 28 Jun 2015 13:30:17 -0700 Subject: Fix self modifying code checks on platforms like OS X on which guest RAM ends up at an address unreachable with a 32-bit displacement --- backend_x86.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/backend_x86.c b/backend_x86.c index f9128ef..63fcdc2 100644 --- a/backend_x86.c +++ b/backend_x86.c @@ -165,11 +165,15 @@ code_ptr gen_mem_fun(cpu_options * opts, memmap_chunk const * memmap, uint32_t n } } else { if (is_write) { - push_r(code, opts->scratch1); - mov_ir(code, (intptr_t)memmap[chunk].buffer, opts->scratch1, SZ_PTR); - add_rr(code, opts->scratch1, opts->scratch2, SZ_PTR); - pop_r(code, opts->scratch1); + push_r(code, opts->scratch2); + mov_ir(code, (intptr_t)memmap[chunk].buffer, opts->scratch2, SZ_PTR); + add_rdispr(code, RSP, 0, opts->scratch2, SZ_PTR); mov_rrind(code, opts->scratch1, opts->scratch2, tmp_size); + if (is_write && (memmap[chunk].flags & MMAP_CODE)) { + pop_r(code, opts->scratch2); + } else { + add_ir(code, sizeof(void*), RSP, SZ_D); + } } else { push_r(code, opts->scratch2); mov_ir(code, (intptr_t)memmap[chunk].buffer, opts->scratch2, SZ_PTR); -- cgit v1.2.3 From 834477c2a7f882752fc6ab272f8e01865db33720 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 28 Jun 2015 17:16:24 -0700 Subject: Add support for making a "portable" build on OSX to Makefile --- Makefile | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index bbd44f4..f1890da 100644 --- a/Makefile +++ b/Makefile @@ -3,11 +3,9 @@ OS:=$(shell uname -s) endif ifeq ($(OS),Windows) -CC:=wine gcc.exe MEM:=mem_win.o BLASTEM:=blastem.exe - CC:=wine gcc.exe CFLAGS:=-O2 -std=gnu99 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -I"C:/MinGW/usr/include/SDL2" -DGLEW_STATIC LDFLAGS:= -L"C:/MinGW/usr/lib" -lm -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lglu32 -mwindows @@ -24,12 +22,34 @@ else LIBS=sdl2 glew gl endif #Darwin +CFLAGS:=-std=gnu99 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -Wno-unused-value -Wno-logical-op-parentheses +FIXUP:= +ifdef PORTABLE +CFLAGS+= -DGLEW_STATIC -Iglew/include +LDFLAGS:=-lm glew/lib/libGLEW.a + +ifeq ($(OS),Darwin) +CFLAGS+= -IFrameworks/SDL2.framework/Headers +LDFLAGS+= -FFrameworks -framework SDL2 -framework OpenGL +FIXUP:=install_name_tool -change @rpath/SDL2.framework/Versions/A/SDL2 @executable_path/Frameworks/SDL2.framework/Versions/A/SDL2 ./blastem +endif #Darwin + +else +CFLAGS:=$(shell pkg-config --cflags-only-I $(LIBS)) $(CFLAGS) +LDFLAGS:=-lm $(shell pkg-config --libs $(LIBS)) + +ifeq ($(OS),Darwin) +LDFLAGS+= -framework OpenGL +endif + +endif #PORTABLE + ifdef DEBUG -CFLAGS:=-ggdb -std=gnu99 $(shell pkg-config --cflags-only-I $(LIBS)) -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -Wno-unused-value -Wno-logical-op-parentheses -LDFLAGS:=-ggdb -lm $(shell pkg-config --libs $(LIBS)) +CFLAGS:=-ggdb $(CFLAGS) +LDFLAGS:=-ggdb $(LDFLAGS) else -CFLAGS:=-O2 -flto -std=gnu99 $(shell pkg-config --cflags-only-I $(LIBS)) -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -Wno-unused-value -Wno-logical-op-parentheses -LDFLAGS:=-O2 -flto -lm $(shell pkg-config --libs $(LIBS)) +CFLAGS:=-O2 -flto $(CFLAGS) +LDFLAGS:=-O2 -flto $(LDFLAGS) endif #DEBUG endif #Windows @@ -59,10 +79,6 @@ ifndef CPU CPU:=$(shell uname -m) endif -ifeq ($(OS),Darwin) -LDFLAGS+= -framework OpenGL -endif - TRANSOBJS=gen.o backend.o $(MEM) M68KOBJS=68kinst.o m68k_core.o ifeq ($(CPU),x86_64) @@ -105,6 +121,7 @@ all : dis zdis stateview vgmplay blastem $(BLASTEM) : $(MAINOBJS) $(CC) -o $(BLASTEM) $(MAINOBJS) $(LDFLAGS) + $(FIXUP) dis : dis.o 68kinst.o tern.o vos_program_module.o $(CC) -o dis dis.o 68kinst.o tern.o vos_program_module.o -- cgit v1.2.3 From 983959f838575b6af3e64be442a63647312fcc61 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 28 Jun 2015 18:44:11 -0700 Subject: Get "portable" builds working on Linux and add a build time check for whether /proc exists --- Makefile | 6 +++++- util.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index f1890da..ceba9d3 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,8 @@ else LIBS=sdl2 glew gl endif #Darwin -CFLAGS:=-std=gnu99 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -Wno-unused-value -Wno-logical-op-parentheses +HAS_PROC:=$(shell if [ -d /proc ]; then echo -e -DHAS_PROC; fi) +CFLAGS:=-std=gnu99 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -Wno-unused-value -Wno-logical-op-parentheses $(HAS_PROC) FIXUP:= ifdef PORTABLE CFLAGS+= -DGLEW_STATIC -Iglew/include @@ -32,6 +33,9 @@ ifeq ($(OS),Darwin) CFLAGS+= -IFrameworks/SDL2.framework/Headers LDFLAGS+= -FFrameworks -framework SDL2 -framework OpenGL FIXUP:=install_name_tool -change @rpath/SDL2.framework/Versions/A/SDL2 @executable_path/Frameworks/SDL2.framework/Versions/A/SDL2 ./blastem +else +CFLAGS+= -Isdl/include +LDFLAGS+= -Wl,-rpath='$$ORIGIN/lib' -Llib -lSDL2 $(shell pkg-config --libs gl) endif #Darwin else diff --git a/util.c b/util.c index fc95011..20aa2ee 100644 --- a/util.c +++ b/util.c @@ -138,11 +138,12 @@ char * get_exe_dir() { static char * exe_dir; if (!exe_dir) { + char * cur; +#ifndef HAS_PROC char * linktext = readlink_alloc("/proc/self/exe"); if (!linktext) { goto fallback; } - char * cur; int linksize = strlen(linktext); for(cur = linktext + linksize - 1; cur != linktext; cur--) { @@ -154,6 +155,7 @@ char * get_exe_dir() if (cur == linktext) { free(linktext); fallback: +#endif if (!exe_str) { fputs("/proc/self/exe is not available and set_exe_str was not called!", stderr); } @@ -167,9 +169,11 @@ fallback: break; } } +#ifndef HAS_PROC } else { exe_dir = linktext; } +#endif } return exe_dir; } -- cgit v1.2.3 From 631c3b800a023f7c7021ada70760dfeb0617d47b Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 28 Jun 2015 19:23:38 -0700 Subject: Fix sense of HAS_PROC check --- util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util.c b/util.c index 20aa2ee..89b5273 100644 --- a/util.c +++ b/util.c @@ -139,7 +139,7 @@ char * get_exe_dir() static char * exe_dir; if (!exe_dir) { char * cur; -#ifndef HAS_PROC +#ifdef HAS_PROC char * linktext = readlink_alloc("/proc/self/exe"); if (!linktext) { goto fallback; @@ -169,7 +169,7 @@ fallback: break; } } -#ifndef HAS_PROC +#ifdef HAS_PROC } else { exe_dir = linktext; } -- cgit v1.2.3 From 8f0979a2c4db824e91ead3290d8088d97b20e189 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 2 Jul 2015 19:19:06 -0700 Subject: Initial work on ROM database --- Makefile | 2 +- blastem.c | 52 ++++++++----------- config.h | 1 + rom.db | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ romdb.c | 83 +++++++++++++++++++++++++++++++ romdb.h | 20 ++++++++ 6 files changed, 293 insertions(+), 33 deletions(-) create mode 100644 rom.db create mode 100644 romdb.c create mode 100644 romdb.h diff --git a/Makefile b/Makefile index ceba9d3..3ec9807 100644 --- a/Makefile +++ b/Makefile @@ -99,7 +99,7 @@ Z80OBJS=z80inst.o z80_to_x86.o AUDIOOBJS=ym2612.o psg.o wave.o 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) +MAINOBJS=blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o romdb.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) ifeq ($(CPU),x86_64) CFLAGS+=-DX86_64 -m64 diff --git a/blastem.c b/blastem.c index fcbcd52..4d7f7cb 100644 --- a/blastem.c +++ b/blastem.c @@ -13,6 +13,7 @@ #include "gdb_remote.h" #include "gst.h" #include "util.h" +#include "romdb.h" #include #include #include @@ -64,13 +65,21 @@ int load_smd_rom(long filesize, FILE * f) while (filesize > 0) { fread(block, 1, SMD_BLOCK_SIZE, f); for (uint8_t *low = block, *high = (block+SMD_BLOCK_SIZE/2), *end = block+SMD_BLOCK_SIZE; high < end; high++, low++) { - *(dst++) = *high << 8 | *low; + *(dst++) = *low << 8 | *high; } filesize -= SMD_BLOCK_SIZE; } return 1; } +void byteswap_rom() +{ + for(unsigned short * cur = cart; cur - cart < CARTRIDGE_WORDS; ++cur) + { + *cur = (*cur >> 8) | (*cur << 8); + } +} + int load_rom(char * filename) { uint8_t header[10]; @@ -103,11 +112,6 @@ int load_rom(char * filename) } fread(cart, 2, filesize/2, f); fclose(f); - for(unsigned short * cur = cart; cur - cart < (filesize/2); ++cur) - { - *cur = (*cur >> 8) | (*cur << 8); - } - //TODO: Mirror ROM return 1; } @@ -1065,37 +1069,18 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u } } -char title[64]; +char *title; #define TITLE_START 0x150 #define TITLE_END (TITLE_START+48) -void update_title() +void update_title(char *rom_name) { - uint16_t *last = cart + TITLE_END/2 - 1; - while(last > cart + TITLE_START/2 && *last == 0x2020) - { - last--; - } - uint16_t *start = cart + TITLE_START/2; - char *cur = title; - char last_char = ' '; - for (; start != last; start++) - { - if ((last_char != ' ' || (*start >> 8) != ' ') && (*start >> 8) < 0x80) { - *(cur++) = *start >> 8; - last_char = *start >> 8; - } - if (last_char != ' ' || (*start & 0xFF) != ' ' && (*start & 0xFF) < 0x80) { - *(cur++) = *start; - last_char = *start & 0xFF; - } - } - *(cur++) = *start >> 8; - if ((*start & 0xFF) != ' ') { - *(cur++) = *start; + if (title) { + free(title); + title = NULL; } - strcpy(cur, " - BlastEm"); + title = alloc_concat(rom_name, " - BlastEm"); } #define REGION_START 0x1F0 @@ -1271,12 +1256,15 @@ int main(int argc, char ** argv) fputs("You must specify a ROM filename!\n", stderr); return 1; } + tern_node *rom_db = load_rom_db(); + rom_info info = configure_rom(rom_db, cart); + byteswap_rom(); if (force_version) { version_reg = force_version; } else { detect_region(); } - update_title(); + update_title(info.name); int def_width = 0; char *config_width = tern_find_ptr(config, "videowidth"); if (config_width) { diff --git a/config.h b/config.h index f0e83a1..8817db1 100644 --- a/config.h +++ b/config.h @@ -7,6 +7,7 @@ #define CONFIG_H_ #include "tern.h" +tern_node * parse_config_file(char * config_path); tern_node * load_config(); #endif //CONFIG_H_ diff --git a/rom.db b/rom.db new file mode 100644 index 0000000..a31ef0a --- /dev/null +++ b/rom.db @@ -0,0 +1,168 @@ +T-081326 { + name NBA Jam + eeprom { + type i2c + size 256 + } + map { + 0 { + device ROM + last 1FFFFF + } + 200000 { + device eeprom + last 3FFFFF + bits_read { + 1 sda + } + bits_write { + 0 sda + 1 scl + } + } + } +} +T-81033 { + name NBA Jam + eeprom { + type i2c + size 256 + } + map { + 0 { + device ROM + last 1FFFFF + } + 200000 { + device eeprom + last 3FFFFF + bits_read { + 1 sda + } + bits_write { + 0 sda + 1 scl + } + } + } +} +T-081276 { + name NFL Quarterback Club + eeprom { + type i2c + size 256 + } + map { + 0 { + device ROM + last 1FFFFF + } + 200000 { + device eeprom + last 3FFFFF + bits_read { + 0 sda + } + bits_write { + 0 sda + 8 scl + } + } + } +} +T-81406 { + name NBA Jam TE + eeprom { + type i2c + size 512 + } + map { + 0 { + device ROM + last 1FFFFF + } + 200000 { + device eeprom + last 3FFFFF + bits_read { + 0 sda + } + bits_write { + 0 sda + 8 scl + } + } + } +} +T-081586 { + name NFL Quarterback Club '96 + eeprom { + type i2c + size 2048 + } + map { + 0 { + device ROM + last 1FFFFF + } + 200000 { + device eeprom + last 3FFFFF + bits_read { + 0 sda + } + bits_write { + 0 sda + 8 scl + } + } + } +} +T-81576 { + name College Slam + eeprom { + type i2c + size 8192 + } + map { + 0 { + device ROM + last 1FFFFF + } + 200000 { + device eeprom + last 3FFFFF + bits_read { + 0 sda + } + bits_write { + 0 sda + 8 scl + } + } + } +} +T-81476 { + name Frank Thomas Big Hurt Baseball + eeprom { + type i2c + size 8192 + } + map { + 0 { + device ROM + last 1FFFFF + } + 200000 { + device eeprom + last 3FFFFF + bits_read { + 0 sda + } + bits_write { + 0 sda + 8 scl + } + } + } +} \ No newline at end of file diff --git a/romdb.c b/romdb.c new file mode 100644 index 0000000..0de4af5 --- /dev/null +++ b/romdb.c @@ -0,0 +1,83 @@ +#include +#include +#include "config.h" +#include "romdb.h" +#include "util.h" + +#define GAME_ID_OFF 0x183 +#define GAME_ID_LEN 8 +#define TITLE_START 0x150 +#define TITLE_END (TITLE_START+48) + +tern_node *load_rom_db() +{ + char *exe_dir = get_exe_dir(); + if (!exe_dir) { + fputs("Failed to find executable path\n", stderr); + exit(1); + } + char *path = alloc_concat(exe_dir, "/rom.db"); + tern_node *db = parse_config_file(path); + free(path); + if (!db) { + fputs("Failed to load ROM DB\n", stderr); + } + return db; +} + +char *get_header_name(uint8_t *rom) +{ + uint8_t *last = rom + TITLE_END - 1; + uint8_t *src = rom + TITLE_START; + + while (last > src && (*last <= 0x20 || *last >= 0x80)) + { + last--; + } + if (last == src) { + //TODO: Use other name field + return strdup("UNKNOWN"); + } else { + last++; + char *ret = malloc(last - (rom + TITLE_START) + 1); + uint8_t *dst; + for (dst = ret; src < last; src++) + { + if (*src >= 0x20 && *src < 0x80) { + *(dst++) = *src; + } + } + *dst = 0; + return ret; + } +} + +rom_info configure_rom_heuristics(uint8_t *rom) +{ + rom_info info; + info.name = get_header_name(rom); + +} + +rom_info configure_rom(tern_node *rom_db, void *vrom) +{ + uint8_t product_id[GAME_ID_LEN+1]; + uint8_t *rom = vrom; + product_id[GAME_ID_LEN] = 0; + for (int i = 0; i < GAME_ID_LEN; i++) + { + if (rom[GAME_ID_OFF + i] <= ' ') { + product_id[i] = 0; + break; + } + product_id[i] = rom[GAME_ID_OFF + i]; + + } + tern_node * entry = tern_find_prefix(rom_db, product_id); + if (!entry) { + return configure_rom_heuristics(rom); + } + rom_info info; + info.name = strdup(tern_find_ptr_default(entry, "name", "UNKNOWN")); + return info; +} \ No newline at end of file diff --git a/romdb.h b/romdb.h new file mode 100644 index 0000000..e204f7d --- /dev/null +++ b/romdb.h @@ -0,0 +1,20 @@ +#ifndef ROMDB_H_ +#define ROMDB_H_ + +#define REGION_J 1 +#define REGION_U 2 +#define REGION_E 4 + +#include "tern.h" +#include "backend.h" + +typedef struct { + char *name; + memmap_chunk *map; + uint8_t regions; +} rom_info; + +tern_node *load_rom_db(); +rom_info configure_rom(tern_node *rom_db, void *vrom); + +#endif //ROMDB_H_ -- cgit v1.2.3 From 249115277c7f488052e07ccbd91f0df9f24f26b7 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Thu, 2 Jul 2015 20:43:01 -0700 Subject: Allow regions to be set in ROM DB. Prefer default region if it is one of the valid regions for the ROM. --- blastem.c | 71 +++++++++++++++------------------------------------------------ romdb.c | 54 +++++++++++++++++++++++++++++++++++++++++++----- romdb.h | 1 + 3 files changed, 67 insertions(+), 59 deletions(-) diff --git a/blastem.c b/blastem.c index 4d7f7cb..727a2d4 100644 --- a/blastem.c +++ b/blastem.c @@ -1071,9 +1071,6 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u char *title; -#define TITLE_START 0x150 -#define TITLE_END (TITLE_START+48) - void update_title(char *rom_name) { if (title) { @@ -1083,42 +1080,25 @@ void update_title(char *rom_name) title = alloc_concat(rom_name, " - BlastEm"); } -#define REGION_START 0x1F0 - -int detect_specific_region(char region) -{ - return (cart[REGION_START/2] & 0xFF) == region || (cart[REGION_START/2] >> 8) == region || (cart[REGION_START/2+1] & 0xFF) == region; -} - -void detect_region() +void set_region(rom_info *info, uint8_t region) { - if (detect_specific_region('U')|| detect_specific_region('B') || detect_specific_region('4')) { - version_reg = NO_DISK | USA; - } else if (detect_specific_region('J')) { - version_reg = NO_DISK | JAP; - } else if (detect_specific_region('E') || detect_specific_region('A')) { - version_reg = NO_DISK | EUR; - } else { + if (!region) { char * def_region = tern_find_ptr(config, "default_region"); - if (def_region) { - switch(*def_region) - { - case 'j': - case 'J': - version_reg = NO_DISK | JAP; - break; - case 'u': - case 'U': - version_reg = NO_DISK | USA; - break; - case 'e': - case 'E': - version_reg = NO_DISK | EUR; - break; - } + if (def_region && (!info->regions || (info->regions & translate_region_char(toupper(*def_region))))) { + region = translate_region_char(toupper(*def_region)); + } else { + region = info->regions; } } + if (region & REGION_E) { + version_reg = NO_DISK | EUR; + } else if (region & REGION_J) { + version_reg = NO_DISK | JAP; + } else { + version_reg = NO_DISK | USA; + } } + #ifndef NO_Z80 const memmap_chunk z80_map[] = { { 0x0000, 0x4000, 0x1FFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, z80_ram, NULL, NULL, NULL, NULL }, @@ -1189,21 +1169,8 @@ int main(int argc, char ** argv) fputs("-r must be followed by region (J, U or E)\n", stderr); return 1; } - switch (argv[i][0]) - { - case 'j': - case 'J': - force_version = NO_DISK | JAP; - break; - case 'u': - case 'U': - force_version = NO_DISK | USA; - break; - case 'e': - case 'E': - force_version = NO_DISK | EUR; - break; - default: + force_version = translate_region_char(toupper(argv[i][0])); + if (!force_version) { fprintf(stderr, "'%c' is not a valid region character for the -r option\n", argv[i][0]); return 1; } @@ -1259,11 +1226,7 @@ int main(int argc, char ** argv) tern_node *rom_db = load_rom_db(); rom_info info = configure_rom(rom_db, cart); byteswap_rom(); - if (force_version) { - version_reg = force_version; - } else { - detect_region(); - } + set_region(&info, force_version); update_title(info.name); int def_width = 0; char *config_width = tern_find_ptr(config, "videowidth"); diff --git a/romdb.c b/romdb.c index 0de4af5..fbfcef9 100644 --- a/romdb.c +++ b/romdb.c @@ -4,10 +4,11 @@ #include "romdb.h" #include "util.h" -#define GAME_ID_OFF 0x183 -#define GAME_ID_LEN 8 #define TITLE_START 0x150 #define TITLE_END (TITLE_START+48) +#define GAME_ID_OFF 0x183 +#define GAME_ID_LEN 8 +#define REGION_START 0x1F0 tern_node *load_rom_db() { @@ -52,11 +53,37 @@ char *get_header_name(uint8_t *rom) } } +char *region_chars = "UB4JEA"; +uint8_t region_bits[] = {REGION_U, REGION_U, REGION_U, REGION_J, REGION_E, REGION_E}; + +uint8_t translate_region_char(uint8_t c) +{ + for (int i = 0; i < sizeof(region_bits); i++) + { + if (c == region_chars[i]) { + return region_bits[i]; + } + } + return 0; +} + +uint8_t get_header_regions(uint8_t *rom) +{ + uint8_t regions = 0; + for (int i = 0; i < 3; i++) + { + regions |= translate_region_char(rom[REGION_START + i]); + } + return regions; +} + + rom_info configure_rom_heuristics(uint8_t *rom) { rom_info info; info.name = get_header_name(rom); - + info.regions = get_header_regions(rom); + return info; } rom_info configure_rom(tern_node *rom_db, void *vrom) @@ -78,6 +105,23 @@ rom_info configure_rom(tern_node *rom_db, void *vrom) return configure_rom_heuristics(rom); } rom_info info; - info.name = strdup(tern_find_ptr_default(entry, "name", "UNKNOWN")); + info.name = tern_find_ptr(entry, "name"); + if (info.name) { + info.name = strdup(info.name); + } else { + info.name = get_header_name(rom); + } + + char *dbreg = tern_find_ptr(entry, "regions"); + info.regions = 0; + if (dbreg) { + while (*dbreg != 0) + { + info.regions |= translate_region_char(*(dbreg++)); + } + } + if (!info.regions) { + info.regions = get_header_regions(rom); + } return info; -} \ No newline at end of file +} diff --git a/romdb.h b/romdb.h index e204f7d..5a1b4bc 100644 --- a/romdb.h +++ b/romdb.h @@ -16,5 +16,6 @@ typedef struct { tern_node *load_rom_db(); rom_info configure_rom(tern_node *rom_db, void *vrom); +uint8_t translate_region_char(uint8_t c); #endif //ROMDB_H_ -- cgit v1.2.3 From 0be7e726ad839d36d50db630b24ea0f1dc141c08 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 5 Jul 2015 14:21:34 -0700 Subject: WIP changes to support reading cart memory map from ROM DB --- blastem.c | 143 +++---------------------------------- blastem.h | 4 -- config.c | 60 +++++++--------- io.c | 113 ++++++++++++++++-------------- render_sdl.c | 13 ++-- romdb.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- romdb.h | 20 ++++-- tern.c | 87 +++++++++++++++++++++++ tern.h | 7 ++ 9 files changed, 436 insertions(+), 237 deletions(-) diff --git a/blastem.c b/blastem.c index 727a2d4..fb5ce4b 100644 --- a/blastem.c +++ b/blastem.c @@ -62,6 +62,7 @@ int load_smd_rom(long filesize, FILE * f) fseek(f, SMD_HEADER_SIZE, SEEK_SET); uint16_t * dst = cart; + int rom_size = filesize; while (filesize > 0) { fread(block, 1, SMD_BLOCK_SIZE, f); for (uint8_t *low = block, *high = (block+SMD_BLOCK_SIZE/2), *end = block+SMD_BLOCK_SIZE; high < end; high++, low++) { @@ -69,7 +70,7 @@ int load_smd_rom(long filesize, FILE * f) } filesize -= SMD_BLOCK_SIZE; } - return 1; + return filesize; } void byteswap_rom() @@ -112,7 +113,7 @@ int load_rom(char * filename) } fread(cart, 2, filesize/2, f); fclose(f); - return 1; + return filesize; } uint16_t read_dma_value(uint32_t address) @@ -766,127 +767,6 @@ void *z80_write_bank_reg(uint32_t location, void * vcontext, uint8_t value) return context; } -uint16_t read_sram_w(uint32_t address, m68k_context * context) -{ - genesis_context * gen = context->system; - address &= gen->save_ram_mask; - switch(gen->save_flags) - { - case RAM_FLAG_BOTH: - return gen->save_ram[address] << 8 | gen->save_ram[address+1]; - case RAM_FLAG_EVEN: - return gen->save_ram[address >> 1] << 8 | 0xFF; - case RAM_FLAG_ODD: - return gen->save_ram[address >> 1] | 0xFF00; - } - return 0xFFFF;//We should never get here -} - -uint8_t read_sram_b(uint32_t address, m68k_context * context) -{ - genesis_context * gen = context->system; - address &= gen->save_ram_mask; - switch(gen->save_flags) - { - case RAM_FLAG_BOTH: - return gen->save_ram[address]; - case RAM_FLAG_EVEN: - if (address & 1) { - return 0xFF; - } else { - return gen->save_ram[address >> 1]; - } - case RAM_FLAG_ODD: - if (address & 1) { - return gen->save_ram[address >> 1]; - } else { - return 0xFF; - } - } - return 0xFF;//We should never get here -} - -m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint16_t value) -{ - genesis_context * gen = context->system; - if ((gen->bank_regs[0] & 0x3) == 1) { - address &= gen->save_ram_mask; - switch(gen->save_flags) - { - case RAM_FLAG_BOTH: - gen->save_ram[address] = value >> 8; - gen->save_ram[address+1] = value; - break; - case RAM_FLAG_EVEN: - gen->save_ram[address >> 1] = value >> 8; - break; - case RAM_FLAG_ODD: - gen->save_ram[address >> 1] = value; - break; - } - } - return context; -} - -m68k_context * write_sram_area_b(uint32_t address, m68k_context * context, uint8_t value) -{ - genesis_context * gen = context->system; - if ((gen->bank_regs[0] & 0x3) == 1) { - address &= gen->save_ram_mask; - switch(gen->save_flags) - { - case RAM_FLAG_BOTH: - gen->save_ram[address] = value; - break; - case RAM_FLAG_EVEN: - if (!(address & 1)) { - gen->save_ram[address >> 1] = value; - } - break; - case RAM_FLAG_ODD: - if (address & 1) { - gen->save_ram[address >> 1] = value; - } - break; - } - } - return context; -} - -m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16_t value) -{ - genesis_context * gen = context->system; - address &= 0xE; - address >>= 1; - gen->bank_regs[address] = value; - if (!address) { - if (value & 1) { - context->mem_pointers[2] = NULL; - } else { - context->mem_pointers[2] = cart + 0x200000/2; - } - } - return context; -} - -m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_t value) -{ - if (address & 1) { - genesis_context * gen = context->system; - address &= 0xE; - address >>= 1; - gen->bank_regs[address] = value; - if (!address) { - if (value & 1) { - context->mem_pointers[2] = NULL; - } else { - context->mem_pointers[2] = cart + 0x200000/2; - } - } - } - return context; -} - void set_speed_percent(genesis_context * context, uint32_t percent) { uint32_t old_clock = context->master_clock; @@ -898,13 +778,7 @@ void set_speed_percent(genesis_context * context, uint32_t percent) psg_adjust_master_clock(context->psg, context->master_clock); } -#define ROM_END 0x1A4 -#define RAM_ID 0x1B0 -#define RAM_FLAGS 0x1B2 -#define RAM_START 0x1B4 -#define RAM_END 0x1B8 #define MAX_MAP_CHUNKS (4+7+1) -#define RAM_FLAG_MASK 0x1800 const memmap_chunk static_map[] = { {0, 0x400000, 0xFFFFFF, 0, MMAP_READ, cart, @@ -947,6 +821,7 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u //TODO: Handle carts larger than 4MB //TODO: Handle non-standard mappers uint32_t size; + /* if ((cart[RAM_ID/2] & 0xFF) == 'A' && (cart[RAM_ID/2] >> 8) == 'R') { //Cart has save RAM uint32_t rom_end = ((cart[ROM_END/2] << 16) | cart[ROM_END/2+1]) + 1; @@ -1020,6 +895,7 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u memcpy(memmap, static_map, sizeof(static_map)); num_chunks = sizeof(static_map)/sizeof(memmap_chunk); } + */ if (gen->save_ram) { memset(gen->save_ram, 0, size); FILE * f = fopen(sram_filename, "rb"); @@ -1126,6 +1002,7 @@ int main(int argc, char ** argv) char * romfname = NULL; FILE *address_log = NULL; char * statefile = NULL; + int rom_size; uint8_t * debuggerfun = NULL; uint8_t fullscreen = 0, use_gl = 1; for (int i = 1; i < argc; i++) { @@ -1207,7 +1084,7 @@ int main(int argc, char ** argv) return 1; } } else if (!loaded) { - if(!load_rom(argv[i])) { + if(rom_size = load_rom(argv[i])) { fprintf(stderr, "Failed to open %s for reading\n", argv[i]); return 1; } @@ -1224,12 +1101,12 @@ int main(int argc, char ** argv) return 1; } tern_node *rom_db = load_rom_db(); - rom_info info = configure_rom(rom_db, cart); + rom_info info = configure_rom(rom_db, cart, rom_size, static_map+1, sizeof(static_map)/sizeof(static_map[0]) - 1); byteswap_rom(); set_region(&info, force_version); update_title(info.name); int def_width = 0; - char *config_width = tern_find_ptr(config, "videowidth"); + char *config_width = tern_find_path(config, "video\0width\0").ptrval; if (config_width) { def_width = atoi(config_width); } @@ -1252,7 +1129,7 @@ int main(int argc, char ** argv) init_vdp_context(&v_context, version_reg & 0x40); gen.frame_end = vdp_cycles_to_frame_end(&v_context); - char * config_cycles = tern_find_ptr(config, "clocksmax_cycles"); + char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0").ptrval; gen.max_cycles = config_cycles ? atoi(config_cycles) : 10000000; ym2612_context y_context; diff --git a/blastem.h b/blastem.h index 23c62dd..f3bf4c6 100644 --- a/blastem.h +++ b/blastem.h @@ -15,10 +15,6 @@ #include "io.h" #include "config.h" -#define RAM_FLAG_ODD 0x1800 -#define RAM_FLAG_EVEN 0x1000 -#define RAM_FLAG_BOTH 0x0000 - typedef struct { m68k_context *m68k; z80_context *z80; diff --git a/config.c b/config.c index eab0308..6fd29b5 100644 --- a/config.c +++ b/config.c @@ -9,8 +9,6 @@ #include #include -#define MAX_NEST 30 //way more than I'll ever need - #ifdef _WIN32 char * strtok_r(char * input, char * sep, char ** state) { @@ -32,69 +30,59 @@ char * strtok_r(char * input, char * sep, char ** state) } #endif -tern_node * parse_config(char * config_data) +tern_node * parse_config_int(char **state, int started, int *line) { - char *state, *curline; - char *prefix = NULL; - int nest_level = 0; - char * prefix_parts[MAX_NEST]; - int line = 1; + char *config_data, *curline; tern_node * head = NULL; - while ((curline = strtok_r(config_data, "\n", &state))) + config_data = started ? NULL : *state; + while ((curline = strtok_r(config_data, "\n", state))) { + config_data = NULL; curline = strip_ws(curline); int len = strlen(curline); if (!len) { + *line++; continue; } if (curline[0] == '#') { + *line++; continue; } if (curline[0] == '}') { - if (!nest_level) { - fprintf(stderr, "unexpected } on line %d\n", line); - exit(1); + if (started) { + return head; } - if (prefix) { - free(prefix); - prefix = NULL; - } - nest_level--; - curline = strip_ws(curline+1); + fprintf(stderr, "unexpected } on line %d\n", *line); + exit(1); } + char * end = curline + len - 1; if (*end == '{') { *end = 0; curline = strip_ws(curline); - prefix_parts[nest_level++] = curline; - if (prefix) { - free(prefix); - prefix = NULL; - } + *line++; + head = tern_insert_node(head, curline, parse_config_int(state, 1, line)); } else { - if (nest_level && !prefix) { - prefix = alloc_concat_m(nest_level, prefix_parts); - } char * val = strip_ws(split_keyval(curline)); char * key = curline; - if (*key) { - if (prefix) { - key = alloc_concat(prefix, key); - } + if (*val) { head = tern_insert_ptr(head, key, strdup(val)); - if (prefix) { - free(key); - } + } else { + fprintf(stderr, "Key %s is missing a value on line %d\n", key, *line); } + *line++; } } - if (prefix) { - free(prefix); - } return head; } +tern_node * parse_config(char * config_data) +{ + int line = 1; + return parse_config_int(&config_data, 0, &line); +} + tern_node * parse_config_file(char * config_path) { tern_node * ret = NULL; diff --git a/io.c b/io.c index d6d55c7..3b89b99 100644 --- a/io.c +++ b/io.c @@ -536,7 +536,7 @@ static void cleanup_sockfile() void setup_io_devices(tern_node * config, io_port * ports) { - tern_node *io_nodes = tern_find_prefix(config, "iodevices"); + tern_node *io_nodes = tern_get_node(tern_find_path(config, "io\0devices\0")); 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"); @@ -550,7 +550,7 @@ void setup_io_devices(tern_node * config, io_port * ports) #ifndef _WIN32 if (ports[i].device_type == IO_SEGA_PARALLEL) { - char *pipe_name = tern_find_ptr(config, "ioparallel_pipe"); + char *pipe_name = tern_find_path(config, "io\0parallel_pipe\0").ptrval; 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)); @@ -576,7 +576,7 @@ void setup_io_devices(tern_node * config, io_port * ports) } } } else if (ports[i].device_type == IO_GENERIC) { - char *sock_name = tern_find_ptr(config, "iosocket"); + char *sock_name = tern_find_path(config, "io\0socket\0").ptrval; if (!sock_name) { fprintf(stderr, "IO port %s is configured to use generic IO, but no socket is set!\n", io_name(i)); @@ -665,64 +665,73 @@ void set_keybindings(io_port *ports) padbuttons = tern_insert_int(padbuttons, ".start", BUTTON_START); padbuttons = tern_insert_int(padbuttons, ".mode", BUTTON_MODE); - tern_node * keys = tern_find_prefix(config, "bindingskeys"); + tern_node * keys = tern_get_node(tern_find_path(config, "bindings\0keys\0")); process_keys(keys, special, padbuttons, NULL); - char prefix[] = "bindingspads00"; - for (int i = 0; i < 100 && i < render_num_joysticks(); i++) - { - if (i < 10) { - prefix[strlen("bindingspads")] = i + '0'; - prefix[strlen("bindingspads")+1] = 0; - } else { - prefix[strlen("bindingspads")] = i/10 + '0'; - prefix[strlen("bindingspads")+1] = i%10 + '0'; - } - tern_node * pad = tern_find_prefix(config, prefix); - if (pad) { - char dprefix[] = "dpads0"; - for (int dpad = 0; dpad < 10 && dpad < render_joystick_num_hats(i); dpad++) - { - dprefix[strlen("dpads")] = dpad + '0'; - tern_node * pad_dpad = tern_find_prefix(pad, dprefix); - char * dirs[] = {"up", "down", "left", "right"}; - int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; - for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) { - char * target = tern_find_ptr(pad_dpad, dirs[dir]); - if (target) { - int ui_func, padnum, button; - int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); - if (bindtype == 1) { - bind_dpad_gamepad(i, dpad, dirnums[dir], padnum, button); - } else if (bindtype == 2) { - bind_dpad_ui(i, dpad, dirnums[dir], ui_func, button); + char numstr[] = "00"; + tern_node * pads = tern_get_node(tern_find_path(config, "bindings\0pads\0")); + if (pads) { + for (int i = 0; i < 100 && i < render_num_joysticks(); i++) + { + + if (i < 10) { + numstr[0] = i + '0'; + numstr[1] = 0; + } else { + numstr[0] = i/10 + '0'; + numstr[1] = i%10 + '0'; + } + tern_node * pad = tern_find_ptr(pads, numstr); + if (pad) { + tern_node * dpad_node = tern_find_ptr(pad, "dpads"); + if (dpad_node) { + for (int dpad = 0; dpad < 10 && dpad < render_joystick_num_hats(i); dpad++) + { + numstr[0] = dpad + '0'; + numstr[1] = 0; + tern_node * pad_dpad = tern_find_ptr(dpad_node, numstr); + char * dirs[] = {"up", "down", "left", "right"}; + int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; + for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) { + char * target = tern_find_ptr(pad_dpad, dirs[dir]); + if (target) { + int ui_func, padnum, button; + int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); + if (bindtype == 1) { + bind_dpad_gamepad(i, dpad, dirnums[dir], padnum, button); + } else if (bindtype == 2) { + bind_dpad_ui(i, dpad, dirnums[dir], ui_func, button); + } + } } } } - } - char bprefix[] = "buttons00"; - for (int but = 0; but < 100 && but < render_joystick_num_buttons(i); but++) - { - if (but < 10) { - bprefix[strlen("buttons")] = but + '0'; - bprefix[strlen("buttons")+1] = 0; - } else { - bprefix[strlen("buttons")] = but/10 + '0'; - bprefix[strlen("buttons")+1] = but%10 + '0'; - } - char * target = tern_find_ptr(pad, bprefix); - if (target) { - int ui_func, padnum, button; - int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); - if (bindtype == 1) { - bind_button_gamepad(i, but, padnum, button); - } else if (bindtype == 2) { - bind_button_ui(i, but, ui_func, button); + tern_node *button_node = tern_find_ptr(pad, "buttons"); + if (button_node) { + for (int but = 0; but < 100 && but < render_joystick_num_buttons(i); but++) + { + if (but < 10) { + numstr[0] = but + '0'; + numstr[1] = 0; + } else { + numstr[0] = but/10 + '0'; + numstr[1] = but%10 + '0'; + } + char * target = tern_find_ptr(button_node, numstr); + if (target) { + int ui_func, padnum, button; + int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); + if (bindtype == 1) { + bind_button_gamepad(i, but, padnum, button); + } else if (bindtype == 2) { + bind_button_ui(i, but, ui_func, button); + } + } } } } } } - tern_node * speed_nodes = tern_find_prefix(config, "clocksspeeds"); + tern_node * speed_nodes = tern_get_node(tern_find_path(config, "clocks\0speeds\0")); speeds = malloc(sizeof(uint32_t)); speeds[0] = 100; process_speeds(speed_nodes, NULL); diff --git a/render_sdl.c b/render_sdl.c index 9de86dd..82f8b12 100644 --- a/render_sdl.c +++ b/render_sdl.c @@ -173,8 +173,10 @@ void render_alloc_surfaces(vdp_context * context) 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); + tern_val def = {.ptrval = "default.v.glsl"}; + vshader = load_shader(tern_find_path_default(config, "video\0vertex_shader\0", def).ptrval, GL_VERTEX_SHADER); + def.ptrval = "default.f.glsl"; + fshader = load_shader(tern_find_path_default(config, "video\0fragment_shader\0", def).ptrval, GL_FRAGMENT_SHADER); program = glCreateProgram(); glAttachShader(program, vshader); glAttachShader(program, fshader); @@ -239,7 +241,8 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full 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")) { + tern_val def = {.ptrval = "normal"}; + if (fabs(aspect - 4.0/3.0) > 0.01 && strcmp(tern_find_path_default(config, "video\0aspect\0", def).ptrval, "stretch")) { for (int i = 0; i < 4; i++) { if (aspect > 4.0/3.0) { @@ -272,7 +275,7 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full audio_ready = SDL_CreateCond(); SDL_AudioSpec desired, actual; - char * rate_str = tern_find_ptr(config, "audiorate"); + char * rate_str = tern_find_path(config, "audio\0rate\0").ptrval; int rate = rate_str ? atoi(rate_str) : 0; if (!rate) { rate = 48000; @@ -280,7 +283,7 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full desired.freq = rate; desired.format = AUDIO_S16SYS; desired.channels = 2; - char * samples_str = tern_find_ptr(config, "audiobuffer"); + char * samples_str = tern_find_path(config, "audio\0buffer\0").ptrval; int samples = samples_str ? atoi(samples_str) : 0; if (!samples) { samples = 512; diff --git a/romdb.c b/romdb.c index fbfcef9..fce0c84 100644 --- a/romdb.c +++ b/romdb.c @@ -3,13 +3,140 @@ #include "config.h" #include "romdb.h" #include "util.h" +#include "blastem.h" #define TITLE_START 0x150 #define TITLE_END (TITLE_START+48) #define GAME_ID_OFF 0x183 #define GAME_ID_LEN 8 +#define ROM_END 0x1A4 +#define RAM_ID 0x1B0 +#define RAM_FLAGS 0x1B2 +#define RAM_START 0x1B4 +#define RAM_END 0x1B8 #define REGION_START 0x1F0 +uint16_t read_sram_w(uint32_t address, m68k_context * context) +{ + genesis_context * gen = context->system; + address &= gen->save_ram_mask; + switch(gen->save_flags) + { + case RAM_FLAG_BOTH: + return gen->save_ram[address] << 8 | gen->save_ram[address+1]; + case RAM_FLAG_EVEN: + return gen->save_ram[address >> 1] << 8 | 0xFF; + case RAM_FLAG_ODD: + return gen->save_ram[address >> 1] | 0xFF00; + } + return 0xFFFF;//We should never get here +} + +uint8_t read_sram_b(uint32_t address, m68k_context * context) +{ + genesis_context * gen = context->system; + address &= gen->save_ram_mask; + switch(gen->save_flags) + { + case RAM_FLAG_BOTH: + return gen->save_ram[address]; + case RAM_FLAG_EVEN: + if (address & 1) { + return 0xFF; + } else { + return gen->save_ram[address >> 1]; + } + case RAM_FLAG_ODD: + if (address & 1) { + return gen->save_ram[address >> 1]; + } else { + return 0xFF; + } + } + return 0xFF;//We should never get here +} + +m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint16_t value) +{ + genesis_context * gen = context->system; + if ((gen->bank_regs[0] & 0x3) == 1) { + address &= gen->save_ram_mask; + switch(gen->save_flags) + { + case RAM_FLAG_BOTH: + gen->save_ram[address] = value >> 8; + gen->save_ram[address+1] = value; + break; + case RAM_FLAG_EVEN: + gen->save_ram[address >> 1] = value >> 8; + break; + case RAM_FLAG_ODD: + gen->save_ram[address >> 1] = value; + break; + } + } + return context; +} + +m68k_context * write_sram_area_b(uint32_t address, m68k_context * context, uint8_t value) +{ + genesis_context * gen = context->system; + if ((gen->bank_regs[0] & 0x3) == 1) { + address &= gen->save_ram_mask; + switch(gen->save_flags) + { + case RAM_FLAG_BOTH: + gen->save_ram[address] = value; + break; + case RAM_FLAG_EVEN: + if (!(address & 1)) { + gen->save_ram[address >> 1] = value; + } + break; + case RAM_FLAG_ODD: + if (address & 1) { + gen->save_ram[address >> 1] = value; + } + break; + } + } + return context; +} + +m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16_t value) +{ + genesis_context * gen = context->system; + address &= 0xE; + address >>= 1; + gen->bank_regs[address] = value; + if (!address) { + if (value & 1) { + context->mem_pointers[2] = NULL; + } else { + context->mem_pointers[2] = cart + 0x200000/2; + } + } + return context; +} + +m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_t value) +{ + if (address & 1) { + genesis_context * gen = context->system; + address &= 0xE; + address >>= 1; + gen->bank_regs[address] = value; + if (!address) { + if (value & 1) { + context->mem_pointers[2] = NULL; + } else { + context->mem_pointers[2] = cart + 0x200000/2; + } + } + } + return context; +} + tern_node *load_rom_db() { char *exe_dir = get_exe_dir(); @@ -77,16 +204,96 @@ uint8_t get_header_regions(uint8_t *rom) return regions; } +uint32_t get_u32be(uint8_t *data) +{ + return *data << 24 | data[1] << 16 | data[2] << 8 | data[3]; +} + +void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk const *base_map, int base_chunks) +{ + if (rom[RAM_ID] == 'R' && rom[RAM_ID+1] == 'A') { + uint32_t rom_end = get_u32be(rom + ROM_END) + 1; + uint32_t ram_start = get_u32be(rom + RAM_START); + uint32_t ram_end = get_u32be(rom + RAM_END); + uint32_t ram_flags = info->save_type = rom[RAM_FLAGS] & RAM_FLAG_MASK; + ram_start &= 0xFFFFFE; + ram_end |= 1; + + info->map_chunks = base_chunks + (ram_start >= rom_end ? 2 : 3); + info->map = malloc(sizeof(memmap_chunk) * info->map_chunks); + memset(info->map, 0, sizeof(memmap_chunk)*2); + memcpy(info->map+2, base_map, sizeof(memmap_chunk) * base_chunks); + + if (ram_start >= rom_end) { + info->map[0].end = rom_end; + //TODO: ROM mirroring + info->map[0].mask = 0xFFFFFF; + info->map[0].flags = MMAP_READ; + info->map[0].buffer = rom; + + info->map[1].start = ram_start; + info->map[1].mask = ram_end - ram_start; + info->map[1].end = ram_end + 1; + info->map[1].flags = MMAP_READ | MMAP_WRITE; + uint32_t size = info->map[1].mask + 1; + if (ram_flags == RAM_FLAG_ODD) { + info->map[1].flags |= MMAP_ONLY_ODD; + size /= 2; + } else if (ram_flags == RAM_FLAG_EVEN) { + info->map[1].flags |= MMAP_ONLY_EVEN; + size /= 2; + } + info->map[1].buffer = malloc(size); + } else { + //Assume the standard Sega mapper + info->map[0].end = 0x200000; + info->map[0].mask = 0xFFFFFF; + info->map[0].flags = MMAP_READ; + info->map[0].buffer = rom; + + info->map[1].start = 0x200000; + info->map[1].end = 0x400000; + info->map[1].mask = 0x1FFFFF; + info->map[1].flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL; + info->map[1].ptr_index = 2; + info->map[1].read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL + info->map[1].read_8 = (read_8_fun)read_sram_b; + info->map[1].write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area + info->map[1].write_8 = (write_8_fun)write_sram_area_b; + info->map[1].buffer = cart + 0x200000; + + memmap_chunk *last = info->map + info->map_chunks - 1; + memset(last, 0, sizeof(memmap_chunk)); + last->start = 0xA13000; + last->end = 0xA13100; + last->mask = 0xFF; + last->write_16 = (write_16_fun)write_bank_reg_w; + last->write_8 = (write_8_fun)write_bank_reg_b; + } + } else { + info->map_chunks = base_chunks + 1; + info->map = malloc(sizeof(memmap_chunk) * info->map_chunks); + memset(info->map, 0, sizeof(memmap_chunk)); + memcpy(info->map+1, base_map, sizeof(memmap_chunk) * base_chunks); + + info->map[0].end = 0x400000; + info->map[0].mask = 0xFFFFFF; + info->map[0].flags = MMAP_READ; + info->map[0].buffer = rom; + info->save_type = SAVE_NONE; + } +} -rom_info configure_rom_heuristics(uint8_t *rom) +rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks) { rom_info info; info.name = get_header_name(rom); info.regions = get_header_regions(rom); + add_memmap_header(&info, rom, rom_size, base_map, base_chunks); return info; } -rom_info configure_rom(tern_node *rom_db, void *vrom) +rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks) { uint8_t product_id[GAME_ID_LEN+1]; uint8_t *rom = vrom; @@ -102,7 +309,7 @@ rom_info configure_rom(tern_node *rom_db, void *vrom) } tern_node * entry = tern_find_prefix(rom_db, product_id); if (!entry) { - return configure_rom_heuristics(rom); + return configure_rom_heuristics(rom, rom_size, base_map, base_chunks); } rom_info info; info.name = tern_find_ptr(entry, "name"); @@ -123,5 +330,18 @@ rom_info configure_rom(tern_node *rom_db, void *vrom) if (!info.regions) { info.regions = get_header_regions(rom); } + + tern_node *map = tern_find_prefix(entry, "map"); + if (map) { + uint32_t map_count = tern_count(map); + if (map_count) { + + } else { + add_memmap_header(&info, rom, rom_size, base_map, base_chunks); + } + } else { + add_memmap_header(&info, rom, rom_size, base_map, base_chunks); + } + return info; } diff --git a/romdb.h b/romdb.h index 5a1b4bc..776c2f5 100644 --- a/romdb.h +++ b/romdb.h @@ -5,17 +5,29 @@ #define REGION_U 2 #define REGION_E 4 +#define RAM_FLAG_ODD 0x18 +#define RAM_FLAG_EVEN 0x10 +#define RAM_FLAG_BOTH 0x00 +#define RAM_FLAG_MASK RAM_FLAG_ODD +#define SAVE_I2C 0x01 +#define SAVE_NONE 0xFF + #include "tern.h" #include "backend.h" typedef struct { - char *name; - memmap_chunk *map; - uint8_t regions; + char *name; + memmap_chunk *map; + uint8_t *save_buffer; + uint32_t map_chunks; + uint32_t save_size; + uint8_t save_type; + uint8_t regions; } rom_info; tern_node *load_rom_db(); -rom_info configure_rom(tern_node *rom_db, void *vrom); +rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks); +rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks); uint8_t translate_region_char(uint8_t c); #endif //ROMDB_H_ diff --git a/tern.c b/tern.c index 73ea08d..2929bd6 100644 --- a/tern.c +++ b/tern.c @@ -6,6 +6,8 @@ #include "tern.h" #include #include +#include +#include tern_node * tern_insert(tern_node * head, char * key, tern_val value) { @@ -115,6 +117,32 @@ void * tern_find_ptr(tern_node * head, char * key) return tern_find_ptr_default(head, key, NULL); } +tern_val tern_find_path_default(tern_node *head, char *key, tern_val def) +{ + tern_val ret; + while (*key) + { + if (!tern_find(head, key, &ret)) { + return def; + } + key = key + strlen(key) + 1; + if (*key) { + head = tern_get_node(ret); + if (!head) { + return def; + } + } + } + return ret; +} + +tern_val tern_find_path(tern_node *head, char *key) +{ + tern_val def; + def.ptrval = NULL; + return tern_find_path_default(head, key, def); +} + tern_node * tern_insert_ptr(tern_node * head, char * key, void * value) { tern_val val; @@ -122,6 +150,60 @@ tern_node * tern_insert_ptr(tern_node * head, char * key, void * value) return tern_insert(head, key, val); } +tern_node * tern_insert_node(tern_node *head, char *key, tern_node *value) +{ + tern_val val; + val.intval = ((intptr_t)value) | 1; + return tern_insert(head, key, val); +} + +uint32_t tern_count(tern_node *head) +{ + uint32_t count = 0; + if (head->left) { + count += tern_count(head->left); + } + if (head->right) { + count += tern_count(head->right); + } + if (!head->el) { + count++; + } else if (head->straight.next) { + count += tern_count(head->straight.next); + } + return count; +} + +#define MAX_ITER_KEY 127 +void tern_foreach_int(tern_node *head, iter_fun fun, void *data, char *keybuf, int pos) +{ + if (!head->el) { + keybuf[pos] = 0; + fun(keybuf, head->straight.value, data); + } + if (head->left) { + tern_foreach_int(head->left, fun, data, keybuf, pos); + } + if (head->el) { + if (pos == MAX_ITER_KEY) { + fputs("exceeded maximum key size", stderr); + exit(1); + } + keybuf[pos] = head->el; + tern_foreach_int(head->straight.next, fun, data, keybuf, pos+1); + } + if (head->right) { + tern_foreach_int(head->left, fun, data, keybuf, pos); + } +} + +void tern_foreach(tern_node *head, iter_fun fun, void *data) +{ + //lame, but good enough for my purposes + char key[MAX_ITER_KEY+1]; + tern_foreach_int(head, fun, data, key, 0); +} + char * tern_int_key(uint32_t key, char * buf) { char * cur = buf; @@ -133,3 +215,8 @@ char * tern_int_key(uint32_t key, char * buf) *cur = 0; return buf; } + +tern_node * tern_get_node(tern_val value) +{ + return value.intval & 1 ? (tern_node *)(value.intval & ~1) : NULL; +} diff --git a/tern.h b/tern.h index cdf6948..c708110 100644 --- a/tern.h +++ b/tern.h @@ -25,6 +25,8 @@ typedef struct tern_node { char el; } tern_node; +typedef void (*iter_fun)(char *key, tern_val val, void *data); + tern_node * tern_insert(tern_node * head, char * key, tern_val value); int tern_find(tern_node * head, char * key, tern_val *ret); tern_node * tern_find_prefix(tern_node * head, char * key); @@ -32,7 +34,12 @@ intptr_t tern_find_int(tern_node * head, char * key, intptr_t def); 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_val tern_find_path_default(tern_node *head, char *key, tern_val def); +tern_val tern_find_path(tern_node *head, char *key); tern_node * tern_insert_ptr(tern_node * head, char * key, void * value); +tern_node * tern_insert_node(tern_node *head, char *key, tern_node *value); +uint32_t tern_count(tern_node *head); char * tern_int_key(uint32_t key, char * buf); +tern_node * tern_get_node(tern_val value); #endif //TERN_H_ -- cgit v1.2.3 From 358991e7fef42ae206231aabfeee045e5214dbe4 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 6 Jul 2015 19:46:46 -0700 Subject: SRAM detection from ROM header is no working correctly again --- blastem.c | 148 +++++++++++++++----------------------------------------------- blastem.h | 5 ++- romdb.c | 49 +++++++++++---------- romdb.h | 1 + 4 files changed, 66 insertions(+), 137 deletions(-) diff --git a/blastem.c b/blastem.c index fb5ce4b..8072132 100644 --- a/blastem.c +++ b/blastem.c @@ -780,9 +780,7 @@ void set_speed_percent(genesis_context * context, uint32_t percent) #define MAX_MAP_CHUNKS (4+7+1) -const memmap_chunk static_map[] = { - {0, 0x400000, 0xFFFFFF, 0, MMAP_READ, cart, - NULL, NULL, NULL, NULL}, +const memmap_chunk base_map[] = { {0xE00000, 0x1000000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, NULL, NULL, NULL, NULL}, {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, NULL, @@ -793,122 +791,44 @@ const memmap_chunk static_map[] = { (read_8_fun)io_read, (write_8_fun)io_write} }; -char * sram_filename; +char * save_filename; genesis_context * genesis; -void save_sram() +void persist_save() { - FILE * f = fopen(sram_filename, "wb"); + FILE * f = fopen(save_filename, "wb"); if (!f) { - fprintf(stderr, "Failed to open SRAM file %s for writing\n", sram_filename); + fprintf(stderr, "Failed to open %s file %s for writing\n", genesis->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); return; } - uint32_t size = genesis->save_ram_mask+1; - if (genesis->save_flags != RAM_FLAG_BOTH) { - size/= 2; - } - fwrite(genesis->save_ram, 1, size, f); + fwrite(genesis->save_storage, 1, genesis->save_size, f); fclose(f); - printf("Saved SRAM to %s\n", sram_filename); + printf("Saved %s to %s\n", genesis->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); } -void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, uint8_t * debugger) +void init_run_cpu(genesis_context * gen, rom_info *rom, FILE * address_log, char * statefile, uint8_t * debugger) { m68k_options opts; - memmap_chunk memmap[MAX_MAP_CHUNKS]; - uint32_t num_chunks; - void * initial_mapped = NULL; - gen->save_ram = NULL; - //TODO: Handle carts larger than 4MB - //TODO: Handle non-standard mappers - uint32_t size; - /* - if ((cart[RAM_ID/2] & 0xFF) == 'A' && (cart[RAM_ID/2] >> 8) == 'R') { - //Cart has save RAM - uint32_t rom_end = ((cart[ROM_END/2] << 16) | cart[ROM_END/2+1]) + 1; - uint32_t ram_start = (cart[RAM_START/2] << 16) | cart[RAM_START/2+1]; - uint32_t ram_end = (cart[RAM_END/2] << 16) | cart[RAM_END/2+1]; - uint16_t ram_flags = cart[RAM_FLAGS/2]; - gen->save_flags = ram_flags & RAM_FLAG_MASK; - memset(memmap, 0, sizeof(memmap_chunk)*2); - if (ram_start >= rom_end) { - memmap[0].end = rom_end; - memmap[0].mask = 0xFFFFFF; - memmap[0].flags = MMAP_READ; - memmap[0].buffer = cart; - - ram_start &= 0xFFFFFE; - ram_end |= 1; - memmap[1].start = ram_start; - gen->save_ram_mask = memmap[1].mask = ram_end-ram_start; - ram_end += 1; - memmap[1].end = ram_end; - memmap[1].flags = MMAP_READ | MMAP_WRITE; - size = ram_end-ram_start; - if ((ram_flags & RAM_FLAG_MASK) == RAM_FLAG_ODD) { - memmap[1].flags |= MMAP_ONLY_ODD; - size /= 2; - } else if((ram_flags & RAM_FLAG_MASK) == RAM_FLAG_EVEN) { - memmap[1].flags |= MMAP_ONLY_EVEN; - size /= 2; - } - memmap[1].buffer = gen->save_ram = malloc(size); - - memcpy(memmap+2, static_map+1, sizeof(static_map)-sizeof(static_map[0])); - num_chunks = sizeof(static_map)/sizeof(memmap_chunk)+1; - } else { - //Assume the standard Sega mapper for now - memmap[0].end = 0x200000; - memmap[0].mask = 0xFFFFFF; - memmap[0].flags = MMAP_READ; - memmap[0].buffer = cart; - - memmap[1].start = 0x200000; - memmap[1].end = 0x400000; - memmap[1].mask = 0x1FFFFF; - ram_start &= 0xFFFFFE; - ram_end |= 1; - gen->save_ram_mask = ram_end-ram_start; - memmap[1].flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL; - memmap[1].ptr_index = 2; - memmap[1].read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL - memmap[1].read_8 = (read_8_fun)read_sram_b; - memmap[1].write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area - memmap[1].write_8 = (write_8_fun)write_sram_area_b; - memcpy(memmap+2, static_map+1, sizeof(static_map)-sizeof(static_map[0])); - num_chunks = sizeof(static_map)/sizeof(memmap_chunk)+1; - memset(memmap+num_chunks, 0, sizeof(memmap[num_chunks])); - memmap[num_chunks].start = 0xA13000; - memmap[num_chunks].end = 0xA13100; - memmap[num_chunks].mask = 0xFF; - memmap[num_chunks].write_16 = (write_16_fun)write_bank_reg_w; - memmap[num_chunks].write_8 = (write_8_fun)write_bank_reg_b; - num_chunks++; - ram_end++; - size = ram_end-ram_start; - if ((ram_flags & RAM_FLAG_MASK) != RAM_FLAG_BOTH) { - size /= 2; - } - gen->save_ram = malloc(size); - memmap[1].buffer = initial_mapped = cart + 0x200000/2; - } - } else { - memcpy(memmap, static_map, sizeof(static_map)); - num_chunks = sizeof(static_map)/sizeof(memmap_chunk); - } - */ - if (gen->save_ram) { - memset(gen->save_ram, 0, size); - FILE * f = fopen(sram_filename, "rb"); + + gen->save_type = rom->save_type; + if (gen->save_type != SAVE_NONE) { + gen->save_ram_mask = rom->save_mask; + gen->save_size = rom->save_size; + gen->save_storage = rom->save_buffer; + memset(gen->save_storage, 0, rom->save_size); + FILE * f = fopen(save_filename, "rb"); if (f) { - uint32_t read = fread(gen->save_ram, 1, size, f); + uint32_t read = fread(gen->save_storage, 1, rom->save_size, f); fclose(f); if (read > 0) { - printf("Loaded SRAM from %s\n", sram_filename); + printf("Loaded %s from %s\n", rom->save_type == SAVE_I2C ? "EEPROM" : "SRAM", save_filename); } } - atexit(save_sram); + atexit(persist_save); + } else { + gen->save_storage = NULL; } - init_m68k_opts(&opts, memmap, num_chunks, MCLKS_PER_68K); + + init_m68k_opts(&opts, rom->map, rom->map_chunks, MCLKS_PER_68K); opts.address_log = address_log; m68k_context *context = init_68k_context(&opts); gen->m68k = context; @@ -921,8 +841,8 @@ void init_run_cpu(genesis_context * gen, FILE * address_log, char * statefile, u //work 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] = rom->map[1].buffer; + context->mem_pointers[3] = (uint16_t *)gen->save_storage; if (statefile) { uint32_t pc = load_gst(gen, statefile); @@ -1084,7 +1004,7 @@ int main(int argc, char ** argv) return 1; } } else if (!loaded) { - if(rom_size = load_rom(argv[i])) { + if (!(rom_size = load_rom(argv[i]))) { fprintf(stderr, "Failed to open %s for reading\n", argv[i]); return 1; } @@ -1101,7 +1021,7 @@ int main(int argc, char ** argv) return 1; } tern_node *rom_db = load_rom_db(); - rom_info info = configure_rom(rom_db, cart, rom_size, static_map+1, sizeof(static_map)/sizeof(static_map[0]) - 1); + rom_info info = configure_rom(rom_db, cart, rom_size, base_map, sizeof(base_map)/sizeof(base_map[0])); byteswap_rom(); set_region(&info, force_version); update_title(info.name); @@ -1158,20 +1078,22 @@ int main(int argc, char ** argv) setup_io_devices(config, gen.ports); int fname_size = strlen(romfname); - sram_filename = malloc(fname_size+6); - memcpy(sram_filename, romfname, fname_size); + char * ext = info.save_type == SAVE_I2C ? "eeprom" : "sram"; + save_filename = malloc(fname_size+strlen(ext) + 2); + memcpy(save_filename, romfname, fname_size); int i; for (i = fname_size-1; fname_size >= 0; --i) { - if (sram_filename[i] == '.') { - strcpy(sram_filename + i + 1, "sram"); + if (save_filename[i] == '.') { + strcpy(save_filename + i + 1, ext); break; } } if (i < 0) { - strcpy(sram_filename + fname_size, ".sram"); + save_filename[fname_size] = '.'; + strcpy(save_filename + fname_size + 1, ext); } set_keybindings(gen.ports); - init_run_cpu(&gen, address_log, statefile, debuggerfun); + init_run_cpu(&gen, &info, address_log, statefile, debuggerfun); return 0; } diff --git a/blastem.h b/blastem.h index f3bf4c6..b761149 100644 --- a/blastem.h +++ b/blastem.h @@ -21,14 +21,15 @@ typedef struct { vdp_context *vdp; ym2612_context *ym; psg_context *psg; - uint8_t *save_ram; + uint8_t *save_storage; + uint32_t save_size; uint32_t save_ram_mask; - 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]; + uint8_t save_type; io_port ports[3]; uint8_t bus_busy; } genesis_context; diff --git a/romdb.c b/romdb.c index fce0c84..c22ec4d 100644 --- a/romdb.c +++ b/romdb.c @@ -20,14 +20,14 @@ uint16_t read_sram_w(uint32_t address, m68k_context * context) { genesis_context * gen = context->system; address &= gen->save_ram_mask; - switch(gen->save_flags) + switch(gen->save_type) { case RAM_FLAG_BOTH: - return gen->save_ram[address] << 8 | gen->save_ram[address+1]; + return gen->save_storage[address] << 8 | gen->save_storage[address+1]; case RAM_FLAG_EVEN: - return gen->save_ram[address >> 1] << 8 | 0xFF; + return gen->save_storage[address >> 1] << 8 | 0xFF; case RAM_FLAG_ODD: - return gen->save_ram[address >> 1] | 0xFF00; + return gen->save_storage[address >> 1] | 0xFF00; } return 0xFFFF;//We should never get here } @@ -36,19 +36,19 @@ uint8_t read_sram_b(uint32_t address, m68k_context * context) { genesis_context * gen = context->system; address &= gen->save_ram_mask; - switch(gen->save_flags) + switch(gen->save_type) { case RAM_FLAG_BOTH: - return gen->save_ram[address]; + return gen->save_storage[address]; case RAM_FLAG_EVEN: if (address & 1) { return 0xFF; } else { - return gen->save_ram[address >> 1]; + return gen->save_storage[address >> 1]; } case RAM_FLAG_ODD: if (address & 1) { - return gen->save_ram[address >> 1]; + return gen->save_storage[address >> 1]; } else { return 0xFF; } @@ -61,17 +61,17 @@ m68k_context * write_sram_area_w(uint32_t address, m68k_context * context, uint1 genesis_context * gen = context->system; if ((gen->bank_regs[0] & 0x3) == 1) { address &= gen->save_ram_mask; - switch(gen->save_flags) + switch(gen->save_type) { case RAM_FLAG_BOTH: - gen->save_ram[address] = value >> 8; - gen->save_ram[address+1] = value; + gen->save_storage[address] = value >> 8; + gen->save_storage[address+1] = value; break; case RAM_FLAG_EVEN: - gen->save_ram[address >> 1] = value >> 8; + gen->save_storage[address >> 1] = value >> 8; break; case RAM_FLAG_ODD: - gen->save_ram[address >> 1] = value; + gen->save_storage[address >> 1] = value; break; } } @@ -83,19 +83,19 @@ m68k_context * write_sram_area_b(uint32_t address, m68k_context * context, uint8 genesis_context * gen = context->system; if ((gen->bank_regs[0] & 0x3) == 1) { address &= gen->save_ram_mask; - switch(gen->save_flags) + switch(gen->save_type) { case RAM_FLAG_BOTH: - gen->save_ram[address] = value; + gen->save_storage[address] = value; break; case RAM_FLAG_EVEN: if (!(address & 1)) { - gen->save_ram[address >> 1] = value; + gen->save_storage[address >> 1] = value; } break; case RAM_FLAG_ODD: if (address & 1) { - gen->save_ram[address >> 1] = value; + gen->save_storage[address >> 1] = value; } break; } @@ -218,6 +218,13 @@ void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk uint32_t ram_flags = info->save_type = rom[RAM_FLAGS] & RAM_FLAG_MASK; ram_start &= 0xFFFFFE; ram_end |= 1; + info->save_mask = ram_end - ram_start; + uint32_t size = info->save_mask + 1; + if (ram_flags != RAM_FLAG_BOTH) { + size /= 2; + } + info->save_size = size; + info->save_buffer = malloc(size); info->map_chunks = base_chunks + (ram_start >= rom_end ? 2 : 3); info->map = malloc(sizeof(memmap_chunk) * info->map_chunks); @@ -232,18 +239,16 @@ void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk info->map[0].buffer = rom; info->map[1].start = ram_start; - info->map[1].mask = ram_end - ram_start; + info->map[1].mask = info->save_mask; info->map[1].end = ram_end + 1; info->map[1].flags = MMAP_READ | MMAP_WRITE; - uint32_t size = info->map[1].mask + 1; + if (ram_flags == RAM_FLAG_ODD) { info->map[1].flags |= MMAP_ONLY_ODD; - size /= 2; } else if (ram_flags == RAM_FLAG_EVEN) { info->map[1].flags |= MMAP_ONLY_EVEN; - size /= 2; } - info->map[1].buffer = malloc(size); + info->map[1].buffer = info->save_buffer; } else { //Assume the standard Sega mapper info->map[0].end = 0x200000; diff --git a/romdb.h b/romdb.h index 776c2f5..5b21840 100644 --- a/romdb.h +++ b/romdb.h @@ -21,6 +21,7 @@ typedef struct { uint8_t *save_buffer; uint32_t map_chunks; uint32_t save_size; + uint32_t save_mask; uint8_t save_type; uint8_t regions; } rom_info; -- cgit v1.2.3 From 8af1d14863bb6ffad2c50b5275a848240c68c62e Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 7 Jul 2015 19:33:33 -0700 Subject: Add support for reading cartridge memory map from ROM database, though without EEPROM support for now --- rom.db | 28 +++++++++--------- romdb.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- tern.c | 8 +++-- tern.h | 1 + util.c | 11 +++++++ util.h | 2 ++ 6 files changed, 132 insertions(+), 21 deletions(-) diff --git a/rom.db b/rom.db index a31ef0a..bc9eea2 100644 --- a/rom.db +++ b/rom.db @@ -1,6 +1,6 @@ T-081326 { name NBA Jam - eeprom { + EEPROM { type i2c size 256 } @@ -10,7 +10,7 @@ T-081326 { last 1FFFFF } 200000 { - device eeprom + device EEPROM last 3FFFFF bits_read { 1 sda @@ -24,7 +24,7 @@ T-081326 { } T-81033 { name NBA Jam - eeprom { + EEPROM { type i2c size 256 } @@ -34,7 +34,7 @@ T-81033 { last 1FFFFF } 200000 { - device eeprom + device EEPROM last 3FFFFF bits_read { 1 sda @@ -48,7 +48,7 @@ T-81033 { } T-081276 { name NFL Quarterback Club - eeprom { + EEPROM { type i2c size 256 } @@ -58,7 +58,7 @@ T-081276 { last 1FFFFF } 200000 { - device eeprom + device EEPROM last 3FFFFF bits_read { 0 sda @@ -72,7 +72,7 @@ T-081276 { } T-81406 { name NBA Jam TE - eeprom { + EEPROM { type i2c size 512 } @@ -82,7 +82,7 @@ T-81406 { last 1FFFFF } 200000 { - device eeprom + device EEPROM last 3FFFFF bits_read { 0 sda @@ -96,7 +96,7 @@ T-81406 { } T-081586 { name NFL Quarterback Club '96 - eeprom { + EEPROM { type i2c size 2048 } @@ -106,7 +106,7 @@ T-081586 { last 1FFFFF } 200000 { - device eeprom + device EEPROM last 3FFFFF bits_read { 0 sda @@ -120,7 +120,7 @@ T-081586 { } T-81576 { name College Slam - eeprom { + EEPROM { type i2c size 8192 } @@ -130,7 +130,7 @@ T-81576 { last 1FFFFF } 200000 { - device eeprom + device EEPROM last 3FFFFF bits_read { 0 sda @@ -144,7 +144,7 @@ T-81576 { } T-81476 { name Frank Thomas Big Hurt Baseball - eeprom { + EEPROM { type i2c size 8192 } @@ -154,7 +154,7 @@ T-81476 { last 1FFFFF } 200000 { - device eeprom + device EEPROM last 3FFFFF bits_read { 0 sda diff --git a/romdb.c b/romdb.c index c22ec4d..bcd8c7b 100644 --- a/romdb.c +++ b/romdb.c @@ -209,6 +209,18 @@ uint32_t get_u32be(uint8_t *data) return *data << 24 | data[1] << 16 | data[2] << 8 | data[3]; } +uint32_t calc_mask(uint32_t src_size, uint32_t start, uint32_t end) +{ + uint32_t map_size = end-start+1; + if (src_size < map_size) { + return nearest_pow2(src_size)-1; + } else if (!start) { + return 0xFFFFFF; + } else { + return nearest_pow2(map_size)-1; + } +} + void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk const *base_map, int base_chunks) { if (rom[RAM_ID] == 'R' && rom[RAM_ID+1] == 'A') { @@ -298,6 +310,77 @@ rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk return info; } +typedef struct { + rom_info *info; + uint8_t *rom; + tern_node *root; + uint32_t rom_size; + int index; +} map_iter_state; + +void map_iter_fun(char *key, tern_val val, void *data) +{ + map_iter_state *state = data; + tern_node *node = tern_get_node(val); + if (!node) { + fprintf(stderr, "ROM DB map entry %d with address %s is not a node\n", state->index, key); + exit(1); + } + uint32_t start = strtol(key, NULL, 16); + uint32_t end = strtol(tern_find_ptr_default(node, "last", "0"), NULL, 16); + if (!end || end < start) { + fprintf(stderr, "'last' value is missing or invalid for ROM DB map entry %d with address %s\n", state->index, key); + exit(1); + } + char * dtype = tern_find_ptr_default(node, "device", "ROM"); + uint32_t offset = strtol(tern_find_ptr_default(node, "offset", "0"), NULL, 0); + memmap_chunk *map = state->info->map + state->index; + map->start = start; + map->end = end; + if (!strcmp(dtype, "ROM")) { + map->buffer = state->rom + offset; + map->flags = MMAP_READ; + map->mask = calc_mask(state->rom_size, start, end); + } else if (!strcmp(dtype, "EEPROM")) { + + + } else if (!strcmp(dtype, "SRAM")) { + if (!state->info->save_size) { + char * size = tern_find_path(state->root, "SRAM\0size\0").ptrval; + if (!size) { + fprintf(stderr, "ROM DB map entry %d with address %s has device type SRAM, but the SRAM size is not defined\n", state->index, key); + exit(1); + } + state->info->save_size = atoi(size); + if (!state->info->save_size) { + fprintf(stderr, "SRAM size %s is invalid\n", size); + exit(1); + } + state->info->save_buffer = malloc(state->info->save_size); + char *bus = tern_find_path(state->root, "SRAM\0bus\0").ptrval; + if (!strcmp(bus, "odd")) { + state->info->save_type = RAM_FLAG_ODD; + } else if(!strcmp(bus, "even")) { + state->info->save_type = RAM_FLAG_EVEN; + } else { + state->info->save_type = RAM_FLAG_BOTH; + } + } + map->buffer = state->info->save_buffer + offset; + map->flags = MMAP_READ | MMAP_WRITE; + if (state->info->save_type == RAM_FLAG_ODD) { + map->flags |= MMAP_ONLY_ODD; + } else if(state->info->save_type == RAM_FLAG_EVEN) { + map->flags |= MMAP_ONLY_EVEN; + } + map->mask = calc_mask(state->info->save_size, start, end); + } else { + fprintf(stderr, "Invalid device type for ROM DB map entry %d with address %s\n", state->index, key); + exit(1); + } + state->index++; +} + rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks) { uint8_t product_id[GAME_ID_LEN+1]; @@ -312,13 +395,16 @@ rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_ product_id[i] = rom[GAME_ID_OFF + i]; } - tern_node * entry = tern_find_prefix(rom_db, product_id); + printf("Product ID: %s\n", product_id); + tern_node * entry = tern_find_ptr(rom_db, product_id); if (!entry) { + puts("Not found in ROM DB, examining header\n"); return configure_rom_heuristics(rom, rom_size, base_map, base_chunks); } rom_info info; info.name = tern_find_ptr(entry, "name"); if (info.name) { + printf("Found name: %s\n", info.name); info.name = strdup(info.name); } else { info.name = get_header_name(rom); @@ -336,11 +422,18 @@ rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_ info.regions = get_header_regions(rom); } - tern_node *map = tern_find_prefix(entry, "map"); + tern_node *map = tern_find_ptr(entry, "map"); if (map) { - uint32_t map_count = tern_count(map); - if (map_count) { - + info.map_chunks = tern_count(map); + if (info.map_chunks) { + info.map_chunks += base_chunks; + info.save_buffer = NULL; + info.save_size = 0; + info.map = malloc(sizeof(memmap_chunk) * info.map_chunks); + memset(info.map, 0, sizeof(memmap_chunk) * (info.map_chunks - base_chunks)); + map_iter_state state = {&info, rom, entry, rom_size, 0}; + tern_foreach(map, map_iter_fun, &state); + memcpy(info.map + state.index, base_map, sizeof(memmap_chunk) * base_chunks); } else { add_memmap_header(&info, rom, rom_size, base_map, base_chunks); } diff --git a/tern.c b/tern.c index 2929bd6..e4f80f8 100644 --- a/tern.c +++ b/tern.c @@ -107,7 +107,11 @@ void * tern_find_ptr_default(tern_node * head, char * key, void * def) { tern_val ret; if (tern_find(head, key, &ret)) { - return ret.ptrval; + if (ret.intval & 1) { + return (void *)(ret.intval & ~1); + } else { + return ret.ptrval; + } } return def; } @@ -193,7 +197,7 @@ void tern_foreach_int(tern_node *head, iter_fun fun, void *data, char *keybuf, i tern_foreach_int(head->straight.next, fun, data, keybuf, pos+1); } if (head->right) { - tern_foreach_int(head->left, fun, data, keybuf, pos); + tern_foreach_int(head->right, fun, data, keybuf, pos); } } diff --git a/tern.h b/tern.h index c708110..5c0dcfd 100644 --- a/tern.h +++ b/tern.h @@ -39,6 +39,7 @@ tern_val tern_find_path(tern_node *head, char *key); tern_node * tern_insert_ptr(tern_node * head, char * key, void * value); tern_node * tern_insert_node(tern_node *head, char *key, tern_node *value); uint32_t tern_count(tern_node *head); +void tern_foreach(tern_node *head, iter_fun fun, void *data); char * tern_int_key(uint32_t key, char * buf); tern_node * tern_get_node(tern_val value); diff --git a/util.c b/util.c index 20aa2ee..361d26b 100644 --- a/util.c +++ b/util.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -68,6 +69,16 @@ char * split_keyval(char * text) return text+1; } +uint32_t nearest_pow2(uint32_t val) +{ + uint32_t ret = 1; + while (ret < val) + { + ret = ret << 1; + } + return ret; +} + static char * exe_str; void set_exe_str(char * str) diff --git a/util.h b/util.h index 780f538..85b0c8f 100644 --- a/util.h +++ b/util.h @@ -15,6 +15,8 @@ long file_size(FILE * f); char * strip_ws(char * text); //Inserts a null after the first word, returns a pointer to the second word char * split_keyval(char * text); +//Gets the smallest power of two that is >= a certain value, won't work for values > 0x80000000 +uint32_t nearest_pow2(uint32_t val); //Should be called by main with the value of argv[0] for use by get_exe_dir void set_exe_str(char * str); //Returns the directory the executable is in -- cgit v1.2.3 From da7c1f27d44cb1bb77c057ce9cca7041931619ae Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 10 Jul 2015 18:46:18 -0700 Subject: Initial work on I2C EEPROM implementation --- blastem.c | 5 ++ blastem.h | 4 ++ romdb.c | 210 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- romdb.h | 17 +++++ 4 files changed, 233 insertions(+), 3 deletions(-) diff --git a/blastem.c b/blastem.c index 8072132..a48ba30 100644 --- a/blastem.c +++ b/blastem.c @@ -814,6 +814,8 @@ void init_run_cpu(genesis_context * gen, rom_info *rom, FILE * address_log, char gen->save_ram_mask = rom->save_mask; gen->save_size = rom->save_size; gen->save_storage = rom->save_buffer; + gen->eeprom_map = rom->eeprom_map; + gen->num_eeprom = rom->num_eeprom; memset(gen->save_storage, 0, rom->save_size); FILE * f = fopen(save_filename, "rb"); if (f) { @@ -824,6 +826,9 @@ void init_run_cpu(genesis_context * gen, rom_info *rom, FILE * address_log, char } } atexit(persist_save); + if (gen->save_type == SAVE_I2C) { + eeprom_init(&gen->eeprom); + } } else { gen->save_storage = NULL; } diff --git a/blastem.h b/blastem.h index b761149..7d051b6 100644 --- a/blastem.h +++ b/blastem.h @@ -14,6 +14,7 @@ #include "psg.h" #include "io.h" #include "config.h" +#include "romdb.h" typedef struct { m68k_context *m68k; @@ -22,6 +23,8 @@ typedef struct { ym2612_context *ym; psg_context *psg; uint8_t *save_storage; + eeprom_map *eeprom_map; + uint32_t num_eeprom; uint32_t save_size; uint32_t save_ram_mask; uint32_t master_clock; //Current master clock value @@ -32,6 +35,7 @@ typedef struct { uint8_t save_type; io_port ports[3]; uint8_t bus_busy; + eeprom_state eeprom; } genesis_context; extern genesis_context * genesis; diff --git a/romdb.c b/romdb.c index bcd8c7b..ed845ab 100644 --- a/romdb.c +++ b/romdb.c @@ -16,6 +16,37 @@ #define RAM_END 0x1B8 #define REGION_START 0x1F0 +void eeprom_init(eeprom_state *state) +{ + state->slave_sda = 1; + state->host_sda = state->scl = 0; +} + +void set_host_sda(eeprom_state *state, uint8_t val) +{ + if (state->scl) { + if (val & ~state->host_sda) { + //stop condition + } else if (~val & state->host_sda) { + //start condition + } + } + state->host_sda = val; +} + +void set_scl(eeprom_state *state, uint8_t val) +{ + if (val & ~state->scl) { + //latch sda + } + state->scl = val; +} + +uint8_t get_sda(eeprom_state *state) +{ + return state->host_sda & state->slave_sda; +} + uint16_t read_sram_w(uint32_t address, m68k_context * context) { genesis_context * gen = context->system; @@ -136,6 +167,98 @@ m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_ } return context; } +eeprom_map *find_eeprom_map(uint32_t address, genesis_context *gen) +{ + for (int i = 0; i < gen->num_eeprom; i++) + { + if (address >= gen->eeprom_map[i].start && address <= gen->eeprom_map[i].end) { + return gen->eeprom_map + i; + } + } + return NULL; +} + +void * write_eeprom_i2c_w(uint32_t address, void * context, uint16_t value) +{ + genesis_context *gen = ((m68k_context *)context)->system; + eeprom_map *map = find_eeprom_map(address, gen); + if (!map) { + fprintf(stderr, "Could not find EEPROM map for address %X\n", address); + exit(1); + } + printf("EEPROM word write: %X - %X\n", address, value); + if (map->sda_write_mask) { + printf("sda: %d\n", (value & map->sda_write_mask) != 0); + set_host_sda(&gen->eeprom, (value & map->sda_write_mask) != 0); + } + if (map->scl_mask) { + printf("scl: %d\n", (value & map->scl_mask) != 0); + set_scl(&gen->eeprom, (value & map->sda_write_mask) != 0); + } + return context; +} + +void * write_eeprom_i2c_b(uint32_t address, void * context, uint8_t value) +{ + genesis_context *gen = ((m68k_context *)context)->system; + eeprom_map *map = find_eeprom_map(address, gen); + if (!map) { + fprintf(stderr, "Could not find EEPROM map for address %X\n", address); + exit(1); + } + + uint16_t expanded, mask; + if (address & 1) { + expanded = value; + mask = 0xFF; + } else { + expanded = value << 8; + mask = 0xFF00; + } + printf("EEPROM byte write: %X - %X (using mask %X and expanded val %X)\n", address, value, mask, expanded); + if (map->sda_write_mask & mask) { + printf("sda: %d\n", (expanded & map->sda_write_mask) != 0); + set_host_sda(&gen->eeprom, (expanded & map->sda_write_mask) != 0); + } + if (map->scl_mask & mask) { + printf("scl: %d\n", (expanded & map->scl_mask) != 0); + set_scl(&gen->eeprom, (expanded & map->scl_mask) != 0); + } + return context; +} + +uint16_t read_eeprom_i2c_w(uint32_t address, void * context) +{ + genesis_context *gen = ((m68k_context *)context)->system; + eeprom_map *map = find_eeprom_map(address, gen); + if (!map) { + fprintf(stderr, "Could not find EEPROM map for address %X\n", address); + exit(1); + } + uint16_t ret = 0; + if (map->sda_read_bit < 16) { + ret = get_sda(&gen->eeprom) << map->sda_read_bit; + } + printf("EEPROM word read: %X - %X\n", address, ret); + return ret; +} + +uint8_t read_eeprom_i2c_b(uint32_t address, void * context) +{ + genesis_context *gen = ((m68k_context *)context)->system; + eeprom_map *map = find_eeprom_map(address, gen); + if (!map) { + fprintf(stderr, "Could not find EEPROM map for address %X\n", address); + exit(1); + } + uint8_t bit = address & 1 ? map->sda_read_bit : map->sda_read_bit - 8; + uint8_t ret = 0; + if (bit < 8) { + ret = get_sda(&gen->eeprom) << bit; + } + printf("EEPROM byte read: %X - %X\n", address, ret); + return ret; +} tern_node *load_rom_db() { @@ -316,8 +439,45 @@ typedef struct { tern_node *root; uint32_t rom_size; int index; + int num_els; } map_iter_state; +void eeprom_read_fun(char *key, tern_val val, void *data) +{ + int bit = atoi(key); + if (bit < 0 || bit > 15) { + fprintf(stderr, "bit %s is out of range", key); + return; + } + char *pin = val.ptrval; + if (strcmp(pin, "sda")) { + fprintf(stderr, "bit %s is connected to unrecognized read pin %s", key, pin); + return; + } + eeprom_map *map = data; + map->sda_read_bit = bit; +} + +void eeprom_write_fun(char *key, tern_val val, void *data) +{ + int bit = atoi(key); + if (bit < 0 || bit > 15) { + fprintf(stderr, "bit %s is out of range", key); + return; + } + char *pin = val.ptrval; + eeprom_map *map = data; + if (!strcmp(pin, "sda")) { + map->sda_write_mask = 1 << bit; + return; + } + if (!strcmp(pin, "scl")) { + map->scl_mask = 1 << bit; + return; + } + fprintf(stderr, "bit %s is connected to unrecognized write pin %s", key, pin); +} + void map_iter_fun(char *key, tern_val val, void *data) { map_iter_state *state = data; @@ -342,8 +502,50 @@ void map_iter_fun(char *key, tern_val val, void *data) map->flags = MMAP_READ; map->mask = calc_mask(state->rom_size, start, end); } else if (!strcmp(dtype, "EEPROM")) { - - + if (!state->info->save_size) { + char * size = tern_find_path(state->root, "EEPROM\0size\0").ptrval; + if (!size) { + fprintf(stderr, "ROM DB map entry %d with address %s has device type EEPROM, but the EEPROM size is not defined\n", state->index, key); + exit(1); + } + state->info->save_size = atoi(size); + if (!state->info->save_size) { + fprintf(stderr, "EEPROM size %s is invalid\n", size); + exit(1); + } + char *etype = tern_find_path(state->root, "EEPROM\0type\0").ptrval; + if (!etype) { + etype = "i2c"; + } + if (!strcmp(etype, "i2c")) { + state->info->save_type = SAVE_I2C; + } else { + fprintf(stderr, "EEPROM type %s is invalid\n", etype); + exit(1); + } + state->info->save_buffer = malloc(state->info->save_size); + state->info->eeprom_map = malloc(sizeof(eeprom_map) * state->num_els); + memset(state->info->eeprom_map, 0, sizeof(eeprom_map) * state->num_els); + } + eeprom_map *eep_map = state->info->eeprom_map + state->info->num_eeprom; + eep_map->start = start; + eep_map->end = end; + eep_map->sda_read_bit = 0xFF; + tern_node * bits_read = tern_find_ptr(node, "bits_read"); + if (bits_read) { + tern_foreach(bits_read, eeprom_read_fun, eep_map); + } + tern_node * bits_write = tern_find_ptr(node, "bits_write"); + if (bits_write) { + tern_foreach(bits_write, eeprom_write_fun, eep_map); + } + printf("EEPROM address %X: sda read: %X, sda write: %X, scl: %X\n", start, eep_map->sda_read_bit, eep_map->sda_write_mask, eep_map->scl_mask); + state->info->num_eeprom++; + map->write_16 = write_eeprom_i2c_w; + map->write_8 = write_eeprom_i2c_b; + map->read_16 = read_eeprom_i2c_w; + map->read_8 = read_eeprom_i2c_b; + map->mask = 0xFFFFFF; } else if (!strcmp(dtype, "SRAM")) { if (!state->info->save_size) { char * size = tern_find_path(state->root, "SRAM\0size\0").ptrval; @@ -430,8 +632,10 @@ rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_ info.save_buffer = NULL; info.save_size = 0; info.map = malloc(sizeof(memmap_chunk) * info.map_chunks); + info.eeprom_map = NULL; + info.num_eeprom = 0; memset(info.map, 0, sizeof(memmap_chunk) * (info.map_chunks - base_chunks)); - map_iter_state state = {&info, rom, entry, rom_size, 0}; + map_iter_state state = {&info, rom, entry, rom_size, 0, info.map_chunks - base_chunks}; tern_foreach(map, map_iter_fun, &state); memcpy(info.map + state.index, base_map, sizeof(memmap_chunk) * base_chunks); } else { diff --git a/romdb.h b/romdb.h index 5b21840..e126640 100644 --- a/romdb.h +++ b/romdb.h @@ -15,10 +15,26 @@ #include "tern.h" #include "backend.h" +typedef struct { + uint32_t start; + uint32_t end; + uint16_t sda_write_mask; + uint16_t scl_mask; + uint8_t sda_read_bit; +} eeprom_map; + +typedef struct { + uint8_t host_sda; + uint8_t slave_sda; + uint8_t scl; +} eeprom_state; + typedef struct { char *name; memmap_chunk *map; uint8_t *save_buffer; + eeprom_map *eeprom_map; + uint32_t num_eeprom; uint32_t map_chunks; uint32_t save_size; uint32_t save_mask; @@ -30,5 +46,6 @@ tern_node *load_rom_db(); rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks); rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks); uint8_t translate_region_char(uint8_t c); +void eeprom_init(eeprom_state *state); #endif //ROMDB_H_ -- cgit v1.2.3 From ec937eb637770838c92864d1d51393297a226d82 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 14 Jul 2015 18:28:05 -0700 Subject: Broken EEPROM support --- blastem.c | 2 +- romdb.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- romdb.h | 8 +++- 3 files changed, 142 insertions(+), 9 deletions(-) diff --git a/blastem.c b/blastem.c index a48ba30..51f188e 100644 --- a/blastem.c +++ b/blastem.c @@ -827,7 +827,7 @@ void init_run_cpu(genesis_context * gen, rom_info *rom, FILE * address_log, char } atexit(persist_save); if (gen->save_type == SAVE_I2C) { - eeprom_init(&gen->eeprom); + eeprom_init(&gen->eeprom, gen->save_storage, gen->save_size); } } else { gen->save_storage = NULL; diff --git a/romdb.c b/romdb.c index ed845ab..072c1b1 100644 --- a/romdb.c +++ b/romdb.c @@ -16,19 +16,55 @@ #define RAM_END 0x1B8 #define REGION_START 0x1F0 -void eeprom_init(eeprom_state *state) +enum { + I2C_IDLE, + I2C_START, + I2C_DEVICE_ACK, + I2C_ADDRESS_HI, + I2C_ADDRESS_HI_ACK, + I2C_ADDRESS, + I2C_ADDRESS_ACK, + I2C_READ, + I2C_READ_ACK, + I2C_WRITE, + I2C_WRITE_ACK +}; + +char * i2c_states[] = { + "idle", + "start", + "device ack", + "address hi", + "address hi ack", + "address", + "address ack", + "read", + "read_ack", + "write", + "write_ack" +}; + +void eeprom_init(eeprom_state *state, uint8_t *buffer, uint32_t size) { state->slave_sda = 1; state->host_sda = state->scl = 0; + state->buffer = buffer; + state->size = size; + state->state = I2C_IDLE; } void set_host_sda(eeprom_state *state, uint8_t val) { if (state->scl) { if (val & ~state->host_sda) { - //stop condition + //low to high, stop condition + state->state = I2C_IDLE; + state->slave_sda = 1; } else if (~val & state->host_sda) { - //start condition + //high to low, start condition + state->state = I2C_START; + state->slave_sda = 1; + state->counter = 8; } } state->host_sda = val; @@ -37,7 +73,98 @@ void set_host_sda(eeprom_state *state, uint8_t val) void set_scl(eeprom_state *state, uint8_t val) { if (val & ~state->scl) { - //latch sda + //low to high transition + switch (state->state) + { + case I2C_START: + case I2C_ADDRESS_HI: + case I2C_ADDRESS: + case I2C_WRITE: + state->latch = state->host_sda << 7 | state->latch >> 1; + state->counter--; + if (!state->counter) { + switch (state->state & 0x7F) + { + case I2C_START: + state->state = I2C_DEVICE_ACK; + break; + case I2C_ADDRESS_HI: + state->address = state->latch << 8; + state->state = I2C_ADDRESS_HI_ACK; + break; + case I2C_ADDRESS: + state->address |= state->latch; + state->state = I2C_ADDRESS_ACK; + break; + case I2C_WRITE: + state->buffer[state->address] = state->latch; + state->state = I2C_WRITE_ACK; + state->address++; + //TODO: page mask + state->address &= state->size-1; + break; + } + } + break; + case I2C_DEVICE_ACK: + if (state->latch & 1) { + state->state = I2C_READ; + state->counter = 8; + state->latch = state->buffer[state->address]; + state->address++; + //TODO: page mask + state->address &= state->size-1; + } else { + if (state->size < 256) { + state->address = state->latch >> 1; + state->state = I2C_WRITE; + } else if (state->size < 8192) { + state->address = state->latch << 8; + state->state = I2C_ADDRESS; + } else { + state->state = I2C_ADDRESS_HI; + } + state->counter = 8; + } + break; + case I2C_ADDRESS_HI_ACK: + state->state = I2C_ADDRESS; + break; + case I2C_ADDRESS_ACK: + state->state = I2C_WRITE; + break; + case I2C_READ: + state->counter--; + if (!state->counter) { + state->state = I2C_READ_ACK; + } + break; + case I2C_READ_ACK: + state->state = I2C_READ; + break; + case I2C_WRITE_ACK: + state->state = I2C_WRITE; + break; + } + } else if (~val & state->scl) { + //high to low transition + switch (state->state & 0x7F) + { + case I2C_DEVICE_ACK: + case I2C_ADDRESS_HI_ACK: + case I2C_ADDRESS_ACK: + case I2C_READ_ACK: + case I2C_WRITE_ACK: + state->slave_sda = 0; + break; + case I2C_READ: + state->slave_sda = state->latch >> 7; + state->latch = state->latch << 1; + break; + default: + state->slave_sda = 1; + break; + } } state->scl = val; } @@ -192,8 +319,8 @@ void * write_eeprom_i2c_w(uint32_t address, void * context, uint16_t value) set_host_sda(&gen->eeprom, (value & map->sda_write_mask) != 0); } if (map->scl_mask) { - printf("scl: %d\n", (value & map->scl_mask) != 0); - set_scl(&gen->eeprom, (value & map->sda_write_mask) != 0); + set_scl(&gen->eeprom, (value & map->scl_mask) != 0); + printf("scl: %d, state: %s, counter: %d\n", (value & map->scl_mask) != 0, i2c_states[gen->eeprom.state], gen->eeprom.counter); } return context; } @@ -221,7 +348,7 @@ void * write_eeprom_i2c_b(uint32_t address, void * context, uint8_t value) set_host_sda(&gen->eeprom, (expanded & map->sda_write_mask) != 0); } if (map->scl_mask & mask) { - printf("scl: %d\n", (expanded & map->scl_mask) != 0); + printf("scl: %d, state: %s\n", (expanded & map->scl_mask) != 0, i2c_states[gen->eeprom.state]); set_scl(&gen->eeprom, (expanded & map->scl_mask) != 0); } return context; diff --git a/romdb.h b/romdb.h index e126640..3bf9fa6 100644 --- a/romdb.h +++ b/romdb.h @@ -24,9 +24,15 @@ typedef struct { } eeprom_map; typedef struct { + char *buffer; + uint32_t size; + uint16_t address; uint8_t host_sda; uint8_t slave_sda; uint8_t scl; + uint8_t state; + uint8_t counter; + uint8_t latch; } eeprom_state; typedef struct { @@ -46,6 +52,6 @@ tern_node *load_rom_db(); rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks); rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks); uint8_t translate_region_char(uint8_t c); -void eeprom_init(eeprom_state *state); +void eeprom_init(eeprom_state *state, uint8_t *buffer, uint32_t size); #endif //ROMDB_H_ -- cgit v1.2.3 From fb73e9f0a60befdec0b81331e994cfd4424e1e65 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 17 Jul 2015 08:49:23 -0700 Subject: Add ability to change start address for VRAM viewer. Fix handling of DMA enable flag when it comes to DMA fills. This fixes a bug in James Pond 3 --- io.c | 2 +- vdp.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/io.c b/io.c index 3b89b99..50d4df7 100644 --- a/io.c +++ b/io.c @@ -248,7 +248,7 @@ void handle_binding_up(keybinding * binding) { case UI_DEBUG_MODE_INC: ui_debug_mode++; - if (ui_debug_mode == 4) { + if (ui_debug_mode == 7) { ui_debug_mode = 0; } genesis->vdp->debug = ui_debug_mode; diff --git a/vdp.c b/vdp.c index bfc301c..11777c4 100644 --- a/vdp.c +++ b/vdp.c @@ -910,15 +910,16 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context) } } } else { - uint32_t cell = (line / 8) * (context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32) + col; - uint32_t address = cell * 32 + (line % 8) * 4; + uint32_t base = (context->debug - 3) * 0x200; + uint32_t cell = base + (line / 8) * (context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32) + col; + uint32_t address = (cell * 32 + (line % 8) * 4) & 0xFFFF; 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; + address = (cell * 32 + (line % 8) * 4) & 0xFFFF; 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)]; @@ -1739,7 +1740,7 @@ int vdp_data_port_write(vdp_context * context, uint16_t value) 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) { + if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80 && (context->regs[REG_MODE_2] & BIT_DMA_ENABLE)) { context->flags |= FLAG_DMA_RUN; } cur->cd = context->cd; -- cgit v1.2.3 From 95c8581b8681a83c628409d8394c8fe95ccdfc33 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Fri, 17 Jul 2015 22:16:33 -0700 Subject: Less broken EEPROM support --- romdb.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/romdb.c b/romdb.c index 072c1b1..fc154c9 100644 --- a/romdb.c +++ b/romdb.c @@ -80,7 +80,7 @@ void set_scl(eeprom_state *state, uint8_t val) case I2C_ADDRESS_HI: case I2C_ADDRESS: case I2C_WRITE: - state->latch = state->host_sda << 7 | state->latch >> 1; + state->latch = state->host_sda | state->latch << 1; state->counter--; if (!state->counter) { switch (state->state & 0x7F) @@ -129,9 +129,11 @@ void set_scl(eeprom_state *state, uint8_t val) break; case I2C_ADDRESS_HI_ACK: state->state = I2C_ADDRESS; + state->counter = 8; break; case I2C_ADDRESS_ACK: state->state = I2C_WRITE; + state->counter = 8; break; case I2C_READ: state->counter--; @@ -141,9 +143,11 @@ void set_scl(eeprom_state *state, uint8_t val) break; case I2C_READ_ACK: state->state = I2C_READ; + state->counter = 8; break; case I2C_WRITE_ACK: state->state = I2C_WRITE; + state->counter = 8; break; } } else if (~val & state->scl) { @@ -314,14 +318,14 @@ void * write_eeprom_i2c_w(uint32_t address, void * context, uint16_t value) exit(1); } printf("EEPROM word write: %X - %X\n", address, value); + if (map->scl_mask) { + set_scl(&gen->eeprom, (value & map->scl_mask) != 0); + printf("scl: %d, state: %s, counter: %d, latch: %X\n", (value & map->scl_mask) != 0, i2c_states[gen->eeprom.state], gen->eeprom.counter, gen->eeprom.latch); + } if (map->sda_write_mask) { printf("sda: %d\n", (value & map->sda_write_mask) != 0); set_host_sda(&gen->eeprom, (value & map->sda_write_mask) != 0); } - if (map->scl_mask) { - set_scl(&gen->eeprom, (value & map->scl_mask) != 0); - printf("scl: %d, state: %s, counter: %d\n", (value & map->scl_mask) != 0, i2c_states[gen->eeprom.state], gen->eeprom.counter); - } return context; } @@ -343,14 +347,14 @@ void * write_eeprom_i2c_b(uint32_t address, void * context, uint8_t value) mask = 0xFF00; } printf("EEPROM byte write: %X - %X (using mask %X and expanded val %X)\n", address, value, mask, expanded); - if (map->sda_write_mask & mask) { - printf("sda: %d\n", (expanded & map->sda_write_mask) != 0); - set_host_sda(&gen->eeprom, (expanded & map->sda_write_mask) != 0); - } if (map->scl_mask & mask) { printf("scl: %d, state: %s\n", (expanded & map->scl_mask) != 0, i2c_states[gen->eeprom.state]); set_scl(&gen->eeprom, (expanded & map->scl_mask) != 0); } + if (map->sda_write_mask & mask) { + printf("sda: %d\n", (expanded & map->sda_write_mask) != 0); + set_host_sda(&gen->eeprom, (expanded & map->sda_write_mask) != 0); + } return context; } -- cgit v1.2.3 From df9080c523fd7a0f504b92e5f002645b484df9af Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 19 Jul 2015 20:51:09 -0700 Subject: Fix map for NFL Quarterback Club 96. Fix default EEPROM value. Initial work for supporing Sega mapper in ROM DB --- blastem.c | 1 - rom.db | 10 +++- romdb.c | 178 ++++++++++++++++++++++++++++++++++++++++---------------------- 3 files changed, 123 insertions(+), 66 deletions(-) diff --git a/blastem.c b/blastem.c index 51f188e..3f71631 100644 --- a/blastem.c +++ b/blastem.c @@ -816,7 +816,6 @@ void init_run_cpu(genesis_context * gen, rom_info *rom, FILE * address_log, char gen->save_storage = rom->save_buffer; gen->eeprom_map = rom->eeprom_map; gen->num_eeprom = rom->num_eeprom; - memset(gen->save_storage, 0, rom->save_size); FILE * f = fopen(save_filename, "rb"); if (f) { uint32_t read = fread(gen->save_storage, 1, rom->save_size, f); diff --git a/rom.db b/rom.db index bc9eea2..5759789 100644 --- a/rom.db +++ b/rom.db @@ -107,7 +107,10 @@ T-081586 { } 200000 { device EEPROM - last 3FFFFF + #This is almost certainly not correct based on the address pins + #available to the Acclaim mapper. It's probably available up to + #2FFFFF at least and just fights with D0 from the mask ROM + last 200001 bits_read { 0 sda } @@ -116,6 +119,11 @@ T-081586 { 8 scl } } + 200002 { + device ROM + last 3FFFFF + offset 200000 + } } } T-81576 { diff --git a/romdb.c b/romdb.c index fc154c9..7748de0 100644 --- a/romdb.c +++ b/romdb.c @@ -609,6 +609,80 @@ void eeprom_write_fun(char *key, tern_val val, void *data) fprintf(stderr, "bit %s is connected to unrecognized write pin %s", key, pin); } +void process_sram_def(char *key, map_iter_state *state) +{ + if (!state->info->save_size) { + char * size = tern_find_path(state->root, "SRAM\0size\0").ptrval; + if (!size) { + fprintf(stderr, "ROM DB map entry %d with address %s has device type SRAM, but the SRAM size is not defined\n", state->index, key); + exit(1); + } + state->info->save_size = atoi(size); + if (!state->info->save_size) { + fprintf(stderr, "SRAM size %s is invalid\n", size); + exit(1); + } + state->info->save_buffer = malloc(state->info->save_size); + memset(state->info->save_buffer, 0, state->info->save_size); + char *bus = tern_find_path(state->root, "SRAM\0bus\0").ptrval; + if (!strcmp(bus, "odd")) { + state->info->save_type = RAM_FLAG_ODD; + } else if(!strcmp(bus, "even")) { + state->info->save_type = RAM_FLAG_EVEN; + } else { + state->info->save_type = RAM_FLAG_BOTH; + } + } +} + +void process_eeprom_def(char * key, map_iter_state *state) +{ + if (!state->info->save_size) { + char * size = tern_find_path(state->root, "EEPROM\0size\0").ptrval; + if (!size) { + fprintf(stderr, "ROM DB map entry %d with address %s has device type EEPROM, but the EEPROM size is not defined\n", state->index, key); + exit(1); + } + state->info->save_size = atoi(size); + if (!state->info->save_size) { + fprintf(stderr, "EEPROM size %s is invalid\n", size); + exit(1); + } + char *etype = tern_find_path(state->root, "EEPROM\0type\0").ptrval; + if (!etype) { + etype = "i2c"; + } + if (!strcmp(etype, "i2c")) { + state->info->save_type = SAVE_I2C; + } else { + fprintf(stderr, "EEPROM type %s is invalid\n", etype); + exit(1); + } + state->info->save_buffer = malloc(state->info->save_size); + memset(state->info->save_buffer, 0xFF, state->info->save_size); + state->info->eeprom_map = malloc(sizeof(eeprom_map) * state->num_els); + memset(state->info->eeprom_map, 0, sizeof(eeprom_map) * state->num_els); + } +} + +void add_eeprom_map(tern_node *node, uint32_t start, uint32_t end, map_iter_state *state) +{ + eeprom_map *eep_map = state->info->eeprom_map + state->info->num_eeprom; + eep_map->start = start; + eep_map->end = end; + eep_map->sda_read_bit = 0xFF; + tern_node * bits_read = tern_find_ptr(node, "bits_read"); + if (bits_read) { + tern_foreach(bits_read, eeprom_read_fun, eep_map); + } + tern_node * bits_write = tern_find_ptr(node, "bits_write"); + if (bits_write) { + tern_foreach(bits_write, eeprom_write_fun, eep_map); + } + printf("EEPROM address %X: sda read: %X, sda write: %X, scl: %X\n", start, eep_map->sda_read_bit, eep_map->sda_write_mask, eep_map->scl_mask); + state->info->num_eeprom++; +} + void map_iter_fun(char *key, tern_val val, void *data) { map_iter_state *state = data; @@ -624,81 +698,25 @@ void map_iter_fun(char *key, tern_val val, void *data) exit(1); } char * dtype = tern_find_ptr_default(node, "device", "ROM"); - uint32_t offset = strtol(tern_find_ptr_default(node, "offset", "0"), NULL, 0); + uint32_t offset = strtol(tern_find_ptr_default(node, "offset", "0"), NULL, 16); memmap_chunk *map = state->info->map + state->index; map->start = start; - map->end = end; + map->end = end + 1; if (!strcmp(dtype, "ROM")) { map->buffer = state->rom + offset; map->flags = MMAP_READ; - map->mask = calc_mask(state->rom_size, start, end); + map->mask = calc_mask(state->rom_size - offset, start, end); } else if (!strcmp(dtype, "EEPROM")) { - if (!state->info->save_size) { - char * size = tern_find_path(state->root, "EEPROM\0size\0").ptrval; - if (!size) { - fprintf(stderr, "ROM DB map entry %d with address %s has device type EEPROM, but the EEPROM size is not defined\n", state->index, key); - exit(1); - } - state->info->save_size = atoi(size); - if (!state->info->save_size) { - fprintf(stderr, "EEPROM size %s is invalid\n", size); - exit(1); - } - char *etype = tern_find_path(state->root, "EEPROM\0type\0").ptrval; - if (!etype) { - etype = "i2c"; - } - if (!strcmp(etype, "i2c")) { - state->info->save_type = SAVE_I2C; - } else { - fprintf(stderr, "EEPROM type %s is invalid\n", etype); - exit(1); - } - state->info->save_buffer = malloc(state->info->save_size); - state->info->eeprom_map = malloc(sizeof(eeprom_map) * state->num_els); - memset(state->info->eeprom_map, 0, sizeof(eeprom_map) * state->num_els); - } - eeprom_map *eep_map = state->info->eeprom_map + state->info->num_eeprom; - eep_map->start = start; - eep_map->end = end; - eep_map->sda_read_bit = 0xFF; - tern_node * bits_read = tern_find_ptr(node, "bits_read"); - if (bits_read) { - tern_foreach(bits_read, eeprom_read_fun, eep_map); - } - tern_node * bits_write = tern_find_ptr(node, "bits_write"); - if (bits_write) { - tern_foreach(bits_write, eeprom_write_fun, eep_map); - } - printf("EEPROM address %X: sda read: %X, sda write: %X, scl: %X\n", start, eep_map->sda_read_bit, eep_map->sda_write_mask, eep_map->scl_mask); - state->info->num_eeprom++; + process_eeprom_def(key, state); + add_eeprom_map(node, start, end, state); + map->write_16 = write_eeprom_i2c_w; map->write_8 = write_eeprom_i2c_b; map->read_16 = read_eeprom_i2c_w; map->read_8 = read_eeprom_i2c_b; map->mask = 0xFFFFFF; } else if (!strcmp(dtype, "SRAM")) { - if (!state->info->save_size) { - char * size = tern_find_path(state->root, "SRAM\0size\0").ptrval; - if (!size) { - fprintf(stderr, "ROM DB map entry %d with address %s has device type SRAM, but the SRAM size is not defined\n", state->index, key); - exit(1); - } - state->info->save_size = atoi(size); - if (!state->info->save_size) { - fprintf(stderr, "SRAM size %s is invalid\n", size); - exit(1); - } - state->info->save_buffer = malloc(state->info->save_size); - char *bus = tern_find_path(state->root, "SRAM\0bus\0").ptrval; - if (!strcmp(bus, "odd")) { - state->info->save_type = RAM_FLAG_ODD; - } else if(!strcmp(bus, "even")) { - state->info->save_type = RAM_FLAG_EVEN; - } else { - state->info->save_type = RAM_FLAG_BOTH; - } - } + process_sram_def(key, state); map->buffer = state->info->save_buffer + offset; map->flags = MMAP_READ | MMAP_WRITE; if (state->info->save_type == RAM_FLAG_ODD) { @@ -707,6 +725,37 @@ void map_iter_fun(char *key, tern_val val, void *data) map->flags |= MMAP_ONLY_EVEN; } map->mask = calc_mask(state->info->save_size, start, end); + } else if (!strcmp(dtype, "Sega mapper")) { + map->buffer = state->rom + offset; + //TODO: Calculate this + map->ptr_index = 2; + map->flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL; + map->mask = calc_mask(state->rom_size - offset, start, end); + char *save_device = tern_find_path(node, "save\0device\0").ptrval; + if (save_device && !strcmp(save_device, "SRAM")) { + process_sram_def(key, state); + map->read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL + map->read_8 = (read_8_fun)read_sram_b; + map->write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area + map->write_8 = (write_8_fun)write_sram_area_b; + } else if (save_device && !strcmp(save_device, "EEPROM")) { + process_eeprom_def(key, state); + add_eeprom_map(node, start & map->mask, end & map->mask, state); + map->write_16 = write_eeprom_i2c_w; + map->write_8 = write_eeprom_i2c_b; + map->read_16 = read_eeprom_i2c_w; + map->read_8 = read_eeprom_i2c_b; + } + state->info->map_chunks++; + state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks); + state->index++; + memset(state->info->map + state->info->map_chunks - 1, 0, sizeof(memmap_chunk)); + map = state->info->map + state->index; + map->start = 0xA13000; + map->end = 0xA13100; + map->mask = 0xFF; + map->write_16 = (write_16_fun)write_bank_reg_w; + map->write_8 = (write_8_fun)write_bank_reg_b; } else { fprintf(stderr, "Invalid device type for ROM DB map entry %d with address %s\n", state->index, key); exit(1); @@ -757,6 +806,7 @@ rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_ tern_node *map = tern_find_ptr(entry, "map"); if (map) { + info.save_type = SAVE_NONE; info.map_chunks = tern_count(map); if (info.map_chunks) { info.map_chunks += base_chunks; @@ -765,7 +815,7 @@ rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_ info.map = malloc(sizeof(memmap_chunk) * info.map_chunks); info.eeprom_map = NULL; info.num_eeprom = 0; - memset(info.map, 0, sizeof(memmap_chunk) * (info.map_chunks - base_chunks)); + memset(info.map, 0, sizeof(memmap_chunk) * info.map_chunks); map_iter_state state = {&info, rom, entry, rom_size, 0, info.map_chunks - base_chunks}; tern_foreach(map, map_iter_fun, &state); memcpy(info.map + state.index, base_map, sizeof(memmap_chunk) * base_chunks); -- cgit v1.2.3 From 5733306bcd4e653994b5830cf035e7487869aeb7 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 19 Jul 2015 22:30:40 -0700 Subject: Populate save mask when SRAM is defined in ROM DB rather than cart header --- romdb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/romdb.c b/romdb.c index 7748de0..a422fe7 100644 --- a/romdb.c +++ b/romdb.c @@ -622,6 +622,7 @@ void process_sram_def(char *key, map_iter_state *state) fprintf(stderr, "SRAM size %s is invalid\n", size); exit(1); } + state->info->save_mask = nearest_pow2(state->info->save_size)-1; state->info->save_buffer = malloc(state->info->save_size); memset(state->info->save_buffer, 0, state->info->save_size); char *bus = tern_find_path(state->root, "SRAM\0bus\0").ptrval; -- cgit v1.2.3 From 9d475a3ccb5b2e1e206cf4c219ec5984cec3574f Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 20 Jul 2015 21:15:34 -0700 Subject: Full support for Sega mapper when it comes to data. Code in remapped sections may not work reliably. SSF2 now works. --- blastem.c | 37 ++++++++++++++------------- blastem.h | 4 +-- gst.c | 4 +-- m68k_core.h | 2 +- rom.db | 28 +++++++++++++++++++++ romdb.c | 84 +++++++++++++++++++++++++++++++++++-------------------------- romdb.h | 1 + 7 files changed, 101 insertions(+), 59 deletions(-) diff --git a/blastem.c b/blastem.c index 3f71631..256f152 100644 --- a/blastem.c +++ b/blastem.c @@ -34,7 +34,7 @@ #define MAX_SOUND_CYCLES 100000 -uint16_t cart[CARTRIDGE_WORDS]; +uint16_t *cart; uint16_t ram[RAM_WORDS]; uint8_t z80_ram[Z80_RAM_BYTES]; @@ -73,9 +73,9 @@ int load_smd_rom(long filesize, FILE * f) return filesize; } -void byteswap_rom() +void byteswap_rom(int filesize) { - for(unsigned short * cur = cart; cur - cart < CARTRIDGE_WORDS; ++cur) + for(unsigned short * cur = cart; cur - cart < filesize/2; ++cur) { *cur = (*cur >> 8) | (*cur << 8); } @@ -88,13 +88,12 @@ int load_rom(char * filename) if (!f) { return 0; } - fread(header, 1, sizeof(header), f); + if (sizeof(header) != fread(header, 1, sizeof(header), f)) { + fprintf(stderr, "Error reading from %s\n", filename); + exit(1); + } fseek(f, 0, SEEK_END); long filesize = ftell(f); - if (filesize/2 > CARTRIDGE_WORDS) { - //carts bigger than 4MB not currently supported - filesize = CARTRIDGE_WORDS*2; - } fseek(f, 0, SEEK_SET); if (header[1] == SMD_MAGIC1 && header[8] == SMD_MAGIC2 && header[9] == SMD_MAGIC3) { int i; @@ -111,7 +110,11 @@ int load_rom(char * filename) return load_smd_rom(filesize, f); } } - fread(cart, 2, filesize/2, f); + cart = malloc(filesize); + if (filesize != fread(cart, 1, filesize, f)) { + fprintf(stderr, "Error reading from %s\n", filename); + exit(1); + } fclose(f); return filesize; } @@ -839,14 +842,12 @@ void init_run_cpu(genesis_context * gen, rom_info *rom, FILE * address_log, char context->video_context = gen->vdp; context->system = gen; - //cartridge ROM - context->mem_pointers[0] = cart; - 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 - context->mem_pointers[2] = rom->map[1].buffer; - context->mem_pointers[3] = (uint16_t *)gen->save_storage; + for (int i = 0; i < rom->map_chunks; i++) + { + if (rom->map[i].flags & MMAP_PTR_IDX) { + context->mem_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; + } + } if (statefile) { uint32_t pc = load_gst(gen, statefile); @@ -1026,7 +1027,7 @@ int main(int argc, char ** argv) } tern_node *rom_db = load_rom_db(); rom_info info = configure_rom(rom_db, cart, rom_size, base_map, sizeof(base_map)/sizeof(base_map[0])); - byteswap_rom(); + byteswap_rom(rom_size); set_region(&info, force_version); update_title(info.name); int def_width = 0; diff --git a/blastem.h b/blastem.h index 7d051b6..43f694d 100644 --- a/blastem.h +++ b/blastem.h @@ -32,6 +32,7 @@ typedef struct { uint32_t frame_end; uint32_t max_cycles; uint8_t bank_regs[8]; + uint16_t mapper_start_index; uint8_t save_type; io_port ports[3]; uint8_t bus_busy; @@ -44,11 +45,10 @@ extern int break_on_sync; extern int save_state; extern tern_node * config; -#define CARTRIDGE_WORDS 0x200000 #define RAM_WORDS 32 * 1024 #define Z80_RAM_BYTES 8 * 1024 -extern uint16_t cart[CARTRIDGE_WORDS]; +extern uint16_t *cart; extern uint16_t ram[RAM_WORDS]; extern uint8_t z80_ram[Z80_RAM_BYTES]; diff --git a/gst.c b/gst.c index 28cc4ca..48dbd0e 100644 --- a/gst.c +++ b/gst.c @@ -100,7 +100,7 @@ uint32_t m68k_load_gst(m68k_context * context, FILE * gstfile) return 0; } for(curpos = buffer; curpos < (buffer + sizeof(buffer)); curpos += sizeof(uint16_t)) { - context->mem_pointers[1][i++] = read_be_16(curpos); + ram[i++] = read_be_16(curpos); } } return pc; @@ -141,7 +141,7 @@ uint8_t m68k_save_gst(m68k_context * context, uint32_t pc, FILE * gstfile) fseek(gstfile, GST_68K_RAM, SEEK_SET); for (int i = 0; i < (32*1024);) { for(curpos = buffer; curpos < (buffer + sizeof(buffer)); curpos += sizeof(uint16_t)) { - write_be_16(curpos, context->mem_pointers[1][i++]); + write_be_16(curpos, ram[i++]); } if (fwrite(buffer, 1, sizeof(buffer), gstfile) != sizeof(buffer)) { fputs("Failed to write 68K RAM to savestate\n", stderr); diff --git a/m68k_core.h b/m68k_core.h index b91a37b..421302f 100644 --- a/m68k_core.h +++ b/m68k_core.h @@ -11,7 +11,7 @@ //#include "68kinst.h" struct m68kinst; -#define NUM_MEM_AREAS 4 +#define NUM_MEM_AREAS 8 #define NATIVE_MAP_CHUNKS (64*1024) #define NATIVE_CHUNK_SIZE ((16 * 1024 * 1024 / NATIVE_MAP_CHUNKS)/2) #define MAX_NATIVE_SIZE 255 diff --git a/rom.db b/rom.db index 5759789..a2a00fe 100644 --- a/rom.db +++ b/rom.db @@ -173,4 +173,32 @@ T-81476 { } } } +} +MK-12056 { + name Super Street Fighter 2: The New Challengers + map { + 0 { + device ROM + last 7FFFF + } + 80000 { + device Sega mapper + last 3FFFFF + offset 80000 + } + } +} +T-12056 { + name Super Street Fighter 2: The New Challengers + map { + 0 { + device ROM + last 7FFFF + } + 80000 { + device Sega mapper + last 3FFFFF + offset 80000 + } + } } \ No newline at end of file diff --git a/romdb.c b/romdb.c index a422fe7..b79635e 100644 --- a/romdb.c +++ b/romdb.c @@ -273,10 +273,21 @@ m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16 gen->bank_regs[address] = value; if (!address) { if (value & 1) { - context->mem_pointers[2] = NULL; + for (int i = 0; i < 8; i++) + { + context->mem_pointers[gen->mapper_start_index + i] = NULL; + } } else { - context->mem_pointers[2] = cart + 0x200000/2; + //Used for games that only use the mapper for SRAM + context->mem_pointers[gen->mapper_start_index] = cart + 0x200000/2; + //For games that need more than 4MB + for (int i = 1; i < 8; i++) + { + context->mem_pointers[gen->mapper_start_index + i] = cart + 0x40000*gen->bank_regs[i]; + } } + } else { + context->mem_pointers[gen->mapper_start_index + address] = cart + 0x40000*value; } return context; } @@ -284,17 +295,7 @@ m68k_context * write_bank_reg_w(uint32_t address, m68k_context * context, uint16 m68k_context * write_bank_reg_b(uint32_t address, m68k_context * context, uint8_t value) { if (address & 1) { - genesis_context * gen = context->system; - address &= 0xE; - address >>= 1; - gen->bank_regs[address] = value; - if (!address) { - if (value & 1) { - context->mem_pointers[2] = NULL; - } else { - context->mem_pointers[2] = cart + 0x200000/2; - } - } + write_bank_reg_w(address, context, value); } return context; } @@ -526,7 +527,7 @@ void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk info->map[1].end = 0x400000; info->map[1].mask = 0x1FFFFF; info->map[1].flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL; - info->map[1].ptr_index = 2; + info->map[1].ptr_index = info->mapper_start_index = 0; info->map[1].read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL info->map[1].read_8 = (read_8_fun)read_sram_b; info->map[1].write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area @@ -571,6 +572,7 @@ typedef struct { uint32_t rom_size; int index; int num_els; + uint16_t ptr_index; } map_iter_state; void eeprom_read_fun(char *key, tern_val val, void *data) @@ -727,31 +729,41 @@ void map_iter_fun(char *key, tern_val val, void *data) } map->mask = calc_mask(state->info->save_size, start, end); } else if (!strcmp(dtype, "Sega mapper")) { - map->buffer = state->rom + offset; - //TODO: Calculate this - map->ptr_index = 2; - map->flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL; - map->mask = calc_mask(state->rom_size - offset, start, end); + state->info->mapper_start_index = state->ptr_index++; + state->info->map_chunks+=7; + state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks); + memset(state->info->map + state->info->map_chunks - 7, 0, sizeof(memmap_chunk) * 7); + map = state->info->map + state->index; char *save_device = tern_find_path(node, "save\0device\0").ptrval; - if (save_device && !strcmp(save_device, "SRAM")) { - process_sram_def(key, state); - map->read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL - map->read_8 = (read_8_fun)read_sram_b; - map->write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area - map->write_8 = (write_8_fun)write_sram_area_b; - } else if (save_device && !strcmp(save_device, "EEPROM")) { + if (save_device && !strcmp(save_device, "EEPROM")) { process_eeprom_def(key, state); add_eeprom_map(node, start & map->mask, end & map->mask, state); - map->write_16 = write_eeprom_i2c_w; - map->write_8 = write_eeprom_i2c_b; - map->read_16 = read_eeprom_i2c_w; - map->read_8 = read_eeprom_i2c_b; } - state->info->map_chunks++; - state->info->map = realloc(state->info->map, sizeof(memmap_chunk) * state->info->map_chunks); - state->index++; - memset(state->info->map + state->info->map_chunks - 1, 0, sizeof(memmap_chunk)); - map = state->info->map + state->index; + for (int i = 0; i < 7; i++, state->index++, map++) + { + map->start = start + i * 0x80000; + map->end = start + (i + 1) * 0x80000; + map->mask = 0x7FFFF; + map->buffer = state->rom + offset + i * 0x80000; + map->ptr_index = state->ptr_index++; + if (i < 3 || !save_device) { + map->flags = MMAP_READ | MMAP_PTR_IDX; + } else { + map->flags = MMAP_READ | MMAP_PTR_IDX | MMAP_FUNC_NULL; + if (!strcmp(save_device, "SRAM")) { + process_sram_def(key, state); + map->read_16 = (read_16_fun)read_sram_w;//these will only be called when mem_pointers[2] == NULL + map->read_8 = (read_8_fun)read_sram_b; + map->write_16 = (write_16_fun)write_sram_area_w;//these will be called all writes to the area + map->write_8 = (write_8_fun)write_sram_area_b; + } else if (!strcmp(save_device, "EEPROM")) { + map->write_16 = write_eeprom_i2c_w; + map->write_8 = write_eeprom_i2c_b; + map->read_16 = read_eeprom_i2c_w; + map->read_8 = read_eeprom_i2c_b; + } + } + } map->start = 0xA13000; map->end = 0xA13100; map->mask = 0xFF; @@ -817,7 +829,7 @@ rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, memmap_ info.eeprom_map = NULL; info.num_eeprom = 0; memset(info.map, 0, sizeof(memmap_chunk) * info.map_chunks); - map_iter_state state = {&info, rom, entry, rom_size, 0, info.map_chunks - base_chunks}; + map_iter_state state = {&info, rom, entry, rom_size, 0, info.map_chunks - base_chunks, 0}; tern_foreach(map, map_iter_fun, &state); memcpy(info.map + state.index, base_map, sizeof(memmap_chunk) * base_chunks); } else { diff --git a/romdb.h b/romdb.h index 3bf9fa6..e2af1de 100644 --- a/romdb.h +++ b/romdb.h @@ -44,6 +44,7 @@ typedef struct { uint32_t map_chunks; uint32_t save_size; uint32_t save_mask; + uint16_t mapper_start_index; uint8_t save_type; uint8_t regions; } rom_info; -- cgit v1.2.3 From 3a192413d7a2251f3c69504d13ae3611e6c58404 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 20 Jul 2015 21:43:17 -0700 Subject: Support large flat-mapped ROMs like Bad Apple or that Mortal Kombat hack --- blastem.c | 4 ++-- romdb.c | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/blastem.c b/blastem.c index 256f152..566dd79 100644 --- a/blastem.c +++ b/blastem.c @@ -110,7 +110,7 @@ int load_rom(char * filename) return load_smd_rom(filesize, f); } } - cart = malloc(filesize); + cart = malloc(nearest_pow2(filesize)); if (filesize != fread(cart, 1, filesize, f)) { fprintf(stderr, "Error reading from %s\n", filename); exit(1); @@ -760,7 +760,7 @@ 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) { + if (context->bank_reg < 0x100) { 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 { diff --git a/romdb.c b/romdb.c index b79635e..2cab3c2 100644 --- a/romdb.c +++ b/romdb.c @@ -478,20 +478,25 @@ uint32_t calc_mask(uint32_t src_size, uint32_t start, uint32_t end) void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk const *base_map, int base_chunks) { + uint32_t rom_end = get_u32be(rom + ROM_END) + 1; + if (size > rom_end) { + rom_end = size; + } else if (rom_end > nearest_pow2(size)) { + rom_end = nearest_pow2(size); + } if (rom[RAM_ID] == 'R' && rom[RAM_ID+1] == 'A') { - uint32_t rom_end = get_u32be(rom + ROM_END) + 1; uint32_t ram_start = get_u32be(rom + RAM_START); uint32_t ram_end = get_u32be(rom + RAM_END); uint32_t ram_flags = info->save_type = rom[RAM_FLAGS] & RAM_FLAG_MASK; ram_start &= 0xFFFFFE; ram_end |= 1; info->save_mask = ram_end - ram_start; - uint32_t size = info->save_mask + 1; + uint32_t save_size = info->save_mask + 1; if (ram_flags != RAM_FLAG_BOTH) { - size /= 2; + save_size /= 2; } - info->save_size = size; - info->save_buffer = malloc(size); + info->save_size = save_size; + info->save_buffer = malloc(save_size); info->map_chunks = base_chunks + (ram_start >= rom_end ? 2 : 3); info->map = malloc(sizeof(memmap_chunk) * info->map_chunks); @@ -499,7 +504,7 @@ void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk memcpy(info->map+2, base_map, sizeof(memmap_chunk) * base_chunks); if (ram_start >= rom_end) { - info->map[0].end = rom_end; + info->map[0].end = rom_end > 0x400000 ? rom_end : 0x400000; //TODO: ROM mirroring info->map[0].mask = 0xFFFFFF; info->map[0].flags = MMAP_READ; @@ -548,7 +553,7 @@ void add_memmap_header(rom_info *info, uint8_t *rom, uint32_t size, memmap_chunk memset(info->map, 0, sizeof(memmap_chunk)); memcpy(info->map+1, base_map, sizeof(memmap_chunk) * base_chunks); - info->map[0].end = 0x400000; + info->map[0].end =rom_end > 0x400000 ? rom_end : 0x400000; info->map[0].mask = 0xFFFFFF; info->map[0].flags = MMAP_READ; info->map[0].buffer = rom; -- cgit v1.2.3 From f1b0a41176cea556ee4cc16442eb0265f0982210 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 20 Jul 2015 21:58:31 -0700 Subject: Remove extraneous define --- blastem.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/blastem.c b/blastem.c index 566dd79..eb09d3e 100644 --- a/blastem.c +++ b/blastem.c @@ -781,8 +781,6 @@ void set_speed_percent(genesis_context * context, uint32_t percent) psg_adjust_master_clock(context->psg, context->master_clock); } -#define MAX_MAP_CHUNKS (4+7+1) - const memmap_chunk base_map[] = { {0xE00000, 0x1000000, 0xFFFF, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, ram, NULL, NULL, NULL, NULL}, -- cgit v1.2.3 From dcff6b6b16c292943e905ed7986664ff0f4a05be Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 20 Jul 2015 22:22:49 -0700 Subject: EEPROM writes now seem to work for NFL Quarterback Club 96 --- romdb.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/romdb.c b/romdb.c index 2cab3c2..ff4e65a 100644 --- a/romdb.c +++ b/romdb.c @@ -99,9 +99,6 @@ void set_scl(eeprom_state *state, uint8_t val) case I2C_WRITE: state->buffer[state->address] = state->latch; state->state = I2C_WRITE_ACK; - state->address++; - //TODO: page mask - state->address &= state->size-1; break; } } @@ -111,15 +108,12 @@ void set_scl(eeprom_state *state, uint8_t val) state->state = I2C_READ; state->counter = 8; state->latch = state->buffer[state->address]; - state->address++; - //TODO: page mask - state->address &= state->size-1; } else { if (state->size < 256) { state->address = state->latch >> 1; state->state = I2C_WRITE; - } else if (state->size < 8192) { - state->address = state->latch << 8; + } else if (state->size < 4096) { + state->address = (state->latch & 0xE) << 7; state->state = I2C_ADDRESS; } else { state->state = I2C_ADDRESS_HI; @@ -133,6 +127,8 @@ void set_scl(eeprom_state *state, uint8_t val) break; case I2C_ADDRESS_ACK: state->state = I2C_WRITE; + state->address &= state->size-1; + printf("EEPROM address is %X\n", state->address); state->counter = 8; break; case I2C_READ: @@ -144,10 +140,16 @@ void set_scl(eeprom_state *state, uint8_t val) case I2C_READ_ACK: state->state = I2C_READ; state->counter = 8; + state->address++; + //TODO: page mask + state->address &= state->size-1; break; case I2C_WRITE_ACK: state->state = I2C_WRITE; state->counter = 8; + state->address++; + //TODO: page mask + state->address &= state->size-1; break; } } else if (~val & state->scl) { @@ -349,8 +351,8 @@ void * write_eeprom_i2c_b(uint32_t address, void * context, uint8_t value) } printf("EEPROM byte write: %X - %X (using mask %X and expanded val %X)\n", address, value, mask, expanded); if (map->scl_mask & mask) { - printf("scl: %d, state: %s\n", (expanded & map->scl_mask) != 0, i2c_states[gen->eeprom.state]); set_scl(&gen->eeprom, (expanded & map->scl_mask) != 0); + printf("scl: %d, state: %s, counter: %d, latch: %X\n", (expanded & map->scl_mask) != 0, i2c_states[gen->eeprom.state], gen->eeprom.counter, gen->eeprom.latch); } if (map->sda_write_mask & mask) { printf("sda: %d\n", (expanded & map->sda_write_mask) != 0); -- cgit v1.2.3 From 6f6468a4e6cb2e4c487d9ef3f59f87390e0f3015 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 20 Jul 2015 23:11:42 -0700 Subject: EEPROM reads now work for NFL Quarterback Club 96 --- romdb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/romdb.c b/romdb.c index ff4e65a..6dd70a7 100644 --- a/romdb.c +++ b/romdb.c @@ -143,6 +143,7 @@ void set_scl(eeprom_state *state, uint8_t val) state->address++; //TODO: page mask state->address &= state->size-1; + state->latch = state->buffer[state->address]; break; case I2C_WRITE_ACK: state->state = I2C_WRITE; -- cgit v1.2.3 From 25488e46291a19514f81194f8fd1cef10e2a7549 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Mon, 20 Jul 2015 23:18:29 -0700 Subject: Remove debug printf from EEPROM code --- romdb.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/romdb.c b/romdb.c index 6dd70a7..925fcd1 100644 --- a/romdb.c +++ b/romdb.c @@ -128,7 +128,6 @@ void set_scl(eeprom_state *state, uint8_t val) case I2C_ADDRESS_ACK: state->state = I2C_WRITE; state->address &= state->size-1; - printf("EEPROM address is %X\n", state->address); state->counter = 8; break; case I2C_READ: @@ -321,13 +320,10 @@ void * write_eeprom_i2c_w(uint32_t address, void * context, uint16_t value) fprintf(stderr, "Could not find EEPROM map for address %X\n", address); exit(1); } - printf("EEPROM word write: %X - %X\n", address, value); if (map->scl_mask) { set_scl(&gen->eeprom, (value & map->scl_mask) != 0); - printf("scl: %d, state: %s, counter: %d, latch: %X\n", (value & map->scl_mask) != 0, i2c_states[gen->eeprom.state], gen->eeprom.counter, gen->eeprom.latch); } if (map->sda_write_mask) { - printf("sda: %d\n", (value & map->sda_write_mask) != 0); set_host_sda(&gen->eeprom, (value & map->sda_write_mask) != 0); } return context; @@ -350,13 +346,10 @@ void * write_eeprom_i2c_b(uint32_t address, void * context, uint8_t value) expanded = value << 8; mask = 0xFF00; } - printf("EEPROM byte write: %X - %X (using mask %X and expanded val %X)\n", address, value, mask, expanded); if (map->scl_mask & mask) { set_scl(&gen->eeprom, (expanded & map->scl_mask) != 0); - printf("scl: %d, state: %s, counter: %d, latch: %X\n", (expanded & map->scl_mask) != 0, i2c_states[gen->eeprom.state], gen->eeprom.counter, gen->eeprom.latch); } if (map->sda_write_mask & mask) { - printf("sda: %d\n", (expanded & map->sda_write_mask) != 0); set_host_sda(&gen->eeprom, (expanded & map->sda_write_mask) != 0); } return context; @@ -374,7 +367,6 @@ uint16_t read_eeprom_i2c_w(uint32_t address, void * context) if (map->sda_read_bit < 16) { ret = get_sda(&gen->eeprom) << map->sda_read_bit; } - printf("EEPROM word read: %X - %X\n", address, ret); return ret; } @@ -391,7 +383,6 @@ uint8_t read_eeprom_i2c_b(uint32_t address, void * context) if (bit < 8) { ret = get_sda(&gen->eeprom) << bit; } - printf("EEPROM byte read: %X - %X\n", address, ret); return ret; } -- cgit v1.2.3 From 0f58f43d7125de5144614de7b3c57db813d2464d Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 21 Jul 2015 00:41:39 -0700 Subject: Add more EEPROM games to ROM DB --- rom.db | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 156 insertions(+), 4 deletions(-) diff --git a/rom.db b/rom.db index a2a00fe..57f448c 100644 --- a/rom.db +++ b/rom.db @@ -59,7 +59,10 @@ T-081276 { } 200000 { device EEPROM - last 3FFFFF + #This is almost certainly not correct based on the address pins + #available to the Acclaim mapper. It's probably available up to + #2FFFFF at least and just fights with D0 from the mask ROM + last 200001 bits_read { 0 sda } @@ -68,6 +71,11 @@ T-081276 { 8 scl } } + 200002 { + device ROM + offset 200000 + last 2FFFFF + } } } T-81406 { @@ -83,7 +91,10 @@ T-81406 { } 200000 { device EEPROM - last 3FFFFF + #This is almost certainly not correct based on the address pins + #available to the Acclaim mapper. It's probably available up to + #2FFFFF at least and just fights with D0 from the mask ROM + last 200001 bits_read { 0 sda } @@ -92,6 +103,11 @@ T-81406 { 8 scl } } + 200002 { + device ROM + offset 200000 + last 2FFFFF + } } } T-081586 { @@ -139,7 +155,10 @@ T-81576 { } 200000 { device EEPROM - last 3FFFFF + #This is almost certainly not correct based on the address pins + #available to the Acclaim mapper. It's probably available up to + #2FFFFF at least and just fights with D0 from the mask ROM + last 200001 bits_read { 0 sda } @@ -148,6 +167,11 @@ T-81576 { 8 scl } } + 200002 { + device ROM + offset 200000 + last 2FFFFF + } } } T-81476 { @@ -163,7 +187,10 @@ T-81476 { } 200000 { device EEPROM - last 3FFFFF + #This is almost certainly not correct based on the address pins + #available to the Acclaim mapper. It's probably available up to + #2FFFFF at least and just fights with D0 from the mask ROM + last 200001 bits_read { 0 sda } @@ -172,6 +199,131 @@ T-81476 { 8 scl } } + 200002 { + device ROM + last 3FFFFF + offset 200000 + } + } +} +T-50176 { + name Rings of Power + EEPROM { + type i2c + size 128 + } + map { + 0 { + device ROM + last FFFFF + } + 200000 { + device EEPROM + last 3FFFFF + bits_read { + 7 sda + } + bits_write { + 6 scl + 7 sda + } + } + } +} +T-50396 { + name NHLPA Hockey '93 + EEPROM { + type i2c + size 128 + } + map { + 0 { + device ROM + last 7FFFF + } + 200000 { + device EEPROM + last 3FFFFF + bits_read { + 7 sda + } + bits_write { + 6 scl + 7 sda + } + } + } +} +T-50446 { + name John Madden Football '93 + EEPROM { + type i2c + size 128 + } + map { + 0 { + device ROM + last FFFFF + } + 200000 { + device EEPROM + last 3FFFFF + bits_read { + 7 sda + } + bits_write { + 6 scl + 7 sda + } + } + } +} +T-50516 { + name John Madden Football '93: Championship Edition + EEPROM { + type i2c + size 128 + } + map { + 0 { + device ROM + last FFFFF + } + 200000 { + device EEPROM + last 3FFFFF + bits_read { + 7 sda + } + bits_write { + 6 scl + 7 sda + } + } + } +} +T-50606 { + name Bill Walsh College Football + EEPROM { + type i2c + size 128 + } + map { + 0 { + device ROM + last FFFFF + } + 200000 { + device EEPROM + last 3FFFFF + bits_read { + 7 sda + } + bits_write { + 6 scl + 7 sda + } + } } } MK-12056 { -- cgit v1.2.3 From e7b2812fbdb135338db7a5bade0db8a16dc772b2 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 21 Jul 2015 00:52:21 -0700 Subject: Fix stateview build and fix Makefile to use /bin/echo since builtin echo does not always support -e --- Makefile | 2 +- stateview.c | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3ec9807..40ffb72 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ else LIBS=sdl2 glew gl endif #Darwin -HAS_PROC:=$(shell if [ -d /proc ]; then echo -e -DHAS_PROC; fi) +HAS_PROC:=$(shell if [ -d /proc ]; then /bin/echo -e -DHAS_PROC; fi) CFLAGS:=-std=gnu99 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -Wno-unused-value -Wno-logical-op-parentheses $(HAS_PROC) FIXUP:= ifdef PORTABLE diff --git a/stateview.c b/stateview.c index 0d2286d..751d2af 100644 --- a/stateview.c +++ b/stateview.c @@ -15,6 +15,9 @@ io_port gamepad_2; uint8_t reset = 1; uint8_t busreq = 0; +uint16_t ram[RAM_WORDS]; +uint8_t z80_ram[Z80_RAM_BYTES]; + uint16_t read_dma_value(uint32_t address) { return 0; -- cgit v1.2.3 From 5aa414e068c120a74a1f42e8e7de8692e8c1a55a Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 21 Jul 2015 21:29:43 -0700 Subject: Better error handling in alloc_code --- mem.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mem.c b/mem.c index 048f751..c9bb75a 100644 --- a/mem.c +++ b/mem.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include "mem.h" #ifndef MAP_ANONYMOUS @@ -25,6 +27,10 @@ void * alloc_code(size_t *size) static uint8_t *next = (uint8_t *)0x40000000; *size += PAGE_SIZE - (*size & (PAGE_SIZE - 1)); uint8_t *ret = mmap(NULL, *size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0); + if (ret == MAP_FAILED) { + perror("alloc_code"); + return NULL; + } next = ret + *size; return ret; } -- cgit v1.2.3 From bf0c615eb2b507834613cffc8f0c7c35963063f4 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 21 Jul 2015 22:03:58 -0700 Subject: Prep for 0.3.0 release --- README | 4 +++- blastem.c | 10 +++------- default.cfg | 1 + 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/README b/README index 2acf38c..e9c386b 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -BlastEm 0.2.0 +BlastEm 0.3.0 ------------- Installation @@ -110,3 +110,5 @@ License version 3 or higher. This gives you the right to redistribute and/or modify the program as long as you follow the terms of the license. See the file COPYING for full license details. +Binary releases of BlastEm are packaged with GLEW and SDL2 which have thier own +licenses. See GLEW-LICENSE and SDL-LICENSE for details. diff --git a/blastem.c b/blastem.c index eb09d3e..2e0add7 100644 --- a/blastem.c +++ b/blastem.c @@ -18,7 +18,7 @@ #include #include -#define BLASTEM_VERSION "0.2.0" +#define BLASTEM_VERSION "0.3.0" #define MCLKS_NTSC 53693175 #define MCLKS_PAL 53203395 @@ -27,6 +27,7 @@ #define MCLKS_PER_YM MCLKS_PER_68K #define MCLKS_PER_Z80 15 #define MCLKS_PER_PSG (MCLKS_PER_Z80*16) +#define DEFAULT_SYNC_INTERVAL MCLKS_LINE //TODO: Figure out the exact value for this #define LINES_NTSC 262 @@ -225,11 +226,6 @@ 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); @@ -1053,7 +1049,7 @@ int main(int argc, char ** argv) init_vdp_context(&v_context, version_reg & 0x40); gen.frame_end = vdp_cycles_to_frame_end(&v_context); char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0").ptrval; - gen.max_cycles = config_cycles ? atoi(config_cycles) : 10000000; + gen.max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL; 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/default.cfg b/default.cfg index 1b939be..77dcb52 100644 --- a/default.cfg +++ b/default.cfg @@ -73,6 +73,7 @@ audio { } clocks { + max_cycles 3420 speeds { 1 150 2 200 -- cgit v1.2.3 From e39675e0c563dbcc405d61424e8b97551f8e75aa Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Tue, 21 Jul 2015 22:04:33 -0700 Subject: Added tag v0.3.0 for changeset 0e5f14d9a579 --- .hgtags | 1 + 1 file changed, 1 insertion(+) diff --git a/.hgtags b/.hgtags index a084a67..3f353aa 100644 --- a/.hgtags +++ b/.hgtags @@ -1,2 +1,3 @@ 949c7d8756931ca19d93d6de5cc507405a007937 v0.1.0 6b7a96d0eda8ed9f1a1436c3ac590a1c4db94f27 v0.2.0 +0e5f14d9a57990a2c449a0d7c93250bbb4f6b9e5 v0.3.0 -- cgit v1.2.3 From a1165d0718544bb5c0e5f6a8e7895b70a120d529 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 22 Jul 2015 00:41:41 -0700 Subject: Fix missing include --- blastem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/blastem.c b/blastem.c index 2e0add7..baa4343 100644 --- a/blastem.c +++ b/blastem.c @@ -17,6 +17,7 @@ #include #include #include +#include #define BLASTEM_VERSION "0.3.0" -- cgit v1.2.3 From 5650f51d8c23623a68eafbb8aa5a6c146407666c Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Wed, 22 Jul 2015 00:42:22 -0700 Subject: Added tag v0.3.0 for changeset 283bdcd5bdb8 --- .hgtags | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.hgtags b/.hgtags index 3f353aa..cdd52e8 100644 --- a/.hgtags +++ b/.hgtags @@ -1,3 +1,5 @@ 949c7d8756931ca19d93d6de5cc507405a007937 v0.1.0 6b7a96d0eda8ed9f1a1436c3ac590a1c4db94f27 v0.2.0 0e5f14d9a57990a2c449a0d7c93250bbb4f6b9e5 v0.3.0 +0e5f14d9a57990a2c449a0d7c93250bbb4f6b9e5 v0.3.0 +283bdcd5bdb8cacaef8da9dfc72c56f6686dca29 v0.3.0 -- cgit v1.2.3 From e7f006e461acaaa2e2cb687e49bc5a5aa106ed51 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 25 Jul 2015 02:25:44 -0700 Subject: Initial work on silly Genesis based menu --- font_interlace_variable.xcf | Bin 0 -> 6259 bytes menu.s68 | 211 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 font_interlace_variable.xcf create mode 100644 menu.s68 diff --git a/font_interlace_variable.xcf b/font_interlace_variable.xcf new file mode 100644 index 0000000..67707c8 Binary files /dev/null and b/font_interlace_variable.xcf differ diff --git a/menu.s68 b/menu.s68 new file mode 100644 index 0000000..3f6a769 --- /dev/null +++ b/menu.s68 @@ -0,0 +1,211 @@ + 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: + rte + + rsset $FFFF8000 +x_pos rs.w 1 +base_cmd rs.l 1 + +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 #$8405, (a1) ;Scroll b table $A000 + move.w #$8560, (a1) ;SAT table $C000 + move.w #$8700, (a1) ;backdrop color 0 + move.w #$8B00, (a1) ;full screen scroll + move.w #$8C87, (a1) ;40 cell mode, double-res interlace + move.w #$8D00, (a1) ;hscroll table at 0 + move.w #$8F02, (a1) ;autoinc 2 + move.w #$9001, (a1) ;64x32 scroll size + move.l #$C0000000, (a1) + move.w #$000, (a0) + move.w #$EEE, (a0) + + ;init scroll table + move.l #$40000000, (a1) + move.w #0, (a0) + move.w #4, (a0) + + ;load tiles + move.l #$48000000, (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 + + move.l #$40000002, d3, + move.l d3, (a1) + move.l d3, base_cmd.w + + lea Message(pc), a6 + moveq #0, d0 + bsr print_string + + + + move.w #$8144, (a1) ;enable display + move #$2300, sr + + +wait_forever + bra wait_forever + +Message: + dc.b "Journey From Darkness - Strider Returns (U) [c][!].bin", $A + dc.b "Toejam & Earl in Panic on Funkotron (U) [!].bin", $A + dc.b "Fire Shark (U) [c][!].bin", $A + dc.b "Sonic and Knuckles (W) [!].bin", 0 + + align 1 + +;Prints a null terminated string +;a6 - pointer to string +;a0 - VDP data port +;d0 - base tile attribute +; +;Clobbers: d1.w, d2.w, d3.l +print_string: + lea widths(pc), a5 + move.w x_pos.w, d2 + move.l base_cmd.w, d3 +.loop + moveq #0, d1 + move.b (a6)+, d1 + beq .end + cmp.b #$A, d1 + beq .newline + tst.b (-32, a5, d1.w) + beq .narrow + add.w d0, d1 + move.w d1, (a0) + addq #2, d2 + bra .loop +.narrow + add.w d0, d1 + move.w d1, (a0) + addq #1, d2 + move.l d2, d1 + ;add.w d1, d1 + and.w #$FFFE, d1 + swap d1 + eor.l #$20000000, d3 + or.l d3, d1 + move.l d1, (a1) + bra .loop +.newline + moveq #0, d2 + and.l #$DFFFFFFF, d3 + add.l #$00800000, d3 + move.l d3, (a1) + bra .loop +.end + move.w d2, x_pos.w + move.l d3, base_cmd.w + rts + + align 1 +font: + incbin font_interlace_variable.tiles +fontend + +widths: + dc.b 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1 + dc.b 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0 + dc.b 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 + dc.b 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 + dc.b 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1 -- cgit v1.2.3 From 7bd703813717b7c099f9f89eafa256d5dd35a6db Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 25 Jul 2015 02:54:00 -0700 Subject: Add something resembling a proper header --- menu.s68 | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/menu.s68 b/menu.s68 index 3f6a769..65dd1d2 100644 --- a/menu.s68 +++ b/menu.s68 @@ -76,7 +76,23 @@ dc.l empty_handler dc.l empty_handler dc.l empty_handler - dc.b "SEGA" + dc.b "SEGA GENESIS " + dc.b "(c) 2015.JULY " + dc.b "Menu " + dc.b " " + dc.b " " + dc.b "Menu " + dc.b " " + dc.b " " + dc.b "GM MK-00000-00", 0, 0 + dc.b " " + dc.l $0, rom_end-1, $FF0000, $FFFFFF + dc.b " " + dc.b " " + dc.b " " + dc.b " " + dc.b "JUE " + empty_handler: int_6: rte @@ -209,3 +225,5 @@ widths: dc.b 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1 dc.b 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 dc.b 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1 + +rom_end: -- cgit v1.2.3 From 7406c8bf64624feff0bf982e4667a194d31f8484 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 25 Jul 2015 18:19:00 -0700 Subject: Add a couple of comments to menu.s68 --- menu.s68 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/menu.s68 b/menu.s68 index 65dd1d2..f603ebf 100644 --- a/menu.s68 +++ b/menu.s68 @@ -196,7 +196,7 @@ print_string: move.w d1, (a0) addq #1, d2 move.l d2, d1 - ;add.w d1, d1 + ;switch to other plane and.w #$FFFE, d1 swap d1 eor.l #$20000000, d3 @@ -205,7 +205,9 @@ print_string: bra .loop .newline moveq #0, d2 + ;switch back to plane A and.l #$DFFFFFFF, d3 + ;skip to next row add.l #$00800000, d3 move.l d3, (a1) bra .loop -- cgit v1.2.3 From 80ff833dd8ad011b579bff26ac654819e6735bce Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sat, 25 Jul 2015 18:22:07 -0700 Subject: Use a new fatal_error function instead of calling fprintf and exit for fatal errors. This new function more gracefully handles the case in which BlastEm was not started from a terminal or disconnected from ther terminal (Windows). --- blastem.c | 68 +++++++++++++++++++-------------------------------------- config.c | 8 +++---- debug.c | 13 +++++------ gdb_remote.c | 16 +++++--------- gen.c | 4 ++-- gen_arm.c | 3 +-- gen_x86.c | 58 +++++++++++++++++------------------------------- m68k_core.c | 16 +++++--------- m68k_core_x86.c | 7 +++--- render.h | 4 +++- render_sdl.c | 38 +++++++++++++++++--------------- romdb.c | 41 ++++++++++++---------------------- stateview.c | 6 ++--- tern.c | 4 ++-- util.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++ util.h | 4 ++++ vgmplay.c | 3 +-- z80_to_x86.c | 17 ++++++--------- 18 files changed, 182 insertions(+), 187 deletions(-) diff --git a/blastem.c b/blastem.c index baa4343..29d6f05 100644 --- a/blastem.c +++ b/blastem.c @@ -91,8 +91,7 @@ int load_rom(char * filename) return 0; } if (sizeof(header) != fread(header, 1, sizeof(header), f)) { - fprintf(stderr, "Error reading from %s\n", filename); - exit(1); + fatal_error("Error reading from %s\n", filename); } fseek(f, 0, SEEK_END); long filesize = ftell(f); @@ -106,16 +105,14 @@ int load_rom(char * filename) } if (i == 8) { if (header[2]) { - fprintf(stderr, "%s is a split SMD ROM which is not currently supported", filename); - exit(1); + fatal_error("%s is a split SMD ROM which is not currently supported", filename); } return load_smd_rom(filesize, f); } } cart = malloc(nearest_pow2(filesize)); if (filesize != fread(cart, 1, filesize, f)) { - fprintf(stderr, "Error reading from %s\n", filename); - exit(1); + fatal_error("Error reading from %s\n", filename); } fclose(f); return filesize; @@ -289,8 +286,7 @@ m68k_context * sync_components(m68k_context * context, uint32_t address) m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_t value) { if (vdp_port & 0x2700E0) { - printf("machine freeze due to write to address %X\n", 0xC00000 | vdp_port); - exit(1); + fatal_error("machine freeze due to write to address %X\n", 0xC00000 | vdp_port); } vdp_port &= 0x1F; //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); @@ -339,8 +335,7 @@ m68k_context * vdp_port_write(uint32_t vdp_port, m68k_context * context, uint16_ adjust_int_cycle(context, v_context); } } else { - printf("Illegal write to HV Counter port %X\n", vdp_port); - exit(1); + fatal_error("Illegal write to HV Counter port %X\n", vdp_port); } 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); @@ -369,8 +364,7 @@ void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value) 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); + fatal_error("machine freeze due to write to Z80 address %X\n", 0x7F00 | vdp_port); } if (vdp_port < 0x10) { //These probably won't currently interact well with the 68K accessing the VDP @@ -380,8 +374,7 @@ void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value) } else if (vdp_port < 8) { vdp_control_port_write(gen->vdp, value << 8 | value); } else { - printf("Illegal write to HV Counter port %X\n", vdp_port); - exit(1); + fatal_error("Illegal write to HV Counter port %X\n", vdp_port); } } else if (vdp_port < 0x18) { sync_sound(gen, context->current_cycle); @@ -395,8 +388,7 @@ void * z80_vdp_port_write(uint32_t vdp_port, void * vcontext, uint8_t value) uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) { if (vdp_port & 0x2700E0) { - printf("machine freeze due to read from address %X\n", 0xC00000 | vdp_port); - exit(1); + fatal_error("machine freeze due to read from address %X\n", 0xC00000 | vdp_port); } vdp_port &= 0x1F; uint16_t value; @@ -413,8 +405,7 @@ uint16_t vdp_port_read(uint32_t vdp_port, m68k_context * context) //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles); } } else if (vdp_port < 0x18){ - printf("Illegal read from PSG port %X\n", vdp_port); - exit(1); + fatal_error("Illegal read from PSG port %X\n", vdp_port); } else { value = vdp_test_port_read(v_context); } @@ -444,8 +435,7 @@ 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); + fatal_error("machine freeze due to read from Z80 address %X\n", 0x7F00 | vdp_port); } genesis_context * gen = context->system; //VDP access goes over the 68K bus like a bank area access @@ -467,8 +457,7 @@ uint8_t z80_vdp_port_read(uint32_t vdp_port, void * vcontext) } 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); + fatal_error("Illegal write to HV Counter port %X\n", vdp_port); } } else { //TODO: Figure out the correct value today @@ -507,8 +496,7 @@ m68k_context * io_write(uint32_t location, m68k_context * context, uint8_t value gen->z80->mem_pointers[1] = NULL; } } else { - printf("68K write to unhandled Z80 address %X\n", location); - exit(1); + fatal_error("68K write to unhandled Z80 address %X\n", location); } } } else { @@ -847,8 +835,7 @@ void init_run_cpu(genesis_context * gen, rom_info *rom, FILE * address_log, char if (statefile) { uint32_t pc = load_gst(gen, statefile); if (!pc) { - fprintf(stderr, "Failed to load save state %s\n", statefile); - exit(1); + fatal_error("Failed to load save state %s\n", statefile); } printf("Loaded %s\n", statefile); if (debugger) { @@ -907,10 +894,6 @@ const memmap_chunk z80_map[] = { int main(int argc, char ** argv) { - if (argc < 2) { - fputs("Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n", stderr); - return 1; - } set_exe_str(argv[0]); config = load_config(); int width = -1; @@ -931,8 +914,7 @@ int main(int argc, char ** argv) case 'b': i++; if (i >= argc) { - fputs("-b must be followed by a frame count\n", stderr); - return 1; + fatal_error("-b must be followed by a frame count\n"); } headless = 1; exit_after = atoi(argv[i]); @@ -954,7 +936,7 @@ int main(int argc, char ** argv) address_log = fopen("address.log", "w"); break; case 'v': - printf("blastem %s\n", BLASTEM_VERSION); + info_message("blastem %s\n", BLASTEM_VERSION); return 0; break; case 'n': @@ -963,20 +945,17 @@ int main(int argc, char ** argv) case 'r': i++; if (i >= argc) { - fputs("-r must be followed by region (J, U or E)\n", stderr); - return 1; + fatal_error("-r must be followed by region (J, U or E)\n"); } force_version = translate_region_char(toupper(argv[i][0])); if (!force_version) { - fprintf(stderr, "'%c' is not a valid region character for the -r option\n", argv[i][0]); - return 1; + fatal_error("'%c' is not a valid region character for the -r option\n", argv[i][0]); } break; case 's': i++; if (i >= argc) { - fputs("-s must be followed by a savestate filename\n", stderr); - return 1; + fatal_error("-s must be followed by a savestate filename\n"); } statefile = argv[i]; break; @@ -984,7 +963,7 @@ int main(int argc, char ** argv) ym_log = 1; break; case 'h': - puts( + info_message( "Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n" "Options:\n" " -h Print this help text\n" @@ -1000,13 +979,11 @@ int main(int argc, char ** argv) ); return 0; default: - fprintf(stderr, "Unrecognized switch %s\n", argv[i]); - return 1; + fatal_error("Unrecognized switch %s\n", argv[i]); } } else if (!loaded) { if (!(rom_size = load_rom(argv[i]))) { - fprintf(stderr, "Failed to open %s for reading\n", argv[i]); - return 1; + fatal_error("Failed to open %s for reading\n", argv[i]); } romfname = argv[i]; loaded = 1; @@ -1017,8 +994,7 @@ int main(int argc, char ** argv) } } if (!loaded) { - fputs("You must specify a ROM filename!\n", stderr); - return 1; + fatal_error("Usage: blastem [OPTIONS] ROMFILE [WIDTH] [HEIGHT]\n"); } tern_node *rom_db = load_rom_db(); rom_info info = configure_rom(rom_db, cart, rom_size, base_map, sizeof(base_map)/sizeof(base_map[0])); diff --git a/config.c b/config.c index 6fd29b5..9d71ceb 100644 --- a/config.c +++ b/config.c @@ -53,8 +53,7 @@ tern_node * parse_config_int(char **state, int started, int *line) if (started) { return head; } - fprintf(stderr, "unexpected } on line %d\n", *line); - exit(1); + fatal_error("unexpected } on line %d\n", *line); } char * end = curline + len - 1; @@ -133,7 +132,8 @@ success: return ret; } no_config: - fputs("Failed to find a config file in ~/.config/blastem/blastem.cfg or in the blastem executable directory\n", stderr); - exit(1); + fatal_error("Failed to find a config file in ~/.config/blastem/blastem.cfg or in the blastem executable directory\n"); + //this will never get reached, but the compiler doesn't know that. Let's make it happy + return NULL; } diff --git a/debug.c b/debug.c index 74e076b..a70f790 100644 --- a/debug.c +++ b/debug.c @@ -7,6 +7,7 @@ #include #endif #include "render.h" +#include "util.h" static bp_def * breakpoints = NULL; static bp_def * zbreakpoints = NULL; @@ -298,15 +299,12 @@ z80_context * zdebugger(z80_context * context, uint16_t address) pc = z80_ram + (address & 0x1FFF); } else if (address >= 0x8000) { if (context->bank_reg < (0x400000 >> 15)) { - fprintf(stderr, "Entered Z80 debugger in banked memory address %X, which is not yet supported\n", address); - exit(1); + fatal_error("Entered Z80 debugger in banked memory address %X, which is not yet supported\n", address); } else { - fprintf(stderr, "Entered Z80 debugger in banked memory address %X, but the bank is not pointed to a cartridge address\n", address); - exit(1); + fatal_error("Entered Z80 debugger in banked memory address %X, but the bank is not pointed to a cartridge address\n", address); } } else { - fprintf(stderr, "Entered Z80 debugger at address %X\n", address); - exit(1); + fatal_error("Entered Z80 debugger at address %X\n", address); } for (disp_def * cur = zdisplays; cur; cur = cur->next) { zdebugger_print(context, cur->format_char, cur->param); @@ -504,8 +502,7 @@ m68k_context * debugger(m68k_context * context, uint32_t address) } else if(address > 0xE00000) { pc = ram + (address & 0xFFFF)/2; } else { - fprintf(stderr, "Entered 68K debugger at address %X\n", address); - exit(1); + fatal_error("Entered 68K debugger at address %X\n", address); } uint16_t * after_pc = m68k_decode(pc, &inst, address); m68k_disasm(&inst, input_buf); diff --git a/gdb_remote.c b/gdb_remote.c index 764cf83..0ea20c0 100644 --- a/gdb_remote.c +++ b/gdb_remote.c @@ -6,6 +6,7 @@ #include "gdb_remote.h" #include "68kinst.h" #include "debug.h" +#include "util.h" #include #include #include @@ -76,8 +77,7 @@ void gdb_calc_checksum(char * command, char *out) void write_or_die(int fd, const void *buf, size_t count) { if (write(fd, buf, count) < count) { - fputs("Error writing to stdout\n", stderr); - exit(1); + fatal_error("Error writing to stdout\n"); } } @@ -186,8 +186,7 @@ void gdb_run_command(m68k_context * context, uint32_t pc, char * command) } else if(pc > 0xE00000) { pc_ptr = ram + (pc & 0xFFFF)/2; } else { - fprintf(stderr, "Entered gdb remote debugger stub at address %X\n", pc); - exit(1); + fatal_error("Entered gdb remote debugger stub at address %X\n", pc); } uint16_t * after_pc = m68k_decode(pc_ptr, &inst, pc & 0xFFFFFF); uint32_t after = pc + (after_pc-pc_ptr)*2; @@ -407,8 +406,7 @@ void gdb_run_command(m68k_context * context, uint32_t pc, char * command) } else if(pc > 0xE00000) { pc_ptr = ram + (pc & 0xFFFF)/2; } else { - fprintf(stderr, "Entered gdb remote debugger stub at address %X\n", pc); - exit(1); + fatal_error("Entered gdb remote debugger stub at address %X\n", pc); } uint16_t * after_pc = m68k_decode(pc_ptr, &inst, pc & 0xFFFFFF); uint32_t after = pc + (after_pc-pc_ptr)*2; @@ -452,8 +450,7 @@ void gdb_run_command(m68k_context * context, uint32_t pc, char * command) } return; not_impl: - fprintf(stderr, "Command %s is not implemented, exiting...\n", command); - exit(1); + fatal_error("Command %s is not implemented, exiting...\n", command); } m68k_context * gdb_debug_enter(m68k_context * context, uint32_t pc) @@ -516,8 +513,7 @@ m68k_context * gdb_debug_enter(m68k_context * context, uint32_t pc) *curbuf = 0; //send acknowledgement if (write(STDOUT_FILENO, "+", 1) < 1) { - fputs("Error writing to stdout\n", stderr); - exit(1); + fatal_error("Error writing to stdout\n"); } gdb_run_command(context, pc, start); curbuf += 2; diff --git a/gen.c b/gen.c index 8f1b5f5..52be6a0 100644 --- a/gen.c +++ b/gen.c @@ -2,14 +2,14 @@ #include #include "gen.h" #include "mem.h" +#include "util.h" void init_code_info(code_info *code) { size_t size = CODE_ALLOC_SIZE; code->cur = alloc_code(&size); if (!code->cur) { - fputs("Failed to allocate memory for generated code\n", stderr); - exit(1); + fatal_error("Failed to allocate memory for generated code\n"); } code->last = code->cur + size/sizeof(code_word) - RESERVE_WORDS; } diff --git a/gen_arm.c b/gen_arm.c index 1534ee2..33eccaf 100644 --- a/gen_arm.c +++ b/gen_arm.c @@ -76,8 +76,7 @@ void check_alloc_code(code_info *code) size_t size = CODE_ALLOC_SIZE; uint32_t *next_code = alloc_code(&size); if (!next_code) { - fputs("Failed to allocate memory for generated code\n", stderr); - exit(1); + fatal_error("Failed to allocate memory for generated code\n"); } if (next_code = code->last + RESERVE_WORDS) { //new chunk is contiguous with the current one diff --git a/gen_x86.c b/gen_x86.c index 2bec3e8..3860236 100644 --- a/gen_x86.c +++ b/gen_x86.c @@ -5,6 +5,7 @@ */ #include "gen_x86.h" #include "mem.h" +#include "util.h" #include #include #include @@ -187,8 +188,7 @@ void jmp_nocheck(code_info *code, code_ptr dest) disp >>= 8; *(out++) = disp; } else { - fprintf(stderr, "jmp: %p - %p = %lX\n", dest, out + 6, (long)disp); - exit(1); + fatal_error("jmp: %p - %p = %l which is out of range of a 32-bit displacementX\n", dest, out + 6, (long)disp); } } code->cur = out; @@ -200,8 +200,7 @@ void check_alloc_code(code_info *code, uint32_t inst_size) size_t size = CODE_ALLOC_SIZE; code_ptr next_code = alloc_code(&size); if (!next_code) { - fputs("Failed to allocate memory for generated code\n", stderr); - exit(1); + fatal_error("Failed to allocate memory for generated code\n"); } if (next_code != code->last + RESERVE_WORDS) { //new chunk is not contiguous with the current one @@ -231,8 +230,7 @@ void x86_rr_sizedir(code_info *code, uint16_t opcode, uint8_t src, uint8_t dst, #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); - exit(1); + fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); } if (size == SZ_Q) { *out |= REX_QUAD; @@ -247,8 +245,7 @@ void x86_rr_sizedir(code_info *code, uint16_t opcode, uint8_t src, uint8_t dst, } 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); + fatal_error("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]); #endif } if (size == SZ_B) { @@ -284,8 +281,7 @@ void x86_rrdisp_sizedir(code_info *code, uint16_t opcode, uint8_t reg, uint8_t b #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); - exit(1); + fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); } if (size == SZ_Q) { *out |= REX_QUAD; @@ -300,8 +296,7 @@ void x86_rrdisp_sizedir(code_info *code, uint16_t opcode, uint8_t reg, uint8_t b } 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); + fatal_error("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]); #endif } if (size == SZ_B) { @@ -349,8 +344,7 @@ void x86_rrind_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t bas #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); - exit(1); + fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); } if (size == SZ_Q) { *out |= REX_QUAD; @@ -365,8 +359,7 @@ void x86_rrind_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t bas } 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); + fatal_error("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]); #endif } if (size == SZ_B) { @@ -405,8 +398,7 @@ void x86_rrindex_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t b #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); - exit(1); + fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); } if (size == SZ_Q) { *out |= REX_QUAD; @@ -425,8 +417,7 @@ void x86_rrindex_sizedir(code_info *code, uint8_t opcode, uint8_t reg, uint8_t b } 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); + fatal_error("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]); #endif } if (size == SZ_B) { @@ -461,8 +452,7 @@ void x86_r_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, uint #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); - exit(1); + fatal_error("attempt to use *H reg in an instruction requiring REX prefix. opcode = %X\n", opcode); } if (size == SZ_Q) { *out |= REX_QUAD; @@ -473,8 +463,7 @@ void x86_r_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, uint } 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); + fatal_error("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]); #endif } if (size == SZ_B) { @@ -509,8 +498,7 @@ void x86_rdisp_size(code_info *code, uint8_t opcode, uint8_t opex, uint8_t dst, } 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); + fatal_error("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]); #endif } if (size != SZ_B) { @@ -549,8 +537,7 @@ void x86_ir(code_info *code, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, i #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); + fatal_error("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]); #endif } } @@ -568,8 +555,7 @@ void x86_ir(code_info *code, uint8_t opcode, uint8_t op_ex, uint8_t al_opcode, i } 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); + fatal_error("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]); #endif } if (dst >= AH && dst <= BH) { @@ -620,8 +606,7 @@ void x86_irdisp(code_info *code, uint8_t opcode, uint8_t op_ex, int32_t val, uin } 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); + fatal_error("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]); #endif } if (size != SZ_B) { @@ -1921,8 +1906,7 @@ void jcc(code_info *code, uint8_t cc, code_ptr dest) disp >>= 8; *(out++) = disp; } else { - fprintf(stderr, "jcc: %p - %p = %lX\n", dest, out + 6, (long)disp); - exit(1); + fatal_error("jcc: %p - %p = %lX which is out of range for a 32-bit displacement\n", dest, out + 6, (long)disp); } } code->cur = out; @@ -1948,8 +1932,7 @@ void jmp(code_info *code, code_ptr dest) disp >>= 8; *(out++) = disp; } else { - fprintf(stderr, "jmp: %p - %p = %lX\n", dest, out + 6, (long)disp); - exit(1); + fatal_error("jmp: %p - %p = %lX which is out of range for a 32-bit displacement\n", dest, out + 6, (long)disp); } } code->cur = out; @@ -1997,8 +1980,7 @@ void call(code_info *code, code_ptr fun) *(out++) = disp; } else { //TODO: Implement far call??? - fprintf(stderr, "%p - %p = %lX\n", fun, out + 5, (long)disp); - exit(1); + fatal_error("call: %p - %p = %lX which is out of range for a 32-bit displacement\n", fun, out + 5, (long)disp); } code->cur = out; } diff --git a/m68k_core.c b/m68k_core.c index 5d88a2d..438a1eb 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -8,6 +8,7 @@ #include "68kinst.h" #include "backend.h" #include "gen.h" +#include "util.h" #include #include #include @@ -174,8 +175,7 @@ void translate_m68k_lea_pea(m68k_options * opts, m68kinst * inst) break; default: m68k_disasm(inst, disasm_buf); - printf("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode); - exit(1); + fatal_error("%X: %s\naddress mode %d not implemented (lea src)\n", inst->address, disasm_buf, inst->src.addr_mode); } if (inst->op == M68K_PEA) { subi_areg(opts, 4, 7); @@ -283,8 +283,7 @@ void translate_m68k_jmp_jsr(m68k_options * opts, m68kinst * inst) break; default: m68k_disasm(inst, disasm_buf); - printf("%s\naddress mode %d not yet supported (%s)\n", disasm_buf, inst->src.addr_mode, is_jsr ? "jsr" : "jmp"); - exit(1); + fatal_error("%s\naddress mode %d not yet supported (%s)\n", disasm_buf, inst->src.addr_mode, is_jsr ? "jsr" : "jmp"); } } @@ -410,8 +409,7 @@ void translate_m68k_movem(m68k_options * opts, m68kinst * inst) break; default: m68k_disasm(inst, disasm_buf); - printf("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode); - exit(1); + fatal_error("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode); } if (inst->dst.addr_mode == MODE_AREG_PREDEC) { reg = 15; @@ -481,8 +479,7 @@ void translate_m68k_movem(m68k_options * opts, m68kinst * inst) break; default: m68k_disasm(inst, disasm_buf); - printf("%X: %s\naddress mode %d not implemented (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode); - exit(1); + fatal_error("%X: %s\naddress mode %d not implemented (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode); } cycles(&opts->gen, early_cycles); for(reg = 0; reg < 16; reg ++) { @@ -830,8 +827,7 @@ void translate_m68k(m68k_options * opts, m68kinst * inst) translate_m68k_unary(opts, inst, info->impl.flag_mask, inst->dst.addr_mode != MODE_UNUSED ? &dst_op : &src_op); } else { m68k_disasm(inst, disasm_buf); - printf("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op); - exit(1); + fatal_error("%X: %s\ninstruction %d not yet implemented\n", inst->address, disasm_buf, inst->op); } } diff --git a/m68k_core_x86.c b/m68k_core_x86.c index 5429bfd..c0b527c 100644 --- a/m68k_core_x86.c +++ b/m68k_core_x86.c @@ -9,6 +9,7 @@ #include "68kinst.h" #include "mem.h" #include "backend.h" +#include "util.h" #include #include #include @@ -507,8 +508,7 @@ void translate_m68k_op(m68kinst * inst, host_ea * ea, m68k_options * opts, uint8 return; default: m68k_disasm(inst, disasm_buf); - printf("%X: %s\naddress mode %d not implemented (%s)\n", inst->address, disasm_buf, op->addr_mode, dst ? "dst" : "src"); - exit(1); + fatal_error("%X: %s\naddress mode %d not implemented (%s)\n", inst->address, disasm_buf, op->addr_mode, dst ? "dst" : "src"); } if (!dst && inst->dst.addr_mode == MODE_AREG && inst->extra.size == OPSIZE_WORD) { if (ea->mode == MODE_REG_DIRECT) { @@ -684,8 +684,7 @@ void translate_m68k_move(m68k_options * opts, m68kinst * inst) break; default: m68k_disasm(inst, disasm_buf); - printf("%X: %s\naddress mode %d not implemented (move dst)\n", inst->address, disasm_buf, inst->dst.addr_mode); - exit(1); + fatal_error("%X: %s\naddress mode %d not implemented (move dst)\n", inst->address, disasm_buf, inst->dst.addr_mode); } if (inst->dst.addr_mode != MODE_AREG) { diff --git a/render.h b/render.h index 9445448..cdae018 100644 --- a/render.h +++ b/render.h @@ -50,7 +50,9 @@ int render_joystick_num_buttons(int joystick); int render_joystick_num_hats(int joystick); int render_num_joysticks(); void process_events(); - +void render_errorbox(char *title, char *message); +void render_warnbox(char *title, char *message); +void render_infobox(char *title, char *message); #endif //RENDER_H_ diff --git a/render_sdl.c b/render_sdl.c index 82f8b12..1b25052 100644 --- a/render_sdl.c +++ b/render_sdl.c @@ -184,8 +184,7 @@ void render_alloc_surfaces(vdp_context * context) GLint link_status; glGetProgramiv(program, GL_LINK_STATUS, &link_status); if (!link_status) { - fputs("Failed to link shader program\n", stderr); - exit(1); + fatal_error("Failed to link shader program\n"); } un_textures[0] = glGetUniformLocation(program, "textures[0]"); un_textures[1] = glGetUniformLocation(program, "textures[1]"); @@ -198,9 +197,9 @@ char * caption = NULL; 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); + fatal_error("Unable to init SDL: %s\n", SDL_GetError()); } + atexit(SDL_Quit); printf("width: %d, height: %d\n", width, height); uint32_t flags = SDL_WINDOW_OPENGL; @@ -222,23 +221,17 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full } 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); + fatal_error("Unable to create SDL window: %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); + fatal_error("Initialization of GLEW failed with code %d\n", res); } if (!GLEW_VERSION_2_0) { - fputs("BlastEm requires at least OpenGL 2.0, but it is unavailable\n", stderr); - SDL_Quit(); - exit(1); + fatal_error("BlastEm requires at least OpenGL 2.0, but it is unavailable\n"); } float aspect = (float)width / height; tern_val def = {.ptrval = "normal"}; @@ -294,9 +287,7 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full desired.userdata = NULL; if (SDL_OpenAudio(&desired, &actual) < 0) { - fprintf(stderr, "Unable to open SDL audio: %s\n", SDL_GetError()); - SDL_Quit(); - exit(1); + fatal_error("Unable to open SDL audio: %s\n", SDL_GetError()); } buffer_samples = actual.samples; sample_rate = actual.freq; @@ -315,7 +306,6 @@ 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); } @@ -530,4 +520,18 @@ uint32_t render_sample_rate() return sample_rate; } +void render_errorbox(char *title, char *message) +{ + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, title, message, NULL); +} + +void render_warnbox(char *title, char *message) +{ + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_WARNING, title, message, NULL); +} + +void render_infobox(char *title, char *message) +{ + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, title, message, NULL); +} diff --git a/romdb.c b/romdb.c index 925fcd1..8ccd76b 100644 --- a/romdb.c +++ b/romdb.c @@ -317,8 +317,7 @@ void * write_eeprom_i2c_w(uint32_t address, void * context, uint16_t value) genesis_context *gen = ((m68k_context *)context)->system; eeprom_map *map = find_eeprom_map(address, gen); if (!map) { - fprintf(stderr, "Could not find EEPROM map for address %X\n", address); - exit(1); + fatal_error("Could not find EEPROM map for address %X\n", address); } if (map->scl_mask) { set_scl(&gen->eeprom, (value & map->scl_mask) != 0); @@ -334,8 +333,7 @@ void * write_eeprom_i2c_b(uint32_t address, void * context, uint8_t value) genesis_context *gen = ((m68k_context *)context)->system; eeprom_map *map = find_eeprom_map(address, gen); if (!map) { - fprintf(stderr, "Could not find EEPROM map for address %X\n", address); - exit(1); + fatal_error("Could not find EEPROM map for address %X\n", address); } uint16_t expanded, mask; @@ -360,8 +358,7 @@ uint16_t read_eeprom_i2c_w(uint32_t address, void * context) genesis_context *gen = ((m68k_context *)context)->system; eeprom_map *map = find_eeprom_map(address, gen); if (!map) { - fprintf(stderr, "Could not find EEPROM map for address %X\n", address); - exit(1); + fatal_error("Could not find EEPROM map for address %X\n", address); } uint16_t ret = 0; if (map->sda_read_bit < 16) { @@ -375,8 +372,7 @@ uint8_t read_eeprom_i2c_b(uint32_t address, void * context) genesis_context *gen = ((m68k_context *)context)->system; eeprom_map *map = find_eeprom_map(address, gen); if (!map) { - fprintf(stderr, "Could not find EEPROM map for address %X\n", address); - exit(1); + fatal_error("Could not find EEPROM map for address %X\n", address); } uint8_t bit = address & 1 ? map->sda_read_bit : map->sda_read_bit - 8; uint8_t ret = 0; @@ -390,14 +386,13 @@ tern_node *load_rom_db() { char *exe_dir = get_exe_dir(); if (!exe_dir) { - fputs("Failed to find executable path\n", stderr); - exit(1); + fatal_error("Failed to find executable path\n"); } char *path = alloc_concat(exe_dir, "/rom.db"); tern_node *db = parse_config_file(path); free(path); if (!db) { - fputs("Failed to load ROM DB\n", stderr); + fatal_error("Failed to load ROM DB\n"); } return db; } @@ -615,13 +610,11 @@ void process_sram_def(char *key, map_iter_state *state) if (!state->info->save_size) { char * size = tern_find_path(state->root, "SRAM\0size\0").ptrval; if (!size) { - fprintf(stderr, "ROM DB map entry %d with address %s has device type SRAM, but the SRAM size is not defined\n", state->index, key); - exit(1); + fatal_error("ROM DB map entry %d with address %s has device type SRAM, but the SRAM size is not defined\n", state->index, key); } state->info->save_size = atoi(size); if (!state->info->save_size) { - fprintf(stderr, "SRAM size %s is invalid\n", size); - exit(1); + fatal_error("SRAM size %s is invalid\n", size); } state->info->save_mask = nearest_pow2(state->info->save_size)-1; state->info->save_buffer = malloc(state->info->save_size); @@ -642,13 +635,11 @@ void process_eeprom_def(char * key, map_iter_state *state) if (!state->info->save_size) { char * size = tern_find_path(state->root, "EEPROM\0size\0").ptrval; if (!size) { - fprintf(stderr, "ROM DB map entry %d with address %s has device type EEPROM, but the EEPROM size is not defined\n", state->index, key); - exit(1); + fatal_error("ROM DB map entry %d with address %s has device type EEPROM, but the EEPROM size is not defined\n", state->index, key); } state->info->save_size = atoi(size); if (!state->info->save_size) { - fprintf(stderr, "EEPROM size %s is invalid\n", size); - exit(1); + fatal_error("EEPROM size %s is invalid\n", size); } char *etype = tern_find_path(state->root, "EEPROM\0type\0").ptrval; if (!etype) { @@ -657,8 +648,7 @@ void process_eeprom_def(char * key, map_iter_state *state) if (!strcmp(etype, "i2c")) { state->info->save_type = SAVE_I2C; } else { - fprintf(stderr, "EEPROM type %s is invalid\n", etype); - exit(1); + fatal_error("EEPROM type %s is invalid\n", etype); } state->info->save_buffer = malloc(state->info->save_size); memset(state->info->save_buffer, 0xFF, state->info->save_size); @@ -690,14 +680,12 @@ void map_iter_fun(char *key, tern_val val, void *data) map_iter_state *state = data; tern_node *node = tern_get_node(val); if (!node) { - fprintf(stderr, "ROM DB map entry %d with address %s is not a node\n", state->index, key); - exit(1); + fatal_error("ROM DB map entry %d with address %s is not a node\n", state->index, key); } uint32_t start = strtol(key, NULL, 16); uint32_t end = strtol(tern_find_ptr_default(node, "last", "0"), NULL, 16); if (!end || end < start) { - fprintf(stderr, "'last' value is missing or invalid for ROM DB map entry %d with address %s\n", state->index, key); - exit(1); + fatal_error("'last' value is missing or invalid for ROM DB map entry %d with address %s\n", state->index, key); } char * dtype = tern_find_ptr_default(node, "device", "ROM"); uint32_t offset = strtol(tern_find_ptr_default(node, "offset", "0"), NULL, 16); @@ -769,8 +757,7 @@ void map_iter_fun(char *key, tern_val val, void *data) map->write_16 = (write_16_fun)write_bank_reg_w; map->write_8 = (write_8_fun)write_bank_reg_b; } else { - fprintf(stderr, "Invalid device type for ROM DB map entry %d with address %s\n", state->index, key); - exit(1); + fatal_error("Invalid device type for ROM DB map entry %d with address %s\n", state->index, key); } state->index++; } diff --git a/stateview.c b/stateview.c index 751d2af..1e8632f 100644 --- a/stateview.c +++ b/stateview.c @@ -61,13 +61,11 @@ int headless = 0; int main(int argc, char ** argv) { if (argc < 2) { - fprintf(stderr, "Usage: stateview FILENAME\n"); - exit(1); + fatal_error("Usage: stateview FILENAME\n"); } FILE * state_file = fopen(argv[1], "rb"); if (!state_file) { - fprintf(stderr, "Failed to open %s\n", argv[1]); - exit(1); + fatal_error("Failed to open %s\n", argv[1]); } config = load_config(argv[0]); int width = -1; diff --git a/tern.c b/tern.c index e4f80f8..dda6497 100644 --- a/tern.c +++ b/tern.c @@ -8,6 +8,7 @@ #include #include #include +#include "util.h" tern_node * tern_insert(tern_node * head, char * key, tern_val value) { @@ -190,8 +191,7 @@ void tern_foreach_int(tern_node *head, iter_fun fun, void *data, char *keybuf, i } if (head->el) { if (pos == MAX_ITER_KEY) { - fputs("exceeded maximum key size", stderr); - exit(1); + fatal_error("tern_foreach_int: exceeded maximum key size"); } keybuf[pos] = head->el; tern_foreach_int(head->straight.next, fun, data, keybuf, pos+1); diff --git a/util.c b/util.c index 2a59b08..3ad290d 100644 --- a/util.c +++ b/util.c @@ -8,6 +8,9 @@ #include #include +#include "blastem.h" //for headless global +#include "render.h" //for render_errorbox + char * alloc_concat(char * first, char * second) { int flen = strlen(first); @@ -86,6 +89,62 @@ void set_exe_str(char * str) exe_str = str; } +void fatal_error(char *format, ...) +{ + va_list args; + va_start(args, format); + if (!headless) { + //take a guess at the final size + size_t size = strlen(format) * 2; + char *buf = malloc(size); + size_t actual = vsnprintf(buf, size, format, args); + if (actual >= size) { + actual++; + free(buf); + buf = malloc(actual); + va_end(args); + va_start(args, format); + vsnprintf(buf, actual, format, args); + } + fputs(buf, stderr); + render_errorbox("Fatal Error", buf); + free(buf); + } else { + vfprintf(stderr, format, args); + } + va_end(args); + exit(1); +} + +void info_message(char *format, ...) +{ + va_list args; + va_start(args, format); +#ifndef _WIN32 + if (headless || (isatty(STDOUT_FILENO) && isatty(STDIN_FILENO))) { + vprintf(format, args); + } else { +#endif + size_t size = strlen(format) * 2; + char *buf = malloc(size); + size_t actual = vsnprintf(buf, size, format, args); + if (actual >= size) { + actual++; + free(buf); + buf = malloc(actual); + va_end(args); + va_start(args, format); + vsnprintf(buf, actual, format, args); + } + fputs(buf, stdout); + render_infobox("BlastEm Info", buf); + free(buf); +#ifndef _WIN32 + } +#endif + va_end(args); +} + #ifdef _WIN32 #include "Shlobj.h" #include "Windows.h" diff --git a/util.h b/util.h index 85b0c8f..537c97e 100644 --- a/util.h +++ b/util.h @@ -25,5 +25,9 @@ char * get_exe_dir(); char * get_home_dir(); //Returns the contents of a symlink in a newly allocated string char * readlink_alloc(char * path); +//Prints an error message to stderr and to a message box if not in headless mode and then exits +void fatal_error(char *format, ...); +//Prints an information message to stdout and to a message box if not in headless mode and not attached to a console +void info_message(char *format, ...); #endif //UTIL_H_ diff --git a/vgmplay.c b/vgmplay.c index 879a399..0473a40 100644 --- a/vgmplay.c +++ b/vgmplay.c @@ -282,8 +282,7 @@ int main(int argc, char ** argv) wait(&y_context, &p_context, ¤t_cycle, wait_time); } } else { - printf("unimplemented command: %X at offset %X\n", cmd, (unsigned int)(cur - data - 1)); - exit(1); + fatal_error("unimplemented command: %X at offset %X\n", cmd, (unsigned int)(cur - data - 1)); } } } diff --git a/z80_to_x86.c b/z80_to_x86.c index 23b19b8..7205d16 100644 --- a/z80_to_x86.c +++ b/z80_to_x86.c @@ -7,6 +7,7 @@ #include "z80_to_x86.h" #include "gen_x86.h" #include "mem.h" +#include "util.h" #include #include #include @@ -256,8 +257,7 @@ void translate_z80_ea(z80inst * inst, host_ea * ea, z80_options * opts, uint8_t ea->mode = MODE_UNUSED; break; default: - fprintf(stderr, "Unrecognized Z80 addressing mode %d\n", inst->addr_mode & 0x1F); - exit(1); + fatal_error("Unrecognized Z80 addressing mode %d\n", inst->addr_mode & 0x1F); } } @@ -1939,11 +1939,10 @@ void translate_z80inst(z80inst * inst, z80_context * context, uint16_t address, default: { char disbuf[80]; z80_disasm(inst, disbuf, address); - fprintf(stderr, "unimplemented instruction: %s at %X\n", disbuf, address); FILE * f = fopen("zram.bin", "wb"); fwrite(context->mem_pointers[0], 1, 8 * 1024, f); fclose(f); - exit(1); + fatal_error("unimplemented Z80 instruction: %s at %X\nZ80 RAM has been saved to zram.bin for debugging", disbuf, address); } } } @@ -1952,8 +1951,7 @@ 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); + fatal_error("Encountered prefix byte %X at address %X. Z80 interpeter doesn't support those yet.", opcode, context->pc); } uint8_t codebuf[8]; memset(codebuf, 0, sizeof(codebuf)); @@ -1961,8 +1959,7 @@ uint8_t * z80_interp_handler(uint8_t opcode, z80_context * context) 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); + fatal_error("Encountered multi-byte Z80 instruction at %X. Z80 interpeter doesn't support those yet.", context->pc); } z80_options * opts = context->options; @@ -2243,7 +2240,7 @@ void translate_z80_stream(z80_context * context, uint32_t address) if (opts->gen.deferred) { address = opts->gen.deferred->address; dprintf("defferred address: %X\n", address); - } + } } while (opts->gen.deferred); } @@ -2749,6 +2746,6 @@ void zremove_breakpoint(z80_context * context, uint16_t address) opts->gen.code.last = native + 16; check_cycles_int(&opts->gen, address); opts->gen.code = tmp_code; -} + } } -- cgit v1.2.3 From 25fc1e88deea8253d9d4b8084485e176eb69abd0 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 26 Jul 2015 01:09:05 -0700 Subject: Fix missing includes of util.h --- stateview.c | 1 + vgmplay.c | 1 + 2 files changed, 2 insertions(+) diff --git a/stateview.c b/stateview.c index 1e8632f..3f860e7 100644 --- a/stateview.c +++ b/stateview.c @@ -7,6 +7,7 @@ #include #include "vdp.h" #include "render.h" +#include "util.h" #include "blastem.h" //not used, but referenced by the renderer since it handles input diff --git a/vgmplay.c b/vgmplay.c index 0473a40..f87c570 100644 --- a/vgmplay.c +++ b/vgmplay.c @@ -7,6 +7,7 @@ #include "ym2612.h" #include "psg.h" #include "config.h" +#include "util.h" #include #include -- cgit v1.2.3 From bee8b42029900ca034675c54d98813a61ca4407a Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 26 Jul 2015 01:11:04 -0700 Subject: Spawn a terminal for the debugger when needed if we are not already attached to one --- Makefile | 11 +++++++--- debug.c | 5 +++++ termhelper.c | 44 +++++++++++++++++++++++++++++++++++++++ terminal.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ terminal.h | 9 ++++++++ terminal_win.c | 13 ++++++++++++ util.c | 29 ++++++++++++++++++++++++++ util.h | 2 ++ 8 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 termhelper.c create mode 100644 terminal.c create mode 100644 terminal.h create mode 100644 terminal_win.c diff --git a/Makefile b/Makefile index 40ffb72..b5b1be9 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,7 @@ endif ifeq ($(OS),Windows) MEM:=mem_win.o +TERMINAL:=terminal_win.o BLASTEM:=blastem.exe CC:=wine gcc.exe CFLAGS:=-O2 -std=gnu99 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -I"C:/MinGW/usr/include/SDL2" -DGLEW_STATIC @@ -14,6 +15,7 @@ CPU:=i686 else MEM:=mem.o +TERMINAL:=terminal.o BLASTEM:=blastem ifeq ($(OS),Darwin) @@ -99,7 +101,7 @@ Z80OBJS=z80inst.o z80_to_x86.o AUDIOOBJS=ym2612.o psg.o wave.o CONFIGOBJS=config.o tern.o util.o -MAINOBJS=blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o romdb.o $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) +MAINOBJS=blastem.o debug.o gdb_remote.o vdp.o render_sdl.o io.o romdb.o $(TERMINAL) $(CONFIGOBJS) gst.o $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) ifeq ($(CPU),x86_64) CFLAGS+=-DX86_64 -m64 @@ -119,9 +121,12 @@ endif ifeq ($(OS),Windows) MAINOBJS+= glew32s.lib +ALL=$(BLASTEM) +else +ALL= dis zdis stateview vgmplay blastem termhelper endif -all : dis zdis stateview vgmplay blastem +all : $(ALL) $(BLASTEM) : $(MAINOBJS) $(CC) -o $(BLASTEM) $(MAINOBJS) $(LDFLAGS) @@ -188,4 +193,4 @@ vos_prog_info : vos_prog_info.o vos_program_module.o vasmz80_mot -Fbin -spaces -o $@ $< clean : - rm -rf dis trans stateview test_x86 gen_fib *.o + rm -rf $(ALL) trans ztestrun ztestgen *.o diff --git a/debug.c b/debug.c index a70f790..5fedb73 100644 --- a/debug.c +++ b/debug.c @@ -8,6 +8,7 @@ #endif #include "render.h" #include "util.h" +#include "terminal.h" static bp_def * breakpoints = NULL; static bp_def * zbreakpoints = NULL; @@ -287,6 +288,7 @@ z80_context * zdebugger(z80_context * context, uint16_t address) static uint16_t branch_t; static uint16_t branch_f; z80inst inst; + init_terminal(); //Check if this is a user set breakpoint, or just a temporary one bp_def ** this_bp = find_breakpoint(&zbreakpoints, address); if (*this_bp) { @@ -473,6 +475,9 @@ m68k_context * debugger(m68k_context * context, uint32_t address) static uint32_t branch_t; static uint32_t branch_f; m68kinst inst; + + init_terminal(); + sync_components(context, 0); //probably not necessary, but let's play it safe address &= 0xFFFFFF; diff --git a/termhelper.c b/termhelper.c new file mode 100644 index 0000000..a5cf17c --- /dev/null +++ b/termhelper.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include +#include +#include "terminal.h" + +char buf[4096]; + +void copy_data(int to, int from) +{ + ssize_t bytes = read(from, buf, sizeof(buf)); + while (bytes > 0) + { + ssize_t written = write(to, buf, bytes); + if (written == -1) { + exit(1); + } + bytes -= written; + } +} + +int main(int argc, char **argv) +{ + //these will block so order is important + int input_fd = open(INPUT_PATH, O_WRONLY); + int output_fd = open(OUTPUT_PATH, O_RDONLY); + fd_set read_fds; + FD_ZERO(&read_fds); + for (;;) + { + FD_SET(STDIN_FILENO, &read_fds); + FD_SET(output_fd, &read_fds); + select(output_fd+1, &read_fds, NULL, NULL, NULL); + + if (FD_ISSET(STDIN_FILENO, &read_fds)) { + copy_data(input_fd, STDIN_FILENO); + } + if (FD_ISSET(output_fd, &read_fds)) { + copy_data(STDOUT_FILENO, output_fd); + } + } + return 0; +} diff --git a/terminal.c b/terminal.c new file mode 100644 index 0000000..0e952f2 --- /dev/null +++ b/terminal.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include +#include "util.h" +#include "terminal.h" + +pid_t child; + +void cleanup_terminal() +{ + kill(child, SIGKILL); + unlink(INPUT_PATH); + unlink(OUTPUT_PATH); +} + +void init_terminal() +{ + static char init_done; + if (!init_done) { + if (!(isatty(STDIN_FILENO) && isatty(STDOUT_FILENO))) { +#ifndef __APPLE__ + //check to see if x-terminal-emulator exists, just use xterm if it doesn't + char *term = system("which x-terminal-emulator > /dev/null") ? "xterm" : "x-terminal-emulator"; +#endif + //get rid of FIFO's if they already exist + unlink(INPUT_PATH); + unlink(OUTPUT_PATH); + //create FIFOs for talking to helper process in terminal app + mkfifo(INPUT_PATH, 0666); + mkfifo(OUTPUT_PATH, 0666); + + //close existing file descriptors + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + + child = fork(); + if (child == -1) { + //error, oh well + warning("Failed to fork for terminal spawn"); + } else if (!child) { + //child process, exec our terminal emulator +#ifdef __APPLE__ + execlp("open", "open", "./termhelper", NULL); +#else + execlp(term, term, "-title", "BlastEm Debugger", "-e", "./termhelper", NULL); +#endif + } else { + //connect to the FIFOs, these will block so order is important + open(INPUT_PATH, O_RDONLY); + open(OUTPUT_PATH, O_WRONLY); + atexit(cleanup_terminal); + if (-1 == dup(STDOUT_FILENO)) { + fatal_error("failed to dup STDOUT to STDERR after terminal fork"); + } + } + } + + init_done = 1; + } +} diff --git a/terminal.h b/terminal.h new file mode 100644 index 0000000..08986c2 --- /dev/null +++ b/terminal.h @@ -0,0 +1,9 @@ +#ifndef TERMINAL_H_ +#define TERMINAL_H_ + +void init_terminal(); + +#define INPUT_PATH "/tmp/blastem_input" +#define OUTPUT_PATH "/tmp/blastem_output" + +#endif //TERMINAL_H_ diff --git a/terminal_win.c b/terminal_win.c new file mode 100644 index 0000000..120a086 --- /dev/null +++ b/terminal_win.c @@ -0,0 +1,13 @@ +#include +#include + +void init_terminal() +{ + static init_done; + if (!init_done) { + AllocConsole(); + freopen("CONIN$", "r", stdin); + freopen("CONOUT$", "w", stdout); + freopen("CONOUT$", "w", stderr); + } +} diff --git a/util.c b/util.c index 3ad290d..c0131b2 100644 --- a/util.c +++ b/util.c @@ -116,6 +116,35 @@ void fatal_error(char *format, ...) exit(1); } +void warning(char *format, ...) +{ + va_list args; + va_start(args, format); +#ifndef _WIN32 + if (headless || (isatty(STDERR_FILENO) && isatty(STDIN_FILENO))) { + vfprintf(stderr, format, args); + } else { +#endif + size_t size = strlen(format) * 2; + char *buf = malloc(size); + size_t actual = vsnprintf(buf, size, format, args); + if (actual >= size) { + actual++; + free(buf); + buf = malloc(actual); + va_end(args); + va_start(args, format); + vsnprintf(buf, actual, format, args); + } + fputs(buf, stderr); + render_infobox("BlastEm Info", buf); + free(buf); +#ifndef _WIN32 + } +#endif + va_end(args); +} + void info_message(char *format, ...) { va_list args; diff --git a/util.h b/util.h index 537c97e..ffa3385 100644 --- a/util.h +++ b/util.h @@ -29,5 +29,7 @@ char * readlink_alloc(char * path); void fatal_error(char *format, ...); //Prints an information message to stdout and to a message box if not in headless mode and not attached to a console void info_message(char *format, ...); +//Prints an information message to stderr and to a message box if not in headless mode and not attached to a console +void warning(char *format, ...); #endif //UTIL_H_ -- cgit v1.2.3 From eb2f5614ca10aed240f2d7b310c6929874effc3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=3D=3FUTF-8=3Fq=3FHigor=3D20Eur=3DC3=3DADpedes=3F=3D?= Date: Sun, 26 Jul 2015 10:59:41 -0700 Subject: Fix mingw-w64 build and cross-compilation --- Makefile | 16 +++++++++------- config.c | 8 +++++++- mem_win.c | 2 +- util.c | 4 ++-- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 40ffb72..5b4fd5e 100644 --- a/Makefile +++ b/Makefile @@ -3,12 +3,18 @@ OS:=$(shell uname -s) endif ifeq ($(OS),Windows) +ifndef SDL2_PREFIX +SDL2_PREFIX:="C:/MinGW/usr" +endif +ifndef GLEW32S_LIB +GLEW32S_LIB=glew32s.lib +endif MEM:=mem_win.o BLASTEM:=blastem.exe CC:=wine gcc.exe -CFLAGS:=-O2 -std=gnu99 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -I"C:/MinGW/usr/include/SDL2" -DGLEW_STATIC -LDFLAGS:= -L"C:/MinGW/usr/lib" -lm -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lglu32 -mwindows +CFLAGS:=-O2 -std=gnu99 -Wreturn-type -Werror=return-type -Werror=implicit-function-declaration -I"$(SDL2_PREFIX)/include/SDL2" -DGLEW_STATIC +LDFLAGS:= $(GLEW32S_LIB) -L"$(SDL2_PREFIX)/lib" -lm -lmingw32 -lSDL2main -lSDL2 -lopengl32 -lglu32 -mwindows CPU:=i686 else @@ -117,11 +123,7 @@ else MAINOBJS+= $(Z80OBJS) endif -ifeq ($(OS),Windows) -MAINOBJS+= glew32s.lib -endif - -all : dis zdis stateview vgmplay blastem +all : dis zdis stateview vgmplay $(BLASTEM) $(BLASTEM) : $(MAINOBJS) $(CC) -o $(BLASTEM) $(MAINOBJS) $(LDFLAGS) diff --git a/config.c b/config.c index 6fd29b5..b34aec0 100644 --- a/config.c +++ b/config.c @@ -9,7 +9,13 @@ #include #include -#ifdef _WIN32 +#ifdef __MINGW64_VERSION_MAJOR +#define MINGW_W64_VERSION (__MINGW64_VERSION_MAJOR * 1000 + __MINGW64_VERSION_MINOR) +#else +#define MINGW_W64_VERSION 0 +#endif + +#if defined(_WIN32) && (MINGW_W64_VERSION < 3003) char * strtok_r(char * input, char * sep, char ** state) { if (input) { diff --git a/mem_win.c b/mem_win.c index 8a76712..4076afd 100644 --- a/mem_win.c +++ b/mem_win.c @@ -5,7 +5,7 @@ */ #include "mem.h" -#include +#include void * alloc_code(size_t *size) { diff --git a/util.c b/util.c index 2a59b08..9722d3e 100644 --- a/util.c +++ b/util.c @@ -87,8 +87,8 @@ void set_exe_str(char * str) } #ifdef _WIN32 -#include "Shlobj.h" -#include "Windows.h" +#include +#include char * get_home_dir() { -- cgit v1.2.3 From 6c280f3b1f8e072f86fc41b371cf616be1483030 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=3D=3FUTF-8=3Fq=3FHigor=3D20Eur=3DC3=3DADpedes=3F=3D?= Date: Sun, 26 Jul 2015 11:00:25 -0700 Subject: Fix some memory issues --- config.c | 12 +++++++----- io.c | 6 +++--- m68k_core.c | 5 +++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/config.c b/config.c index b34aec0..16091b0 100644 --- a/config.c +++ b/config.c @@ -48,11 +48,11 @@ tern_node * parse_config_int(char **state, int started, int *line) curline = strip_ws(curline); int len = strlen(curline); if (!len) { - *line++; + *line = *line + 1; continue; } if (curline[0] == '#') { - *line++; + *line = *line + 1; continue; } if (curline[0] == '}') { @@ -67,7 +67,7 @@ tern_node * parse_config_int(char **state, int started, int *line) if (*end == '{') { *end = 0; curline = strip_ws(curline); - *line++; + *line = *line + 1; head = tern_insert_node(head, curline, parse_config_int(state, 1, line)); } else { char * val = strip_ws(split_keyval(curline)); @@ -77,7 +77,7 @@ tern_node * parse_config_int(char **state, int started, int *line) } else { fprintf(stderr, "Key %s is missing a value on line %d\n", key, *line); } - *line++; + *line = *line + 1; } } return head; @@ -100,10 +100,12 @@ tern_node * parse_config_file(char * config_path) if (!config_size) { goto config_empty; } - char * config_data = malloc(config_size); + char * config_data = malloc(config_size+1); if (fread(config_data, 1, config_size, config_file) != config_size) { goto config_read_fail; } + config_data[config_size] = '\0'; + ret = parse_config(config_data); config_read_fail: free(config_data); diff --git a/io.c b/io.c index 50d4df7..6199af0 100644 --- a/io.c +++ b/io.c @@ -340,7 +340,7 @@ void handle_joy_dpad(int joystick, int dpadnum, uint8_t value) int parse_binding_target(char * target, tern_node * padbuttons, int * ui_out, int * padnum_out, int * padbutton_out) { int gpadslen = strlen("gamepads."); - if (!memcmp(target, "gamepads.", gpadslen)) { + if (!strncmp(target, "gamepads.", gpadslen)) { if (target[gpadslen] >= '1' && target[gpadslen] <= '8') { int padnum = target[gpadslen] - '0'; int button = tern_find_int(padbuttons, target + gpadslen + 1, 0); @@ -358,7 +358,7 @@ int parse_binding_target(char * target, tern_node * padbuttons, int * ui_out, in } else { fprintf(stderr, "Gamepad mapping string '%s' refers to an invalid gamepad number %c\n", target, target[gpadslen]); } - } else if(!memcmp(target, "ui.", strlen("ui."))) { + } else if(!strncmp(target, "ui.", strlen("ui."))) { *padbutton_out = 0; if (!strcmp(target + 3, "vdp_debug_mode")) { *ui_out = UI_DEBUG_MODE_INC; @@ -368,7 +368,7 @@ int parse_binding_target(char * target, tern_node * padbuttons, int * ui_out, in *ui_out = UI_ENTER_DEBUGGER; } else if(!strcmp(target + 3, "save_state")) { *ui_out = UI_SAVE_STATE; - } else if(!memcmp(target + 3, "set_speed.", strlen("set_speed."))) { + } else if(!strncmp(target + 3, "set_speed.", strlen("set_speed."))) { *ui_out = UI_SET_SPEED; *padbutton_out = atoi(target + 3 + strlen("set_speed.")); } else if(!strcmp(target + 3, "next_speed")) { diff --git a/m68k_core.c b/m68k_core.c index 5d88a2d..6b48080 100644 --- a/m68k_core.c +++ b/m68k_core.c @@ -1004,8 +1004,9 @@ void m68k_reset(m68k_context * context) 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)); + size_t ctx_size = sizeof(m68k_context) + ram_size(&opts->gen) / (1 << opts->gen.ram_flags_shift) / 8; + m68k_context * context = malloc(ctx_size); + memset(context, 0, ctx_size); context->native_code_map = opts->gen.native_code_map; context->options = opts; context->int_cycle = CYCLE_NEVER; -- cgit v1.2.3 From 711f53c6685783e5effb17e493450ed5d09b3aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=3D=3FUTF-8=3Fq=3FHigor=3D20Eur=3DC3=3DADpedes=3F=3D?= Date: Sun, 26 Jul 2015 13:05:05 -0700 Subject: Add pure SDL2 renderer --- render_sdl.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 110 insertions(+), 17 deletions(-) mode change 100644 => 100755 render_sdl.c diff --git a/render_sdl.c b/render_sdl.c old mode 100644 new mode 100755 index 82f8b12..a80acc4 --- a/render_sdl.c +++ b/render_sdl.c @@ -15,7 +15,14 @@ #include SDL_Window *main_window; +#ifdef DISABLE_OPENGL +SDL_Renderer *main_renderer; +SDL_Texture *main_texture; +SDL_Rect main_clip; +#else SDL_GLContext *main_context; +#endif + uint8_t render_dbg = 0; uint8_t debug_pal = 0; @@ -153,6 +160,11 @@ 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; + +#ifdef DISABLE_OPENGL + /* height=480 to fit interlaced output */ + main_texture = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 480); +#else glGenTextures(3, textures); for (int i = 0; i < 3; i++) { @@ -191,10 +203,20 @@ void render_alloc_surfaces(vdp_context * context) un_textures[1] = glGetUniformLocation(program, "textures[1]"); un_width = glGetUniformLocation(program, "width"); at_pos = glGetAttribLocation(program, "pos"); +#endif } char * caption = NULL; +static void render_quit() +{ + render_close_audio(); +#ifdef DISABLE_OPENGL + SDL_DestroyTexture(main_texture); +#endif + SDL_Quit(); +} + 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) { @@ -202,14 +224,9 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full exit(1); } printf("width: %d, height: %d\n", width, height); - uint32_t flags = SDL_WINDOW_OPENGL; + uint32_t flags = 0; - 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; @@ -220,14 +237,31 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full width = mode.w; height = mode.h; } + +#ifdef DISABLE_OPENGL + SDL_CreateWindowAndRenderer(width, height, flags, &main_window, &main_renderer); + + if (!main_window || !main_renderer) { + fprintf(stderr, "unable to create SDL window: %s\n", SDL_GetError()); + SDL_Quit(); + exit(1); + } + main_clip.x = main_clip.y = 0; + main_clip.w = width; + main_clip.h = height; +#else + 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); 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); } - 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) { @@ -240,18 +274,36 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full SDL_Quit(); exit(1); } - float aspect = (float)width / height; +#endif + SDL_GetWindowSize(main_window, &width, &height); + printf("Window created with size: %d x %d\n", width, height); + float src_aspect = 4.0/3.0; + float aspect = (float)width / height; tern_val def = {.ptrval = "normal"}; - if (fabs(aspect - 4.0/3.0) > 0.01 && strcmp(tern_find_path_default(config, "video\0aspect\0", def).ptrval, "stretch")) { + int stretch = fabs(aspect - src_aspect) > 0.01 && !strcmp(tern_find_path_default(config, "video\0aspect\0", def).ptrval, "stretch"); + +#ifdef DISABLE_OPENGL + if (!stretch) { + float scale_x = (float)width / 320.0; + float scale_y = (float)height / 240.0; + float scale = scale_x > scale_y ? scale_y : scale_x; + main_clip.w = 320.0 * scale; + main_clip.h = 240.0 * scale; + main_clip.x = (width - main_clip.w) / 2; + main_clip.y = (height - main_clip.h) / 2; + } +#else + if (!stretch) { for (int i = 0; i < 4; i++) { - if (aspect > 4.0/3.0) { - vertex_data[i*2] *= (4.0/3.0)/aspect; + if (aspect > src_aspect) { + vertex_data[i*2] *= src_aspect/aspect; } else { - vertex_data[i*2+1] *= aspect/(4.0/3.0); + vertex_data[i*2+1] *= aspect/src_aspect; } } } +#endif caption = title; min_delay = 0; for (int i = 0; i < 100; i++) { @@ -315,14 +367,54 @@ 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); + atexit(render_quit); } void render_context(vdp_context * context) { + int width = context->regs[REG_MODE_4] & BIT_H40 ? 320.0f : 256.0f; + int height = 240; + last_frame = SDL_GetTicks(); - +#ifdef DISABLE_OPENGL + SDL_Rect area; + + area.x = area.y = 0; + area.w = width; + area.h = height; + + if (context->regs[REG_MODE_4] & BIT_INTERLACE) + { + unsigned skip; + uint32_t *src = (uint32_t*)context->framebuf; + uint8_t *dst; + int i; + + area.h *= 2; + + SDL_LockTexture(main_texture, &area, (void**)&dst, &skip); + + if (context->framebuf == context->evenbuf) + dst += skip; + + skip *= 2; + + for (i = 0; i < 240; ++i) + { + memcpy(dst, src, width*sizeof(uint32_t)); + src += 320; + dst += skip; + } + + SDL_UnlockTexture(main_texture); + } + else /* possibly faster path for non-interlaced output */ + SDL_UpdateTexture(main_texture, &area, context->framebuf, 320*sizeof(uint32_t)); + + SDL_RenderClear(main_renderer); + SDL_RenderCopy(main_renderer, main_texture, &area, &main_clip); + SDL_RenderPresent(main_renderer); +#else 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);; @@ -338,7 +430,7 @@ void render_context(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->regs[REG_MODE_4] & BIT_H40 ? 320.0f : 256.0f); + glUniform1f(un_width, width); glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); @@ -350,6 +442,7 @@ void render_context(vdp_context * context) glDisableVertexAttribArray(at_pos); SDL_GL_SwapWindow(main_window); +#endif if (context->regs[REG_MODE_4] & BIT_INTERLACE) { context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; -- cgit v1.2.3 From 4755aa94deb0a8fb90bf74033d370e9370d69ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=3D=3FUTF-8=3Fq=3FHigor=3D20Eur=3DC3=3DADpedes=3F=3D?= Date: Sun, 26 Jul 2015 13:08:22 -0700 Subject: Use SDL2 renderer as a fallback --- render_sdl.c | 275 +++++++++++++++++++++++++++++++---------------------------- 1 file changed, 146 insertions(+), 129 deletions(-) diff --git a/render_sdl.c b/render_sdl.c index a80acc4..b20808e 100755 --- a/render_sdl.c +++ b/render_sdl.c @@ -12,19 +12,19 @@ #include "io.h" #include "util.h" +#ifndef DISABLE_OPENGL #include +#endif SDL_Window *main_window; -#ifdef DISABLE_OPENGL SDL_Renderer *main_renderer; SDL_Texture *main_texture; SDL_Rect main_clip; -#else SDL_GLContext *main_context; -#endif uint8_t render_dbg = 0; uint8_t debug_pal = 0; +uint8_t render_gl = 1; uint32_t last_frame = 0; @@ -101,6 +101,7 @@ uint32_t render_map_color(uint8_t r, uint8_t g, uint8_t 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[] = { @@ -154,6 +155,7 @@ GLuint load_shader(char * fname, GLenum shader_type) } return ret; } +#endif void render_alloc_surfaces(vdp_context * context) { @@ -161,48 +163,52 @@ void render_alloc_surfaces(vdp_context * context) memset(context->oddbuf, 0, 512 * 256 * 4 * 2); context->evenbuf = ((char *)context->oddbuf) + 512 * 256 * 4; -#ifdef DISABLE_OPENGL - /* height=480 to fit interlaced output */ - main_texture = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 480); -#else - 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); +#ifndef DISABLE_OPENGL + if (render_gl) { + 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); + tern_val def = {.ptrval = "default.v.glsl"}; + vshader = load_shader(tern_find_path_default(config, "video\0vertex_shader\0", def).ptrval, GL_VERTEX_SHADER); + def.ptrval = "default.f.glsl"; + fshader = load_shader(tern_find_path_default(config, "video\0fragment_shader\0", def).ptrval, 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"); + } else { +#endif + /* height=480 to fit interlaced output */ + main_texture = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 480); +#ifndef DISABLE_OPENGL } - 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); - tern_val def = {.ptrval = "default.v.glsl"}; - vshader = load_shader(tern_find_path_default(config, "video\0vertex_shader\0", def).ptrval, GL_VERTEX_SHADER); - def.ptrval = "default.f.glsl"; - fshader = load_shader(tern_find_path_default(config, "video\0fragment_shader\0", def).ptrval, 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"); #endif } @@ -238,18 +244,9 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full height = mode.h; } -#ifdef DISABLE_OPENGL - SDL_CreateWindowAndRenderer(width, height, flags, &main_window, &main_renderer); + render_gl = 0; - if (!main_window || !main_renderer) { - fprintf(stderr, "unable to create SDL window: %s\n", SDL_GetError()); - SDL_Quit(); - exit(1); - } - main_clip.x = main_clip.y = 0; - main_clip.w = width; - main_clip.h = height; -#else +#ifndef DISABLE_OPENGL flags |= SDL_WINDOW_OPENGL; SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5); @@ -266,15 +263,30 @@ 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); + SDL_DestroyWindow(main_window); } - if (!GLEW_VERSION_2_0) { - fputs("BlastEm requires at least OpenGL 2.0, but it is unavailable\n", stderr); - SDL_Quit(); - exit(1); + + if (GLEW_VERSION_2_0) { + render_gl = 1; } + else { + SDL_DestroyWindow(main_window); + fputs("OpenGL 2.0 is unavailable, falling back to SDL2 renderer\n", stderr); #endif + SDL_CreateWindowAndRenderer(width, height, flags, &main_window, &main_renderer); + + if (!main_window || !main_renderer) { + fprintf(stderr, "unable to create SDL window: %s\n", SDL_GetError()); + SDL_Quit(); + exit(1); + } + main_clip.x = main_clip.y = 0; + main_clip.w = width; + main_clip.h = height; +#ifndef DISABLE_OPENGL + } +#endif + SDL_GetWindowSize(main_window, &width, &height); printf("Window created with size: %d x %d\n", width, height); float src_aspect = 4.0/3.0; @@ -282,28 +294,31 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full tern_val def = {.ptrval = "normal"}; int stretch = fabs(aspect - src_aspect) > 0.01 && !strcmp(tern_find_path_default(config, "video\0aspect\0", def).ptrval, "stretch"); -#ifdef DISABLE_OPENGL - if (!stretch) { - float scale_x = (float)width / 320.0; - float scale_y = (float)height / 240.0; - float scale = scale_x > scale_y ? scale_y : scale_x; - main_clip.w = 320.0 * scale; - main_clip.h = 240.0 * scale; - main_clip.x = (width - main_clip.w) / 2; - main_clip.y = (height - main_clip.h) / 2; - } -#else if (!stretch) { - for (int i = 0; i < 4; i++) - { - if (aspect > src_aspect) { - vertex_data[i*2] *= src_aspect/aspect; - } else { - vertex_data[i*2+1] *= aspect/src_aspect; +#ifndef DISABLE_OPENGL + if (render_gl) { + for (int i = 0; i < 4; i++) + { + if (aspect > src_aspect) { + vertex_data[i*2] *= src_aspect/aspect; + } else { + vertex_data[i*2+1] *= aspect/src_aspect; + } } + } else { +#endif + float scale_x = (float)width / 320.0; + float scale_y = (float)height / 240.0; + float scale = scale_x > scale_y ? scale_y : scale_x; + main_clip.w = 320.0 * scale; + main_clip.h = 240.0 * scale; + main_clip.x = (width - main_clip.w) / 2; + main_clip.y = (height - main_clip.h) / 2; +#ifndef DISABLE_OPENGL } - } #endif + } + caption = title; min_delay = 0; for (int i = 0; i < 100; i++) { @@ -376,75 +391,77 @@ void render_context(vdp_context * context) int height = 240; last_frame = SDL_GetTicks(); -#ifdef DISABLE_OPENGL - SDL_Rect area; +#ifndef DISABLE_OPENGL + if (render_gl) { + 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);; - area.x = area.y = 0; - area.w = width; - area.h = height; + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT); - if (context->regs[REG_MODE_4] & BIT_INTERLACE) - { - unsigned skip; - uint32_t *src = (uint32_t*)context->framebuf; - uint8_t *dst; - int i; + glUseProgram(program); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textures[0]); + glUniform1i(un_textures[0], 0); - area.h *= 2; + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, (context->regs[REG_MODE_4] & BIT_INTERLACE) ? textures[1] : textures[2]); + glUniform1i(un_textures[1], 1); - SDL_LockTexture(main_texture, &area, (void**)&dst, &skip); + glUniform1f(un_width, width); - if (context->framebuf == context->evenbuf) - dst += skip; + glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); + glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); + glEnableVertexAttribArray(at_pos); - skip *= 2; + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); + glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0); - for (i = 0; i < 240; ++i) - { - memcpy(dst, src, width*sizeof(uint32_t)); - src += 320; - dst += skip; - } + glDisableVertexAttribArray(at_pos); - SDL_UnlockTexture(main_texture); - } - else /* possibly faster path for non-interlaced output */ - SDL_UpdateTexture(main_texture, &area, context->framebuf, 320*sizeof(uint32_t)); + SDL_GL_SwapWindow(main_window); + } else { +#endif + SDL_Rect area; - SDL_RenderClear(main_renderer); - SDL_RenderCopy(main_renderer, main_texture, &area, &main_clip); - SDL_RenderPresent(main_renderer); -#else - 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);; + area.x = area.y = 0; + area.w = width; + area.h = height; - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT); + if (context->regs[REG_MODE_4] & BIT_INTERLACE) { + unsigned skip; + uint32_t *src = (uint32_t*)context->framebuf; + uint8_t *dst; + int i; - glUseProgram(program); - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, textures[0]); - glUniform1i(un_textures[0], 0); + area.h *= 2; - glActiveTexture(GL_TEXTURE1); - glBindTexture(GL_TEXTURE_2D, (context->regs[REG_MODE_4] & BIT_INTERLACE) ? textures[1] : textures[2]); - glUniform1i(un_textures[1], 1); + SDL_LockTexture(main_texture, &area, (void**)&dst, &skip); - glUniform1f(un_width, width); + if (context->framebuf == context->evenbuf) + dst += skip; - glBindBuffer(GL_ARRAY_BUFFER, buffers[0]); - glVertexAttribPointer(at_pos, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat[2]), (void *)0); - glEnableVertexAttribArray(at_pos); + skip *= 2; - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[1]); - glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, (void *)0); + for (i = 0; i < 240; ++i) { + memcpy(dst, src, width*sizeof(uint32_t)); + src += 320; + dst += skip; + } - glDisableVertexAttribArray(at_pos); + SDL_UnlockTexture(main_texture); + } + else /* possibly faster path for non-interlaced output */ + SDL_UpdateTexture(main_texture, &area, context->framebuf, 320*sizeof(uint32_t)); - SDL_GL_SwapWindow(main_window); + SDL_RenderClear(main_renderer); + SDL_RenderCopy(main_renderer, main_texture, &area, &main_clip); + SDL_RenderPresent(main_renderer); +#ifndef DISABLE_OPENGL + } #endif - if (context->regs[REG_MODE_4] & BIT_INTERLACE) - { + + if (context->regs[REG_MODE_4] & BIT_INTERLACE) { context->framebuf = context->framebuf == context->oddbuf ? context->evenbuf : context->oddbuf; } } -- cgit v1.2.3 From ddf40125853bc97a5122a1f4e740a6ba6ae526c3 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 26 Jul 2015 13:33:48 -0700 Subject: Minor cleanup --- render_sdl.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/render_sdl.c b/render_sdl.c index 8a4b20d..a2f094e 100755 --- a/render_sdl.c +++ b/render_sdl.c @@ -126,14 +126,14 @@ GLuint load_shader(char * fname, GLenum shader_type) f = fopen(shader_path, "r"); free(shader_path); if (!f) { - fprintf(stderr, "Failed to open shader file %s for reading\n", fname); + warning("Failed to open shader file %s for reading\n", fname); return 0; } } long fsize = file_size(f); GLchar * text = malloc(fsize); if (fread(text, 1, fsize, f) != fsize) { - fprintf(stderr, "Error reading from shader file %s\n", fname); + warning("Error reading from shader file %s\n", fname); free(text); return 0; } @@ -144,11 +144,10 @@ GLuint load_shader(char * fname, GLenum shader_type) GLint compile_status, loglen; glGetShaderiv(ret, GL_COMPILE_STATUS, &compile_status); if (!compile_status) { - fprintf(stderr, "Shader %s failed to compile\n", fname); glGetShaderiv(ret, GL_INFO_LOG_LENGTH, &loglen); text = malloc(loglen); glGetShaderInfoLog(ret, loglen, NULL, text); - fputs(text, stderr); + warning("Shader %s failed to compile:\n%s\n", fname, text); free(text); glDeleteShader(ret); return 0; @@ -259,22 +258,19 @@ void render_init(int width, int height, char * title, uint32_t fps, uint8_t full 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); + warning("Initialization of GLEW failed with code %d\n", res); } - if (GLEW_VERSION_2_0) { + if (res == GLEW_OK && GLEW_VERSION_2_0) { render_gl = 1; - } - else { + } else { SDL_DestroyWindow(main_window); - fputs("OpenGL 2.0 is unavailable, falling back to SDL2 renderer\n", stderr); + warning("OpenGL 2.0 is unavailable, falling back to SDL2 renderer\n", stderr); #endif SDL_CreateWindowAndRenderer(width, height, flags, &main_window, &main_renderer); if (!main_window || !main_renderer) { - fprintf(stderr, "unable to create SDL window: %s\n", SDL_GetError()); - SDL_Quit(); - exit(1); + fatal_error("unable to create SDL window: %s\n", SDL_GetError()); } main_clip.x = main_clip.y = 0; main_clip.w = width; -- cgit v1.2.3 From 6cd1ab5ac4004b9e9433c5d16a6ed7fa049cf767 Mon Sep 17 00:00:00 2001 From: Michael Pavone Date: Sun, 26 Jul 2015 16:32:34 -0700 Subject: Fix GDB remote debugging support --- blastem.c | 2 ++ blastem.h | 2 ++ gdb_remote.c | 71 ++++++++++++++++++++++++++++-------------------------------- 3 files changed, 37 insertions(+), 38 deletions(-) diff --git a/blastem.c b/blastem.c index 29d6f05..350a04d 100644 --- a/blastem.c +++ b/blastem.c @@ -1050,6 +1050,8 @@ int main(int argc, char ** argv) gen.vdp = &v_context; gen.ym = &y_context; gen.psg = &p_context; + gen.work_ram = ram; + gen.zram = z80_ram; genesis = &gen; setup_io_devices(config, gen.ports); diff --git a/blastem.h b/blastem.h index 43f694d..43ca592 100644 --- a/blastem.h +++ b/blastem.h @@ -22,6 +22,8 @@ typedef struct { vdp_context *vdp; ym2612_context *ym; psg_context *psg; + uint16_t *work_ram; + uint8_t *zram; uint8_t *save_storage; eeprom_map *eeprom_map; uint32_t num_eeprom; diff --git a/gdb_remote.c b/gdb_remote.c index 0ea20c0..91d6a99 100644 --- a/gdb_remote.c +++ b/gdb_remote.c @@ -115,34 +115,40 @@ void update_status(m68k_context * context, uint16_t value) uint8_t read_byte(m68k_context * context, uint32_t address) { - uint16_t * word; - //TODO: Use generated read/write functions so that memory map is properly respected - if (address < 0x400000) { - word = context->mem_pointers[0] + address/2; - } else if (address >= 0xE00000) { - word = context->mem_pointers[1] + (address & 0xFFFF)/2; - } else if (address >= 0xA00000 && address < 0xA04000) { - return z80_ram[address & 0x1FFF]; - } else { - return 0; + + genesis_context *gen = context->system; + //TODO: Use generated read/write functions to support access to hardware that is not ROM or RAM + uint16_t * word = get_native_pointer(address & 0xFFFFFFFE, (void **)context->mem_pointers, &context->options->gen); + if (word) { + if (address & 1) { + return *word; + } + return *word >> 8; } - if (address & 1) { - return *word; + if (address >= 0xA00000 && address < 0xA04000) { + return gen->zram[address & 0x1FFF]; } - return *word >> 8; + return 0; } void write_byte(m68k_context * context, uint32_t address, uint8_t value) { - uint16_t * word; + genesis_context *gen = context->system; //TODO: Use generated read/write functions so that memory map is properly respected - if (address < 0x400000) { - //TODO: Invalidate translated code - word = context->mem_pointers[0] + address/2; - } else if (address >= 0xE00000) { - m68k_handle_code_write(address & 0xFFFF, context); - word = context->mem_pointers[1] + (address & 0xFFFF)/2; - } else if (address >= 0xA00000 && address < 0xA04000) { + uint16_t * word = get_native_pointer(address & 0xFFFFFFFE, (void **)context->mem_pointers, &context->options->gen); + if (word) { + if (address & 1) { + *word = (*word & 0xFF00) | value; + } else { + *word = (*word & 0xFF) | value << 8; + } + //TODO: Deal with this more generally once m68k_handle_code_write can handle it + if (address >= 0xE00000) { + m68k_handle_code_write(address, context); + } + return; + } + if (address >= 0xA00000 && address < 0xA04000) { z80_ram[address & 0x1FFF] = value; genesis_context * gen = context->system; #ifndef NO_Z80 @@ -152,11 +158,6 @@ void write_byte(m68k_context * context, uint32_t address, uint8_t value) } else { return; } - if (address & 1) { - *word = (*word & 0xFF00) | value; - } else { - *word = (*word & 0xFF) | value << 8; - } } void gdb_run_command(m68k_context * context, uint32_t pc, char * command) @@ -180,12 +181,9 @@ void gdb_run_command(m68k_context * context, uint32_t pc, char * command) goto not_impl; } m68kinst inst; - uint16_t * pc_ptr; - if (pc < 0x400000) { - pc_ptr = cart + pc/2; - } else if(pc > 0xE00000) { - pc_ptr = ram + (pc & 0xFFFF)/2; - } else { + genesis_context *gen = context->system; + uint16_t * pc_ptr = get_native_pointer(pc, (void **)context->mem_pointers, &context->options->gen); + if (!pc_ptr) { fatal_error("Entered gdb remote debugger stub at address %X\n", pc); } uint16_t * after_pc = m68k_decode(pc_ptr, &inst, pc & 0xFFFFFF); @@ -400,12 +398,9 @@ void gdb_run_command(m68k_context * context, uint32_t pc, char * command) case 's': case 'S': { m68kinst inst; - uint16_t * pc_ptr; - if (pc < 0x400000) { - pc_ptr = cart + pc/2; - } else if(pc > 0xE00000) { - pc_ptr = ram + (pc & 0xFFFF)/2; - } else { + genesis_context *gen = context->system; + uint16_t * pc_ptr = get_native_pointer(pc, (void **)context->mem_pointers, &context->options->gen); + if (!pc_ptr) { fatal_error("Entered gdb remote debugger stub at address %X\n", pc); } uint16_t * after_pc = m68k_decode(pc_ptr, &inst, pc & 0xFFFFFF); -- cgit v1.2.3