Mercurial > repos > blastem
diff vdp.c @ 1648:b7ecd0d6a77b mame_interp
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 25 Dec 2018 11:12:26 -0800 |
parents | cf4e387a8db6 |
children | b500e971da75 |
line wrap: on
line diff
--- a/vdp.c Sun Dec 31 10:11:16 2017 -0800 +++ b/vdp.c Tue Dec 25 11:12:26 2018 -0800 @@ -19,7 +19,6 @@ #define MAP_BIT_H_FLIP 0x800 #define MAP_BIT_V_FLIP 0x1000 -#define SCROLL_BUFFER_SIZE 32 #define SCROLL_BUFFER_MASK (SCROLL_BUFFER_SIZE-1) #define SCROLL_BUFFER_DRAW (SCROLL_BUFFER_SIZE/2) @@ -138,13 +137,9 @@ static uint8_t color_map_init_done; -void init_vdp_context(vdp_context * context, uint8_t region_pal) +vdp_context *init_vdp_context(uint8_t region_pal) { - memset(context, 0, sizeof(*context)); - context->vdpmem = malloc(VRAM_SIZE); - memset(context->vdpmem, 0, VRAM_SIZE); - /* - */ + vdp_context *context = calloc(1, sizeof(vdp_context) + VRAM_SIZE); if (headless) { context->output = malloc(LINEBUF_SIZE * sizeof(uint32_t)); context->output_pitch = 0; @@ -152,10 +147,6 @@ context->cur_buffer = FRAMEBUFFER_ODD; 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); - context->tmp_buf_a = context->linebuf + LINEBUF_SIZE; - context->tmp_buf_b = context->tmp_buf_a + SCROLL_BUFFER_SIZE; context->sprite_draws = MAX_DRAWS; context->fifo_write = 0; context->fifo_read = -1; @@ -250,12 +241,11 @@ if (!headless) { context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * context->border_top); } + return context; } void vdp_free(vdp_context *context) { - free(context->vdpmem); - free(context->linebuf); free(context); } @@ -528,6 +518,8 @@ context->regs[REG_DMASRC_H], 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]); + uint8_t old_flags = context->flags; + uint8_t old_flags2 = context->flags2; printf("\n**Internal Group**\n" "Address: %X\n" "CD: %X - %s\n" @@ -541,8 +533,9 @@ (context->flags & FLAG_PENDING) ? "word" : (context->flags2 & FLAG2_BYTE_PENDING) ? "byte" : "none", context->vcounter, context->hslot*2, (context->flags2 & FLAG2_VINT_PENDING) ? "true" : "false", (context->flags2 & FLAG2_HINT_PENDING) ? "true" : "false", vdp_control_port_read(context)); - - //TODO: Window Group, DMA Group + //restore flags as calling vdp_control_port_read can change them + context->flags = old_flags; + context->flags2 = old_flags2; } static uint8_t is_active(vdp_context *context) @@ -875,14 +868,17 @@ context->vdpmem[address] = value; } +#define DMA_FILL 0x80 +#define DMA_COPY 0xC0 +#define DMA_TYPE_MASK 0xC0 static void external_slot(vdp_context * context) { - if ((context->flags & FLAG_DMA_RUN) && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80 && context->fifo_read < 0) { + if ((context->flags & FLAG_DMA_RUN) && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_FILL && context->fifo_read < 0) { context->fifo_read = (context->fifo_write-1) & (FIFO_SIZE-1); fifo_entry * cur = context->fifo + context->fifo_read; cur->cycle = context->cycles; cur->address = context->address; - cur->partial = 2; + cur->partial = 1; vdp_advance_dma(context); } fifo_entry * start = context->fifo + context->fifo_read; @@ -893,20 +889,16 @@ if ((context->regs[REG_MODE_2] & (BIT_128K_VRAM|BIT_MODE_5)) == (BIT_128K_VRAM|BIT_MODE_5)) { vdp_check_update_sat(context, start->address, start->value); write_vram_word(context, start->address, start->value); - } else if (start->partial) { - //printf("VRAM Write: %X to %X at %d (line %d, slot %d)\n", start->value, start->address ^ 1, context->cycles, context->cycles/MCLKS_LINE, (context->cycles%MCLKS_LINE)/16); - uint8_t byte = start->partial == 2 ? start->value >> 8 : start->value; - if (start->partial > 1) { - vdp_check_update_sat_byte(context, start->address ^ 1, byte); - } + } else { + uint8_t byte = start->partial == 1 ? start->value >> 8 : start->value; + vdp_check_update_sat_byte(context, start->address ^ 1, byte); write_vram_byte(context, start->address ^ 1, byte); - } else { - //printf("VRAM Write High: %X to %X at %d (line %d, slot %d)\n", start->value >> 8, start->address, context->cycles, context->cycles/MCLKS_LINE, (context->cycles%MCLKS_LINE)/16); - vdp_check_update_sat(context, start->address, start->value); - write_vram_byte(context, start->address, start->value >> 8); - start->partial = 1; - //skip auto-increment and removal of entry from fifo - return; + if (!start->partial) { + start->address = start->address ^ 1; + start->partial = 1; + //skip auto-increment and removal of entry from fifo + return; + } } break; case CRAM_WRITE: { @@ -921,7 +913,7 @@ } write_cram(context, start->address, val); } else { - write_cram(context, start->address, start->partial == 2 ? context->fifo[context->fifo_write].value : start->value); + write_cram(context, start->address, start->partial ? context->fifo[context->fifo_write].value : start->value); } break; } @@ -937,7 +929,7 @@ context->vsram[(start->address/2) & 63] |= start->value; } } else { - context->vsram[(start->address/2) & 63] = start->partial == 2 ? context->fifo[context->fifo_write].value : start->value; + context->vsram[(start->address/2) & 63] = start->partial ? context->fifo[context->fifo_write].value : start->value; } } @@ -945,12 +937,12 @@ } context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1); if (context->fifo_read == context->fifo_write) { - if ((context->cd & 0x20) && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { + if ((context->cd & 0x20) && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_FILL) { context->flags |= FLAG_DMA_RUN; } context->fifo_read = -1; } - } else if ((context->flags & FLAG_DMA_RUN) && (context->regs[REG_DMASRC_H] & 0xC0) == 0xC0) { + } else if ((context->flags & FLAG_DMA_RUN) && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_COPY) { if (context->flags & FLAG_READ_FETCHED) { write_vram_byte(context, context->address ^ 1, context->prefetch); @@ -1275,6 +1267,7 @@ static void render_map_output(uint32_t line, int32_t col, vdp_context * context) { uint32_t *dst; + uint8_t *debug_dst; uint8_t output_disabled = (context->test_port & TEST_BIT_DISABLE) != 0; uint8_t test_layer = context->test_port >> 7 & 3; if (context->state == PREPARING && !test_layer) { @@ -1307,31 +1300,34 @@ { col-=2; dst = context->output + BORDER_LEFT + col * 8; - if (context->debug < 2) { - sprite_buf = context->linebuf + col * 8; - uint8_t a_src, src; - if (context->flags & FLAG_WINDOW) { - plane_a_off = context->buf_a_off; - a_src = DBG_SRC_W; - } else { - plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF); - a_src = DBG_SRC_A; - } - plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF); - //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7)); + debug_dst = context->layer_debug_buf + BORDER_LEFT + col * 8; + + sprite_buf = context->linebuf + col * 8; + uint8_t a_src, src; + if (context->flags & FLAG_WINDOW) { + plane_a_off = context->buf_a_off; + a_src = DBG_SRC_W; + } else { + plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF); + a_src = DBG_SRC_A; + } + plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF); + //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7)); - if (context->regs[REG_MODE_4] & BIT_HILIGHT) { - for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { - plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); - plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); - uint8_t pixel = context->regs[REG_BG_COLOR]; - uint32_t *colors = context->colors; - src = DBG_SRC_BG; + if (context->regs[REG_MODE_4] & BIT_HILIGHT) { + for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { + plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); + plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); + uint8_t pixel = context->regs[REG_BG_COLOR]; + uint32_t *colors = context->colors; + src = DBG_SRC_BG; + uint8_t intensity = 0; + if (col || !(context->regs[REG_MODE_1] & BIT_COL0_MASK) || i >= 8) { if (*plane_b & 0xF) { pixel = *plane_b; src = DBG_SRC_B; } - uint8_t intensity = *plane_b & BUF_BIT_PRIORITY; + intensity = *plane_b & BUF_BIT_PRIORITY; if (*plane_a & 0xF && (*plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) { pixel = *plane_a; src = a_src; @@ -1352,57 +1348,53 @@ } } } - if (output_disabled) { - pixel = 0x3F; - } - if (!intensity) { - src |= DBG_SHADOW; - colors += CRAM_SIZE; - } else if (intensity == BUF_BIT_PRIORITY*2) { - src |= DBG_HILIGHT; - colors += CRAM_SIZE*2; + } + if (output_disabled) { + pixel = 0x3F; + } + if (!intensity) { + src |= DBG_SHADOW; + colors += CRAM_SIZE; + } else if (intensity == BUF_BIT_PRIORITY*2) { + src |= DBG_HILIGHT; + colors += CRAM_SIZE*2; + } + //TODO: Verify how test register stuff interacts with shadow/highlight + //TODO: Simulate CRAM corruption from bus fight + switch (test_layer) + { + case 1: + pixel &= *sprite_buf; + if (output_disabled && pixel) { + src = DBG_SRC_S; } - //TODO: Verify how test register stuff interacts with shadow/highlight - //TODO: Simulate CRAM corruption from bus fight - switch (test_layer) - { - 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; + 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; } - - uint32_t outpixel; - if (context->debug) { - outpixel = context->debugcolors[src]; - } else { - outpixel = colors[pixel & 0x3F]; - } - *(dst++) = outpixel; + break; } - } else { - for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { - plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); - plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); - uint8_t pixel = context->regs[REG_BG_COLOR]; - src = DBG_SRC_BG; - if (output_disabled) { - pixel = 0x3F; - } else { + *(debug_dst++) = src; + *(dst++) = colors[pixel & 0x3F]; + } + } else { + for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { + plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); + plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); + uint8_t pixel = context->regs[REG_BG_COLOR]; + src = DBG_SRC_BG; + if (output_disabled) { + pixel = 0x3F; + } else { + if (col || !(context->regs[REG_MODE_1] & BIT_COL0_MASK) || i >= 8) { if (*plane_b & 0xF) { pixel = *plane_b; src = DBG_SRC_B; @@ -1416,83 +1408,36 @@ src = DBG_SRC_S; } } - //TODO: Simulate CRAM corruption from bus fight - switch (test_layer) - { - 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; - if (context->debug) { - outpixel = context->debugcolors[src]; - } else { - outpixel = context->colors[pixel & 0x3F]; - } - *(dst++) = outpixel; } - } - } else if (context->debug == 2) { - if (col < 32) { - *(dst++) = context->colors[col * 2]; - *(dst++) = context->colors[col * 2]; - *(dst++) = context->colors[col * 2]; - *(dst++) = context->colors[col * 2]; - *(dst++) = context->colors[col * 2 + 1]; - *(dst++) = context->colors[col * 2 + 1]; - *(dst++) = context->colors[col * 2 + 1]; - *(dst++) = context->colors[col * 2 + 1]; - *(dst++) = context->colors[col * 2 + 2]; - *(dst++) = context->colors[col * 2 + 2]; - *(dst++) = context->colors[col * 2 + 2]; - *(dst++) = context->colors[col * 2 + 2]; - *(dst++) = context->colors[col * 2 + 3]; - *(dst++) = context->colors[col * 2 + 3]; - *(dst++) = context->colors[col * 2 + 3]; - *(dst++) = context->colors[col * 2 + 3]; - } else if (col == 32 || line >= 192) { - for (int32_t i = 0; i < 16; i ++) { - *(dst++) = 0; + //TODO: Simulate CRAM corruption from bus fight + switch (test_layer) + { + 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; } - } else { - for (int32_t i = 0; i < 16; i ++) { - *(dst++) = context->colors[line / 3 + (col - 34) * 0x20]; - } - } - } else { - uint32_t base = (context->debug - 3) * 0x200; - uint32_t cell = base + (line / 8) * (context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32) + col; - uint32_t address = (cell * 32 + (line % 8) * 4) & 0xFFFF; - for (int32_t i = 0; i < 4; i ++) { - *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] >> 4)]; - *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] & 0xF)]; - address++; - } - cell++; - address = (cell * 32 + (line % 8) * 4) & 0xFFFF; - for (int32_t i = 0; i < 4; i ++) { - *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] >> 4)]; - *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] & 0xF)]; - address++; + *(dst++) = context->colors[pixel & 0x3F]; + *(debug_dst++) = src; } } } else { dst = context->output; + debug_dst = context->layer_debug_buf; uint8_t pixel = context->regs[REG_BG_COLOR] & 0x3F; if (output_disabled) { pixel = 0x3F; @@ -1503,9 +1448,11 @@ { case 1: bg_color = context->colors[0]; - for (int i = 0; i < BORDER_LEFT; i++, dst++) + for (int i = 0; i < BORDER_LEFT; i++, dst++, debug_dst++) { *dst = bg_color; + *debug_dst = DBG_SRC_BG; + } break; case 2: { @@ -1515,9 +1462,10 @@ i = 0; uint8_t buf_off = context->buf_a_off - (context->hscroll_a & 0xF) + (16 - BORDER_LEFT); //uint8_t *src = context->tmp_buf_a + ((context->buf_a_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_a & 0xF))) & SCROLL_BUFFER_MASK); - for (; i < BORDER_LEFT; buf_off++, i++, dst++) + for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++) { *dst = context->colors[context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK]]; + *debug_dst = DBG_SRC_A; } break; } @@ -1527,17 +1475,19 @@ i = 0; uint8_t buf_off = context->buf_b_off - (context->hscroll_b & 0xF) + (16 - BORDER_LEFT); //uint8_t *src = context->tmp_buf_b + ((context->buf_b_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_b & 0xF))) & SCROLL_BUFFER_MASK); - for (; i < BORDER_LEFT; buf_off++, i++, dst++) + for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++) { *dst = context->colors[context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK]]; + *debug_dst = DBG_SRC_B; } break; } } } else { - for (int i = 0; i < BORDER_LEFT; i++, dst++) + for (int i = 0; i < BORDER_LEFT; i++, dst++, debug_dst++) { *dst = bg_color; + *debug_dst = DBG_SRC_BG; } } } @@ -1588,6 +1538,7 @@ uint8_t bgcolor = 0x10 | (context->regs[REG_BG_COLOR] & 0xF) + CRAM_SIZE*3; uint32_t *dst = context->output + col * 8 + BORDER_LEFT; + uint8_t *debug_dst = context->layer_debug_buf + col * 8 + BORDER_LEFT; if (context->state == PREPARING) { for (int i = 0; i < 16; i++) { @@ -1596,65 +1547,30 @@ context->done_output = dst; return; } - if (context->debug < 2) { - if (col || !(context->regs[REG_MODE_1] & BIT_COL0_MASK)) { - uint8_t *sprite_src = context->linebuf + col * 8; - if (context->regs[REG_MODE_1] & BIT_SPRITE_8PX) { - sprite_src += 8; - } - for (int i = 0; i < 8; i++, sprite_src++) - { - uint8_t *bg_src = context->tmp_buf_a + ((8 + i + col * 8 - (context->hscroll_a & 0x7)) & 15); - if ((*bg_src & 0x4F) > 0x40 || !*sprite_src) { - //background plane has priority and is opaque or sprite layer is transparent - if (context->debug) { - *(dst++) = context->debugcolors[DBG_SRC_A]; - } else { - *(dst++) = context->colors[(*bg_src & 0x1F) + CRAM_SIZE*3]; - } - } else { - //sprite layer is opaque and not covered by high priority BG pixels - if (context->debug) { - *(dst++) = context->debugcolors[DBG_SRC_S]; - } else { - *(dst++) = context->colors[*sprite_src | 0x10 + CRAM_SIZE*3]; - } - } - } - } else { - for (int i = 0; i < 8; i++) - { - *(dst++) = context->colors[bgcolor]; + + if (col || !(context->regs[REG_MODE_1] & BIT_COL0_MASK)) { + uint8_t *sprite_src = context->linebuf + col * 8; + if (context->regs[REG_MODE_1] & BIT_SPRITE_8PX) { + sprite_src += 8; + } + for (int i = 0; i < 8; i++, sprite_src++) + { + uint8_t *bg_src = context->tmp_buf_a + ((8 + i + col * 8 - (context->hscroll_a & 0x7)) & 15); + if ((*bg_src & 0x4F) > 0x40 || !*sprite_src) { + //background plane has priority and is opaque or sprite layer is transparent + *(dst++) = context->colors[(*bg_src & 0x1F) + CRAM_SIZE*3]; + *(debug_dst++) = DBG_SRC_A; + } else { + //sprite layer is opaque and not covered by high priority BG pixels + *(dst++) = context->colors[*sprite_src | 0x10 + CRAM_SIZE*3]; + *(debug_dst++) = DBG_SRC_S; } } - } else if (context->debug == 2) { + } else { for (int i = 0; i < 8; i++) { - *(dst++) = context->colors[CRAM_SIZE*3 + col]; - } - } else { - uint32_t cell = (line / 8) * 32 + col; - uint32_t address = cell * 32 + (line % 8) * 4; - uint32_t m4_address = mode4_address_map[address & 0x3FFF]; - uint32_t pixel = planar_to_chunky[context->vdpmem[m4_address]] << 1; - pixel |= planar_to_chunky[context->vdpmem[m4_address + 1]]; - m4_address = mode4_address_map[(address + 2) & 0x3FFF]; - pixel |= planar_to_chunky[context->vdpmem[m4_address]] << 3; - pixel |= planar_to_chunky[context->vdpmem[m4_address + 1]] << 2; - if (context->debug_pal < 2) { - for (int i = 28; i >= 0; i -= 4) - { - *(dst++) = context->colors[CRAM_SIZE*3 | (context->debug_pal << 4) | (pixel >> i & 0xF)]; - } - } else { - for (int i = 28; i >= 0; i -= 4) - { - uint8_t value = (pixel >> i & 0xF) * 17; - if (context->debug_pal == 3) { - value = 255 - value; - } - *(dst++) = render_map_color(value, value, value); - } + *(dst++) = context->colors[bgcolor]; + *(debug_dst++) = DBG_SRC_BG; } } context->done_output = dst; @@ -1674,31 +1590,69 @@ } last_line = context->cycles; #endif - context->vcounter++; - + uint16_t jump_start, jump_end; 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->regs[REG_MODE_2] & BIT_PAL) { - if (context->vcounter == 0x10B) { - context->vcounter = 0x1D2; - } - } else if (context->vcounter == 0x103){ - context->vcounter = 0x1CA; + jump_start = 0x10B; + jump_end = 0x1D2; + } else { + jump_start = 0x103; + jump_end = 0x1CA; } + } else if (context->regs[REG_MODE_2] & BIT_PAL) { + jump_start = 0x100; + jump_end = 0x1FA; } else { - if (context->regs[REG_MODE_2] & BIT_PAL) { - if (context->vcounter == 0x100) { - context->vcounter = 0x1FA; + jump_start = 0xEB; + jump_end = 0x1E5; + } + } else { + jump_start = 0xDB; + jump_end = 0x1D5; + } + + if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM | 1 << VDP_DEBUG_COMPOSITE)) { + uint32_t line = context->vcounter; + if (line >= jump_end) { + line -= jump_end - jump_start; + } + uint32_t total_lines = (context->flags2 & FLAG2_REGION_PAL) ? 313 : 262; + + if (total_lines - line <= context->border_top) { + line -= total_lines - context->border_top; + } else { + line += context->border_top; + } + if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) { + uint32_t *fb = context->debug_fbs[VDP_DEBUG_CRAM] + context->debug_fb_pitch[VDP_DEBUG_CRAM] * line / sizeof(uint32_t); + for (int i = 0; i < 64; i++) + { + for (int x = 0; x < 8; x++) + { + *(fb++) = context->colors[i]; } - } else if (context->vcounter == 0xEB) { - context->vcounter = 0x1E5; } } - } else if (context->vcounter == 0xDB) { - context->vcounter = 0x1D5; + if ( + context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE) + && line < (context->inactive_start + context->border_bot + context->border_top) + ) { + uint32_t *fb = context->debug_fbs[VDP_DEBUG_COMPOSITE] + context->debug_fb_pitch[VDP_DEBUG_COMPOSITE] * line / sizeof(uint32_t); + for (int i = 0; i < LINEBUF_SIZE; i++) + { + *(fb++) = context->debugcolors[context->layer_debug_buf[i]]; + } + } } - context->vcounter &= 0x1FF; + + context->vcounter++; + if (context->vcounter == jump_start) { + context->vcounter = jump_end; + } else { + context->vcounter &= 0x1FF; + } if (context->state == PREPARING) { context->state = ACTIVE; } @@ -1717,6 +1671,190 @@ } } +static void vdp_update_per_frame_debug(vdp_context *context) +{ + if (context->enabled_debuggers & (1 << VDP_DEBUG_PLANE)) { + uint32_t pitch; + uint32_t *fb = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_PLANE], &pitch); + uint16_t hscroll_mask; + uint16_t v_mul; + uint16_t vscroll_mask = 0x1F | (context->regs[REG_SCROLL] & 0x30) << 1; + switch(context->regs[REG_SCROLL] & 0x3) + { + case 0: + hscroll_mask = 0x1F; + v_mul = 64; + break; + case 0x1: + hscroll_mask = 0x3F; + v_mul = 128; + break; + case 0x2: + //TODO: Verify this behavior + hscroll_mask = 0x1F; + v_mul = 0; + break; + case 0x3: + hscroll_mask = 0x7F; + v_mul = 256; + break; + } + uint16_t table_address; + switch(context->debug_modes[VDP_DEBUG_PLANE] % 3) + { + case 0: + table_address = context->regs[REG_SCROLL_A] << 10 & 0xE000; + break; + case 1: + table_address = context->regs[REG_SCROLL_B] << 13 & 0xE000; + break; + case 2: + table_address = context->regs[REG_WINDOW] << 10; + if (context->regs[REG_MODE_4] & BIT_H40) { + table_address &= 0xF000; + v_mul = 128; + hscroll_mask = 0x3F; + } else { + table_address &= 0xF800; + v_mul = 64; + hscroll_mask = 0x1F; + } + vscroll_mask = 0x1F; + break; + } + uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR & 0x3F]]; + for (uint16_t row = 0; row < 128; row++) + { + uint16_t row_address = table_address + (row & vscroll_mask) * v_mul; + for (uint16_t col = 0; col < 128; col++) + { + uint16_t address = row_address + (col & hscroll_mask) * 2; + //pccv hnnn nnnn nnnn + // + uint16_t entry = context->vdpmem[address] << 8 | context->vdpmem[address + 1]; + uint8_t pal = entry >> 9 & 0x30; + + uint32_t *dst = fb + (row * pitch * 8 / sizeof(uint32_t)) + col * 8; + address = (entry & 0x7FF) * 32; + int y_diff = 4; + if (entry & 0x1000) { + y_diff = -4; + address += 7 * 4; + } + int x_diff = 1; + if (entry & 0x800) { + x_diff = -1; + address += 3; + } + for (int y = 0; y < 8; y++) + { + uint16_t trow_address = address; + uint32_t *row_dst = dst; + for (int x = 0; x < 4; x++) + { + uint8_t byte = context->vdpmem[trow_address]; + trow_address += x_diff; + uint8_t left, right; + if (x_diff > 0) { + left = byte >> 4; + right = byte & 0xF; + } else { + left = byte & 0xF; + right = byte >> 4; + } + *(row_dst++) = left ? context->colors[left|pal] : bg_color; + *(row_dst++) = right ? context->colors[right|pal] : bg_color; + } + address += y_diff; + dst += pitch / sizeof(uint32_t); + } + } + } + render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_PLANE], 1024); + } + + if (context->enabled_debuggers & (1 << VDP_DEBUG_VRAM)) { + uint32_t pitch; + uint32_t *fb = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_VRAM], &pitch); + + uint8_t pal = (context->debug_modes[VDP_DEBUG_VRAM] % 4) << 4; + for (int y = 0; y < 512; y++) + { + uint32_t *line = fb + y * pitch / sizeof(uint32_t); + int row = y >> 4; + int yoff = y >> 1 & 7; + for (int col = 0; col < 64; col++) + { + uint16_t address = (row * 64 + col) * 32 + yoff * 4; + for (int x = 0; x < 4; x++) + { + uint8_t byte = context->vdpmem[address++]; + uint8_t left = byte >> 4 | pal; + uint8_t right = byte & 0xF | pal; + *(line++) = context->colors[left]; + *(line++) = context->colors[left]; + *(line++) = context->colors[right]; + *(line++) = context->colors[right]; + } + } + } + + render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_VRAM], 1024); + } + + if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) { + uint32_t starting_line = 512 - 32*4; + uint32_t *line = context->debug_fbs[VDP_DEBUG_CRAM] + + context->debug_fb_pitch[VDP_DEBUG_CRAM] * starting_line / sizeof(uint32_t); + for (int pal = 0; pal < 4; pal ++) + { + uint32_t *cur; + for (int y = 0; y < 31; y++) + { + cur = line; + for (int offset = 0; offset < 16; offset++) + { + for (int x = 0; x < 31; x++) + { + *(cur++) = context->colors[pal * 16 + offset]; + } + *(cur++) = 0xFF000000; + } + line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t); + } + cur = line; + for (int x = 0; x < 512; x++) + { + *(cur++) = 0xFF000000; + } + line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t); + } + render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_CRAM], 512); + context->debug_fbs[VDP_DEBUG_CRAM] = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_CRAM], &context->debug_fb_pitch[VDP_DEBUG_CRAM]); + } + if (context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE)) { + render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_COMPOSITE], LINEBUF_SIZE); + context->debug_fbs[VDP_DEBUG_COMPOSITE] = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_COMPOSITE], &context->debug_fb_pitch[VDP_DEBUG_COMPOSITE]); + } +} + +void vdp_force_update_framebuffer(vdp_context *context) +{ + 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; + + uint16_t to_fill = lines_max - context->output_lines; + memset( + ((char *)context->fb) + context->output_pitch * context->output_lines, + 0, + to_fill * context->output_pitch + ); + render_framebuffer_updated(context->cur_buffer, context->h40_lines > context->output_lines / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER)); + context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch); + vdp_update_per_frame_debug(context); +} + static void advance_output_line(vdp_context *context) { if (headless) { @@ -1733,6 +1871,7 @@ render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER)); context->cur_buffer = context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD; context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch); + vdp_update_per_frame_debug(context); context->h40_lines = 0; context->frame++; context->output_lines = 0; @@ -2763,18 +2902,26 @@ active_line = 0x200; } } - uint32_t *dst = ( - context->vcounter < context->inactive_start + context->border_bot - || context->vcounter >= 0x200 - context->border_top - ) && context->hslot >= BG_START_SLOT && context->hslot < bg_end_slot - ? context->output + 2 * (context->hslot - BG_START_SLOT) - : NULL; + uint32_t *dst; + uint8_t *debug_dst; + if ( + ( + context->vcounter < context->inactive_start + context->border_bot + || context->vcounter >= 0x200 - context->border_top + ) && context->hslot >= BG_START_SLOT && context->hslot < bg_end_slot + ) { + dst = context->output + 2 * (context->hslot - BG_START_SLOT); + debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT); + } else { + dst = NULL; + } if ( !dst && context->vcounter == context->inactive_start + context->border_bot && context->hslot >= line_change && context->hslot < bg_end_slot ) { dst = context->output + 2 * (context->hslot - BG_START_SLOT); + debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT); } uint8_t test_layer = context->test_port >> 7 & 3; @@ -2790,6 +2937,7 @@ || context->vcounter >= 0x200 - context->border_top )) { dst = context->output + (context->hslot - BG_START_SLOT) * 2; + debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT); } else if (context->hslot == bg_end_slot) { advance_output_line(context); dst = NULL; @@ -2850,17 +2998,22 @@ } if (dst >= context->done_output) { *(dst++) = bg_color; + *(debug_dst++) = DBG_SRC_BG; } else { dst++; + debug_dst++; } if (dst >= context->done_output) { *(dst++) = bg_color; + *(debug_dst++) = DBG_SRC_BG; context->done_output = dst; } else { dst++; + debug_dst++; } if (context->hslot == (bg_end_slot-1)) { *(dst++) = bg_color; + *(debug_dst++) = DBG_SRC_BG; context->done_output = dst; } } @@ -2949,7 +3102,7 @@ } uint32_t min_dma_complete = dmalen * (context->regs[REG_MODE_4] & BIT_H40 ? 16 : 20); if ( - (context->regs[REG_DMASRC_H] & 0xC0) == 0xC0 + (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_COPY || (((context->cd & 0xF) == VRAM_WRITE) && !(context->regs[REG_MODE_2] & BIT_128K_VRAM))) { //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 @@ -3025,7 +3178,7 @@ //printf("New Address: %X, New CD: %X\n", context->address, context->cd); if (context->cd & 0x20) { // - if((context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { + if((context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) != DMA_FILL) { //DMA copy or 68K -> VDP, transfer starts immediately //printf("DMA start (length: %X) at cycle %d, frame: %d, vcounter: %d, hslot: %d\n", (context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L], context->cycles, context->frame, context->vcounter, context->hslot); if (!(context->regs[REG_DMASRC_H] & 0x80)) { @@ -3106,7 +3259,7 @@ int vdp_data_port_write(vdp_context * context, uint16_t value) { //printf("data port write: %X at %d\n", value, context->cycles); - if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { + if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) != DMA_FILL) { return -1; } if (context->flags & FLAG_PENDING) { @@ -3118,7 +3271,7 @@ /*if (context->fifo_cur == context->fifo_end) { printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles); }*/ - if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { + if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_FILL) { context->flags &= ~FLAG_DMA_RUN; } while (context->fifo_write == context->fifo_read) { @@ -3154,7 +3307,7 @@ /*if (context->fifo_cur == context->fifo_end) { printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles); }*/ - if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { + if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_FILL) { context->flags &= ~FLAG_DMA_RUN; } while (context->fifo_write == context->fifo_read) { @@ -3721,3 +3874,63 @@ context->pending_hint_start = load_int32(buf); update_video_params(context); } + +void vdp_toggle_debug_view(vdp_context *context, uint8_t debug_type) +{ + if (context->enabled_debuggers & 1 << debug_type) { + render_destroy_window(context->debug_fb_indices[debug_type]); + context->enabled_debuggers &= ~(1 << debug_type); + } else { + uint32_t width,height; + uint8_t fetch_immediately = 0; + char *caption; + switch(debug_type) + { + case VDP_DEBUG_PLANE: + caption = "BlastEm - VDP Plane Debugger"; + width = height = 1024; + break; + case VDP_DEBUG_VRAM: + caption = "BlastEm - VDP VRAM Debugger"; + width = 1024; + height = 512; + break; + case VDP_DEBUG_CRAM: + caption = "BlastEm - VDP CRAM Debugger"; + width = 512; + height = 512; + fetch_immediately = 1; + break; + case VDP_DEBUG_COMPOSITE: + caption = "BlastEm - VDP Plane Composition Debugger"; + width = LINEBUF_SIZE; + height = context->inactive_start + context->border_top + context->border_bot; + fetch_immediately = 1; + break; + default: + return; + } + context->debug_fb_indices[debug_type] = render_create_window(caption, width, height); + if (context->debug_fb_indices[debug_type]) { + context->enabled_debuggers |= 1 << debug_type; + } + if (fetch_immediately) { + context->debug_fbs[debug_type] = render_get_framebuffer(context->debug_fb_indices[debug_type], &context->debug_fb_pitch[debug_type]); + } + } +} + +void vdp_inc_debug_mode(vdp_context *context) +{ + uint8_t active = render_get_active_framebuffer(); + if (active < FRAMEBUFFER_USER_START) { + return; + } + for (int i = 0; i < VDP_NUM_DEBUG_TYPES; i++) + { + if (context->enabled_debuggers & (1 << i) && context->debug_fb_indices[i] == active) { + context->debug_modes[i]++; + return; + } + } +}