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 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 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 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