From f55d4a3023f1dc520b54bca1cd4bcb334a0ba25c Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Fri, 12 Jul 2013 19:11:55 -0700 Subject: Implement the scroll ring buffer properly without memcpy --- vdp.c | 54 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 26 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index bc39390..265b006 100644 --- a/vdp.c +++ b/vdp.c @@ -12,7 +12,8 @@ #define MAP_BIT_V_FLIP 0x1000 #define SCROLL_BUFFER_SIZE 32 -#define SCROLL_BUFFER_DRAW 16 +#define SCROLL_BUFFER_MASK (SCROLL_BUFFER_SIZE-1) +#define SCROLL_BUFFER_DRAW (SCROLL_BUFFER_SIZE/2) #define FIFO_SIZE 4 @@ -612,7 +613,7 @@ void read_map_scroll_b(uint16_t column, uint32_t line, vdp_context * context) read_map_scroll(column, 1, line, (context->regs[REG_SCROLL_B] & 0x7) << 13, context->hscroll_b, context); } -void render_map(uint16_t col, uint8_t * tmp_buf, vdp_context * context) +void render_map(uint16_t col, uint8_t * tmp_buf, uint8_t offset, vdp_context * context) { uint16_t address; uint8_t shift, add; @@ -633,33 +634,36 @@ void render_map(uint16_t col, uint8_t * tmp_buf, vdp_context * context) uint16_t pal_priority = (col >> 9) & 0x70; int32_t dir; if (col & MAP_BIT_H_FLIP) { - tmp_buf += 7; + offset += 7; + offset &= SCROLL_BUFFER_MASK; dir = -1; } else { dir = 1; } for (uint32_t i=0; i < 4; i++, address++) { - *tmp_buf = pal_priority | (context->vdpmem[address] >> 4); - tmp_buf += dir; - *tmp_buf = pal_priority | (context->vdpmem[address] & 0xF); - tmp_buf += dir; + tmp_buf[offset] = pal_priority | (context->vdpmem[address] >> 4); + offset += dir; + offset &= SCROLL_BUFFER_MASK; + tmp_buf[offset] = pal_priority | (context->vdpmem[address] & 0xF); + offset += dir; + offset &= SCROLL_BUFFER_MASK; } } void render_map_1(vdp_context * context) { - render_map(context->col_1, context->tmp_buf_a+SCROLL_BUFFER_DRAW, context); + render_map(context->col_1, context->tmp_buf_a, context->buf_a_off, context); } void render_map_2(vdp_context * context) { - render_map(context->col_2, context->tmp_buf_a+SCROLL_BUFFER_DRAW+8, context); + render_map(context->col_2, context->tmp_buf_a, context->buf_a_off+8, context); } void render_map_3(vdp_context * context) { - render_map(context->col_1, context->tmp_buf_b+SCROLL_BUFFER_DRAW, context); + render_map(context->col_1, context->tmp_buf_b, context->buf_b_off, context); } void render_map_output(uint32_t line, int32_t col, vdp_context * context) @@ -667,10 +671,11 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context) if (line >= 240) { return; } - render_map(context->col_2, context->tmp_buf_b+SCROLL_BUFFER_DRAW+8, context); + render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context); uint16_t *dst; uint32_t *dst32; - uint8_t *sprite_buf, *plane_a, *plane_b; + uint8_t *sprite_buf, *plane_a, *plane_b; + int plane_a_off, plane_b_off; if (col) { col-=2; @@ -684,20 +689,21 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context) sprite_buf = context->linebuf + col * 8; uint16_t a_src; if (context->flags & FLAG_WINDOW) { - plane_a = context->tmp_buf_a + SCROLL_BUFFER_DRAW; + plane_a_off = context->buf_a_off; //a_src = FBUF_SRC_W; } else { - plane_a = context->tmp_buf_a + SCROLL_BUFFER_DRAW - (context->hscroll_a & 0xF); + plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF); //a_src = FBUF_SRC_A; } - plane_b = context->tmp_buf_b + SCROLL_BUFFER_DRAW - (context->hscroll_b & 0xF); + plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF); uint16_t src; //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, ++plane_b, ++sprite_buf, ++i) { + for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { uint8_t pixel; - + plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); + plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); src = 0; uint8_t sprite_color = *sprite_buf & 0x3F; if (sprite_color == 0x3E || sprite_color == 0x3F) { @@ -765,8 +771,10 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context) //*dst = (context->cram[pixel & 0x3F] & 0xEEE) | ((pixel & BUF_BIT_PRIORITY) ? FBUF_BIT_PRIORITY : 0) | src; } } else { - for (int i = 0; i < 16; ++plane_a, ++plane_b, ++sprite_buf, ++i) { + for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { uint8_t pixel; + plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); + plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); if (*sprite_buf & BUF_BIT_PRIORITY && *sprite_buf & 0xF) { pixel = *sprite_buf; //src = FBUF_SRC_S; @@ -804,14 +812,8 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context) //plane_b = context->tmp_buf_b + 16 - (context->hscroll_b & 0x7); //end = dst + 8; } - - uint16_t remaining; - if (!(context->flags & FLAG_WINDOW)) { - remaining = context->hscroll_a & 0xF; - memcpy(context->tmp_buf_a + SCROLL_BUFFER_DRAW - remaining, context->tmp_buf_a + SCROLL_BUFFER_SIZE - remaining, remaining); - } - remaining = context->hscroll_b & 0xF; - memcpy(context->tmp_buf_b + SCROLL_BUFFER_DRAW - remaining, context->tmp_buf_b + SCROLL_BUFFER_SIZE - remaining, remaining); + context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; + context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; } #define COLUMN_RENDER_BLOCK(column, startcyc) \ -- cgit v1.2.3 From de1c3145d57e6efc3022012d26744f7a79e3cde2 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Mon, 15 Jul 2013 23:07:45 -0700 Subject: Restore one of the VDP debugging modes --- vdp.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 99 insertions(+), 34 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 265b006..0eb0655 100644 --- a/vdp.c +++ b/vdp.c @@ -31,6 +31,14 @@ int32_t color_map[1 << 12]; uint8_t levels[] = {0, 27, 49, 71, 87, 103, 119, 130, 146, 157, 174, 190, 206, 228, 255}; +uint8_t debug_base[][3] = { + {127, 127, 127}, //BG + {0, 0, 127}, //A + {127, 0, 0}, //Window + {0, 127, 0}, //B + {127, 0, 127} //Sprites +}; + uint8_t color_map_init_done; void init_vdp_context(vdp_context * context) @@ -70,6 +78,47 @@ void init_vdp_context(vdp_context * context) } color_map_init_done = 1; } + for (uint8_t color = 0; color < (1 << (3 + 1 + 1 + 1)); color++) + { + uint8_t src = color & DBG_SRC_MASK; + if (src > DBG_SRC_S) { + context->debugcolors[color] = 0; + } else { + uint8_t r,g,b; + b = debug_base[src][0]; + g = debug_base[src][1]; + r = debug_base[src][2]; + if (color & DBG_PRIORITY) + { + if (b) { + b += 48; + } + if (g) { + g += 48; + } + if (r) { + r += 48; + } + } + if (color & DBG_SHADOW) { + b /= 2; + g /= 2; + r /=2 ; + } + if (color & DBG_HILIGHT) { + if (b) { + b += 72; + } + if (g) { + g += 72; + } + if (r) { + r += 72; + } + } + context->debugcolors[color] = render_map_color(r, g, b); + } + } } void render_sprite_cells(vdp_context * context) @@ -687,16 +736,15 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context) dst += line * 320 + col * 8; } sprite_buf = context->linebuf + col * 8; - uint16_t a_src; + uint8_t a_src, src; if (context->flags & FLAG_WINDOW) { plane_a_off = context->buf_a_off; - //a_src = FBUF_SRC_W; + a_src = DBG_SRC_W; } else { plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF); - //a_src = FBUF_SRC_A; + a_src = DBG_SRC_A; } plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF); - uint16_t src; //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7)); if (context->regs[REG_MODE_4] & BIT_HILIGHT) { @@ -704,103 +752,120 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context) uint8_t pixel; plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); + uint32_t * colors = context->colors; src = 0; uint8_t sprite_color = *sprite_buf & 0x3F; if (sprite_color == 0x3E || sprite_color == 0x3F) { if (sprite_color == 0x3F) { - src = CRAM_SIZE;//FBUF_SHADOW; + colors += CRAM_SIZE; + src = DBG_SHADOW; } else { - src = CRAM_SIZE*2;//FBUF_HILIGHT; + colors += CRAM_SIZE*2; + src = DBG_HILIGHT; } if (*plane_a & BUF_BIT_PRIORITY && *plane_a & 0xF) { pixel = *plane_a; - //src |= a_src; + src |= a_src; } else if (*plane_b & BUF_BIT_PRIORITY && *plane_b & 0xF) { pixel = *plane_b; - //src |= FBUF_SRC_B; + src |= DBG_SRC_B; } else if (*plane_a & 0xF) { pixel = *plane_a; - //src |= a_src; + src |= a_src; } else if (*plane_b & 0xF){ pixel = *plane_b; - //src |= FBUF_SRC_B; + src |= DBG_SRC_B; } else { pixel = context->regs[REG_BG_COLOR] & 0x3F; - //src |= FBUF_SRC_BG; + src |= DBG_SRC_BG; } } else { if (*sprite_buf & BUF_BIT_PRIORITY && *sprite_buf & 0xF) { pixel = *sprite_buf; - //src = FBUF_SRC_S; + src = DBG_SRC_S; } else if (*plane_a & BUF_BIT_PRIORITY && *plane_a & 0xF) { pixel = *plane_a; - //src = a_src; + src = a_src; } else if (*plane_b & BUF_BIT_PRIORITY && *plane_b & 0xF) { pixel = *plane_b; - //src = FBUF_SRC_B; + src = DBG_SRC_B; } else { if (!(*plane_a & BUF_BIT_PRIORITY || *plane_a & BUF_BIT_PRIORITY)) { - src = CRAM_SIZE;//FBUF_SHADOW; + colors += CRAM_SIZE; + src = DBG_SHADOW; } if (*sprite_buf & 0xF) { pixel = *sprite_buf; if (*sprite_buf & 0xF == 0xE) { - src = 0;//FBUF_SRC_S; - } /*else { - src |= FBUF_SRC_S; - }*/ + colors = context->colors; + src = DBG_SRC_S; + } else { + src |= DBG_SRC_S; + } } else if (*plane_a & 0xF) { pixel = *plane_a; - //src |= a_src; + src |= a_src; } else if (*plane_b & 0xF){ pixel = *plane_b; - //src |= FBUF_SRC_B; + src |= DBG_SRC_B; } else { pixel = context->regs[REG_BG_COLOR] & 0x3F; - //src |= FBUF_SRC_BG; + src |= DBG_SRC_BG; } } } pixel &= 0x3F; - pixel += src; + uint32_t outpixel; + if (context->debug) { + outpixel = context->debugcolors[src]; + } else { + outpixel = colors[pixel]; + } if (context->b32) { - *(dst32++) = context->colors[pixel]; + *(dst32++) = outpixel; } else { - *(dst++) = context->colors[pixel]; + *(dst++) = outpixel; } //*dst = (context->cram[pixel & 0x3F] & 0xEEE) | ((pixel & BUF_BIT_PRIORITY) ? FBUF_BIT_PRIORITY : 0) | src; } } else { for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { uint8_t pixel; + src = 0; plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); if (*sprite_buf & BUF_BIT_PRIORITY && *sprite_buf & 0xF) { pixel = *sprite_buf; - //src = FBUF_SRC_S; + src = DBG_SRC_S; } else if (*plane_a & BUF_BIT_PRIORITY && *plane_a & 0xF) { pixel = *plane_a; - //src = a_src; + src = a_src; } else if (*plane_b & BUF_BIT_PRIORITY && *plane_b & 0xF) { pixel = *plane_b; - //src = FBUF_SRC_B; + src = DBG_SRC_B; } else if (*sprite_buf & 0xF) { pixel = *sprite_buf; - //src = FBUF_SRC_S; + src = DBG_SRC_S; } else if (*plane_a & 0xF) { pixel = *plane_a; - //src = a_src; + src = a_src; } else if (*plane_b & 0xF){ pixel = *plane_b; - //src = FBUF_SRC_B; + src = DBG_SRC_B; } else { pixel = context->regs[REG_BG_COLOR] & 0x3F; - //src = FBUF_SRC_BG; + src = DBG_SRC_BG; + } + uint32_t outpixel; + if (context->debug) { + outpixel = context->debugcolors[src]; + } else { + outpixel = context->colors[pixel & 0x3F]; } if (context->b32) { - *(dst32++) = context->colors[pixel & 0x3F]; + *(dst32++) = outpixel; } else { - *(dst++) = context->colors[pixel & 0x3F]; + *(dst++) = outpixel; } //*dst = (context->cram[pixel & 0x3F] & 0xEEE) | ((pixel & BUF_BIT_PRIORITY) ? FBUF_BIT_PRIORITY : 0) | src; } -- cgit v1.2.3 From 079a2c40b940e7ed09aa727effb2981a1eed4839 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Tue, 16 Jul 2013 23:16:14 -0700 Subject: Add address/cd registers to VDP debug message --- vdp.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 0eb0655..7154548 100644 --- a/vdp.c +++ b/vdp.c @@ -207,6 +207,11 @@ 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]); + printf("\n**Internal Group**\n" + "Address: %X\n" + "CD: %X\n" + "Pending: %s\n", + context->address, context->cd, (context->flags & FLAG_PENDING) ? "true" : "false"); //TODO: Window Group, DMA Group } -- cgit v1.2.3 From a75eb24bfbbf0dd3492c8414cfaafa0569a1539a Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Fri, 26 Jul 2013 19:55:04 -0700 Subject: Added support for saving savestates. Added gst savestate format test harness --- vdp.c | 91 +++++++++++-------------------------------------------------------- 1 file changed, 15 insertions(+), 76 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 7154548..6e20009 100644 --- a/vdp.c +++ b/vdp.c @@ -125,7 +125,7 @@ void render_sprite_cells(vdp_context * context) { if (context->cur_slot >= context->sprite_draws) { sprite_draw * d = context->sprite_draw_list + context->cur_slot; - + uint16_t dir; int16_t x; if (d->h_flip) { @@ -164,7 +164,7 @@ void vdp_print_sprite_table(vdp_context * context) uint16_t link = context->vdpmem[address+3] & 0x7F; uint8_t pal = context->vdpmem[address + 4] >> 5 & 0x3; uint8_t pri = context->vdpmem[address + 4] >> 7; - uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5; + uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5; //printf("Sprite %d: X=%d(%d), Y=%d(%d), Width=%u, Height=%u, Link=%u, Pal=%u, Pri=%u, Pat=%X\n", current_index, x, x-128, y, y-128, width, height, link, pal, pri, pattern); current_index = link; count++; @@ -179,9 +179,9 @@ void vdp_print_reg_explain(vdp_context * context) "01: %.2X | Display %s, V-ints %s, Height: %d, Mode %d\n" "0B: %.2X | E-ints %s, V-Scroll: %s, H-Scroll: %s\n" "0C: %.2X | Width: %d, Shadow/Highlight: %s\n", - context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_PAL_SEL != 0, + context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_PAL_SEL != 0, context->regs[REG_MODE_1] & BIT_HVC_LATCH ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_DISP_DIS ? "disabled" : "enabled", - context->regs[REG_MODE_2], context->regs[REG_MODE_2] & BIT_DISP_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_VINT_EN ? "enabled" : "disabled", + context->regs[REG_MODE_2], context->regs[REG_MODE_2] & BIT_DISP_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_VINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_PAL ? 30 : 28, context->regs[REG_MODE_2] & BIT_MODE_5 ? 5 : 4, context->regs[REG_MODE_3], context->regs[REG_MODE_3] & BIT_EINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_3] & BIT_VSCROLL ? "2 cell" : "full", hscroll[context->regs[REG_MODE_3] & 0x3], @@ -203,8 +203,8 @@ void vdp_print_reg_explain(vdp_context * context) "0A: %.2X | H-Int Counter: %u\n" "0F: %.2X | Auto-increment: $%X\n" "10: %.2X | Scroll A/B Size: %sx%s\n", - context->regs[REG_BG_COLOR], context->regs[REG_BG_COLOR] & 0x3F, - context->regs[REG_HINT], context->regs[REG_HINT], + context->regs[REG_BG_COLOR], context->regs[REG_BG_COLOR] & 0x3F, + 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]); printf("\n**Internal Group**\n" @@ -212,8 +212,8 @@ void vdp_print_reg_explain(vdp_context * context) "CD: %X\n" "Pending: %s\n", context->address, context->cd, (context->flags & FLAG_PENDING) ? "true" : "false"); - - //TODO: Window Group, DMA Group + + //TODO: Window Group, DMA Group } void scan_sprite_table(uint32_t line, vdp_context * context) @@ -295,7 +295,7 @@ void read_sprite_x(uint32_t line, vdp_context * context) height *= 2; } uint16_t att_addr = ((context->regs[REG_SAT] & 0x7F) << 9) + context->sprite_info_list[context->cur_slot].index * 8 + 4; - uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1]; + uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1]; uint8_t pal_priority = (tileinfo >> 9) & 0x70; uint8_t row; if (tileinfo & MAP_BIT_V_FLIP) { @@ -315,7 +315,7 @@ void read_sprite_x(uint32_t line, vdp_context * context) } else if(context->flags & (FLAG_CAN_MASK | FLAG_DOT_OFLOW)) { context->flags |= FLAG_MASKED; } - + context->flags &= ~FLAG_DOT_OFLOW; int16_t i; if (context->flags & FLAG_MASKED) { @@ -415,7 +415,7 @@ void external_slot(vdp_context * context) context->dma_val = (context->dma_val << 8) | ((context->dma_val >> 8) & 0xFF); break; case CRAM_WRITE: - write_cram(context, context->address, context->dma_val); + write_cram(context, context->address, context->dma_val); //printf("CRAM DMA Fill | %X set to %X at %d\n", (context->address/2) & (CRAM_SIZE-1), context->cram[(context->address/2) & (CRAM_SIZE-1)], context->cycles); break; case VSRAM_WRITE: @@ -575,7 +575,7 @@ void read_map_scroll(uint16_t column, uint16_t vsram_off, uint32_t line, uint16_ address &= 0xF000; line_offset = (((line) >> vscroll_shift) * 64 * 2) & 0xFFF; mask = 0x7F; - + } else { address &= 0xF800; line_offset = (((line) >> vscroll_shift) * 32 * 2) & 0xFFF; @@ -751,7 +751,7 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context) } plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF); //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7)); - + if (context->regs[REG_MODE_4] & BIT_HILIGHT) { for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { uint8_t pixel; @@ -1402,9 +1402,9 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) } 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 + //it's used for gathering sprite info for line line = (line - 1) & 0xFF; - + //Convert to slot number if (context->latched_mode & BIT_H40){ vdp_h40(line, slot, context); @@ -1789,64 +1789,3 @@ void vdp_int_ack(vdp_context * context, uint16_t int_num) } } -#define GST_VDP_REGS 0xFA -#define GST_VDP_MEM 0x12478 - -uint8_t vdp_load_gst(vdp_context * context, FILE * state_file) -{ - uint8_t tmp_buf[CRAM_SIZE*2]; - fseek(state_file, GST_VDP_REGS, SEEK_SET); - if (fread(context->regs, 1, VDP_REGS, state_file) != VDP_REGS) { - fputs("Failed to read VDP registers from savestate\n", stderr); - return 0; - } - context->double_res = (context->regs[REG_MODE_4] & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); - if (!context->double_res) { - context->framebuf = context->oddbuf; - } - latch_mode(context); - if (fread(tmp_buf, 1, sizeof(tmp_buf), state_file) != sizeof(tmp_buf)) { - fputs("Failed to read CRAM from savestate\n", stderr); - return 0; - } - for (int i = 0; i < CRAM_SIZE; i++) { - uint16_t value; - context->cram[i] = value = (tmp_buf[i*2+1] << 8) | tmp_buf[i*2]; - context->colors[i] = color_map[value & 0xEEE]; - context->colors[i + CRAM_SIZE] = color_map[(value & 0xEEE) | FBUF_SHADOW]; - context->colors[i + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT]; - } - if (fread(tmp_buf, 2, VSRAM_SIZE, state_file) != VSRAM_SIZE) { - fputs("Failed to read VSRAM from savestate\n", stderr); - return 0; - } - for (int i = 0; i < VSRAM_SIZE; i++) { - context->vsram[i] = (tmp_buf[i*2+1] << 8) | tmp_buf[i*2]; - } - fseek(state_file, GST_VDP_MEM, SEEK_SET); - if (fread(context->vdpmem, 1, VRAM_SIZE, state_file) != VRAM_SIZE) { - fputs("Failed to read VRAM from savestate\n", stderr); - return 0; - } - return 1; -} - -void vdp_save_state(vdp_context * context, FILE * outfile) -{ - uint8_t tmp_buf[CRAM_SIZE*2]; - fseek(outfile, GST_VDP_REGS, SEEK_SET); - fwrite(context->regs, 1, VDP_REGS, outfile); - for (int i = 0; i < CRAM_SIZE; i++) { - tmp_buf[i*2] = context->cram[i]; - tmp_buf[i*2+1] = context->cram[i] >> 8; - } - fwrite(tmp_buf, 1, sizeof(tmp_buf), outfile); - for (int i = 0; i < VSRAM_SIZE; i++) { - tmp_buf[i*2] = context->vsram[i]; - tmp_buf[i*2+1] = context->vsram[i] >> 8; - } - fwrite(tmp_buf, 2, VSRAM_SIZE, outfile); - fseek(outfile, GST_VDP_MEM, SEEK_SET); - fwrite(context->vdpmem, 1, VRAM_SIZE, outfile); -} - -- cgit v1.2.3 From 48e201cf39a18628e33d51a7fba1ee706af18ade Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Sun, 1 Sep 2013 12:11:28 -0700 Subject: Fix bug that caused a DMA fill to start after another DMA operation completed if the FIFO is not empty --- vdp.c | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 7154548..8b2bdaf 100644 --- a/vdp.c +++ b/vdp.c @@ -125,7 +125,7 @@ void render_sprite_cells(vdp_context * context) { if (context->cur_slot >= context->sprite_draws) { sprite_draw * d = context->sprite_draw_list + context->cur_slot; - + uint16_t dir; int16_t x; if (d->h_flip) { @@ -164,7 +164,7 @@ void vdp_print_sprite_table(vdp_context * context) uint16_t link = context->vdpmem[address+3] & 0x7F; uint8_t pal = context->vdpmem[address + 4] >> 5 & 0x3; uint8_t pri = context->vdpmem[address + 4] >> 7; - uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5; + uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5; //printf("Sprite %d: X=%d(%d), Y=%d(%d), Width=%u, Height=%u, Link=%u, Pal=%u, Pri=%u, Pat=%X\n", current_index, x, x-128, y, y-128, width, height, link, pal, pri, pattern); current_index = link; count++; @@ -179,9 +179,9 @@ void vdp_print_reg_explain(vdp_context * context) "01: %.2X | Display %s, V-ints %s, Height: %d, Mode %d\n" "0B: %.2X | E-ints %s, V-Scroll: %s, H-Scroll: %s\n" "0C: %.2X | Width: %d, Shadow/Highlight: %s\n", - context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_PAL_SEL != 0, + context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_PAL_SEL != 0, context->regs[REG_MODE_1] & BIT_HVC_LATCH ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_DISP_DIS ? "disabled" : "enabled", - context->regs[REG_MODE_2], context->regs[REG_MODE_2] & BIT_DISP_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_VINT_EN ? "enabled" : "disabled", + context->regs[REG_MODE_2], context->regs[REG_MODE_2] & BIT_DISP_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_VINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_PAL ? 30 : 28, context->regs[REG_MODE_2] & BIT_MODE_5 ? 5 : 4, context->regs[REG_MODE_3], context->regs[REG_MODE_3] & BIT_EINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_3] & BIT_VSCROLL ? "2 cell" : "full", hscroll[context->regs[REG_MODE_3] & 0x3], @@ -203,8 +203,8 @@ void vdp_print_reg_explain(vdp_context * context) "0A: %.2X | H-Int Counter: %u\n" "0F: %.2X | Auto-increment: $%X\n" "10: %.2X | Scroll A/B Size: %sx%s\n", - context->regs[REG_BG_COLOR], context->regs[REG_BG_COLOR] & 0x3F, - context->regs[REG_HINT], context->regs[REG_HINT], + context->regs[REG_BG_COLOR], context->regs[REG_BG_COLOR] & 0x3F, + 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]); printf("\n**Internal Group**\n" @@ -212,8 +212,8 @@ void vdp_print_reg_explain(vdp_context * context) "CD: %X\n" "Pending: %s\n", context->address, context->cd, (context->flags & FLAG_PENDING) ? "true" : "false"); - - //TODO: Window Group, DMA Group + + //TODO: Window Group, DMA Group } void scan_sprite_table(uint32_t line, vdp_context * context) @@ -295,7 +295,7 @@ void read_sprite_x(uint32_t line, vdp_context * context) height *= 2; } uint16_t att_addr = ((context->regs[REG_SAT] & 0x7F) << 9) + context->sprite_info_list[context->cur_slot].index * 8 + 4; - uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1]; + uint16_t tileinfo = (context->vdpmem[att_addr] << 8) | context->vdpmem[att_addr+1]; uint8_t pal_priority = (tileinfo >> 9) & 0x70; uint8_t row; if (tileinfo & MAP_BIT_V_FLIP) { @@ -315,7 +315,7 @@ void read_sprite_x(uint32_t line, vdp_context * context) } else if(context->flags & (FLAG_CAN_MASK | FLAG_DOT_OFLOW)) { context->flags |= FLAG_MASKED; } - + context->flags &= ~FLAG_DOT_OFLOW; int16_t i; if (context->flags & FLAG_MASKED) { @@ -415,7 +415,7 @@ void external_slot(vdp_context * context) context->dma_val = (context->dma_val << 8) | ((context->dma_val >> 8) & 0xFF); break; case CRAM_WRITE: - write_cram(context, context->address, context->dma_val); + write_cram(context, context->address, context->dma_val); //printf("CRAM DMA Fill | %X set to %X at %d\n", (context->address/2) & (CRAM_SIZE-1), context->cram[(context->address/2) & (CRAM_SIZE-1)], context->cycles); break; case VSRAM_WRITE: @@ -478,13 +478,15 @@ void external_slot(vdp_context * context) context->regs[REG_DMALEN_H] = dma_len >> 8; context->regs[REG_DMALEN_L] = dma_len; if (!dma_len) { + printf("DMA end at cycle %d\n", context->cycles); context->flags &= ~FLAG_DMA_RUN; } } } else { fifo_entry * start = (context->fifo_end - FIFO_SIZE); if (context->fifo_cur != start && start->cycle <= context->cycles) { - if ((context->regs[REG_MODE_2] & BIT_DMA_ENABLE) && (context->cd & DMA_START)) { + if ((context->regs[REG_MODE_2] & BIT_DMA_ENABLE) && (context->cd & DMA_START) && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { + printf("DMA fill started at %d\n", context->cycles); context->flags |= FLAG_DMA_RUN; context->dma_val = start->value; context->address = start->address; //undo auto-increment @@ -575,7 +577,7 @@ void read_map_scroll(uint16_t column, uint16_t vsram_off, uint32_t line, uint16_ address &= 0xF000; line_offset = (((line) >> vscroll_shift) * 64 * 2) & 0xFFF; mask = 0x7F; - + } else { address &= 0xF800; line_offset = (((line) >> vscroll_shift) * 32 * 2) & 0xFFF; @@ -751,7 +753,7 @@ void render_map_output(uint32_t line, int32_t col, vdp_context * context) } plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF); //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7)); - + if (context->regs[REG_MODE_4] & BIT_HILIGHT) { for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { uint8_t pixel; @@ -1402,9 +1404,9 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) } 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 + //it's used for gathering sprite info for line line = (line - 1) & 0xFF; - + //Convert to slot number if (context->latched_mode & BIT_H40){ vdp_h40(line, slot, context); @@ -1458,7 +1460,7 @@ void vdp_run_dma_done(vdp_context * context, uint32_t target_cycles) int vdp_control_port_write(vdp_context * context, uint16_t value) { - //printf("control port write: %X\n", value); + printf("control port write: %X at %d\n", value, context->cycles); if (context->flags & FLAG_DMA_RUN) { return -1; } @@ -1466,13 +1468,14 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) context->address = (context->address & 0x3FFF) | (value << 14); context->cd = (context->cd & 0x3) | ((value >> 2) & 0x3C); context->flags &= ~FLAG_PENDING; - //printf("New Address: %X, New CD: %X\n", context->address, context->cd); + printf("New Address: %X, New CD: %X\n", context->address, context->cd); if (context->cd & 0x20 && (context->regs[REG_MODE_2] & BIT_DMA_ENABLE)) { // if((context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { //DMA copy or 68K -> VDP, transfer starts immediately context->flags |= FLAG_DMA_RUN; context->dma_cd = context->cd; + printf("DMA start at cycle %d\n", context->cycles); if (!(context->regs[REG_DMASRC_H] & 0x80)) { //printf("DMA Address: %X, New CD: %X, Source: %X, Length: %X\n", context->address, context->cd, (context->regs[REG_DMASRC_H] << 17) | (context->regs[REG_DMASRC_M] << 9) | (context->regs[REG_DMASRC_L] << 1), context->regs[REG_DMALEN_H] << 8 | context->regs[REG_DMALEN_L]); return 1; @@ -1480,7 +1483,7 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) //printf("DMA Copy Address: %X, New CD: %X, Source: %X\n", context->address, context->cd, (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]); } } else { - //printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd); + printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd); } } } else { @@ -1488,7 +1491,7 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) //Register write uint8_t reg = (value >> 8) & 0x1F; if (reg < VDP_REGS) { - //printf("register %d set to %X\n", reg, value & 0xFF); + printf("register %d set to %X\n", reg, value & 0xFF); context->regs[reg] = value; if (reg == REG_MODE_2) { //printf("Display is now %s\n", (context->regs[REG_MODE_2] & DISPLAY_ENABLE) ? "enabled" : "disabled"); @@ -1511,7 +1514,7 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) int vdp_data_port_write(vdp_context * context, uint16_t value) { - //printf("data port write: %X\n", value); + printf("data port write: %X at %d\n", value, context->cycles); if (context->flags & FLAG_DMA_RUN) { return -1; } -- cgit v1.2.3 From addb532950e13115b29d888782ce3dac20d62664 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Mon, 2 Sep 2013 00:20:56 -0700 Subject: Adjust VBLANK flag and refresh timing to be in line with logic analyzer and visual observations of direct color DMA demos. Remove debug print statements. --- vdp.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index ceffc77..76aea0d 100644 --- a/vdp.c +++ b/vdp.c @@ -478,7 +478,7 @@ void external_slot(vdp_context * context) context->regs[REG_DMALEN_H] = dma_len >> 8; context->regs[REG_DMALEN_L] = dma_len; if (!dma_len) { - printf("DMA end at cycle %d\n", context->cycles); + //printf("DMA end at cycle %d\n", context->cycles); context->flags &= ~FLAG_DMA_RUN; } } @@ -486,7 +486,7 @@ void external_slot(vdp_context * context) fifo_entry * start = (context->fifo_end - FIFO_SIZE); if (context->fifo_cur != start && start->cycle <= context->cycles) { if ((context->regs[REG_MODE_2] & BIT_DMA_ENABLE) && (context->cd & DMA_START) && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { - printf("DMA fill started at %d\n", context->cycles); + //printf("DMA fill started at %d\n", context->cycles); context->flags |= FLAG_DMA_RUN; context->dma_val = start->value; context->address = start->address; //undo auto-increment @@ -1241,12 +1241,19 @@ void latch_mode(vdp_context * context) int is_refresh(vdp_context * context, uint32_t slot) { if (context->latched_mode & BIT_H40) { - //TODO: Figure out the exact behavior that reduces DMA slots for direct color DMA demos - return (slot == 37 || slot == 69 || slot == 102 || slot == 133 || slot == 165 || slot == 197 || slot >= 210 || (slot < 6 && (context->flags & FLAG_DMA_RUN) && ((context->dma_cd & 0xF) == CRAM_WRITE))); + //TODO: Determine behavior for DMA fills and copies + return (slot == 37 || slot == 69 || slot == 102 || slot == 133 || slot == 165 || slot == 197 || slot >= 210 + || ((context->flags & FLAG_DMA_RUN) && ((context->dma_cd & 0xF) != VRAM_WRITE)) && ( + //both of the missed reads occurred right next to each other, but there seems + //to be some buffering involved, these values produce similar artifacts + //to what I see on my Model 2 + slot == 34 || slot == 66 || slot == 99 || slot == 130 || slot == 162 || slot == 194)); } 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 || (slot < 5 && (context->flags & FLAG_DMA_RUN) && ((context->dma_cd & 0xF) == CRAM_WRITE))); + return (slot == 24 || slot == 56 || slot == 88 || slot == 120 || slot == 152 + || ((context->flags & FLAG_DMA_RUN) && ((context->dma_cd & 0xF) != VRAM_WRITE)) && ( + slot == 21 || slot == 53 || slot == 85 || slot == 117 || slot == 149)); //The numbers below are the refresh slots during active display //return (slot == 66 || slot == 98 || slot == 130 || slot == 162); } @@ -1460,7 +1467,7 @@ void vdp_run_dma_done(vdp_context * context, uint32_t target_cycles) int vdp_control_port_write(vdp_context * context, uint16_t value) { - printf("control port write: %X at %d\n", value, context->cycles); + //printf("control port write: %X at %d\n", value, context->cycles); if (context->flags & FLAG_DMA_RUN) { return -1; } @@ -1468,14 +1475,14 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) context->address = (context->address & 0x3FFF) | (value << 14); context->cd = (context->cd & 0x3) | ((value >> 2) & 0x3C); context->flags &= ~FLAG_PENDING; - printf("New Address: %X, New CD: %X\n", context->address, context->cd); + //printf("New Address: %X, New CD: %X\n", context->address, context->cd); if (context->cd & 0x20 && (context->regs[REG_MODE_2] & BIT_DMA_ENABLE)) { // if((context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { //DMA copy or 68K -> VDP, transfer starts immediately context->flags |= FLAG_DMA_RUN; context->dma_cd = context->cd; - printf("DMA start at cycle %d\n", context->cycles); + //printf("DMA start at cycle %d\n", context->cycles); if (!(context->regs[REG_DMASRC_H] & 0x80)) { //printf("DMA Address: %X, New CD: %X, Source: %X, Length: %X\n", context->address, context->cd, (context->regs[REG_DMASRC_H] << 17) | (context->regs[REG_DMASRC_M] << 9) | (context->regs[REG_DMASRC_L] << 1), context->regs[REG_DMALEN_H] << 8 | context->regs[REG_DMALEN_L]); return 1; @@ -1483,7 +1490,7 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) //printf("DMA Copy Address: %X, New CD: %X, Source: %X\n", context->address, context->cd, (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]); } } else { - printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd); + //printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd); } } } else { @@ -1491,7 +1498,7 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) //Register write uint8_t reg = (value >> 8) & 0x1F; if (reg < VDP_REGS) { - printf("register %d set to %X\n", reg, value & 0xFF); + //printf("register %d set to %X\n", reg, value & 0xFF); context->regs[reg] = value; if (reg == REG_MODE_2) { //printf("Display is now %s\n", (context->regs[REG_MODE_2] & DISPLAY_ENABLE) ? "enabled" : "disabled"); @@ -1514,7 +1521,7 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) int vdp_data_port_write(vdp_context * context, uint16_t value) { - printf("data port write: %X at %d\n", value, context->cycles); + //printf("data port write: %X at %d\n", value, context->cycles); if (context->flags & FLAG_DMA_RUN) { return -1; } @@ -1557,7 +1564,7 @@ uint16_t vdp_control_port_read(vdp_context * context) } 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)) { + if (line >= (context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE) || context->cycles < (context->latched_mode & BIT_H40 ? 16*4 : 16*5)) { value |= 0x8; } if (linecyc < (context->latched_mode & BIT_H40 ? HBLANK_CLEAR_H40 : HBLANK_CLEAR_H32)) { -- cgit v1.2.3 From 437d581f120e762a70a254f5eae030e4eae87679 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Mon, 2 Sep 2013 01:02:18 -0700 Subject: Fix per-column scrolling bug --- vdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 76aea0d..35b0acb 100644 --- a/vdp.c +++ b/vdp.c @@ -619,7 +619,7 @@ void read_map_scroll(uint16_t column, uint16_t vsram_off, uint32_t line, uint16_ vscroll <<= 1; vscroll |= 1; } - vscroll &= (context->vsram[(context->regs[REG_MODE_3] & BIT_VSCROLL ? column : 0) + vsram_off] + line); + vscroll &= (context->vsram[(context->regs[REG_MODE_3] & BIT_VSCROLL ? (column-2)&63 : 0) + vsram_off] + line); context->v_offset = vscroll & v_offset_mask; //printf("%s | line %d, vsram: %d, vscroll: %d, v_offset: %d\n",(vsram_off ? "B" : "A"), line, context->vsram[context->regs[REG_MODE_3] & 0x4 ? column : 0], vscroll, context->v_offset); vscroll >>= vscroll_shift; -- cgit v1.2.3 From 773d8bb91c3d4684e3e6a76e8584e6a97eda31ec Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Sun, 8 Sep 2013 20:48:33 -0700 Subject: Revert change to VBLANK flag timing based on new direct color DMA test --- vdp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 35b0acb..829cb23 100644 --- a/vdp.c +++ b/vdp.c @@ -1564,7 +1564,7 @@ uint16_t vdp_control_port_read(vdp_context * context) } 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->cycles < (context->latched_mode & BIT_H40 ? 16*4 : 16*5)) { + if (line >= (context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE)) { value |= 0x8; } if (linecyc < (context->latched_mode & BIT_H40 ? HBLANK_CLEAR_H40 : HBLANK_CLEAR_H32)) { @@ -1576,6 +1576,7 @@ uint16_t vdp_control_port_read(vdp_context * context) if (context->latched_mode & BIT_PAL) {//Not sure about this, need to verify value |= 0x1; } + //printf("status read at cycle %d returned %X\n", context->cycles, value); //TODO: Sprite overflow, sprite collision, odd frame flag return value; } -- cgit v1.2.3 From 929bc24ebe9477fec8993be92b24dd0a96d001cd Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Tue, 10 Sep 2013 00:29:46 -0700 Subject: Implement FIFO latency and improve DMA accuracy --- vdp.c | 283 ++++++++++++++++++++++++++++-------------------------------------- 1 file changed, 120 insertions(+), 163 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 35b0acb..af14ef4 100644 --- a/vdp.c +++ b/vdp.c @@ -27,6 +27,7 @@ #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 FIFO_LATENCY 3 int32_t color_map[1 << 12]; uint8_t levels[] = {0, 27, 49, 71, 87, 103, 119, 130, 146, 157, 174, 190, 206, 228, 255}; @@ -121,6 +122,19 @@ 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); + } 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); + //The numbers below are the refresh slots during active display + //return (slot == 66 || slot == 98 || slot == 130 || slot == 162); + } +} + void render_sprite_cells(vdp_context * context) { if (context->cur_slot >= context->sprite_draws) { @@ -371,162 +385,115 @@ void write_cram(vdp_context * context, uint16_t address, uint16_t value) void external_slot(vdp_context * context) { - //TODO: Figure out what happens if CD bit 4 is not set in DMA copy mode - //TODO: Figure out what happens when CD:0-3 is not set to a write mode in DMA operations - //TODO: Figure out what happens if DMA gets disabled part way through a DMA fill or DMA copy - if(context->flags & FLAG_DMA_RUN) { - uint16_t dma_len; - switch(context->regs[REG_DMASRC_H] & 0xC0) + fifo_entry * start = (context->fifo_end - FIFO_SIZE); + if (context->fifo_cur != start && start->cycle <= context->cycles) { + switch (start->cd & 0xF) { - //68K -> VDP - case 0: - case 0x40: - switch(context->dma_cd & 0xF) - { - case VRAM_WRITE: - if (context->flags & FLAG_DMA_PROG) { - context->vdpmem[context->address ^ 1] = context->dma_val; - context->flags &= ~FLAG_DMA_PROG; - } else { - context->dma_val = read_dma_value((context->regs[REG_DMASRC_H] << 16) | (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]); - context->vdpmem[context->address] = context->dma_val >> 8; - context->flags |= FLAG_DMA_PROG; - } - break; - case CRAM_WRITE: { - write_cram(context, context->address, read_dma_value((context->regs[REG_DMASRC_H] << 16) | (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L])); - //printf("CRAM DMA | %X set to %X from %X at %d\n", (context->address/2) & (CRAM_SIZE-1), context->cram[(context->address/2) & (CRAM_SIZE-1)], (context->regs[REG_DMASRC_H] << 17) | (context->regs[REG_DMASRC_M] << 9) | (context->regs[REG_DMASRC_L] << 1), context->cycles); - break; + case VRAM_WRITE: + if (start->partial) { + //printf("VRAM Write: %X to %X\n", start->value, context->address ^ 1); + context->vdpmem[start->address ^ 1] = start->value; + } else { + //printf("VRAM Write High: %X to %X\n", start->value >> 8, context->address); + context->vdpmem[start->address] = start->value >> 8; + start->partial = 1; + //skip auto-increment and removal of entry from fifo + return; } - case VSRAM_WRITE: - if (((context->address/2) & 63) < VSRAM_SIZE) { - context->vsram[(context->address/2) & 63] = read_dma_value((context->regs[REG_DMASRC_H] << 16) | (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]); - } - break; + break; + case CRAM_WRITE: { + //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1)); + write_cram(context, start->address, start->value); + break; + } + case VSRAM_WRITE: + if (((start->address/2) & 63) < VSRAM_SIZE) { + //printf("VSRAM Write: %X to %X\n", start->value, context->address); + context->vsram[(start->address/2) & 63] = start->value; } + break; - //Fill - case 0x80: + } + fifo_entry * cur = start+1; + if (cur < context->fifo_cur) { + memmove(start, cur, sizeof(fifo_entry) * (context->fifo_cur - cur)); + } + context->fifo_cur -= 1; + } else { + context->flags |= FLAG_UNUSED_SLOT; + } +} + +void run_dma_src(vdp_context * context, uint32_t slot) +{ + //TODO: Figure out what happens if CD bit 4 is not set in DMA copy mode + //TODO: Figure out what happens when CD:0-3 is not set to a write mode in DMA operations + //TODO: Figure out what happens if DMA gets disabled part way through a DMA fill or DMA copy + if (context->fifo_cur == context->fifo_end) { + return; + } + uint16_t read_val; + uint8_t ran_source = 0, partial = 0; + uint16_t dma_len; + switch(context->regs[REG_DMASRC_H] & 0xC0) + { + //68K -> VDP + case 0: + case 0x40: + if (!slot || !is_refresh(context, slot-1)) { + read_val = read_dma_value((context->regs[REG_DMASRC_H] << 16) | (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]); + ran_source = 1; + } + break; + //Copy + case 0xC0: + if (context->flags & FLAG_UNUSED_SLOT) { switch(context->dma_cd & 0xF) { case VRAM_WRITE: - //Charles MacDonald's VDP doc says that the low byte gets written first - context->vdpmem[context->address] = context->dma_val; - context->dma_val = (context->dma_val << 8) | ((context->dma_val >> 8) & 0xFF); + read_val = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]]; break; case CRAM_WRITE: - write_cram(context, context->address, context->dma_val); - //printf("CRAM DMA Fill | %X set to %X at %d\n", (context->address/2) & (CRAM_SIZE-1), context->cram[(context->address/2) & (CRAM_SIZE-1)], context->cycles); + read_val = context->cram[context->regs[REG_DMASRC_L] & (CRAM_SIZE-1)]; break; case VSRAM_WRITE: - if (((context->address/2) & 63) < VSRAM_SIZE) { - context->vsram[(context->address/2) & 63] = context->dma_val; + if ((context->regs[REG_DMASRC_L] & 63) < VSRAM_SIZE) { + read_val = context->vsram[context->regs[REG_DMASRC_L] & 63]; + } else { + read_val = 0; } break; } - break; - //Copy - case 0xC0: - if (context->flags & FLAG_DMA_PROG) { - switch(context->dma_cd & 0xF) - { - case VRAM_WRITE: - context->vdpmem[context->address] = context->dma_val; - break; - case CRAM_WRITE: { - write_cram(context, context->address, context->dma_val); - //printf("CRAM DMA Copy | %X set to %X from %X at %d\n", (context->address/2) & (CRAM_SIZE-1), context->cram[(context->address/2) & (CRAM_SIZE-1)], context->regs[REG_DMASRC_L] & (CRAM_SIZE-1), context->cycles); - break; - } - case VSRAM_WRITE: - if (((context->address/2) & 63) < VSRAM_SIZE) { - context->vsram[(context->address/2) & 63] = context->dma_val; - } - break; - } - context->flags &= ~FLAG_DMA_PROG; - } else { - //I assume, that DMA copy copies from the same RAM as the destination - //but it's possible I'm mistaken - switch(context->dma_cd & 0xF) - { - case VRAM_WRITE: - context->dma_val = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]]; - break; - case CRAM_WRITE: - context->dma_val = context->cram[context->regs[REG_DMASRC_L] & (CRAM_SIZE-1)]; - break; - case VSRAM_WRITE: - if ((context->regs[REG_DMASRC_L] & 63) < VSRAM_SIZE) { - context->dma_val = context->vsram[context->regs[REG_DMASRC_L] & 63]; - } else { - context->dma_val = 0; - } - break; - } - context->flags |= FLAG_DMA_PROG; - } - break; + ran_source = 1; + context->flags &= ~FLAG_UNUSED_SLOT; } - if (!(context->flags & FLAG_DMA_PROG)) { - context->address += context->regs[REG_AUTOINC]; - context->regs[REG_DMASRC_L] += 1; - if (!context->regs[REG_DMASRC_L]) { - context->regs[REG_DMASRC_M] += 1; - } - dma_len = ((context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]) - 1; - context->regs[REG_DMALEN_H] = dma_len >> 8; - context->regs[REG_DMALEN_L] = dma_len; - if (!dma_len) { - //printf("DMA end at cycle %d\n", context->cycles); - context->flags &= ~FLAG_DMA_RUN; - } + break; + case 0x80: + read_val = (context->cd & 0xF) == VRAM_WRITE ? context->last_write_val >> 8 : context->last_write_val; + partial = 1; + ran_source = 1; + break; + } + + if (ran_source) { + context->fifo_cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; + context->fifo_cur->address = context->address; + context->fifo_cur->value = read_val; + context->fifo_cur->cd = context->cd; + context->fifo_cur->partial = partial; + context->fifo_cur++; + context->regs[REG_DMASRC_L] += 1; + if (!context->regs[REG_DMASRC_L]) { + context->regs[REG_DMASRC_M] += 1; } - } else { - fifo_entry * start = (context->fifo_end - FIFO_SIZE); - if (context->fifo_cur != start && start->cycle <= context->cycles) { - if ((context->regs[REG_MODE_2] & BIT_DMA_ENABLE) && (context->cd & DMA_START) && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { - //printf("DMA fill started at %d\n", context->cycles); - context->flags |= FLAG_DMA_RUN; - context->dma_val = start->value; - context->address = start->address; //undo auto-increment - context->dma_cd = context->cd; - } else { - switch (start->cd & 0xF) - { - case VRAM_WRITE: - if (start->partial) { - //printf("VRAM Write: %X to %X\n", start->value, context->address ^ 1); - context->vdpmem[start->address ^ 1] = start->value; - } else { - //printf("VRAM Write High: %X to %X\n", start->value >> 8, context->address); - context->vdpmem[start->address] = start->value >> 8; - start->partial = 1; - //skip auto-increment and removal of entry from fifo - return; - } - break; - case CRAM_WRITE: { - //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1)); - write_cram(context, start->address, start->value); - break; - } - case VSRAM_WRITE: - if (((start->address/2) & 63) < VSRAM_SIZE) { - //printf("VSRAM Write: %X to %X\n", start->value, context->address); - context->vsram[(start->address/2) & 63] = start->value; - } - break; - } - //context->address += context->regs[REG_AUTOINC]; - } - fifo_entry * cur = start+1; - if (cur < context->fifo_cur) { - memmove(start, cur, sizeof(fifo_entry) * (context->fifo_cur - cur)); - } - context->fifo_cur -= 1; - } else { - context->flags |= FLAG_UNUSED_SLOT; + context->address += context->regs[REG_AUTOINC]; + dma_len = ((context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]) - 1; + context->regs[REG_DMALEN_H] = dma_len >> 8; + context->regs[REG_DMALEN_L] = dma_len; + if (!dma_len) { + //printf("DMA end at cycle %d\n", context->cycles); + context->flags &= ~FLAG_DMA_RUN; + context->cd &= 0xF; } } } @@ -1238,27 +1205,6 @@ void latch_mode(vdp_context * context) context->latched_mode = (context->regs[REG_MODE_4] & 0x81) | (context->regs[REG_MODE_2] & BIT_PAL); } -int is_refresh(vdp_context * context, uint32_t slot) -{ - if (context->latched_mode & BIT_H40) { - //TODO: Determine behavior for DMA fills and copies - return (slot == 37 || slot == 69 || slot == 102 || slot == 133 || slot == 165 || slot == 197 || slot >= 210 - || ((context->flags & FLAG_DMA_RUN) && ((context->dma_cd & 0xF) != VRAM_WRITE)) && ( - //both of the missed reads occurred right next to each other, but there seems - //to be some buffering involved, these values produce similar artifacts - //to what I see on my Model 2 - slot == 34 || slot == 66 || slot == 99 || slot == 130 || slot == 162 || slot == 194)); - } 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 - || ((context->flags & FLAG_DMA_RUN) && ((context->dma_cd & 0xF) != VRAM_WRITE)) && ( - slot == 21 || slot == 53 || slot == 85 || slot == 117 || slot == 149)); - //The numbers below are the refresh slots during active display - //return (slot == 66 || slot == 98 || slot == 130 || slot == 162); - } -} - void check_render_bg(vdp_context * context, int32_t line, uint32_t slot) { if (line > 0) { @@ -1299,6 +1245,7 @@ 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) { @@ -1428,6 +1375,9 @@ void vdp_run_context(vdp_context * context, uint32_t target_cycles) check_render_bg(context, line, slot); } } + if (context->flags & FLAG_DMA_RUN && !is_refresh(context, slot)) { + run_dma_src(context, slot); + } context->cycles += inccycles; } } @@ -1522,7 +1472,7 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) 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) { + if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { return -1; } if (!(context->cd & 1)) { @@ -1533,12 +1483,19 @@ int vdp_data_port_write(vdp_context * context, uint16_t value) /*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) { + context->flags &= ~FLAG_DMA_RUN; + } while (context->fifo_cur == context->fifo_end) { vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); } - context->fifo_cur->cycle = context->cycles; + context->fifo_cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; context->fifo_cur->address = context->address; context->fifo_cur->value = value; + context->last_write_val = value; + if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { + context->flags |= FLAG_DMA_RUN; + } context->fifo_cur->cd = context->cd; context->fifo_cur->partial = 0; context->fifo_cur++; -- cgit v1.2.3 From ef94225ba181d6bf6c164731ec101356ab4d5220 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Tue, 10 Sep 2013 09:55:12 -0700 Subject: Fix timing of backdrop rendering when the display is turned off --- vdp.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 04fd705..74c0857 100644 --- a/vdp.c +++ b/vdp.c @@ -1211,14 +1211,20 @@ void check_render_bg(vdp_context * context, int32_t line, uint32_t slot) line -= 1; int starti = -1; if (context->latched_mode & BIT_H40) { - if (slot >= 50 && slot < 210) { - uint32_t x = (slot-50)*2; + 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; } } else { - if (slot >= 43 && slot < 171) { - uint32_t x = (slot-43)*2; + 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) { -- cgit v1.2.3 From 2c302a78d201d9b594774cec505d14c22e03662c Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Tue, 10 Sep 2013 23:31:08 -0700 Subject: Added copyright notice to source files and added GPL license text in COPYING --- vdp.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 74c0857..cf27ff2 100644 --- a/vdp.c +++ b/vdp.c @@ -1,3 +1,8 @@ +/* + Copyright 2013 Michael Pavone + 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 "vdp.h" #include "blastem.h" #include -- cgit v1.2.3 From 0f6f021093e9b54ca2379fd7d9359648cca03734 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Fri, 13 Sep 2013 19:22:46 -0700 Subject: Properly delay 68K on VDP reads. Dummy VDP test port implementation. Initial stab at handling undefined bits of VSRAM and CRAM. --- vdp.c | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index cf27ff2..ca84554 100644 --- a/vdp.c +++ b/vdp.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 "vdp.h" @@ -391,15 +391,21 @@ void write_cram(vdp_context * context, uint16_t address, uint16_t value) void external_slot(vdp_context * context) { fifo_entry * start = (context->fifo_end - FIFO_SIZE); + if (context->flags2 & FLAG2_READ_PENDING) { + context->flags2 &= ~FLAG2_READ_PENDING; + context->flags |= FLAG_UNUSED_SLOT; + return; + } if (context->fifo_cur != start && start->cycle <= context->cycles) { switch (start->cd & 0xF) { case VRAM_WRITE: if (start->partial) { - //printf("VRAM Write: %X to %X\n", start->value, context->address ^ 1); + 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); + context->last_fifo_val = start->value; context->vdpmem[start->address ^ 1] = start->value; } else { - //printf("VRAM Write High: %X to %X\n", start->value >> 8, context->address); + 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); context->vdpmem[start->address] = start->value >> 8; start->partial = 1; //skip auto-increment and removal of entry from fifo @@ -409,12 +415,14 @@ void external_slot(vdp_context * context) case CRAM_WRITE: { //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1)); write_cram(context, start->address, start->value); + context->last_fifo_val = start->value; break; } case VSRAM_WRITE: if (((start->address/2) & 63) < VSRAM_SIZE) { //printf("VSRAM Write: %X to %X\n", start->value, context->address); context->vsram[(start->address/2) & 63] = start->value; + context->last_fifo_val = start->value; } break; @@ -1428,7 +1436,7 @@ void vdp_run_dma_done(vdp_context * context, uint32_t target_cycles) int vdp_control_port_write(vdp_context * context, uint16_t value) { - //printf("control port write: %X at %d\n", value, context->cycles); + printf("control port write: %X at %d\n", value, context->cycles); if (context->flags & FLAG_DMA_RUN) { return -1; } @@ -1482,7 +1490,7 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) int vdp_data_port_write(vdp_context * context, uint16_t value) { - //printf("data port write: %X at %d\n", value, context->cycles); + printf("data port write: %X at %d\n", value, context->cycles); if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { return -1; } @@ -1514,6 +1522,11 @@ int vdp_data_port_write(vdp_context * context, uint16_t value) return 0; } +void vdp_test_port_write(vdp_context * context, uint16_t value) +{ + //TODO: implement test register +} + uint16_t vdp_control_port_read(vdp_context * context) { context->flags &= ~FLAG_PENDING; @@ -1549,6 +1562,9 @@ uint16_t vdp_control_port_read(vdp_context * context) return value; } +#define CRAM_BITS 0xEEE +#define VSRAM_BITS 0x3FF + uint16_t vdp_data_port_read(vdp_context * context) { context->flags &= ~FLAG_PENDING; @@ -1557,6 +1573,7 @@ uint16_t vdp_data_port_read(vdp_context * context) } //Not sure if the FIFO should be drained before processing a read or not, but it would make sense 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)); } @@ -1566,17 +1583,20 @@ uint16_t vdp_data_port_read(vdp_context * context) case VRAM_READ: value = context->vdpmem[context->address] << 8; 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)); } value |= context->vdpmem[context->address ^ 1]; break; case CRAM_READ: - value = context->cram[(context->address/2) & (CRAM_SIZE-1)]; + value = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS; + value |= context->last_fifo_val & ~CRAM_BITS; break; case VSRAM_READ: if (((context->address / 2) & 63) < VSRAM_SIZE) { - value = context->vsram[context->address & 63]; + value = context->vsram[context->address & 63] & VSRAM_BITS; + value |= context->last_fifo_val & ~VSRAM_BITS; } break; } @@ -1693,6 +1713,12 @@ uint16_t vdp_hv_counter_read(vdp_context * context) return (line << 8) | linecyc; } +uint16_t vdp_test_port_read(vdp_context * context) +{ + //TODO: Find out what actually gets returned here + return 0xFFFF; +} + void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) { context->cycles -= deduction; -- cgit v1.2.3 From e154139fdaa57c8c805167641b9ac0c30bb9d115 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Sun, 15 Sep 2013 22:20:43 -0700 Subject: Implement FIFO as a ring buffer so the behavior of reads from invalid CRAM and VSRAM bits can be implemented properly --- vdp.c | 90 ++++++++++++++++++++++++++++++++++++------------------------------- 1 file changed, 48 insertions(+), 42 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index ca84554..8e5eb81 100644 --- a/vdp.c +++ b/vdp.c @@ -20,8 +20,6 @@ #define SCROLL_BUFFER_MASK (SCROLL_BUFFER_SIZE-1) #define SCROLL_BUFFER_DRAW (SCROLL_BUFFER_SIZE/2) -#define FIFO_SIZE 4 - #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 @@ -61,8 +59,8 @@ void init_vdp_context(vdp_context * context) 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_cur = malloc(sizeof(fifo_entry) * FIFO_SIZE); - context->fifo_end = context->fifo_cur + FIFO_SIZE; + context->fifo_write = 0; + context->fifo_read = -1; context->b32 = render_depth() == 32; if (!color_map_init_done) { uint8_t b,g,r; @@ -390,22 +388,22 @@ void write_cram(vdp_context * context, uint16_t address, uint16_t value) void external_slot(vdp_context * context) { - fifo_entry * start = (context->fifo_end - FIFO_SIZE); + fifo_entry * start = context->fifo + context->fifo_read; if (context->flags2 & FLAG2_READ_PENDING) { context->flags2 &= ~FLAG2_READ_PENDING; context->flags |= FLAG_UNUSED_SLOT; return; } - if (context->fifo_cur != start && start->cycle <= context->cycles) { + if (context->fifo_read >= 0 && start->cycle <= context->cycles) { switch (start->cd & 0xF) { case VRAM_WRITE: 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); + //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); context->last_fifo_val = start->value; context->vdpmem[start->address ^ 1] = start->value; } 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); + //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); context->vdpmem[start->address] = start->value >> 8; start->partial = 1; //skip auto-increment and removal of entry from fifo @@ -427,11 +425,10 @@ void external_slot(vdp_context * context) break; } - fifo_entry * cur = start+1; - if (cur < context->fifo_cur) { - memmove(start, cur, sizeof(fifo_entry) * (context->fifo_cur - cur)); + context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1); + if (context->fifo_read == context->fifo_write) { + context->fifo_read = -1; } - context->fifo_cur -= 1; } else { context->flags |= FLAG_UNUSED_SLOT; } @@ -442,7 +439,7 @@ void run_dma_src(vdp_context * context, uint32_t slot) //TODO: Figure out what happens if CD bit 4 is not set in DMA copy mode //TODO: Figure out what happens when CD:0-3 is not set to a write mode in DMA operations //TODO: Figure out what happens if DMA gets disabled part way through a DMA fill or DMA copy - if (context->fifo_cur == context->fifo_end) { + if (context->fifo_write == context->fifo_read) { return; } uint16_t read_val; @@ -489,12 +486,16 @@ void run_dma_src(vdp_context * context, uint32_t slot) } if (ran_source) { - context->fifo_cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; - context->fifo_cur->address = context->address; - context->fifo_cur->value = read_val; - context->fifo_cur->cd = context->cd; - context->fifo_cur->partial = partial; - context->fifo_cur++; + fifo_entry * cur = context->fifo + context->fifo_write; + cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; + cur->address = context->address; + cur->value = read_val; + cur->cd = context->cd; + cur->partial = partial; + if (context->fifo_read < 0) { + context->fifo_read = context->fifo_write; + } + context->fifo_write = (context->fifo_write+1) & (FIFO_SIZE-1); context->regs[REG_DMASRC_L] += 1; if (!context->regs[REG_DMASRC_L]) { context->regs[REG_DMASRC_M] += 1; @@ -1436,7 +1437,7 @@ void vdp_run_dma_done(vdp_context * context, uint32_t target_cycles) int vdp_control_port_write(vdp_context * context, uint16_t value) { - printf("control port write: %X at %d\n", value, context->cycles); + //printf("control port write: %X at %d\n", value, context->cycles); if (context->flags & FLAG_DMA_RUN) { return -1; } @@ -1490,14 +1491,10 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) int vdp_data_port_write(vdp_context * context, uint16_t value) { - printf("data port write: %X at %d\n", value, context->cycles); + //printf("data port write: %X at %d\n", value, context->cycles); if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { return -1; } - if (!(context->cd & 1)) { - //ignore writes when cd is configured for read - return 0; - } context->flags &= ~FLAG_PENDING; /*if (context->fifo_cur == context->fifo_end) { printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles); @@ -1505,19 +1502,23 @@ int vdp_data_port_write(vdp_context * context, uint16_t value) if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { context->flags &= ~FLAG_DMA_RUN; } - while (context->fifo_cur == context->fifo_end) { + while (context->fifo_write == context->fifo_read) { vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); } - context->fifo_cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; - context->fifo_cur->address = context->address; - context->fifo_cur->value = value; + fifo_entry * cur = context->fifo + context->fifo_write; + cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; + cur->address = context->address; + cur->value = value; context->last_write_val = value; if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { context->flags |= FLAG_DMA_RUN; } - context->fifo_cur->cd = context->cd; - context->fifo_cur->partial = 0; - context->fifo_cur++; + cur->cd = context->cd; + cur->partial = 0; + if (context->fifo_read < 0) { + context->fifo_read = context->fifo_write; + } + context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1); context->address += context->regs[REG_AUTOINC]; return 0; } @@ -1531,10 +1532,10 @@ uint16_t vdp_control_port_read(vdp_context * context) { context->flags &= ~FLAG_PENDING; uint16_t value = 0x3400; - if (context->fifo_cur == (context->fifo_end - FIFO_SIZE)) { + if (context->fifo_read < 0) { value |= 0x200; } - if (context->fifo_cur == context->fifo_end) { + if (context->fifo_read == context->fifo_write) { value |= 0x100; } if (context->flags2 & FLAG2_VINT_PENDING) { @@ -1564,6 +1565,7 @@ uint16_t vdp_control_port_read(vdp_context * context) #define CRAM_BITS 0xEEE #define VSRAM_BITS 0x3FF +#define VSRAM_DIRTY_BITS 0xF800 uint16_t vdp_data_port_read(vdp_context * context) { @@ -1591,12 +1593,12 @@ uint16_t vdp_data_port_read(vdp_context * context) break; case CRAM_READ: value = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS; - value |= context->last_fifo_val & ~CRAM_BITS; + value |= context->fifo[context->fifo_write].value & ~CRAM_BITS; break; case VSRAM_READ: if (((context->address / 2) & 63) < VSRAM_SIZE) { value = context->vsram[context->address & 63] & VSRAM_BITS; - value |= context->last_fifo_val & ~VSRAM_BITS; + value |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS; } break; } @@ -1722,12 +1724,16 @@ uint16_t vdp_test_port_read(vdp_context * context) void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) { context->cycles -= deduction; - for(fifo_entry * start = (context->fifo_end - FIFO_SIZE); start < context->fifo_cur; start++) { - if (start->cycle >= deduction) { - start->cycle -= deduction; - } else { - start->cycle = 0; - } + if (context->fifo_read >= 0) { + int32_t idx = context->fifo_read; + do { + if (context->fifo[idx].cycle >= deduction) { + context->fifo[idx].cycle -= deduction; + } else { + context->fifo[idx].cycle = 0; + } + idx = (idx+1) & (FIFO_SIZE-1); + } while(idx != context->fifo_write); } } -- cgit v1.2.3 From 4437c3730dfbe7e038bc28da6531d140ddbfbcd4 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Sun, 15 Sep 2013 22:43:01 -0700 Subject: Fix VSRAM reads --- vdp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 8e5eb81..87e3d59 100644 --- a/vdp.c +++ b/vdp.c @@ -1583,13 +1583,13 @@ uint16_t vdp_data_port_read(vdp_context * context) switch (context->cd & 0xF) { case VRAM_READ: - value = context->vdpmem[context->address] << 8; + value = context->vdpmem[context->address & 0xFFFE] << 8; 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)); } - value |= context->vdpmem[context->address ^ 1]; + value |= context->vdpmem[context->address | 1]; break; case CRAM_READ: value = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS; @@ -1597,7 +1597,7 @@ uint16_t vdp_data_port_read(vdp_context * context) break; case VSRAM_READ: if (((context->address / 2) & 63) < VSRAM_SIZE) { - value = context->vsram[context->address & 63] & VSRAM_BITS; + value = context->vsram[(context->address / 2) & 63] & VSRAM_BITS; value |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS; } break; -- cgit v1.2.3 From a47dff5923490fd2a5ce5f53ee894f41e6e81962 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Sun, 15 Sep 2013 23:00:17 -0700 Subject: Implement undocumented 8-bit VRAM read --- vdp.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 87e3d59..ffa46f7 100644 --- a/vdp.c +++ b/vdp.c @@ -378,12 +378,22 @@ void write_cram(vdp_context * context, uint16_t address, uint16_t value) context->colors[addr + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT]; } -#define VRAM_READ 0 -#define VRAM_WRITE 1 -#define CRAM_READ 8 -#define CRAM_WRITE 3 -#define VSRAM_READ 4 -#define VSRAM_WRITE 5 +#define VRAM_READ 0 //0000 +#define VRAM_WRITE 1 //0001 +//2 would trigger register write 0010 +#define CRAM_WRITE 3 //0011 +#define VSRAM_READ 4 //0100 +#define VSRAM_WRITE 5//0101 +//6 would trigger regsiter write 0110 +//7 is a mystery +#define CRAM_READ 8 //1000 +//9 is also a mystery //1001 +//A would trigger register write 1010 +//B is a mystery 1011 +#define VRAM_READ8 0xC //1100 +//D is a mystery 1101 +//E would trigger register write 1110 +//F is a mystery 1111 #define DMA_START 0x20 void external_slot(vdp_context * context) @@ -1591,6 +1601,10 @@ uint16_t vdp_data_port_read(vdp_context * context) } value |= context->vdpmem[context->address | 1]; break; + case VRAM_READ8: + value = context->vdpmem[context->address ^ 1]; + value |= context->fifo[context->fifo_write].value & 0xFF00; + break; case CRAM_READ: value = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS; value |= context->fifo[context->fifo_write].value & ~CRAM_BITS; -- cgit v1.2.3 From 87c57b78120c4abbf386634b803ab87b2ec53498 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Sun, 15 Sep 2013 23:33:24 -0700 Subject: Remove read pending stuff, that had been added in an attempt to fix CRAM/VSRAM undefined bit results. Set number of bits actually saved in VSRAM to 11 --- vdp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index ffa46f7..69afcc2 100644 --- a/vdp.c +++ b/vdp.c @@ -399,11 +399,11 @@ void write_cram(vdp_context * context, uint16_t address, uint16_t value) void external_slot(vdp_context * context) { fifo_entry * start = context->fifo + context->fifo_read; - if (context->flags2 & FLAG2_READ_PENDING) { + /*if (context->flags2 & FLAG2_READ_PENDING) { context->flags2 &= ~FLAG2_READ_PENDING; context->flags |= FLAG_UNUSED_SLOT; return; - } + }*/ if (context->fifo_read >= 0 && start->cycle <= context->cycles) { switch (start->cd & 0xF) { @@ -1574,7 +1574,7 @@ uint16_t vdp_control_port_read(vdp_context * context) } #define CRAM_BITS 0xEEE -#define VSRAM_BITS 0x3FF +#define VSRAM_BITS 0x7FF #define VSRAM_DIRTY_BITS 0xF800 uint16_t vdp_data_port_read(vdp_context * context) @@ -1585,7 +1585,7 @@ uint16_t vdp_data_port_read(vdp_context * context) } //Not sure if the FIFO should be drained before processing a read or not, but it would make sense context->flags &= ~FLAG_UNUSED_SLOT; - context->flags2 |= FLAG2_READ_PENDING; + //context->flags2 |= FLAG2_READ_PENDING; while (!(context->flags & FLAG_UNUSED_SLOT)) { vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); } -- cgit v1.2.3 From 0d6a2b753c9733f07932c1bd104a4371cc603894 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Sun, 15 Sep 2013 23:40:18 -0700 Subject: Don't allow register writes to regs above when in Mode 4 --- vdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 69afcc2..f1f28fc 100644 --- a/vdp.c +++ b/vdp.c @@ -1477,7 +1477,7 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) if ((value & 0xC000) == 0x8000) { //Register write uint8_t reg = (value >> 8) & 0x1F; - if (reg < VDP_REGS) { + if (reg < (context->regs[REG_MODE_2] & BIT_MODE_5 ? VDP_REGS : 0xA)) { //printf("register %d set to %X\n", reg, value & 0xFF); context->regs[reg] = value; if (reg == REG_MODE_2) { -- cgit v1.2.3 From 0b85aa8c6991e91f9927f4d77e3f6bf5600dd36c Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Sun, 15 Sep 2013 23:49:09 -0700 Subject: Clear the low 2 bits of CD when a register is written to --- vdp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index f1f28fc..efe7dac 100644 --- a/vdp.c +++ b/vdp.c @@ -1489,6 +1489,7 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) context->framebuf = context->oddbuf; } } + context->cd &= 0x3C; } } else { context->flags |= FLAG_PENDING; -- cgit v1.2.3 From a020d55258a5ebf5db027072c4ef28194aa6564b Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Mon, 16 Sep 2013 09:44:22 -0700 Subject: Partial fix for DMA copy --- vdp.c | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index efe7dac..5de80e5 100644 --- a/vdp.c +++ b/vdp.c @@ -455,6 +455,7 @@ void run_dma_src(vdp_context * context, uint32_t slot) uint16_t read_val; uint8_t ran_source = 0, partial = 0; uint16_t dma_len; + uint8_t cd = context->cd; switch(context->regs[REG_DMASRC_H] & 0xC0) { //68K -> VDP @@ -468,22 +469,9 @@ void run_dma_src(vdp_context * context, uint32_t slot) //Copy case 0xC0: if (context->flags & FLAG_UNUSED_SLOT) { - switch(context->dma_cd & 0xF) - { - case VRAM_WRITE: - read_val = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]]; - break; - case CRAM_WRITE: - read_val = context->cram[context->regs[REG_DMASRC_L] & (CRAM_SIZE-1)]; - break; - case VSRAM_WRITE: - if ((context->regs[REG_DMASRC_L] & 63) < VSRAM_SIZE) { - read_val = context->vsram[context->regs[REG_DMASRC_L] & 63]; - } else { - read_val = 0; - } - break; - } + read_val = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1] | (context->fifo[context->fifo_write].value & 0xFF00); + cd = VRAM_WRITE; + partial = 1; ran_source = 1; context->flags &= ~FLAG_UNUSED_SLOT; } @@ -500,7 +488,7 @@ void run_dma_src(vdp_context * context, uint32_t slot) cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; cur->address = context->address; cur->value = read_val; - cur->cd = context->cd; + cur->cd = cd; cur->partial = partial; if (context->fifo_read < 0) { context->fifo_read = context->fifo_write; -- cgit v1.2.3 From 74af15299f37e5c95f4498cfb2f9456c9d4d61bc Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Tue, 17 Sep 2013 00:11:45 -0700 Subject: Fix DMA fill so that it does not cause observable changes to the FIFO. Get DMA copy mostly correct from an observable ffect perspective. DMA copy probably does not reflect internal implementation still given that evidence seems to suggest no FIFO usage at all. --- vdp.c | 61 ++++++++++++++++++++++++++++++------------------------------- 1 file changed, 30 insertions(+), 31 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 5de80e5..b75f063 100644 --- a/vdp.c +++ b/vdp.c @@ -410,8 +410,7 @@ void external_slot(vdp_context * context) case VRAM_WRITE: 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); - context->last_fifo_val = start->value; - context->vdpmem[start->address ^ 1] = start->value; + context->vdpmem[start->address ^ 1] = start->partial == 2 ? start->value >> 8 : start->value; } 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); context->vdpmem[start->address] = start->value >> 8; @@ -423,14 +422,12 @@ void external_slot(vdp_context * context) case CRAM_WRITE: { //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1)); write_cram(context, start->address, start->value); - context->last_fifo_val = start->value; break; } case VSRAM_WRITE: if (((start->address/2) & 63) < VSRAM_SIZE) { //printf("VSRAM Write: %X to %X\n", start->value, context->address); context->vsram[(start->address/2) & 63] = start->value; - context->last_fifo_val = start->value; } break; @@ -452,54 +449,57 @@ void run_dma_src(vdp_context * context, uint32_t slot) if (context->fifo_write == context->fifo_read) { return; } - uint16_t read_val; - uint8_t ran_source = 0, partial = 0; - uint16_t dma_len; - uint8_t cd = context->cd; + fifo_entry * cur = NULL; switch(context->regs[REG_DMASRC_H] & 0xC0) { //68K -> VDP case 0: case 0x40: if (!slot || !is_refresh(context, slot-1)) { - read_val = read_dma_value((context->regs[REG_DMASRC_H] << 16) | (context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L]); - ran_source = 1; + cur = context->fifo + context->fifo_write; + cur->cycle = context->cycles + ((context->latched_mode & 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; + cur->partial = 0; + if (context->fifo_read < 0) { + context->fifo_read = context->fifo_write; + } + context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1); } break; //Copy case 0xC0: - if (context->flags & FLAG_UNUSED_SLOT) { - read_val = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1] | (context->fifo[context->fifo_write].value & 0xFF00); - cd = VRAM_WRITE; - partial = 1; - ran_source = 1; + if (context->flags & FLAG_UNUSED_SLOT && context->fifo_read < 0) { + //TODO: Fix this to not use the FIFO at all once read-caching is properly implemented + context->fifo_read = (context->fifo_write-1) & (FIFO_SIZE-1); + cur = context->fifo + context->fifo_read; + cur->cycle = context->cycles; + cur->address = context->address; + cur->partial = 1; + cur->value = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1] | (cur->value & 0xFF00); + cur->cd = VRAM_WRITE; context->flags &= ~FLAG_UNUSED_SLOT; } break; case 0x80: - read_val = (context->cd & 0xF) == VRAM_WRITE ? context->last_write_val >> 8 : context->last_write_val; - partial = 1; - ran_source = 1; + if (context->fifo_read < 0) { + context->fifo_read = (context->fifo_write-1) & (FIFO_SIZE-1); + cur = context->fifo + context->fifo_read; + cur->cycle = context->cycles; + cur->address = context->address; + cur->partial = 2; + } break; } - if (ran_source) { - fifo_entry * cur = context->fifo + context->fifo_write; - cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; - cur->address = context->address; - cur->value = read_val; - cur->cd = cd; - cur->partial = partial; - if (context->fifo_read < 0) { - context->fifo_read = context->fifo_write; - } - context->fifo_write = (context->fifo_write+1) & (FIFO_SIZE-1); + if (cur) { context->regs[REG_DMASRC_L] += 1; if (!context->regs[REG_DMASRC_L]) { context->regs[REG_DMASRC_M] += 1; } context->address += context->regs[REG_AUTOINC]; - dma_len = ((context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]) - 1; + uint16_t dma_len = ((context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]) - 1; context->regs[REG_DMALEN_H] = dma_len >> 8; context->regs[REG_DMALEN_L] = dma_len; if (!dma_len) { @@ -1508,7 +1508,6 @@ int vdp_data_port_write(vdp_context * context, uint16_t value) cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; cur->address = context->address; cur->value = value; - context->last_write_val = value; if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { context->flags |= FLAG_DMA_RUN; } -- cgit v1.2.3 From 7f8e47eb7e81a7001f0c6a00f2cf52f1e50a96a2 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Tue, 17 Sep 2013 00:42:49 -0700 Subject: Implement funny behavior for DMA fill to CRAM and VSRAM. Return VSRAM address 0 for reads to VSRAM at >= 40 --- vdp.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index b75f063..5d02ce6 100644 --- a/vdp.c +++ b/vdp.c @@ -421,13 +421,13 @@ void external_slot(vdp_context * context) break; case CRAM_WRITE: { //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1)); - write_cram(context, start->address, start->value); + write_cram(context, start->address, start->partial == 2 ? context->fifo[context->fifo_write].value : start->value); break; } case VSRAM_WRITE: if (((start->address/2) & 63) < VSRAM_SIZE) { //printf("VSRAM Write: %X to %X\n", start->value, context->address); - context->vsram[(start->address/2) & 63] = start->value; + context->vsram[(start->address/2) & 63] = start->partial == 2 ? context->fifo[context->fifo_write].value : start->value; } break; @@ -1597,12 +1597,15 @@ uint16_t vdp_data_port_read(vdp_context * context) value = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS; value |= context->fifo[context->fifo_write].value & ~CRAM_BITS; break; - case VSRAM_READ: - if (((context->address / 2) & 63) < VSRAM_SIZE) { - value = context->vsram[(context->address / 2) & 63] & VSRAM_BITS; - value |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS; + case VSRAM_READ: { + uint16_t address = (context->address /2) & 63; + if (address >= VSRAM_SIZE) { + address = 0; } + value = context->vsram[address] & VSRAM_BITS; + value |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS; break; + } } context->address += context->regs[REG_AUTOINC]; return value; -- cgit v1.2.3 From b1170b0ee50fdb523fdb65e6f99851fe67acd1c1 Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Tue, 17 Sep 2013 09:45:14 -0700 Subject: Implement HV counter latch --- vdp.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 5d02ce6..4d21f1c 100644 --- a/vdp.c +++ b/vdp.c @@ -1467,10 +1467,10 @@ int vdp_control_port_write(vdp_context * context, uint16_t value) uint8_t reg = (value >> 8) & 0x1F; if (reg < (context->regs[REG_MODE_2] & BIT_MODE_5 ? VDP_REGS : 0xA)) { //printf("register %d set to %X\n", reg, value & 0xFF); - context->regs[reg] = value; - if (reg == REG_MODE_2) { - //printf("Display is now %s\n", (context->regs[REG_MODE_2] & DISPLAY_ENABLE) ? "enabled" : "disabled"); + if (reg == REG_MODE_1 && (value & BIT_HVC_LATCH) && !(context->regs[reg] & BIT_HVC_LATCH)) { + context->hv_latch = vdp_hv_counter_read(context); } + context->regs[reg] = value; if (reg == REG_MODE_4) { context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); if (!context->double_res) { @@ -1613,7 +1613,9 @@ uint16_t vdp_data_port_read(vdp_context * context) uint16_t vdp_hv_counter_read(vdp_context * context) { - //TODO: deal with clock adjustemnts handled in vdp_run_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; -- cgit v1.2.3 From b5767c17b138cfb9b264dbc9cad38252cdd2731c Mon Sep 17 00:00:00 2001 From: Mike Pavone Date: Tue, 17 Sep 2013 19:10:00 -0700 Subject: Set VBLANK flag in status register when display is disabled --- vdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'vdp.c') diff --git a/vdp.c b/vdp.c index 4d21f1c..c1e04f0 100644 --- a/vdp.c +++ b/vdp.c @@ -1544,7 +1544,7 @@ uint16_t vdp_control_port_read(vdp_context * context) } 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)) { + if (line >= (context->latched_mode & BIT_PAL ? PAL_ACTIVE : NTSC_ACTIVE) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) { value |= 0x8; } if (linecyc < (context->latched_mode & BIT_H40 ? HBLANK_CLEAR_H40 : HBLANK_CLEAR_H32)) { -- cgit v1.2.3