# HG changeset patch # User Michael Pavone # Date 1484521644 28800 # Node ID e758ddbf0624ba6a855300506b927f8a0e1d610c # Parent 73e36dac5be7ce8787f31dbce7a6ff6f78f5842a Initial work on emulating top and bottom border area diff -r 73e36dac5be7 -r e758ddbf0624 render_sdl.c --- a/render_sdl.c Tue Jan 10 23:45:59 2017 -0800 +++ b/render_sdl.c Sun Jan 15 15:07:24 2017 -0800 @@ -187,7 +187,7 @@ } #endif -static uint32_t texture_buf[512 * 256]; +static uint32_t texture_buf[512 * 513]; static void render_alloc_surfaces() { static uint8_t texture_init; @@ -210,6 +210,7 @@ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); if (i < 2) { + //TODO: Fixme for PAL + invalid display mode glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 512, 256, 0, GL_BGRA, GL_UNSIGNED_BYTE, texture_buf); } else { uint32_t blank = 255 << 24; @@ -242,7 +243,7 @@ } else { #endif - //height=480 to fit interlaced output + //TODO: Fixme for PAL + invalid display mode sdl_textures[0] = sdl_textures[1] = SDL_CreateTexture(main_renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, 320, 480); #ifndef DISABLE_OPENGL } diff -r 73e36dac5be7 -r e758ddbf0624 vdp.c --- a/vdp.c Tue Jan 10 23:45:59 2017 -0800 +++ b/vdp.c Sun Jan 15 15:07:24 2017 -0800 @@ -41,6 +41,20 @@ #define VBLANK_START_H32 (LINE_CHANGE_H32+2) #define FIFO_LATENCY 3 +#define BORDER_TOP_V24 27 +#define BORDER_TOP_V28 11 +#define BORDER_TOP_V24_PAL 54 +#define BORDER_TOP_V28_PAL 38 +#define BORDER_TOP_V30_PAL 30 + +#define BORDER_BOT_V24 24 +#define BORDER_BOT_V28 8 +#define BORDER_BOT_V24_PAL 48 +#define BORDER_BOT_V28_PAL 32 +#define BORDER_BOT_V30_PAL 24 + +#define INVALID_LINE 0x200 + static int32_t color_map[1 << 12]; static uint16_t mode4_address_map[0x4000]; static uint32_t planar_to_chunky[256]; @@ -54,6 +68,40 @@ {127, 0, 127} //Sprites }; +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->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; + } + } else { + context->inactive_start = NTSC_INACTIVE_START; + if (context->flags2 & FLAG2_REGION_PAL) { + context->border_top = BORDER_TOP_V28_PAL; + context->border_bot = BORDER_BOT_V28_PAL; + } else { + context->border_top = BORDER_TOP_V28; + context->border_bot = BORDER_TOP_V28; + } + } + } else { + context->inactive_start = MODE4_INACTIVE_START; + if (context->flags2 & FLAG2_REGION_PAL) { + context->border_top = BORDER_TOP_V24_PAL; + context->border_bot = BORDER_BOT_V24_PAL; + } else { + context->border_top = BORDER_TOP_V24; + context->border_bot = BORDER_BOT_V24; + } + } +} + static uint8_t color_map_init_done; void init_vdp_context(vdp_context * context, uint8_t region_pal) @@ -67,7 +115,7 @@ context->output = malloc(LINEBUF_SIZE); context->output_pitch = 0; } else { - context->output = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch); + context->fb = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch); } context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); @@ -163,6 +211,10 @@ if (region_pal) { context->flags2 |= FLAG2_REGION_PAL; } + update_video_params(context); + if (!headless) { + context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * context->border_top); + } } void vdp_free(vdp_context *context) @@ -1115,15 +1167,28 @@ static void render_map_output(uint32_t line, int32_t col, vdp_context * context) { + uint32_t *dst; + if (line == 0x1FF) { + if (!col) { + return; + } + col -= 2; + dst = context->output + col * 8; + uint32_t color = context->colors[context->regs[REG_BG_COLOR]]; + for (int i = 0; i < 16; i++) + { + *(dst++) = color; + } + return; + } if (line >= 240) { return; } - render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context); - uint32_t *dst; uint8_t *sprite_buf, *plane_a, *plane_b; int plane_a_off, plane_b_off; if (col) { + render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context); col-=2; dst = context->output + col * 8; if (context->debug < 2) { @@ -1373,7 +1438,7 @@ static void vdp_advance_line(vdp_context *context) { context->vcounter++; - context->vcounter &= 0x1FF; + uint8_t is_mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; if (is_mode_5) { if (context->flags2 & FLAG2_REGION_PAL) { @@ -1390,29 +1455,34 @@ } else if (context->vcounter == 0xDB) { context->vcounter = 0x1D5; } - uint32_t inactive_start = (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START); - if (!is_mode_5) { - inactive_start = MODE4_INACTIVE_START; - } - if (!headless) { - if (!context->vcounter && !context->output) { - context->output = render_get_framebuffer(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD, &context->output_pitch); - context->h40_lines = 0; - } else if (context->vcounter == inactive_start) { //TODO: Change this once border emulation is added - context->output = NULL; - render_framebuffer_updated(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN: FRAMEBUFFER_ODD, context->h40_lines > inactive_start / 2 ? 320 : 256); + if (headless) { + context->vcounter &= 0x1FF; + } else { + if (context->vcounter == context->inactive_start) { + render_framebuffer_updated(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN: FRAMEBUFFER_ODD, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? 320 : 256); if (context->double_res) { context->flags2 ^= FLAG2_EVEN_FIELD; } - } else if (context->output) { - context->output = (uint32_t *)(((char *)context->output) + context->output_pitch); - if (context->regs[REG_MODE_4] & BIT_H40) { - context->h40_lines++; - } + context->fb = render_get_framebuffer(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD, &context->output_pitch); + context->h40_lines = 0; + context->frame++; + } + context->vcounter &= 0x1FF; + 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); + } else { + output_line = INVALID_LINE; + } + context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * output_line); + if (output_line != INVALID_LINE && (context->regs[REG_MODE_4] & BIT_H40)) { + context->h40_lines++; } } - if (context->vcounter > inactive_start) { + if (context->vcounter > context->inactive_start) { context->hint_counter = context->regs[REG_HINT]; } else if (context->hint_counter) { context->hint_counter--; @@ -1673,7 +1743,7 @@ scan_sprite_table(context->vcounter, context);//Just a guess CHECK_LIMIT case 0: - if (context->vcounter == (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) { + if (context->vcounter == context->inactive_start) { context->flags2 |= FLAG2_VINT_PENDING; context->pending_vint_start = context->cycles; } @@ -1721,7 +1791,7 @@ case 164: render_sprite_cells(context); vdp_advance_line(context); - if (context->vcounter == (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) { + if (context->vcounter == context->inactive_start) { context->hslot++; context->cycles += slot_cycles; return; @@ -1876,7 +1946,7 @@ case 132: render_sprite_cells(context); vdp_advance_line(context); - if (context->vcounter == (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) { + if (context->vcounter == context->inactive_start) { context->hslot++; context->cycles += slot_cycles; return; @@ -2016,6 +2086,7 @@ void latch_mode(vdp_context * context) { context->latched_mode = context->regs[REG_MODE_2] & BIT_PAL; + update_video_params(context); } static void check_render_bg(vdp_context * context, int32_t line, uint32_t slot) @@ -2031,7 +2102,9 @@ } } if (starti >= 0) { - uint32_t color = context->colors[context->regs[REG_BG_COLOR]]; + uint32_t color = (context->regs[REG_MODE_2] & BIT_MODE_5) + ? context->colors[context->regs[REG_BG_COLOR]] + : context->colors[CRAM_SIZE * 3 + 0x10 + (context->regs[REG_BG_COLOR] & 0xF)]; uint32_t * start = context->output + starti; for (int i = 0; i < 2; i++) { *(start++) = color; @@ -2042,22 +2115,17 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) { + uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; + uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; while(context->cycles < target_cycles) { - uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; - uint8_t active_slot, mode_5; - uint32_t inactive_start; - if (context->regs[REG_MODE_2] & BIT_MODE_5) { - //Mode 5 selected - mode_5 = 1; - inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; + uint8_t active_slot; + if (mode_5) { //line 0x1FF is basically active even though it's not displayed - active_slot = (context->vcounter < inactive_start || context->vcounter == 0x1FF) && (context->regs[REG_MODE_2] & DISPLAY_ENABLE); + active_slot = (context->vcounter < context->inactive_start || context->vcounter == 0x1FF) && (context->regs[REG_MODE_2] & DISPLAY_ENABLE); } else { - mode_5 = 0; - inactive_start = MODE4_INACTIVE_START; //display is effectively disabled if neither mode 5 nor mode 4 are selected - active_slot = context->vcounter < inactive_start && (context->regs[REG_MODE_2] & DISPLAY_ENABLE) && (context->regs[REG_MODE_1] & BIT_MODE_4); + active_slot = context->vcounter < context->inactive_start && (context->regs[REG_MODE_2] & DISPLAY_ENABLE) && (context->regs[REG_MODE_1] & BIT_MODE_4); } if (active_slot) { @@ -2097,7 +2165,7 @@ context->sprite_draws = MAX_DRAWS_H32_MODE4; } } - if(context->vcounter == inactive_start) { + if(context->vcounter == context->inactive_start) { uint32_t intslot = context->regs[REG_MODE_4] & BIT_H40 ? VINT_SLOT_H40 : VINT_SLOT_H32; if (context->hslot == intslot) { context->flags2 |= FLAG2_VINT_PENDING; @@ -2119,7 +2187,7 @@ if (!is_refresh(context, context->hslot)) { external_slot(context); } - if (context->vcounter < inactive_start) { + if (context->vcounter < (context->inactive_start + context->border_bot) || context->vcounter > 0x200 - context->border_top) { check_render_bg(context, context->vcounter, context->hslot); } if (context->flags & FLAG_DMA_RUN && !is_refresh(context, context->hslot)) { @@ -2130,18 +2198,12 @@ if (is_h40) { if (context->hslot == LINE_CHANGE_H40) { vdp_advance_line(context); - if (context->vcounter == (inactive_start + 8)) { - context->frame++; - } } else if (context->hslot == 183) { context->hslot = 229; } } else { if (context->hslot == (mode_5 ? LINE_CHANGE_H32 : LINE_CHANGE_MODE4)) { vdp_advance_line(context); - if (context->vcounter == (inactive_start + 8)) { - context->frame++; - } } else if (context->hslot == 148) { context->hslot = 233; } @@ -2152,8 +2214,10 @@ uint32_t vdp_run_to_vblank(vdp_context * context) { - uint32_t target_cycles = ((context->latched_mode & BIT_PAL) ? PAL_INACTIVE_START : NTSC_INACTIVE_START) * MCLKS_LINE; - vdp_run_context(context, target_cycles); + uint32_t old_frame = context->frame; + while (context->frame == old_frame) { + vdp_run_context(context, MCLKS_LINE); + } return context->cycles; } @@ -2275,6 +2339,9 @@ context->flags2 &= ~FLAG2_EVEN_FIELD; } } + if (reg == REG_MODE_2) { + update_video_params(context); + } } } else if (mode_5) { context->flags |= FLAG_PENDING; @@ -2412,11 +2479,7 @@ } uint32_t line= context->vcounter; uint32_t slot = context->hslot; - uint32_t inactive_start = (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START); - if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) { - inactive_start = MODE4_INACTIVE_START; - } - if ((line >= inactive_start && line < 0x1FF) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) { + if ((line >= context->inactive_start && line < 0x1FF) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) { value |= 0x8; } if (context->regs[REG_MODE_4] & BIT_H40) { @@ -2592,28 +2655,9 @@ return MCLKS_LINE * (lines - 1) + vdp_cycles_next_line(context); } -static uint32_t vdp_frame_end_line(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 frame_end; -} - uint32_t vdp_cycles_to_frame_end(vdp_context * context) { - return context->cycles + vdp_cycles_to_line(context, vdp_frame_end_line(context)); + return context->cycles + vdp_cycles_to_line(context, context->inactive_start); } uint32_t vdp_next_hint(vdp_context * context) @@ -2624,12 +2668,9 @@ if (context->flags2 & FLAG2_HINT_PENDING) { return context->pending_hint_start; } - uint32_t inactive_start = (context->regs[REG_MODE_2] & BIT_MODE_5) - ? (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START) - : MODE4_INACTIVE_START; uint32_t hint_line; - if (context->vcounter + context->hint_counter >= inactive_start) { - if (context->regs[REG_HINT] > inactive_start) { + if (context->vcounter + context->hint_counter >= context->inactive_start) { + if (context->regs[REG_HINT] > context->inactive_start) { return 0xFFFFFFFF; } hint_line = context->regs[REG_HINT]; @@ -2655,11 +2696,7 @@ uint32_t vdp_next_vint_z80(vdp_context * context) { - uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; - if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) { - inactive_start = MODE4_INACTIVE_START; - } - if (context->vcounter == inactive_start) { + if (context->vcounter == context->inactive_start) { if (context->regs[REG_MODE_2] & BIT_MODE_5) { if (context->regs[REG_MODE_4] & BIT_H40) { if (context->hslot >= LINE_CHANGE_H40 && context->hslot <= VINT_SLOT_H40) { @@ -2696,7 +2733,7 @@ } } } - int32_t cycles_to_vint = vdp_cycles_to_line(context, inactive_start); + int32_t cycles_to_vint = vdp_cycles_to_line(context, context->inactive_start); if (context->regs[REG_MODE_2] & BIT_MODE_5) { if (context->regs[REG_MODE_4] & BIT_H40) { cycles_to_vint += MCLKS_LINE - (LINE_CHANGE_H40 + (256 - VINT_SLOT_H40)) * MCLKS_SLOT_H40; diff -r 73e36dac5be7 -r e758ddbf0624 vdp.h --- a/vdp.h Tue Jan 10 23:45:59 2017 -0800 +++ b/vdp.h Sun Jan 15 15:07:24 2017 -0800 @@ -155,6 +155,7 @@ uint8_t *linebuf; //pointer to current line in framebuffer uint32_t *output; + uint32_t *fb; system_header *system; uint16_t cram[CRAM_SIZE]; uint32_t colors[CRAM_SIZE*4]; @@ -164,13 +165,16 @@ uint32_t output_pitch; uint32_t frame; uint16_t vcounter; + uint16_t inactive_start; + uint16_t border_top; + uint16_t border_bot; uint16_t hscroll_a; uint16_t hscroll_b; + uint16_t h40_lines; uint8_t hslot; //hcounter/2 uint8_t latched_mode; uint8_t sprite_index; uint8_t sprite_draws; - uint8_t h40_lines; int8_t slot_counter; int8_t cur_slot; sprite_draw sprite_draw_list[MAX_DRAWS];