Mercurial > repos > blastem
comparison vdp.c @ 1339:35e6a93b4586
Implement the effect of VDP test register usage on the top and bottom borders. Fixes the remaning issue with the border dissolve in the "Ninja Escape" scene of Overdrive 2
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Wed, 03 May 2017 21:28:40 -0700 |
parents | 3706b683cd48 |
children | 4ea094d15cce |
comparison
equal
deleted
inserted
replaced
1338:3706b683cd48 | 1339:35e6a93b4586 |
---|---|
282 } | 282 } |
283 } | 283 } |
284 | 284 |
285 static void render_sprite_cells(vdp_context * context) | 285 static void render_sprite_cells(vdp_context * context) |
286 { | 286 { |
287 sprite_draw * d = context->sprite_draw_list + context->cur_slot; | |
288 context->serial_address = d->address; | |
287 if (context->cur_slot >= context->sprite_draws) { | 289 if (context->cur_slot >= context->sprite_draws) { |
288 sprite_draw * d = context->sprite_draw_list + context->cur_slot; | |
289 | 290 |
290 uint16_t dir; | 291 uint16_t dir; |
291 int16_t x; | 292 int16_t x; |
292 if (d->h_flip) { | 293 if (d->h_flip) { |
293 x = d->x_pos + 7; | 294 x = d->x_pos + 7; |
1268 static void render_map_output(uint32_t line, int32_t col, vdp_context * context) | 1269 static void render_map_output(uint32_t line, int32_t col, vdp_context * context) |
1269 { | 1270 { |
1270 uint32_t *dst; | 1271 uint32_t *dst; |
1271 uint8_t output_disabled = (context->test_port & TEST_BIT_DISABLE) != 0; | 1272 uint8_t output_disabled = (context->test_port & TEST_BIT_DISABLE) != 0; |
1272 uint8_t test_layer = context->test_port >> 7 & 3; | 1273 uint8_t test_layer = context->test_port >> 7 & 3; |
1273 if (context->state == PREPARING) { | 1274 if (context->state == PREPARING && !test_layer) { |
1274 if (col) { | 1275 if (col) { |
1275 col -= 2; | 1276 col -= 2; |
1276 dst = context->output + BORDER_LEFT + col * 8; | 1277 dst = context->output + BORDER_LEFT + col * 8; |
1277 } else { | 1278 } else { |
1278 dst = context->output; | 1279 dst = context->output; |
2037 *dst = bg_color; | 2038 *dst = bg_color; |
2038 external_slot(context); | 2039 external_slot(context); |
2039 } else { | 2040 } else { |
2040 render_sprite_cells(context); | 2041 render_sprite_cells(context); |
2041 } | 2042 } |
2043 if (context->vcounter == context->inactive_start) { | |
2044 context->hslot++; | |
2045 context->cycles += slot_cycles; | |
2046 return; | |
2047 } | |
2042 CHECK_LIMIT | 2048 CHECK_LIMIT |
2043 //sprite attribute table scan starts | 2049 //sprite attribute table scan starts |
2044 case 167: | 2050 case 167: |
2045 if (context->state == PREPARING) { | 2051 if (context->state == PREPARING) { |
2046 uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; | 2052 uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; |
2175 COLUMN_RENDER_BLOCK(38, 145) | 2181 COLUMN_RENDER_BLOCK(38, 145) |
2176 COLUMN_RENDER_BLOCK_REFRESH(40, 153) | 2182 COLUMN_RENDER_BLOCK_REFRESH(40, 153) |
2177 case 161: | 2183 case 161: |
2178 external_slot(context); | 2184 external_slot(context); |
2179 CHECK_LIMIT | 2185 CHECK_LIMIT |
2180 case 162: { | 2186 case 162: |
2181 external_slot(context); | 2187 external_slot(context); |
2182 uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; | 2188 CHECK_LIMIT |
2183 for (int i = LINEBUF_SIZE-BORDER_RIGHT; i < LINEBUF_SIZE; i++) | |
2184 { | |
2185 context->output[i] = bg_color; | |
2186 } | |
2187 CHECK_LIMIT | |
2188 } | |
2189 //sprite render to line buffer starts | 2189 //sprite render to line buffer starts |
2190 case 163: | 2190 case 163: |
2191 context->cur_slot = MAX_DRAWS-1; | 2191 context->cur_slot = MAX_DRAWS-1; |
2192 memset(context->linebuf, 0, LINEBUF_SIZE); | 2192 memset(context->linebuf, 0, LINEBUF_SIZE); |
2193 render_border_garbage( | 2193 render_border_garbage( |
2210 run_dma_src(context, -1); | 2210 run_dma_src(context, -1); |
2211 } | 2211 } |
2212 context->hslot++; | 2212 context->hslot++; |
2213 context->cycles += slot_cycles; | 2213 context->cycles += slot_cycles; |
2214 vdp_advance_line(context); | 2214 vdp_advance_line(context); |
2215 if (context->vcounter == context->inactive_start) { | |
2216 return; | |
2217 } | |
2218 CHECK_ONLY | 2215 CHECK_ONLY |
2219 } | 2216 } |
2220 default: | 2217 default: |
2221 context->hslot++; | 2218 context->hslot++; |
2222 context->cycles += slot_cycles; | 2219 context->cycles += slot_cycles; |
2263 *(dst++) = bg_color; | 2260 *(dst++) = bg_color; |
2264 *dst = bg_color; | 2261 *dst = bg_color; |
2265 external_slot(context); | 2262 external_slot(context); |
2266 } else { | 2263 } else { |
2267 render_sprite_cells(context); | 2264 render_sprite_cells(context); |
2265 } | |
2266 if (context->vcounter == context->inactive_start) { | |
2267 context->hslot++; | |
2268 context->cycles += slot_cycles; | |
2269 return; | |
2268 } | 2270 } |
2269 CHECK_LIMIT | 2271 CHECK_LIMIT |
2270 //sprite attribute table scan starts | 2272 //sprite attribute table scan starts |
2271 case 135: //FIXME - Here | 2273 case 135: //FIXME - Here |
2272 if (context->state == PREPARING) { | 2274 if (context->state == PREPARING) { |
2408 run_dma_src(context, -1); | 2410 run_dma_src(context, -1); |
2409 } | 2411 } |
2410 context->hslot++; | 2412 context->hslot++; |
2411 context->cycles += slot_cycles; | 2413 context->cycles += slot_cycles; |
2412 vdp_advance_line(context); | 2414 vdp_advance_line(context); |
2413 if (context->vcounter == context->inactive_start) { | |
2414 return; | |
2415 } | |
2416 CHECK_ONLY | 2415 CHECK_ONLY |
2417 } | 2416 } |
2418 default: | 2417 default: |
2419 context->hslot++; | 2418 context->hslot++; |
2420 context->cycles += MCLKS_SLOT_H32; | 2419 context->cycles += MCLKS_SLOT_H32; |
2543 context->hslot++; | 2542 context->hslot++; |
2544 context->cycles += MCLKS_SLOT_H32; | 2543 context->cycles += MCLKS_SLOT_H32; |
2545 } | 2544 } |
2546 } | 2545 } |
2547 | 2546 |
2547 static void inactive_test_output(vdp_context *context, uint8_t is_h40, uint8_t test_layer) | |
2548 { | |
2549 uint8_t max_slot = is_h40 ? 169 : 136; | |
2550 if (context->hslot > max_slot) { | |
2551 return; | |
2552 } | |
2553 uint32_t *dst = context->output + (context->hslot >> 3) * SCROLL_BUFFER_DRAW; | |
2554 int32_t len; | |
2555 uint32_t src_off; | |
2556 if (context->hslot) { | |
2557 dst -= SCROLL_BUFFER_DRAW - BORDER_LEFT; | |
2558 src_off = 0; | |
2559 len = context->hslot == max_slot ? BORDER_RIGHT : SCROLL_BUFFER_DRAW; | |
2560 } else { | |
2561 src_off = SCROLL_BUFFER_DRAW - BORDER_LEFT; | |
2562 len = BORDER_LEFT; | |
2563 } | |
2564 uint8_t *src; | |
2565 if (test_layer == 2) { | |
2566 //plane A | |
2567 src_off += context->buf_a_off + context->hscroll_a; | |
2568 src = context->tmp_buf_a; | |
2569 } else { | |
2570 //plane B | |
2571 src_off += context->buf_b_off + context->hscroll_b; | |
2572 src = context->tmp_buf_b; | |
2573 } | |
2574 for (; len >=0; len--, dst++, src_off++) | |
2575 { | |
2576 *dst = context->colors[src[src_off & SCROLL_BUFFER_MASK] & 0x3F]; | |
2577 } | |
2578 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_DRAW; | |
2579 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_DRAW; | |
2580 } | |
2581 | |
2548 static void vdp_inactive(vdp_context *context, uint32_t target_cycles, uint8_t is_h40, uint8_t mode_5) | 2582 static void vdp_inactive(vdp_context *context, uint32_t target_cycles, uint8_t is_h40, uint8_t mode_5) |
2549 { | 2583 { |
2550 uint8_t buf_clear_slot, index_reset_slot, bg_end_slot, vint_slot, line_change, jump_start, jump_dest; | 2584 uint8_t buf_clear_slot, index_reset_slot, bg_end_slot, vint_slot, line_change, jump_start, jump_dest; |
2551 uint8_t index_reset_value, max_draws, max_sprites; | 2585 uint8_t index_reset_value, max_draws, max_sprites; |
2552 uint16_t vint_line, active_line; | 2586 uint16_t vint_line, active_line; |
2603 context->vcounter < context->inactive_start + context->border_bot | 2637 context->vcounter < context->inactive_start + context->border_bot |
2604 || context->vcounter > 0x200 - context->border_top | 2638 || context->vcounter > 0x200 - context->border_top |
2605 ) && context->hslot >= BG_START_SLOT && context->hslot < bg_end_slot | 2639 ) && context->hslot >= BG_START_SLOT && context->hslot < bg_end_slot |
2606 ? context->output + 2 * (context->hslot - BG_START_SLOT) | 2640 ? context->output + 2 * (context->hslot - BG_START_SLOT) |
2607 : NULL; | 2641 : NULL; |
2642 | |
2643 uint8_t test_layer = context->test_port >> 7 & 3; | |
2644 if (test_layer == 1) { | |
2645 //sprite layer doesn't do anything interesting in the passive area | |
2646 test_layer = 0; | |
2647 } else if (test_layer) { | |
2648 dst = NULL; | |
2649 } | |
2608 | 2650 |
2609 while(context->cycles < target_cycles) | 2651 while(context->cycles < target_cycles) |
2610 { | 2652 { |
2611 if (context->hslot == BG_START_SLOT && ( | 2653 if (context->hslot == BG_START_SLOT && !test_layer && ( |
2612 context->vcounter < context->inactive_start + context->border_bot | 2654 context->vcounter < context->inactive_start + context->border_bot |
2613 || context->vcounter > 0x200 - context->border_top | 2655 || context->vcounter > 0x200 - context->border_top |
2614 )) { | 2656 )) { |
2615 dst = context->output + (context->hslot - BG_START_SLOT) * 2; | 2657 dst = context->output + (context->hslot - BG_START_SLOT) * 2; |
2616 } else if (context->hslot == bg_end_slot) { | 2658 } else if (context->hslot == bg_end_slot) { |
2617 advance_output_line(context); | 2659 advance_output_line(context); |
2618 dst = NULL; | 2660 dst = NULL; |
2619 } | 2661 } |
2662 //this will need some tweaking to properly interact with 128K mode, | |
2663 //but this should be good enough for now | |
2664 context->serial_address += 1024; | |
2665 if (test_layer) { | |
2666 switch (context->hslot & 7) | |
2667 { | |
2668 case 3: | |
2669 render_border_garbage(context, context->serial_address, context->tmp_buf_a, context->buf_a_off, context->col_1); | |
2670 break; | |
2671 case 4: | |
2672 render_border_garbage(context, context->serial_address, context->tmp_buf_a, context->buf_a_off+8, context->col_2); | |
2673 break; | |
2674 case 7: | |
2675 render_border_garbage(context, context->serial_address, context->tmp_buf_b, context->buf_b_off, context->col_1); | |
2676 break; | |
2677 case 0: | |
2678 render_border_garbage(context, context->serial_address, context->tmp_buf_b, context->buf_b_off+8, context->col_2); | |
2679 inactive_test_output(context, is_h40, test_layer); | |
2680 break; | |
2681 } | |
2682 } | |
2620 | 2683 |
2621 if (context->hslot == buf_clear_slot) { | 2684 if (context->hslot == buf_clear_slot) { |
2622 if (mode_5) { | 2685 if (mode_5) { |
2623 context->cur_slot = max_draws; | 2686 context->cur_slot = max_draws; |
2624 } else { | 2687 } else { |
2682 { | 2745 { |
2683 uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; | 2746 uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; |
2684 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; | 2747 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; |
2685 while(context->cycles < target_cycles) | 2748 while(context->cycles < target_cycles) |
2686 { | 2749 { |
2687 if (context->state == ACTIVE && context->vcounter == context->inactive_start) { | 2750 //technically the second hcounter check should be different for H40, but this is probably close enough for now |
2751 if (context->state == ACTIVE && context->vcounter == context->inactive_start && (context->hslot >= (is_h40 ? 167 : 135) || context->hslot < 133)) { | |
2688 context->state = INACTIVE; | 2752 context->state = INACTIVE; |
2689 } | 2753 } |
2690 | 2754 |
2691 if (is_active(context)) { | 2755 if (is_active(context)) { |
2692 if (mode_5) { | 2756 if (mode_5) { |