comparison vdp.c @ 1167:e758ddbf0624

Initial work on emulating top and bottom border area
author Michael Pavone <pavone@retrodev.com>
date Sun, 15 Jan 2017 15:07:24 -0800
parents b251899f2b97
children fa73a77ddf92
comparison
equal deleted inserted replaced
1166:73e36dac5be7 1167:e758ddbf0624
39 #define LINE_CHANGE_MODE4 249 39 #define LINE_CHANGE_MODE4 249
40 #define VBLANK_START_H40 (LINE_CHANGE_H40+2) 40 #define VBLANK_START_H40 (LINE_CHANGE_H40+2)
41 #define VBLANK_START_H32 (LINE_CHANGE_H32+2) 41 #define VBLANK_START_H32 (LINE_CHANGE_H32+2)
42 #define FIFO_LATENCY 3 42 #define FIFO_LATENCY 3
43 43
44 #define BORDER_TOP_V24 27
45 #define BORDER_TOP_V28 11
46 #define BORDER_TOP_V24_PAL 54
47 #define BORDER_TOP_V28_PAL 38
48 #define BORDER_TOP_V30_PAL 30
49
50 #define BORDER_BOT_V24 24
51 #define BORDER_BOT_V28 8
52 #define BORDER_BOT_V24_PAL 48
53 #define BORDER_BOT_V28_PAL 32
54 #define BORDER_BOT_V30_PAL 24
55
56 #define INVALID_LINE 0x200
57
44 static int32_t color_map[1 << 12]; 58 static int32_t color_map[1 << 12];
45 static uint16_t mode4_address_map[0x4000]; 59 static uint16_t mode4_address_map[0x4000];
46 static uint32_t planar_to_chunky[256]; 60 static uint32_t planar_to_chunky[256];
47 static uint8_t levels[] = {0, 27, 49, 71, 87, 103, 119, 130, 146, 157, 174, 190, 206, 228, 255}; 61 static uint8_t levels[] = {0, 27, 49, 71, 87, 103, 119, 130, 146, 157, 174, 190, 206, 228, 255};
48 62
51 {0, 0, 127}, //A 65 {0, 0, 127}, //A
52 {127, 0, 0}, //Window 66 {127, 0, 0}, //Window
53 {0, 127, 0}, //B 67 {0, 127, 0}, //B
54 {127, 0, 127} //Sprites 68 {127, 0, 127} //Sprites
55 }; 69 };
70
71 static void update_video_params(vdp_context *context)
72 {
73 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
74 if (context->latched_mode & BIT_PAL) {
75 if (context->flags2 & FLAG2_REGION_PAL) {
76 context->inactive_start = PAL_INACTIVE_START;
77 context->border_top = BORDER_TOP_V30_PAL;
78 context->border_bot = BORDER_BOT_V30_PAL;
79 } else {
80 context->inactive_start = 0x200;
81 context->border_top = context->border_bot = 0;
82 }
83 } else {
84 context->inactive_start = NTSC_INACTIVE_START;
85 if (context->flags2 & FLAG2_REGION_PAL) {
86 context->border_top = BORDER_TOP_V28_PAL;
87 context->border_bot = BORDER_BOT_V28_PAL;
88 } else {
89 context->border_top = BORDER_TOP_V28;
90 context->border_bot = BORDER_TOP_V28;
91 }
92 }
93 } else {
94 context->inactive_start = MODE4_INACTIVE_START;
95 if (context->flags2 & FLAG2_REGION_PAL) {
96 context->border_top = BORDER_TOP_V24_PAL;
97 context->border_bot = BORDER_BOT_V24_PAL;
98 } else {
99 context->border_top = BORDER_TOP_V24;
100 context->border_bot = BORDER_BOT_V24;
101 }
102 }
103 }
56 104
57 static uint8_t color_map_init_done; 105 static uint8_t color_map_init_done;
58 106
59 void init_vdp_context(vdp_context * context, uint8_t region_pal) 107 void init_vdp_context(vdp_context * context, uint8_t region_pal)
60 { 108 {
65 */ 113 */
66 if (headless) { 114 if (headless) {
67 context->output = malloc(LINEBUF_SIZE); 115 context->output = malloc(LINEBUF_SIZE);
68 context->output_pitch = 0; 116 context->output_pitch = 0;
69 } else { 117 } else {
70 context->output = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch); 118 context->fb = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch);
71 } 119 }
72 context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); 120 context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2);
73 memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); 121 memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2);
74 context->tmp_buf_a = context->linebuf + LINEBUF_SIZE; 122 context->tmp_buf_a = context->linebuf + LINEBUF_SIZE;
75 context->tmp_buf_b = context->tmp_buf_a + SCROLL_BUFFER_SIZE; 123 context->tmp_buf_b = context->tmp_buf_a + SCROLL_BUFFER_SIZE;
160 context->debugcolors[color] = render_map_color(r, g, b); 208 context->debugcolors[color] = render_map_color(r, g, b);
161 } 209 }
162 } 210 }
163 if (region_pal) { 211 if (region_pal) {
164 context->flags2 |= FLAG2_REGION_PAL; 212 context->flags2 |= FLAG2_REGION_PAL;
213 }
214 update_video_params(context);
215 if (!headless) {
216 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * context->border_top);
165 } 217 }
166 } 218 }
167 219
168 void vdp_free(vdp_context *context) 220 void vdp_free(vdp_context *context)
169 { 221 {
1113 context->fetch_tmp[1] = context->vdpmem[address+1]; 1165 context->fetch_tmp[1] = context->vdpmem[address+1];
1114 } 1166 }
1115 1167
1116 static void render_map_output(uint32_t line, int32_t col, vdp_context * context) 1168 static void render_map_output(uint32_t line, int32_t col, vdp_context * context)
1117 { 1169 {
1170 uint32_t *dst;
1171 if (line == 0x1FF) {
1172 if (!col) {
1173 return;
1174 }
1175 col -= 2;
1176 dst = context->output + col * 8;
1177 uint32_t color = context->colors[context->regs[REG_BG_COLOR]];
1178 for (int i = 0; i < 16; i++)
1179 {
1180 *(dst++) = color;
1181 }
1182 return;
1183 }
1118 if (line >= 240) { 1184 if (line >= 240) {
1119 return; 1185 return;
1120 } 1186 }
1121 render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context);
1122 uint32_t *dst;
1123 uint8_t *sprite_buf, *plane_a, *plane_b; 1187 uint8_t *sprite_buf, *plane_a, *plane_b;
1124 int plane_a_off, plane_b_off; 1188 int plane_a_off, plane_b_off;
1125 if (col) 1189 if (col)
1126 { 1190 {
1191 render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context);
1127 col-=2; 1192 col-=2;
1128 dst = context->output + col * 8; 1193 dst = context->output + col * 8;
1129 if (context->debug < 2) { 1194 if (context->debug < 2) {
1130 sprite_buf = context->linebuf + col * 8; 1195 sprite_buf = context->linebuf + col * 8;
1131 uint8_t a_src, src; 1196 uint8_t a_src, src;
1371 static uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19}; 1436 static uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19};
1372 1437
1373 static void vdp_advance_line(vdp_context *context) 1438 static void vdp_advance_line(vdp_context *context)
1374 { 1439 {
1375 context->vcounter++; 1440 context->vcounter++;
1376 context->vcounter &= 0x1FF; 1441
1377 uint8_t is_mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; 1442 uint8_t is_mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
1378 if (is_mode_5) { 1443 if (is_mode_5) {
1379 if (context->flags2 & FLAG2_REGION_PAL) { 1444 if (context->flags2 & FLAG2_REGION_PAL) {
1380 if (context->latched_mode & BIT_PAL) { 1445 if (context->latched_mode & BIT_PAL) {
1381 if (context->vcounter == 0x10B) { 1446 if (context->vcounter == 0x10B) {
1388 context->vcounter = 0x1E5; 1453 context->vcounter = 0x1E5;
1389 } 1454 }
1390 } else if (context->vcounter == 0xDB) { 1455 } else if (context->vcounter == 0xDB) {
1391 context->vcounter = 0x1D5; 1456 context->vcounter = 0x1D5;
1392 } 1457 }
1393 uint32_t inactive_start = (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START); 1458 if (headless) {
1394 if (!is_mode_5) { 1459 context->vcounter &= 0x1FF;
1395 inactive_start = MODE4_INACTIVE_START; 1460 } else {
1396 } 1461 if (context->vcounter == context->inactive_start) {
1397 if (!headless) { 1462 render_framebuffer_updated(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN: FRAMEBUFFER_ODD, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? 320 : 256);
1398 if (!context->vcounter && !context->output) {
1399 context->output = render_get_framebuffer(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD, &context->output_pitch);
1400 context->h40_lines = 0;
1401 } else if (context->vcounter == inactive_start) { //TODO: Change this once border emulation is added
1402 context->output = NULL;
1403 render_framebuffer_updated(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN: FRAMEBUFFER_ODD, context->h40_lines > inactive_start / 2 ? 320 : 256);
1404 if (context->double_res) { 1463 if (context->double_res) {
1405 context->flags2 ^= FLAG2_EVEN_FIELD; 1464 context->flags2 ^= FLAG2_EVEN_FIELD;
1406 } 1465 }
1407 } else if (context->output) { 1466 context->fb = render_get_framebuffer(context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD, &context->output_pitch);
1408 context->output = (uint32_t *)(((char *)context->output) + context->output_pitch); 1467 context->h40_lines = 0;
1409 if (context->regs[REG_MODE_4] & BIT_H40) { 1468 context->frame++;
1410 context->h40_lines++; 1469 }
1411 } 1470 context->vcounter &= 0x1FF;
1412 } 1471 uint32_t output_line;
1413 } 1472 if (context->vcounter < context->inactive_start + context->border_bot) {
1414 1473 output_line = context->border_top + context->vcounter;
1415 if (context->vcounter > inactive_start) { 1474 } else if (context->vcounter > 0x200 - context->border_top) {
1475 output_line = context->vcounter - (0x200 - context->border_top);
1476 } else {
1477 output_line = INVALID_LINE;
1478 }
1479 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * output_line);
1480 if (output_line != INVALID_LINE && (context->regs[REG_MODE_4] & BIT_H40)) {
1481 context->h40_lines++;
1482 }
1483 }
1484
1485 if (context->vcounter > context->inactive_start) {
1416 context->hint_counter = context->regs[REG_HINT]; 1486 context->hint_counter = context->regs[REG_HINT];
1417 } else if (context->hint_counter) { 1487 } else if (context->hint_counter) {
1418 context->hint_counter--; 1488 context->hint_counter--;
1419 } else { 1489 } else {
1420 context->flags2 |= FLAG2_HINT_PENDING; 1490 context->flags2 |= FLAG2_HINT_PENDING;
1671 case 255: 1741 case 255:
1672 render_map_3(context); 1742 render_map_3(context);
1673 scan_sprite_table(context->vcounter, context);//Just a guess 1743 scan_sprite_table(context->vcounter, context);//Just a guess
1674 CHECK_LIMIT 1744 CHECK_LIMIT
1675 case 0: 1745 case 0:
1676 if (context->vcounter == (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) { 1746 if (context->vcounter == context->inactive_start) {
1677 context->flags2 |= FLAG2_VINT_PENDING; 1747 context->flags2 |= FLAG2_VINT_PENDING;
1678 context->pending_vint_start = context->cycles; 1748 context->pending_vint_start = context->cycles;
1679 } 1749 }
1680 render_map_output(context->vcounter, 0, context); 1750 render_map_output(context->vcounter, 0, context);
1681 scan_sprite_table(context->vcounter, context);//Just a guess 1751 scan_sprite_table(context->vcounter, context);//Just a guess
1719 render_sprite_cells(context); 1789 render_sprite_cells(context);
1720 CHECK_LIMIT 1790 CHECK_LIMIT
1721 case 164: 1791 case 164:
1722 render_sprite_cells(context); 1792 render_sprite_cells(context);
1723 vdp_advance_line(context); 1793 vdp_advance_line(context);
1724 if (context->vcounter == (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) { 1794 if (context->vcounter == context->inactive_start) {
1725 context->hslot++; 1795 context->hslot++;
1726 context->cycles += slot_cycles; 1796 context->cycles += slot_cycles;
1727 return; 1797 return;
1728 } 1798 }
1729 CHECK_LIMIT 1799 CHECK_LIMIT
1874 render_sprite_cells(context); 1944 render_sprite_cells(context);
1875 CHECK_LIMIT 1945 CHECK_LIMIT
1876 case 132: 1946 case 132:
1877 render_sprite_cells(context); 1947 render_sprite_cells(context);
1878 vdp_advance_line(context); 1948 vdp_advance_line(context);
1879 if (context->vcounter == (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)) { 1949 if (context->vcounter == context->inactive_start) {
1880 context->hslot++; 1950 context->hslot++;
1881 context->cycles += slot_cycles; 1951 context->cycles += slot_cycles;
1882 return; 1952 return;
1883 } 1953 }
1884 CHECK_LIMIT 1954 CHECK_LIMIT
2014 } 2084 }
2015 2085
2016 void latch_mode(vdp_context * context) 2086 void latch_mode(vdp_context * context)
2017 { 2087 {
2018 context->latched_mode = context->regs[REG_MODE_2] & BIT_PAL; 2088 context->latched_mode = context->regs[REG_MODE_2] & BIT_PAL;
2089 update_video_params(context);
2019 } 2090 }
2020 2091
2021 static void check_render_bg(vdp_context * context, int32_t line, uint32_t slot) 2092 static void check_render_bg(vdp_context * context, int32_t line, uint32_t slot)
2022 { 2093 {
2023 int starti = -1; 2094 int starti = -1;
2029 if (slot >= 11 && slot < 139) { 2100 if (slot >= 11 && slot < 139) {
2030 starti = (slot-11)*2; 2101 starti = (slot-11)*2;
2031 } 2102 }
2032 } 2103 }
2033 if (starti >= 0) { 2104 if (starti >= 0) {
2034 uint32_t color = context->colors[context->regs[REG_BG_COLOR]]; 2105 uint32_t color = (context->regs[REG_MODE_2] & BIT_MODE_5)
2106 ? context->colors[context->regs[REG_BG_COLOR]]
2107 : context->colors[CRAM_SIZE * 3 + 0x10 + (context->regs[REG_BG_COLOR] & 0xF)];
2035 uint32_t * start = context->output + starti; 2108 uint32_t * start = context->output + starti;
2036 for (int i = 0; i < 2; i++) { 2109 for (int i = 0; i < 2; i++) {
2037 *(start++) = color; 2110 *(start++) = color;
2038 } 2111 }
2039 } 2112 }
2040 } 2113 }
2041 2114
2042 2115
2043 void vdp_run_context(vdp_context * context, uint32_t target_cycles) 2116 void vdp_run_context(vdp_context * context, uint32_t target_cycles)
2044 { 2117 {
2118 uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40;
2119 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
2045 while(context->cycles < target_cycles) 2120 while(context->cycles < target_cycles)
2046 { 2121 {
2047 uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; 2122 uint8_t active_slot;
2048 uint8_t active_slot, mode_5; 2123 if (mode_5) {
2049 uint32_t inactive_start;
2050 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
2051 //Mode 5 selected
2052 mode_5 = 1;
2053 inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START;
2054 //line 0x1FF is basically active even though it's not displayed 2124 //line 0x1FF is basically active even though it's not displayed
2055 active_slot = (context->vcounter < inactive_start || context->vcounter == 0x1FF) && (context->regs[REG_MODE_2] & DISPLAY_ENABLE); 2125 active_slot = (context->vcounter < context->inactive_start || context->vcounter == 0x1FF) && (context->regs[REG_MODE_2] & DISPLAY_ENABLE);
2056 } else { 2126 } else {
2057 mode_5 = 0;
2058 inactive_start = MODE4_INACTIVE_START;
2059 //display is effectively disabled if neither mode 5 nor mode 4 are selected 2127 //display is effectively disabled if neither mode 5 nor mode 4 are selected
2060 active_slot = context->vcounter < inactive_start && (context->regs[REG_MODE_2] & DISPLAY_ENABLE) && (context->regs[REG_MODE_1] & BIT_MODE_4); 2128 active_slot = context->vcounter < context->inactive_start && (context->regs[REG_MODE_2] & DISPLAY_ENABLE) && (context->regs[REG_MODE_1] & BIT_MODE_4);
2061 } 2129 }
2062 2130
2063 if (active_slot) { 2131 if (active_slot) {
2064 if (mode_5) { 2132 if (mode_5) {
2065 if (is_h40) { 2133 if (is_h40) {
2095 memset(context->linebuf, 0, LINEBUF_SIZE); 2163 memset(context->linebuf, 0, LINEBUF_SIZE);
2096 context->cur_slot = context->sprite_index = MAX_DRAWS_H32_MODE4-1; 2164 context->cur_slot = context->sprite_index = MAX_DRAWS_H32_MODE4-1;
2097 context->sprite_draws = MAX_DRAWS_H32_MODE4; 2165 context->sprite_draws = MAX_DRAWS_H32_MODE4;
2098 } 2166 }
2099 } 2167 }
2100 if(context->vcounter == inactive_start) { 2168 if(context->vcounter == context->inactive_start) {
2101 uint32_t intslot = context->regs[REG_MODE_4] & BIT_H40 ? VINT_SLOT_H40 : VINT_SLOT_H32; 2169 uint32_t intslot = context->regs[REG_MODE_4] & BIT_H40 ? VINT_SLOT_H40 : VINT_SLOT_H32;
2102 if (context->hslot == intslot) { 2170 if (context->hslot == intslot) {
2103 context->flags2 |= FLAG2_VINT_PENDING; 2171 context->flags2 |= FLAG2_VINT_PENDING;
2104 context->pending_vint_start = context->cycles; 2172 context->pending_vint_start = context->cycles;
2105 } 2173 }
2117 inccycles = MCLKS_SLOT_H32; 2185 inccycles = MCLKS_SLOT_H32;
2118 } 2186 }
2119 if (!is_refresh(context, context->hslot)) { 2187 if (!is_refresh(context, context->hslot)) {
2120 external_slot(context); 2188 external_slot(context);
2121 } 2189 }
2122 if (context->vcounter < inactive_start) { 2190 if (context->vcounter < (context->inactive_start + context->border_bot) || context->vcounter > 0x200 - context->border_top) {
2123 check_render_bg(context, context->vcounter, context->hslot); 2191 check_render_bg(context, context->vcounter, context->hslot);
2124 } 2192 }
2125 if (context->flags & FLAG_DMA_RUN && !is_refresh(context, context->hslot)) { 2193 if (context->flags & FLAG_DMA_RUN && !is_refresh(context, context->hslot)) {
2126 run_dma_src(context, context->hslot); 2194 run_dma_src(context, context->hslot);
2127 } 2195 }
2128 context->cycles += inccycles; 2196 context->cycles += inccycles;
2129 context->hslot++; 2197 context->hslot++;
2130 if (is_h40) { 2198 if (is_h40) {
2131 if (context->hslot == LINE_CHANGE_H40) { 2199 if (context->hslot == LINE_CHANGE_H40) {
2132 vdp_advance_line(context); 2200 vdp_advance_line(context);
2133 if (context->vcounter == (inactive_start + 8)) {
2134 context->frame++;
2135 }
2136 } else if (context->hslot == 183) { 2201 } else if (context->hslot == 183) {
2137 context->hslot = 229; 2202 context->hslot = 229;
2138 } 2203 }
2139 } else { 2204 } else {
2140 if (context->hslot == (mode_5 ? LINE_CHANGE_H32 : LINE_CHANGE_MODE4)) { 2205 if (context->hslot == (mode_5 ? LINE_CHANGE_H32 : LINE_CHANGE_MODE4)) {
2141 vdp_advance_line(context); 2206 vdp_advance_line(context);
2142 if (context->vcounter == (inactive_start + 8)) {
2143 context->frame++;
2144 }
2145 } else if (context->hslot == 148) { 2207 } else if (context->hslot == 148) {
2146 context->hslot = 233; 2208 context->hslot = 233;
2147 } 2209 }
2148 } 2210 }
2149 } 2211 }
2150 } 2212 }
2151 } 2213 }
2152 2214
2153 uint32_t vdp_run_to_vblank(vdp_context * context) 2215 uint32_t vdp_run_to_vblank(vdp_context * context)
2154 { 2216 {
2155 uint32_t target_cycles = ((context->latched_mode & BIT_PAL) ? PAL_INACTIVE_START : NTSC_INACTIVE_START) * MCLKS_LINE; 2217 uint32_t old_frame = context->frame;
2156 vdp_run_context(context, target_cycles); 2218 while (context->frame == old_frame) {
2219 vdp_run_context(context, MCLKS_LINE);
2220 }
2157 return context->cycles; 2221 return context->cycles;
2158 } 2222 }
2159 2223
2160 void vdp_run_dma_done(vdp_context * context, uint32_t target_cycles) 2224 void vdp_run_dma_done(vdp_context * context, uint32_t target_cycles)
2161 { 2225 {
2273 context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); 2337 context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES);
2274 if (!context->double_res) { 2338 if (!context->double_res) {
2275 context->flags2 &= ~FLAG2_EVEN_FIELD; 2339 context->flags2 &= ~FLAG2_EVEN_FIELD;
2276 } 2340 }
2277 } 2341 }
2342 if (reg == REG_MODE_2) {
2343 update_video_params(context);
2344 }
2278 } 2345 }
2279 } else if (mode_5) { 2346 } else if (mode_5) {
2280 context->flags |= FLAG_PENDING; 2347 context->flags |= FLAG_PENDING;
2281 //Should these be taken care of here or after the second write? 2348 //Should these be taken care of here or after the second write?
2282 //context->flags &= ~FLAG_READ_FETCHED; 2349 //context->flags &= ~FLAG_READ_FETCHED;
2410 if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && !(context->flags2 & FLAG2_EVEN_FIELD)) { 2477 if ((context->regs[REG_MODE_4] & BIT_INTERLACE) && !(context->flags2 & FLAG2_EVEN_FIELD)) {
2411 value |= 0x10; 2478 value |= 0x10;
2412 } 2479 }
2413 uint32_t line= context->vcounter; 2480 uint32_t line= context->vcounter;
2414 uint32_t slot = context->hslot; 2481 uint32_t slot = context->hslot;
2415 uint32_t inactive_start = (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START); 2482 if ((line >= context->inactive_start && line < 0x1FF) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) {
2416 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) {
2417 inactive_start = MODE4_INACTIVE_START;
2418 }
2419 if ((line >= inactive_start && line < 0x1FF) || !(context->regs[REG_MODE_2] & BIT_DISP_EN)) {
2420 value |= 0x8; 2483 value |= 0x8;
2421 } 2484 }
2422 if (context->regs[REG_MODE_4] & BIT_H40) { 2485 if (context->regs[REG_MODE_4] & BIT_H40) {
2423 if (slot < HBLANK_END_H40 || slot > HBLANK_START_H40) { 2486 if (slot < HBLANK_END_H40 || slot > HBLANK_START_H40) {
2424 value |= 0x4; 2487 value |= 0x4;
2590 } 2653 }
2591 } 2654 }
2592 return MCLKS_LINE * (lines - 1) + vdp_cycles_next_line(context); 2655 return MCLKS_LINE * (lines - 1) + vdp_cycles_next_line(context);
2593 } 2656 }
2594 2657
2595 static uint32_t vdp_frame_end_line(vdp_context * context)
2596 {
2597 uint32_t frame_end;
2598 if (context->flags2 & FLAG2_REGION_PAL) {
2599 if (context->latched_mode & BIT_PAL) {
2600 frame_end = PAL_INACTIVE_START + 8;
2601 } else {
2602 frame_end = NTSC_INACTIVE_START + 8;
2603 }
2604 } else {
2605 if (context->latched_mode & BIT_PAL) {
2606 frame_end = 512;
2607 } else {
2608 frame_end = NTSC_INACTIVE_START + 8;
2609 }
2610 }
2611 return frame_end;
2612 }
2613
2614 uint32_t vdp_cycles_to_frame_end(vdp_context * context) 2658 uint32_t vdp_cycles_to_frame_end(vdp_context * context)
2615 { 2659 {
2616 return context->cycles + vdp_cycles_to_line(context, vdp_frame_end_line(context)); 2660 return context->cycles + vdp_cycles_to_line(context, context->inactive_start);
2617 } 2661 }
2618 2662
2619 uint32_t vdp_next_hint(vdp_context * context) 2663 uint32_t vdp_next_hint(vdp_context * context)
2620 { 2664 {
2621 if (!(context->regs[REG_MODE_1] & BIT_HINT_EN)) { 2665 if (!(context->regs[REG_MODE_1] & BIT_HINT_EN)) {
2622 return 0xFFFFFFFF; 2666 return 0xFFFFFFFF;
2623 } 2667 }
2624 if (context->flags2 & FLAG2_HINT_PENDING) { 2668 if (context->flags2 & FLAG2_HINT_PENDING) {
2625 return context->pending_hint_start; 2669 return context->pending_hint_start;
2626 } 2670 }
2627 uint32_t inactive_start = (context->regs[REG_MODE_2] & BIT_MODE_5)
2628 ? (context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START)
2629 : MODE4_INACTIVE_START;
2630 uint32_t hint_line; 2671 uint32_t hint_line;
2631 if (context->vcounter + context->hint_counter >= inactive_start) { 2672 if (context->vcounter + context->hint_counter >= context->inactive_start) {
2632 if (context->regs[REG_HINT] > inactive_start) { 2673 if (context->regs[REG_HINT] > context->inactive_start) {
2633 return 0xFFFFFFFF; 2674 return 0xFFFFFFFF;
2634 } 2675 }
2635 hint_line = context->regs[REG_HINT]; 2676 hint_line = context->regs[REG_HINT];
2636 } else { 2677 } else {
2637 hint_line = context->vcounter + context->hint_counter + 1; 2678 hint_line = context->vcounter + context->hint_counter + 1;
2653 return vdp_next_vint_z80(context); 2694 return vdp_next_vint_z80(context);
2654 } 2695 }
2655 2696
2656 uint32_t vdp_next_vint_z80(vdp_context * context) 2697 uint32_t vdp_next_vint_z80(vdp_context * context)
2657 { 2698 {
2658 uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START; 2699 if (context->vcounter == context->inactive_start) {
2659 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) {
2660 inactive_start = MODE4_INACTIVE_START;
2661 }
2662 if (context->vcounter == inactive_start) {
2663 if (context->regs[REG_MODE_2] & BIT_MODE_5) { 2700 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
2664 if (context->regs[REG_MODE_4] & BIT_H40) { 2701 if (context->regs[REG_MODE_4] & BIT_H40) {
2665 if (context->hslot >= LINE_CHANGE_H40 && context->hslot <= VINT_SLOT_H40) { 2702 if (context->hslot >= LINE_CHANGE_H40 && context->hslot <= VINT_SLOT_H40) {
2666 uint32_t cycles = context->cycles; 2703 uint32_t cycles = context->cycles;
2667 if (context->hslot < 182) { 2704 if (context->hslot < 182) {
2694 if (context->hslot <= VINT_SLOT_MODE4) { 2731 if (context->hslot <= VINT_SLOT_MODE4) {
2695 return context->cycles + (VINT_SLOT_MODE4 - context->hslot) * MCLKS_SLOT_H32; 2732 return context->cycles + (VINT_SLOT_MODE4 - context->hslot) * MCLKS_SLOT_H32;
2696 } 2733 }
2697 } 2734 }
2698 } 2735 }
2699 int32_t cycles_to_vint = vdp_cycles_to_line(context, inactive_start); 2736 int32_t cycles_to_vint = vdp_cycles_to_line(context, context->inactive_start);
2700 if (context->regs[REG_MODE_2] & BIT_MODE_5) { 2737 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
2701 if (context->regs[REG_MODE_4] & BIT_H40) { 2738 if (context->regs[REG_MODE_4] & BIT_H40) {
2702 cycles_to_vint += MCLKS_LINE - (LINE_CHANGE_H40 + (256 - VINT_SLOT_H40)) * MCLKS_SLOT_H40; 2739 cycles_to_vint += MCLKS_LINE - (LINE_CHANGE_H40 + (256 - VINT_SLOT_H40)) * MCLKS_SLOT_H40;
2703 } else { 2740 } else {
2704 cycles_to_vint += (VINT_SLOT_H32 - 233 + 148 - LINE_CHANGE_H32) * MCLKS_SLOT_H32; 2741 cycles_to_vint += (VINT_SLOT_H32 - 233 + 148 - LINE_CHANGE_H32) * MCLKS_SLOT_H32;