# HG changeset patch # User Michael Pavone # Date 1492762972 25200 # Node ID 58bfbed6cdb500b565cbe3398ef4cbecec4e4df6 # Parent 2fc444b69351dc10fe4e7ffa2e6ff147302fc7c7 Fairly major rework of how active/passive is handled along with how the V30 mode bit is handled. Allows the vertical border extension trick in Overdrive 2 to work right diff -r 2fc444b69351 -r 58bfbed6cdb5 gst.c --- a/gst.c Fri Apr 21 01:19:40 2017 -0700 +++ b/gst.c Fri Apr 21 01:22:52 2017 -0700 @@ -230,7 +230,6 @@ { vdp_control_port_write(context, 0x8000 | (i << 8) | tmp_buf[i]); } - latch_mode(context); if (fread(tmp_buf, 1, CRAM_SIZE*2, state_file) != CRAM_SIZE*2) { fputs("Failed to read CRAM from savestate\n", stderr); return 0; diff -r 2fc444b69351 -r 58bfbed6cdb5 vdp.c --- a/vdp.c Fri Apr 21 01:19:40 2017 -0700 +++ b/vdp.c Fri Apr 21 01:22:52 2017 -0700 @@ -55,6 +55,12 @@ #define INVALID_LINE 0x200 +enum { + INACTIVE = 0, + PREPARING, //used for line 0x1FF + ACTIVE +}; + static int32_t color_map[1 << 12]; static uint16_t mode4_address_map[0x4000]; static uint32_t planar_to_chunky[256]; @@ -71,14 +77,16 @@ static void update_video_params(vdp_context *context) { if (context->regs[REG_MODE_2] & BIT_MODE_5) { - if (context->latched_mode & BIT_PAL) { + if (context->regs[REG_MODE_2] & BIT_PAL) { if (context->flags2 & FLAG2_REGION_PAL) { context->inactive_start = PAL_INACTIVE_START; context->border_top = BORDER_TOP_V30_PAL; context->border_bot = BORDER_BOT_V30_PAL; } else { - context->inactive_start = 0x200; - context->border_top = context->border_bot = 0; + //the behavior here is rather weird and needs more investigation + context->inactive_start = 0xF0; + context->border_top = 1; + context->border_bot = 3; } } else { context->inactive_start = NTSC_INACTIVE_START; @@ -90,6 +98,14 @@ context->border_bot = BORDER_TOP_V28; } } + if (context->state == INACTIVE) { + //Undo forced INACTIVE state due to neither Mode 4 nor Mode 5 being active + if (context->vcounter < context->inactive_start) { + context->state = ACTIVE; + } else if (context->vcounter == 0x1FF) { + context->state = PREPARING; + } + } } else { context->inactive_start = MODE4_INACTIVE_START; if (context->flags2 & FLAG2_REGION_PAL) { @@ -99,6 +115,20 @@ context->border_top = BORDER_TOP_V24; context->border_bot = BORDER_BOT_V24; } + if (!(context->regs[REG_MODE_1] & BIT_MODE_4)){ + context->state = INACTIVE; + } else if (context->state == INACTIVE) { + //Undo forced INACTIVE state due to neither Mode 4 nor Mode 5 being active + if (context->vcounter < context->inactive_start) { + context->state = ACTIVE; + } + /* + FIXME: uncomment this once mode 4 renderer is updated to handle this + else if (context->vcounter == 0x1FF) { + context->state = PREPARING; + } + */ + } } } @@ -507,6 +537,11 @@ //TODO: Window Group, DMA Group } +static uint8_t is_active(vdp_context *context) +{ + return context->state != INACTIVE && (context->regs[REG_MODE_2] & BIT_DISP_EN) != 0; +} + static void scan_sprite_table(uint32_t line, vdp_context * context) { if (context->sprite_index && context->slot_counter) { @@ -1201,7 +1236,7 @@ static void render_map_output(uint32_t line, int32_t col, vdp_context * context) { uint32_t *dst; - if (line == 0x1FF) { + if (context->state == PREPARING) { if (!col) { return; } @@ -1223,9 +1258,7 @@ } return; } - if (line >= 240) { - return; - } + line &= 0xFF; render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context); uint8_t *sprite_buf, *plane_a, *plane_b; int plane_a_off, plane_b_off; @@ -1305,12 +1338,21 @@ { case 1: pixel &= *sprite_buf; + if (output_disabled && pixel) { + src = DBG_SRC_S; + } break; case 2: pixel &= *plane_a; + if (output_disabled && pixel) { + src = DBG_SRC_A; + } break; case 3: pixel &= *plane_b; + if (output_disabled && pixel) { + src = DBG_SRC_B; + } break; } @@ -1349,12 +1391,21 @@ { case 1: pixel &= *sprite_buf; + if (output_disabled && pixel) { + src = DBG_SRC_S; + } break; case 2: pixel &= *plane_a; + if (output_disabled && pixel) { + src = DBG_SRC_A; + } break; case 3: pixel &= *plane_b; + if (output_disabled && pixel) { + src = DBG_SRC_B; + } break; } uint32_t outpixel; @@ -1539,25 +1590,31 @@ uint8_t is_mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; if (is_mode_5) { if (context->flags2 & FLAG2_REGION_PAL) { - if (context->latched_mode & BIT_PAL) { + if (context->regs[REG_MODE_2] & BIT_PAL) { if (context->vcounter == 0x10B) { context->vcounter = 0x1D2; } } else if (context->vcounter == 0x103){ context->vcounter = 0x1CA; } - } else if (!(context->latched_mode & BIT_PAL) && context->vcounter == 0xEB) { - context->vcounter = 0x1E5; - } - if (context->vcounter == 0x200 - context->border_top) { - latch_mode(context); + } else { + if (context->regs[REG_MODE_2] & BIT_PAL) { + if (context->vcounter == 0x100) { + context->vcounter = 0x1FA; + } + } else if (context->vcounter == 0xEB) { + context->vcounter = 0x1E5; + } } } else if (context->vcounter == 0xDB) { context->vcounter = 0x1D5; } context->vcounter &= 0x1FF; + if (context->state == PREPARING) { + context->state = ACTIVE; + } - if (context->vcounter > context->inactive_start) { + if (context->state != ACTIVE) { context->hint_counter = context->regs[REG_HINT]; } else if (context->hint_counter) { context->hint_counter--; @@ -1576,7 +1633,11 @@ } context->vcounter &= 0x1FF; } else { - if (context->vcounter == (context->inactive_start & 0x1FF)) { + uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL) + ? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL + : 224 + BORDER_TOP_V28 + BORDER_BOT_V28; + + if (context->output_lines == lines_max) { render_framebuffer_updated(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN: FRAMEBUFFER_ODD, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER)); if (context->double_res) { context->flags2 ^= FLAG2_EVEN_FIELD; @@ -1584,15 +1645,16 @@ context->fb = render_get_framebuffer(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD, &context->output_pitch); context->h40_lines = 0; context->frame++; + context->output_lines = 0; } uint32_t output_line; - if (context->vcounter < context->inactive_start + context->border_bot) { - output_line = context->border_top + context->vcounter; - } else if (context->vcounter > 0x200 - context->border_top) { - output_line = context->vcounter - (0x200 - context->border_top); + if (context->vcounter < context->inactive_start + context->border_bot && context->output_lines > 0) { + output_line = context->output_lines++;//context->border_top + context->vcounter; + } else if (context->vcounter >= 0x200 - context->border_top) { + output_line = context->output_lines++;//context->vcounter - (0x200 - context->border_top); } else { output_line = INVALID_LINE; - } + } context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * output_line); #ifdef DEBUG_FB_FILL for (int i = 0; i < LINEBUF_SIZE; i++) @@ -1770,7 +1832,7 @@ for (;;) { case 165: - if (context->vcounter == 0x1FF) { + if (context->state == PREPARING) { uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; uint32_t *dst; if (headless) { @@ -1787,7 +1849,7 @@ } CHECK_LIMIT case 166: - if (context->vcounter == 0x1FF) { + if (context->state == PREPARING) { uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; uint32_t *dst; if (headless) { @@ -1805,7 +1867,7 @@ CHECK_LIMIT //sprite attribute table scan starts case 167: - if (context->vcounter == 0x1FF) { + if (context->state == PREPARING) { uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; uint32_t *dst; if (headless) { @@ -1977,7 +2039,7 @@ for (;;) { case 133: - if (context->vcounter == 0x1FF) { + if (context->state == PREPARING) { uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; uint32_t *dst; if (headless) { @@ -1994,7 +2056,7 @@ } CHECK_LIMIT case 134: - if (context->vcounter == 0x1FF) { + if (context->state == PREPARING) { uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; uint32_t *dst; if (headless) { @@ -2012,7 +2074,7 @@ CHECK_LIMIT //sprite attribute table scan starts case 135: //FIXME - Here - if (context->vcounter == 0x1FF) { + if (context->state == PREPARING) { uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; uint32_t *dst; if (headless) { @@ -2288,12 +2350,6 @@ } } -void latch_mode(vdp_context * context) -{ - context->latched_mode = context->regs[REG_MODE_2] & BIT_PAL; - update_video_params(context); -} - static void vdp_inactive(vdp_context *context, uint32_t target_cycles, uint8_t is_h40, uint8_t mode_5) { uint8_t buf_clear_slot, index_reset_slot, bg_end_slot, vint_slot, line_change, jump_start, jump_dest; @@ -2340,7 +2396,13 @@ bg_color = render_map_color(0, 0, 0); jump_start = 147; jump_dest = 233; - active_line = 0; + if (context->regs[REG_MODE_1] & BIT_MODE_4) { + //FIXME: This is actually 0x1FF like in Mode 5 + active_line = 0; + } else { + //never active unless either mode 4 or mode 5 is turned on + active_line = 0x200; + } } uint32_t *dst = ( context->vcounter < context->inactive_start + context->border_bot @@ -2414,6 +2476,7 @@ if (context->hslot == line_change) { vdp_advance_line(context); if (context->vcounter == active_line) { + context->state = PREPARING; return; } } @@ -2426,16 +2489,11 @@ uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; while(context->cycles < target_cycles) { - uint8_t active_slot; - if (mode_5) { - //line 0x1FF is basically active even though it's not displayed - active_slot = (context->vcounter < context->inactive_start || context->vcounter == 0x1FF) && (context->regs[REG_MODE_2] & DISPLAY_ENABLE); - } else { - //display is effectively disabled if neither mode 5 nor mode 4 are selected - active_slot = context->vcounter < context->inactive_start && (context->regs[REG_MODE_2] & DISPLAY_ENABLE) && (context->regs[REG_MODE_1] & BIT_MODE_4); + if (context->state == ACTIVE && context->vcounter == context->inactive_start) { + context->state = INACTIVE; } - if (active_slot) { + if (is_active(context)) { if (mode_5) { if (is_h40) { vdp_h40(context, target_cycles); @@ -2725,9 +2783,8 @@ if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && !(context->flags2 & FLAG2_EVEN_FIELD)) { value |= 0x10; } - uint32_t line= context->vcounter; uint32_t slot = context->hslot; - if ((line >= context->inactive_start && line < 0x1FF) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) { + if (!is_active(context)) { value |= 0x8; } if (context->regs[REG_MODE_4] & BIT_H40) { @@ -2856,34 +2913,39 @@ } } +static void get_jump_params(vdp_context *context, uint32_t *jump_start, uint32_t *jump_dst) +{ + if (context->regs[REG_MODE_2] & BIT_MODE_5) { + if (context->flags2 & FLAG2_REGION_PAL) { + if (context->regs[REG_MODE_2] & BIT_PAL) { + *jump_start = 0x10B; + *jump_dst = 0x1D2; + } else { + *jump_start = 0x103; + *jump_dst = 0x1CA; + } + } else { + if (context->regs[REG_MODE_2] & BIT_PAL) { + *jump_start = 0x100; + *jump_dst = 0x1FA; + } else { + *jump_start = 0xEB; + *jump_dst = 0x1E5; + } + } + } else { + *jump_start = 0xDB; + *jump_dst = 0x1D5; + } +} + static uint32_t vdp_cycles_to_line(vdp_context * context, uint32_t target) { uint32_t jump_start, jump_dst; - if (context->regs[REG_MODE_2] & BIT_MODE_5) { - 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; - } - } - } else { - jump_start = 0xDB; - jump_dst = 0x1D5; - } + get_jump_params(context, &jump_start, &jump_dst); uint32_t lines; if (context->vcounter < target) { - if (target < jump_start) { + if (target < jump_start || context->vcounter > jump_start) { lines = target - context->vcounter; } else { lines = jump_start - context->vcounter + target - jump_dst; @@ -2917,15 +2979,31 @@ return context->pending_hint_start; } uint32_t hint_line; - if (context->vcounter + context->hint_counter >= context->inactive_start) { - if (context->regs[REG_HINT] > context->inactive_start) { + if (context->state != ACTIVE) { + hint_line = context->regs[REG_HINT]; + if (hint_line > context->inactive_start) { return 0xFFFFFFFF; } - hint_line = context->regs[REG_HINT]; } else { hint_line = context->vcounter + context->hint_counter + 1; + if (context->vcounter < context->inactive_start) { + if (hint_line > context->inactive_start) { + hint_line = context->regs[REG_HINT]; + if (hint_line > context->inactive_start) { + return 0xFFFFFFFF; + } + } + } else { + uint32_t jump_start, jump_dst; + get_jump_params(context, &jump_start, &jump_dst); + if (hint_line >= jump_start && context->vcounter < jump_dst) { + hint_line = (hint_line + jump_dst - jump_start) & 0x1FF; + } + if (hint_line < context->vcounter && hint_line > context->inactive_start) { + return 0xFFFFFFFF; + } + } } - return context->cycles + vdp_cycles_to_line(context, hint_line); } diff -r 2fc444b69351 -r 58bfbed6cdb5 vdp.h --- a/vdp.h Fri Apr 21 01:19:40 2017 -0700 +++ b/vdp.h Fri Apr 21 01:22:52 2017 -0700 @@ -177,9 +177,9 @@ uint16_t border_bot; uint16_t hscroll_a; uint16_t hscroll_b; - uint16_t h40_lines; + uint16_t h40_lines; + uint16_t output_lines; uint8_t hslot; //hcounter/2 - uint8_t latched_mode; uint8_t sprite_index; uint8_t sprite_draws; int8_t slot_counter; @@ -204,6 +204,7 @@ uint8_t debug; uint8_t debug_pal; uint8_t pending_byte; + uint8_t state; uint8_t *tmp_buf_a; uint8_t *tmp_buf_b; } vdp_context;