Mercurial > repos > blastem
comparison vdp.c @ 2257:1e626d0ecf9c
WIP SG-1000/TMS9918A mode support
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 17 Dec 2022 23:32:34 -0800 |
parents | e6bad7bd8751 |
children | a28e1042f4de |
comparison
equal
deleted
inserted
replaced
2256:cbe1ba70c247 | 2257:1e626d0ecf9c |
---|---|
34 #define HBLANK_END_H40 0 //should be 5.5 according to Nemesis, but 0 seems to fit better with my test ROM results | 34 #define HBLANK_END_H40 0 //should be 5.5 according to Nemesis, but 0 seems to fit better with my test ROM results |
35 #define HBLANK_START_H32 233 //should be 147 according to Nemesis which is very different from my test ROM result | 35 #define HBLANK_START_H32 233 //should be 147 according to Nemesis which is very different from my test ROM result |
36 #define HBLANK_END_H32 0 //should be 5 according to Nemesis, but 0 seems to fit better with my test ROM results | 36 #define HBLANK_END_H32 0 //should be 5 according to Nemesis, but 0 seems to fit better with my test ROM results |
37 #define LINE_CHANGE_H40 165 | 37 #define LINE_CHANGE_H40 165 |
38 #define LINE_CHANGE_H32 133 | 38 #define LINE_CHANGE_H32 133 |
39 #define LINE_CHANGE_MODE4 249 | 39 #define LINE_CHANGE_MODE4 248 |
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 #define READ_LATENCY 3 | 43 #define READ_LATENCY 3 |
44 | 44 |
162 context->fifo_write = 0; | 162 context->fifo_write = 0; |
163 context->fifo_read = -1; | 163 context->fifo_read = -1; |
164 context->regs[REG_HINT] = context->hint_counter = 0xFF; | 164 context->regs[REG_HINT] = context->hint_counter = 0xFF; |
165 context->vsram_size = has_max_vsram ? MAX_VSRAM_SIZE : MIN_VSRAM_SIZE; | 165 context->vsram_size = has_max_vsram ? MAX_VSRAM_SIZE : MIN_VSRAM_SIZE; |
166 context->type = type; | 166 context->type = type; |
167 uint8_t b,g,r; | 167 uint8_t b,g,r,index; |
168 for (uint16_t color = 0; color < (1 << 12); color++) { | 168 for (uint16_t color = 0; color < (1 << 12); color++) { |
169 if (type == VDP_GAMEGEAR) { | 169 if (type == VDP_GAMEGEAR) { |
170 b = (color >> 8 & 0xF) * 0x11; | 170 b = (color >> 8 & 0xF) * 0x11; |
171 g = (color >> 4 & 0xF) * 0x11; | 171 g = (color >> 4 & 0xF) * 0x11; |
172 r = (color & 0xF) * 0x11; | 172 r = (color & 0xF) * 0x11; |
173 }else if (color & FBUF_SHADOW) { | |
174 b = levels[(color >> 9) & 0x7]; | |
175 g = levels[(color >> 5) & 0x7]; | |
176 r = levels[(color >> 1) & 0x7]; | |
177 } else if(color & FBUF_HILIGHT) { | |
178 b = levels[((color >> 9) & 0x7) + 7]; | |
179 g = levels[((color >> 5) & 0x7) + 7]; | |
180 r = levels[((color >> 1) & 0x7) + 7]; | |
181 } else if(color & FBUF_MODE4) { | |
182 //TODO: Mode 4 has a separate DAC tap so this isn't quite correct | |
183 b = levels[(color >> 4 & 0xC) | (color >> 6 & 0x2)]; | |
184 g = levels[(color >> 2 & 0x8) | (color >> 1 & 0x4) | (color >> 4 & 0x2)]; | |
185 r = levels[(color << 1 & 0xC) | (color >> 1 & 0x2)]; | |
186 } else { | 173 } else { |
187 b = levels[(color >> 8) & 0xE]; | 174 switch (color & FBUF_MASK) |
188 g = levels[(color >> 4) & 0xE]; | 175 { |
189 r = levels[color & 0xE]; | 176 case FBUF_SHADOW: |
177 b = levels[(color >> 9) & 0x7]; | |
178 g = levels[(color >> 5) & 0x7]; | |
179 r = levels[(color >> 1) & 0x7]; | |
180 break; | |
181 case FBUF_HILIGHT: | |
182 b = levels[((color >> 9) & 0x7) + 7]; | |
183 g = levels[((color >> 5) & 0x7) + 7]; | |
184 r = levels[((color >> 1) & 0x7) + 7]; | |
185 break; | |
186 case FBUF_MODE4: | |
187 //TODO: Mode 4 has a separate DAC tap so this isn't quite correct | |
188 //TODO: blue channel has one of its taps offest on SMS1 and MD | |
189 b = levels[(color >> 4 & 0xC) | (color >> 6 & 0x2)]; | |
190 g = levels[(color >> 2 & 0x8) | (color >> 1 & 0x4) | (color >> 4 & 0x2)]; | |
191 r = levels[(color << 1 & 0xC) | (color >> 1 & 0x2)]; | |
192 break; | |
193 case FBUF_TMS: | |
194 index = color >> 1 & 0x7; | |
195 index |= color >> 2 & 0x8; | |
196 if (type == VDP_TMS9918A) { | |
197 switch (index) | |
198 { | |
199 case 0: | |
200 case 1: | |
201 r = g = b = 0; | |
202 break; | |
203 case 2: | |
204 r = 0x21; g = 0xC8; b = 0x42; | |
205 break; | |
206 case 3: | |
207 r = 0x5E; g = 0xDC; b = 0x78; | |
208 break; | |
209 case 4: | |
210 r = 0x54; g = 0x55; b = 0xED; | |
211 break; | |
212 case 5: | |
213 r = 0x7D; g = 0x76; b = 0xFC; | |
214 break; | |
215 case 6: | |
216 r = 0xD4; g = 0x52; b = 0x4D; | |
217 break; | |
218 case 7: | |
219 r = 0x42; g = 0xEB; b = 0xF5; | |
220 break; | |
221 case 8: | |
222 r = 0xFC; g = 0x55; b = 0x54; | |
223 break; | |
224 case 9: | |
225 r = 0xFF; g = 0x79; b = 0x78; | |
226 break; | |
227 case 10: | |
228 r = 0xD4; g = 0xC1; b = 0x54; | |
229 break; | |
230 case 11: | |
231 r = 0xE6; g = 0xCE; b = 0x80; | |
232 break; | |
233 case 12: | |
234 r = 0x21; g = 0xB0; b = 0x3B; | |
235 break; | |
236 case 13: | |
237 r = 0xC9; g = 0x5B; b = 0xBA; | |
238 break; | |
239 case 14: | |
240 r = g = b = 0xCC; | |
241 break; | |
242 case 15: | |
243 r = g = b = 0xFF; | |
244 break; | |
245 } | |
246 } else { | |
247 static const uint8_t tms_to_sms[] = { | |
248 0x00, 0x00, 0x08, 0x0C, 0x10, 0x30, 0x01, 0x3C, 0x02, 0x03, 0x05, 0x0F, 0x04, 0x33, 0x15, 0x3F | |
249 }; | |
250 index = tms_to_sms[index] << 1; | |
251 index = (index & 0xE) | (index << 1 & 0x80); | |
252 //TODO: Mode 4 has a separate DAC tap so this isn't quite correct | |
253 //TODO: blue channel has one of its taps offest on SMS1 and MD | |
254 b = levels[(index >> 4 & 0xC) | (index >> 6 & 0x2)]; | |
255 g = levels[(index >> 2 & 0x8) | (index >> 1 & 0x4) | (index >> 4 & 0x2)]; | |
256 r = levels[(index << 1 & 0xC) | (index >> 1 & 0x2)]; | |
257 } | |
258 break; | |
259 default: | |
260 b = levels[(color >> 8) & 0xE]; | |
261 g = levels[(color >> 4) & 0xE]; | |
262 r = levels[color & 0xE]; | |
263 } | |
190 } | 264 } |
191 context->color_map[color] = render_map_color(r, g, b); | 265 context->color_map[color] = render_map_color(r, g, b); |
192 } | 266 } |
193 | 267 |
194 if (!static_table_init_done) { | 268 if (!static_table_init_done) { |
448 return addr; | 522 return addr; |
449 } | 523 } |
450 | 524 |
451 void vdp_print_sprite_table(vdp_context * context) | 525 void vdp_print_sprite_table(vdp_context * context) |
452 { | 526 { |
453 if (context->regs[REG_MODE_2] & BIT_MODE_5) { | 527 if (context->type == VDP_GENESIS && context->regs[REG_MODE_2] & BIT_MODE_5) { |
454 uint16_t sat_address = mode5_sat_address(context); | 528 uint16_t sat_address = mode5_sat_address(context); |
455 uint16_t current_index = 0; | 529 uint16_t current_index = 0; |
456 uint8_t count = 0; | 530 uint8_t count = 0; |
457 do { | 531 do { |
458 uint16_t address = current_index * 8 + sat_address; | 532 uint16_t address = current_index * 8 + sat_address; |
467 uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5; | 541 uint16_t pattern = ((context->vdpmem[address + 4] << 8 | context->vdpmem[address + 5]) & 0x7FF) << 5; |
468 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); | 542 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); |
469 current_index = link; | 543 current_index = link; |
470 count++; | 544 count++; |
471 } while (current_index != 0 && count < 80); | 545 } while (current_index != 0 && count < 80); |
472 } else { | 546 } else if (context->type != VDP_TMS9918A && context->regs[REG_MODE_1] & BIT_MODE_4) { |
473 uint16_t sat_address = (context->regs[REG_SAT] & 0x7E) << 7; | 547 uint16_t sat_address = (context->regs[REG_SAT] & 0x7E) << 7; |
474 for (int i = 0; i < 64; i++) | 548 for (int i = 0; i < 64; i++) |
475 { | 549 { |
476 uint8_t y = context->vdpmem[mode4_address_map[sat_address + (i ^ 1)]]; | 550 uint8_t y = context->vdpmem[mode4_address_map[sat_address + (i ^ 1)]]; |
477 if (y == 0xD0) { | 551 if (y == 0xD0) { |
482 + (context->regs[REG_STILE_BASE] << 11 & 0x2000); | 556 + (context->regs[REG_STILE_BASE] << 11 & 0x2000); |
483 if (context->regs[REG_MODE_2] & BIT_SPRITE_SZ) { | 557 if (context->regs[REG_MODE_2] & BIT_SPRITE_SZ) { |
484 tile_address &= ~32; | 558 tile_address &= ~32; |
485 } | 559 } |
486 printf("Sprite %d: X=%d, Y=%d, Pat=%X\n", i, x, y, tile_address); | 560 printf("Sprite %d: X=%d, Y=%d, Pat=%X\n", i, x, y, tile_address); |
561 } | |
562 } else if (context->type != VDP_GENESIS) { | |
563 uint16_t sat_address = context->regs[REG_SAT] << 7 & 0x3F80; | |
564 for (int i = 0; i < 32; i++) | |
565 { | |
566 uint16_t address = i << 2 | sat_address; | |
567 int16_t y = context->vdpmem[mode4_address_map[address++] ^ 1]; | |
568 if (y == 208) { | |
569 break; | |
570 } | |
571 if (y > 192) { | |
572 y -= 256; | |
573 } | |
574 int16_t x = context->vdpmem[mode4_address_map[address++] ^ 1]; | |
575 uint8_t name = context->vdpmem[mode4_address_map[address++] ^ 1]; | |
576 uint8_t tag = context->vdpmem[mode4_address_map[address] ^ 1]; | |
577 if (tag & 0x80) { | |
578 x -= 32; | |
579 } | |
580 tag &= 0xF; | |
581 printf("Sprite %d: X=%d, Y=%d, Pat=%X, Color=%X\n", i, x, y, name, tag); | |
487 } | 582 } |
488 } | 583 } |
489 } | 584 } |
490 | 585 |
491 #define VRAM_READ 0 //0000 | 586 #define VRAM_READ 0 //0000 |
1968 context->pending_hint_start = context->cycles; | 2063 context->pending_hint_start = context->cycles; |
1969 context->hint_counter = context->regs[REG_HINT]; | 2064 context->hint_counter = context->regs[REG_HINT]; |
1970 } | 2065 } |
1971 } | 2066 } |
1972 | 2067 |
2068 static void vram_debug_mode5(uint32_t *fb, uint32_t pitch, vdp_context *context) | |
2069 { | |
2070 uint8_t pal = (context->debug_modes[DEBUG_VRAM] % 4) << 4; | |
2071 for (int y = 0; y < 512; y++) | |
2072 { | |
2073 uint32_t *line = fb + y * pitch / sizeof(uint32_t); | |
2074 int row = y >> 4; | |
2075 int yoff = y >> 1 & 7; | |
2076 for (int col = 0; col < 64; col++) | |
2077 { | |
2078 uint16_t address = (row * 64 + col) * 32 + yoff * 4; | |
2079 for (int x = 0; x < 4; x++) | |
2080 { | |
2081 uint8_t byte = context->vdpmem[address++]; | |
2082 uint8_t left = byte >> 4 | pal; | |
2083 uint8_t right = byte & 0xF | pal; | |
2084 *(line++) = context->colors[left]; | |
2085 *(line++) = context->colors[left]; | |
2086 *(line++) = context->colors[right]; | |
2087 *(line++) = context->colors[right]; | |
2088 } | |
2089 } | |
2090 } | |
2091 } | |
2092 | |
2093 static void vram_debug_mode4(uint32_t *fb, uint32_t pitch, vdp_context *context) | |
2094 { | |
2095 for (int y = 0; y < 256; y++) | |
2096 { | |
2097 uint32_t *line = fb + y * pitch / sizeof(uint32_t); | |
2098 int row = y >> 4; | |
2099 int yoff = y >> 1 & 7; | |
2100 for (int col = 0; col < 64; col++) | |
2101 { | |
2102 uint8_t pal = (col >= 32) << 4; | |
2103 uint16_t address = (row * 32 + (col & 31)) * 32 + yoff * 4; | |
2104 uint32_t pixels = 0; | |
2105 for (int x = 0; x < 4; x++) | |
2106 { | |
2107 uint8_t byte = context->vdpmem[mode4_address_map[address++]]; | |
2108 pixels |= planar_to_chunky[byte] << (x ^ 1); | |
2109 } | |
2110 for (int x = 0; x < 32; x+=4) | |
2111 { | |
2112 uint8_t pixel = (pixels >> (28 - x) & 0xF) | pal; | |
2113 *(line++) = context->colors[pixel + MODE4_OFFSET]; | |
2114 *(line++) = context->colors[pixel + MODE4_OFFSET]; | |
2115 } | |
2116 } | |
2117 } | |
2118 } | |
2119 | |
2120 static void vram_debug_tms(uint32_t *fb, uint32_t pitch, vdp_context *context) | |
2121 { | |
2122 uint8_t pal = ((context->debug_modes[DEBUG_VRAM] % 14) + 2) << 1; | |
2123 pal = (pal & 0xE) | (pal << 1 & 0x20); | |
2124 for (int y = 0; y < 512; y++) | |
2125 { | |
2126 uint32_t *line = fb + y * pitch / sizeof(uint32_t); | |
2127 int row = y >> 4; | |
2128 int yoff = y >> 1 & 7; | |
2129 for (int col = 0; col < 64; col++) | |
2130 { | |
2131 uint16_t address = (row * 64 + col) * 8 + yoff; | |
2132 uint8_t byte = context->vdpmem[mode4_address_map[address^1]]; | |
2133 for (int x = 0; x < 8; x++) | |
2134 { | |
2135 uint16_t pixel = (byte & 0x80) ? pal : 0; | |
2136 byte <<= 1; | |
2137 *(line++) = context->color_map[pixel | FBUF_TMS]; | |
2138 *(line++) = context->color_map[pixel | FBUF_TMS]; | |
2139 } | |
2140 } | |
2141 } | |
2142 } | |
2143 | |
2144 | |
1973 static void vdp_update_per_frame_debug(vdp_context *context) | 2145 static void vdp_update_per_frame_debug(vdp_context *context) |
1974 { | 2146 { |
1975 if (context->enabled_debuggers & (1 << DEBUG_PLANE)) { | 2147 if (context->enabled_debuggers & (1 << DEBUG_PLANE)) { |
1976 uint32_t pitch; | 2148 uint32_t pitch; |
1977 uint32_t *fb = render_get_framebuffer(context->debug_fb_indices[DEBUG_PLANE], &pitch); | 2149 uint32_t *fb = render_get_framebuffer(context->debug_fb_indices[DEBUG_PLANE], &pitch); |
2073 } | 2245 } |
2074 | 2246 |
2075 if (context->enabled_debuggers & (1 << DEBUG_VRAM)) { | 2247 if (context->enabled_debuggers & (1 << DEBUG_VRAM)) { |
2076 uint32_t pitch; | 2248 uint32_t pitch; |
2077 uint32_t *fb = render_get_framebuffer(context->debug_fb_indices[DEBUG_VRAM], &pitch); | 2249 uint32_t *fb = render_get_framebuffer(context->debug_fb_indices[DEBUG_VRAM], &pitch); |
2078 | 2250 if (context->type == VDP_GENESIS && (context->regs[REG_MODE_2] & BIT_MODE_5)) { |
2079 uint8_t pal = (context->debug_modes[DEBUG_VRAM] % 4) << 4; | 2251 vram_debug_mode5(fb, pitch, context); |
2080 for (int y = 0; y < 512; y++) | 2252 } else if (context->type != VDP_TMS9918A && (context->regs[REG_MODE_1] & BIT_MODE_4)) { |
2081 { | 2253 vram_debug_mode4(fb, pitch, context); |
2082 uint32_t *line = fb + y * pitch / sizeof(uint32_t); | 2254 } else if (context->type != VDP_GENESIS) { |
2083 int row = y >> 4; | 2255 vram_debug_tms(fb, pitch, context); |
2084 int yoff = y >> 1 & 7; | 2256 } |
2085 for (int col = 0; col < 64; col++) | |
2086 { | |
2087 uint16_t address = (row * 64 + col) * 32 + yoff * 4; | |
2088 for (int x = 0; x < 4; x++) | |
2089 { | |
2090 uint8_t byte = context->vdpmem[address++]; | |
2091 uint8_t left = byte >> 4 | pal; | |
2092 uint8_t right = byte & 0xF | pal; | |
2093 *(line++) = context->colors[left]; | |
2094 *(line++) = context->colors[left]; | |
2095 *(line++) = context->colors[right]; | |
2096 *(line++) = context->colors[right]; | |
2097 } | |
2098 } | |
2099 } | |
2100 | |
2101 render_framebuffer_updated(context->debug_fb_indices[DEBUG_VRAM], 1024); | 2257 render_framebuffer_updated(context->debug_fb_indices[DEBUG_VRAM], 1024); |
2102 } | 2258 } |
2103 | 2259 |
2104 if (context->enabled_debuggers & (1 << DEBUG_CRAM)) { | 2260 if (context->enabled_debuggers & (1 << DEBUG_CRAM)) { |
2105 uint32_t starting_line = 512 - 32*4; | 2261 uint32_t starting_line = 512 - 32*4; |
3418 context->hslot++; | 3574 context->hslot++; |
3419 context->cycles += MCLKS_SLOT_H32; | 3575 context->cycles += MCLKS_SLOT_H32; |
3420 } | 3576 } |
3421 } | 3577 } |
3422 | 3578 |
3579 | |
3580 static void tms_fetch_pattern_name(vdp_context *context) | |
3581 { | |
3582 uint16_t address = context->regs[REG_SCROLL_A] << 10 & 0x3C00; | |
3583 address |= context->vcounter << 2 & 0x03E0; | |
3584 address += context->hslot >> 2; | |
3585 //TODO: 4K/16K mode address remapping when emulating TMS9918A | |
3586 address = mode4_address_map[address] ^ 1; | |
3587 context->col_1 = context->vdpmem[address]; | |
3588 } | |
3589 | |
3590 static void tms_fetch_color(vdp_context *context) | |
3591 { | |
3592 if (context->regs[REG_MODE_2] & BIT_M2) { | |
3593 //Multicolor | |
3594 external_slot(context); | |
3595 return; | |
3596 } | |
3597 uint16_t address = context->regs[REG_COLOR_TABLE] << 6; | |
3598 if (context->regs[REG_MODE_2] & BIT_M3) { | |
3599 //Graphics II | |
3600 uint16_t upper_vcounter_mask; | |
3601 uint16_t pattern_name_mask; | |
3602 if (context->type > VDP_SMS2) { | |
3603 //SMS1 and TMS9918A | |
3604 upper_vcounter_mask = address & 0x1800; | |
3605 pattern_name_mask = (address & 0x07C0) | 0x0038; | |
3606 } else { | |
3607 //SMS2 and Game Gear | |
3608 upper_vcounter_mask = 0x1800; | |
3609 pattern_name_mask = 0x07F8; | |
3610 } | |
3611 address &= 0x2000; | |
3612 address |= context->vcounter << 5 & upper_vcounter_mask; | |
3613 address |= context->col_1 << 3 & pattern_name_mask; | |
3614 address |= context->vcounter & 3; | |
3615 } else { | |
3616 address |= context->col_1 >> 3; | |
3617 } | |
3618 //TODO: 4K/16K mode address remapping when emulating TMS9918A | |
3619 address = mode4_address_map[address] ^ 1; | |
3620 context->col_2 = context->vdpmem[address]; | |
3621 } | |
3622 | |
3623 static void tms_fetch_pattern_value(vdp_context *context) | |
3624 { | |
3625 uint16_t address = context->regs[REG_PATTERN_GEN] << 11 & 0x3800; | |
3626 if (context->regs[REG_MODE_1] & BIT_M3) { | |
3627 //Graphics II | |
3628 uint16_t mask = context->type > VDP_SMS2 ? address & 0x1800 : 0x1800; | |
3629 address &= 0x2000; | |
3630 address |= context->vcounter << 5 & mask; | |
3631 } | |
3632 address |= context->col_1 << 3; | |
3633 if (context->regs[REG_MODE_2] & BIT_M2) { | |
3634 //Multicolor | |
3635 address |= context->vcounter >> 2 & 0x3; | |
3636 } else { | |
3637 address |= context->vcounter & 0x7; | |
3638 } | |
3639 | |
3640 //TODO: 4K/16K mode address remapping when emulating TMS9918A | |
3641 address = mode4_address_map[address] ^ 1; | |
3642 uint8_t value = context->vdpmem[address]; | |
3643 if (context->regs[REG_MODE_2] & BIT_M2) { | |
3644 //Multicolor | |
3645 context->tmp_buf_a[0] = 0xF0; | |
3646 context->tmp_buf_b[0] = value; | |
3647 } else { | |
3648 context->tmp_buf_a[0] = value; | |
3649 context->tmp_buf_b[0] = context->col_2; | |
3650 } | |
3651 } | |
3652 | |
3653 static void tms_sprite_scan(vdp_context *context) | |
3654 { | |
3655 if (context->sprite_draws > 4 || context->sprite_index == 32) { | |
3656 return; | |
3657 } | |
3658 uint16_t address = context->regs[REG_SAT] << 7 & 0x3F80; | |
3659 address |= context->sprite_index << 2; | |
3660 address = mode4_address_map[address] ^ 1; | |
3661 uint8_t y = context->vdpmem[address]; | |
3662 if (y == 208) { | |
3663 context->sprite_index = 32; | |
3664 context->sprite_info_list[4].index = context->sprite_index; | |
3665 } | |
3666 uint8_t diff = context->vcounter + 1 - y; | |
3667 uint8_t size = 8; | |
3668 if (context->regs[REG_MODE_2] & BIT_SPRITE_SZ) { | |
3669 size *= 2; | |
3670 } | |
3671 if (context->regs[REG_MODE_2] & BIT_SPRITE_ZM) { | |
3672 size *= 2; | |
3673 } | |
3674 if (diff < size) { | |
3675 context->sprite_info_list[context->sprite_draws++].index = context->sprite_index; | |
3676 if (context->sprite_draws == 5) { | |
3677 context->flags |= FLAG_DOT_OFLOW; | |
3678 } | |
3679 } else { | |
3680 context->sprite_info_list[4].index = context->sprite_index; | |
3681 } | |
3682 context->sprite_index++; | |
3683 } | |
3684 | |
3685 static void tms_sprite_vert(vdp_context *context) | |
3686 { | |
3687 if (context->sprite_index >= 4 || context->sprite_index >= context->sprite_draws) { | |
3688 return; | |
3689 } | |
3690 uint16_t address = context->regs[REG_SAT] << 7 & 0x3F80; | |
3691 address |= context->sprite_info_list[context->sprite_index].index << 2; | |
3692 address = mode4_address_map[address] ^ 1; | |
3693 context->sprite_info_list[context->sprite_index].y = context->vdpmem[address]; | |
3694 } | |
3695 | |
3696 static void tms_sprite_horiz(vdp_context *context) | |
3697 { | |
3698 if (context->sprite_index >= 4 || context->sprite_index >= context->sprite_draws) { | |
3699 return; | |
3700 } | |
3701 uint16_t address = context->regs[REG_SAT] << 7 & 0x3F80; | |
3702 address |= context->sprite_info_list[context->sprite_index].index << 2 | 1; | |
3703 address = mode4_address_map[address] ^ 1; | |
3704 context->sprite_draw_list[context->sprite_index].x_pos = context->vdpmem[address]; | |
3705 } | |
3706 | |
3707 static void tms_sprite_name(vdp_context *context) | |
3708 { | |
3709 if (context->sprite_index >= 4 || context->sprite_index >= context->sprite_draws) { | |
3710 return; | |
3711 } | |
3712 uint16_t address = context->regs[REG_SAT] << 7 & 0x3F80; | |
3713 address |= context->sprite_info_list[context->sprite_index].index << 2 | 2; | |
3714 address = context->vdpmem[mode4_address_map[address] ^ 1] << 3; | |
3715 address |= context->regs[REG_STILE_BASE] << 11 & 0x3800; | |
3716 uint8_t diff = context->vcounter + 1 - context->sprite_info_list[context->sprite_index].y; | |
3717 address += diff; | |
3718 context->sprite_draw_list[context->sprite_index].address = address; | |
3719 } | |
3720 | |
3721 static void tms_sprite_tag(vdp_context *context) | |
3722 { | |
3723 if (context->sprite_index >= 4 || context->sprite_index >= context->sprite_draws) { | |
3724 return; | |
3725 } | |
3726 uint16_t address = context->regs[REG_SAT] << 7 & 0x3F80; | |
3727 address |= context->sprite_info_list[context->sprite_index].index << 2 | 3; | |
3728 address = mode4_address_map[address] ^ 1; | |
3729 uint8_t tag = context->vdpmem[address]; | |
3730 if (tag & 0x80) { | |
3731 //early clock flag | |
3732 context->sprite_draw_list[context->sprite_index].x_pos -= 32; | |
3733 } | |
3734 context->sprite_draw_list[context->sprite_index].pal_priority = tag & 0xF; | |
3735 context->col_1 = 0; | |
3736 } | |
3737 | |
3738 static void tms_sprite_pattern1(vdp_context *context) | |
3739 { | |
3740 if (context->sprite_index >= 4 || context->sprite_index >= context->sprite_draws) { | |
3741 return; | |
3742 } | |
3743 context->col_1 = context->vdpmem[mode4_address_map[context->sprite_draw_list[context->sprite_index].address] ^ 1] << 8; | |
3744 context->sprite_draw_list[context->sprite_index].address += 16; | |
3745 } | |
3746 | |
3747 static void tms_sprite_pattern2(vdp_context *context) | |
3748 { | |
3749 if (context->sprite_index >= 4 || context->sprite_index >= context->sprite_draws) { | |
3750 return; | |
3751 } | |
3752 uint16_t pixels = context->col_1; | |
3753 if (context->regs[REG_MODE_2] & BIT_SPRITE_SZ) { | |
3754 pixels |= context->vdpmem[mode4_address_map[context->sprite_draw_list[context->sprite_index].address] ^ 1]; | |
3755 } | |
3756 context->sprite_draw_list[context->sprite_index++].address = pixels; | |
3757 } | |
3758 | |
3759 static uint8_t tms_sprite_clock(vdp_context *context, int16_t offset) | |
3760 { | |
3761 int16_t x = context->hslot << 1; | |
3762 if (x > 294) { | |
3763 x -= 512; | |
3764 } | |
3765 x += offset; | |
3766 uint8_t output = 0; | |
3767 for (int i = 0; i < 4; i++) { | |
3768 if (x >= context->sprite_draw_list[i].x_pos) { | |
3769 if (context->sprite_draw_list[i].address & 0x8000) { | |
3770 if (output) { | |
3771 context->flags2 |= FLAG2_SPRITE_COLLIDE; | |
3772 } | |
3773 output = context->sprite_draw_list[i].pal_priority; | |
3774 } | |
3775 context->sprite_draw_list[i].address <<= 1; | |
3776 } | |
3777 } | |
3778 return output; | |
3779 } | |
3780 | |
3781 static void tms_border(vdp_context *context) | |
3782 { | |
3783 if (context->hslot < (256 + BORDER_LEFT - (BORDER_LEFT-8))/2 || context->hslot > 256-32) { | |
3784 tms_sprite_clock(context, 0); | |
3785 tms_sprite_clock(context, 1); | |
3786 } | |
3787 if (!context->output) { | |
3788 return; | |
3789 } | |
3790 uint32_t color; | |
3791 if (context->type == VDP_GAMEGEAR) { | |
3792 //Game Gear uses CRAM entries 16-31 for TMS9918A modes | |
3793 color = context->colors[(context->regs[REG_BG_COLOR] & 0xF) + 16 + MODE4_OFFSET]; | |
3794 } else { | |
3795 color = context->regs[REG_BG_COLOR] << 1 & 0x1E; | |
3796 color = (color & 0xE) | (color << 1 & 0x20); | |
3797 color = context->color_map[color | FBUF_TMS]; | |
3798 } | |
3799 if (context->hslot == (520 - BORDER_LEFT) / 2) { | |
3800 context->output[0] = color; | |
3801 return; | |
3802 } | |
3803 if (context->hslot < (256 + BORDER_LEFT + BORDER_RIGHT - (BORDER_LEFT - 8)) / 2) { | |
3804 context->output[context->hslot * 2 - 8 + BORDER_LEFT] = color; | |
3805 context->output[context->hslot * 2 - 7 + BORDER_LEFT] = color; | |
3806 if ((context->hslot * 2 - 6 + BORDER_LEFT) == (256 + BORDER_LEFT + BORDER_RIGHT)) { | |
3807 advance_output_line(context); | |
3808 } | |
3809 } else { | |
3810 int slot = (context->hslot - (520 - BORDER_LEFT) / 2) * 2 - 1; | |
3811 context->output[slot] = color; | |
3812 context->output[slot + 1] = color; | |
3813 } | |
3814 } | |
3815 | |
3816 static void tms_composite(vdp_context *context) | |
3817 { | |
3818 if (context->state == PREPARING) { | |
3819 tms_border(context); | |
3820 return; | |
3821 } | |
3822 uint8_t color = tms_sprite_clock(context, 0); | |
3823 if (!context->output) { | |
3824 tms_sprite_clock(context, 1); | |
3825 return; | |
3826 } | |
3827 uint8_t pattern = context->tmp_buf_a[0] & 0x80; | |
3828 context->tmp_buf_a[0] <<= 1; | |
3829 if (!color) { | |
3830 uint8_t fg,bg; | |
3831 if (context->regs[REG_MODE_2] & BIT_M1) { | |
3832 //Text mode uses TC and BD colors | |
3833 fg = context->regs[REG_BG_COLOR] >> 4; | |
3834 bg = context->regs[REG_BG_COLOR] & 0xF; | |
3835 } else { | |
3836 fg = context->tmp_buf_b[0] >> 4; | |
3837 bg = context->tmp_buf_b[0] & 0xF; | |
3838 if (!bg) { | |
3839 bg = context->regs[REG_BG_COLOR] & 0xF; | |
3840 } | |
3841 } | |
3842 color = pattern ? fg : bg; | |
3843 } | |
3844 //TODO: composite debug output | |
3845 if (context->type == VDP_GAMEGEAR) { | |
3846 //Game Gear uses CRAM entries 16-31 for TMS9918A modes | |
3847 context->output[context->hslot * 2 - 8 + BORDER_LEFT] = context->colors[color + 16 + MODE4_OFFSET]; | |
3848 } else { | |
3849 color <<= 1; | |
3850 color = (color & 0xE) | (color << 1 & 0x20); | |
3851 context->output[context->hslot * 2 - 8 + BORDER_LEFT] = context->color_map[color | FBUF_TMS]; | |
3852 } | |
3853 color = tms_sprite_clock(context, 1); | |
3854 pattern = context->tmp_buf_a[0] & 0x80; | |
3855 context->tmp_buf_a[0] <<= 1; | |
3856 if (!color) { | |
3857 uint8_t fg,bg; | |
3858 if (context->regs[REG_MODE_2] & BIT_M1) { | |
3859 //Text mode uses TC and BD colors | |
3860 fg = context->regs[REG_BG_COLOR] >> 4; | |
3861 bg = context->regs[REG_BG_COLOR] & 0xF; | |
3862 } else { | |
3863 fg = context->tmp_buf_b[0] >> 4; | |
3864 bg = context->tmp_buf_b[0] & 0xF; | |
3865 if (!bg) { | |
3866 bg = context->regs[REG_BG_COLOR] & 0xF; | |
3867 } | |
3868 } | |
3869 color = pattern ? fg : bg; | |
3870 } | |
3871 //TODO: composite debug output | |
3872 if (context->type == VDP_GAMEGEAR) { | |
3873 //Game Gear uses CRAM entries 16-31 for TMS9918A modes | |
3874 context->output[context->hslot * 2 - 7 + BORDER_LEFT] = context->colors[color + 16 + MODE4_OFFSET]; | |
3875 } else { | |
3876 color <<= 1; | |
3877 color = (color & 0xE) | (color << 1 & 0x20); | |
3878 context->output[context->hslot * 2 - 7 + BORDER_LEFT] = context->color_map[color | FBUF_TMS]; | |
3879 } | |
3880 } | |
3881 | |
3882 #define TMS_OUTPUT(slot) if ((slot) < 8 || (slot) > (256 + BORDER_LEFT - 8) / 2) { tms_border(context); } else { tms_composite(context); } | |
3883 #define TMS_OUTPUT_RIGHT(slot) \ | |
3884 if ((slot) < (256 + BORDER_LEFT - (BORDER_LEFT - 8))/2) {\ | |
3885 tms_composite(context);\ | |
3886 } else if ((slot < (256 + BORDER_LEFT + BORDER_RIGHT -(BORDER_LEFT - 8))/2)) {\ | |
3887 tms_border(context);\ | |
3888 } | |
3889 #define TMS_CHECK_LIMIT context->hslot++; context->cycles += MCLKS_SLOT_H32; if (context->cycles >= target_cycles) { return; } | |
3890 #define TMS_GRAPHICS_PATTERN_CPU_BLOCK(slot) \ | |
3891 case slot:\ | |
3892 TMS_OUTPUT(slot)\ | |
3893 tms_fetch_pattern_name(context);\ | |
3894 TMS_CHECK_LIMIT \ | |
3895 case slot+1:\ | |
3896 TMS_OUTPUT(slot+1)\ | |
3897 external_slot(context);\ | |
3898 TMS_CHECK_LIMIT \ | |
3899 case slot+2:\ | |
3900 TMS_OUTPUT(slot+2)\ | |
3901 tms_fetch_color(context);\ | |
3902 TMS_CHECK_LIMIT \ | |
3903 case slot+3:\ | |
3904 TMS_OUTPUT(slot+3)\ | |
3905 tms_fetch_pattern_value(context);\ | |
3906 TMS_CHECK_LIMIT | |
3907 | |
3908 #define TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(slot) \ | |
3909 case slot:\ | |
3910 TMS_OUTPUT(slot)\ | |
3911 tms_fetch_pattern_name(context);\ | |
3912 TMS_CHECK_LIMIT \ | |
3913 case slot+1:\ | |
3914 TMS_OUTPUT(slot+1)\ | |
3915 tms_sprite_scan(context);\ | |
3916 TMS_CHECK_LIMIT \ | |
3917 case slot+2:\ | |
3918 TMS_OUTPUT(slot+2)\ | |
3919 tms_fetch_color(context);\ | |
3920 TMS_CHECK_LIMIT \ | |
3921 case slot+3:\ | |
3922 TMS_OUTPUT(slot+3)\ | |
3923 tms_fetch_pattern_value(context);\ | |
3924 TMS_CHECK_LIMIT | |
3925 | |
3926 #define TMS_SPRITE_SCAN_SLOT(slot) \ | |
3927 case slot:\ | |
3928 if (context->hslot >= (520 - BORDER_LEFT) / 2) { tms_border(context); }\ | |
3929 tms_sprite_scan(context);\ | |
3930 TMS_CHECK_LIMIT | |
3931 | |
3932 #define TMS_SPRITE_BLOCK(slot) \ | |
3933 case slot:\ | |
3934 TMS_OUTPUT_RIGHT(slot)\ | |
3935 tms_sprite_vert(context);\ | |
3936 TMS_CHECK_LIMIT \ | |
3937 case slot+1:\ | |
3938 TMS_OUTPUT_RIGHT(slot+1)\ | |
3939 tms_sprite_horiz(context);\ | |
3940 TMS_CHECK_LIMIT \ | |
3941 case slot+2:\ | |
3942 TMS_OUTPUT_RIGHT(slot+2)\ | |
3943 tms_sprite_name(context);\ | |
3944 TMS_CHECK_LIMIT \ | |
3945 case slot+3:\ | |
3946 TMS_OUTPUT_RIGHT(slot+3)\ | |
3947 tms_sprite_tag(context);\ | |
3948 TMS_CHECK_LIMIT \ | |
3949 case slot+4:\ | |
3950 TMS_OUTPUT_RIGHT(slot+4)\ | |
3951 tms_sprite_pattern1(context);\ | |
3952 TMS_CHECK_LIMIT \ | |
3953 case slot+5:\ | |
3954 TMS_OUTPUT_RIGHT(slot+5)\ | |
3955 tms_sprite_pattern2(context);\ | |
3956 TMS_CHECK_LIMIT | |
3957 | |
3958 static void vdp_tms_graphics(vdp_context * context, uint32_t target_cycles) | |
3959 { | |
3960 switch (context->hslot) | |
3961 { | |
3962 for (;;) | |
3963 { | |
3964 TMS_GRAPHICS_PATTERN_CPU_BLOCK(0) | |
3965 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(4) | |
3966 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(8) | |
3967 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(12) | |
3968 TMS_GRAPHICS_PATTERN_CPU_BLOCK(16) | |
3969 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(20) | |
3970 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(24) | |
3971 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(28) | |
3972 TMS_GRAPHICS_PATTERN_CPU_BLOCK(32) | |
3973 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(36) | |
3974 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(40) | |
3975 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(44) | |
3976 TMS_GRAPHICS_PATTERN_CPU_BLOCK(48) | |
3977 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(52) | |
3978 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(56) | |
3979 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(60) | |
3980 TMS_GRAPHICS_PATTERN_CPU_BLOCK(64) | |
3981 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(68) | |
3982 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(72) | |
3983 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(76) | |
3984 TMS_GRAPHICS_PATTERN_CPU_BLOCK(80) | |
3985 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(84) | |
3986 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(88) | |
3987 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(92) | |
3988 TMS_GRAPHICS_PATTERN_CPU_BLOCK(96) | |
3989 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(100) | |
3990 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(104) | |
3991 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(108) | |
3992 TMS_GRAPHICS_PATTERN_CPU_BLOCK(112) | |
3993 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(116) | |
3994 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(120) | |
3995 TMS_GRAPHICS_PATTERN_SPRITE_BLOCK(124) | |
3996 case 128: | |
3997 tms_composite(context); | |
3998 external_slot(context); | |
3999 TMS_CHECK_LIMIT | |
4000 case 129: | |
4001 tms_composite(context); | |
4002 external_slot(context); | |
4003 context->sprite_index = 0; | |
4004 TMS_CHECK_LIMIT | |
4005 | |
4006 TMS_SPRITE_BLOCK(130) | |
4007 TMS_SPRITE_BLOCK(136) | |
4008 case 142: | |
4009 tms_sprite_vert(context); | |
4010 TMS_CHECK_LIMIT | |
4011 case 143: | |
4012 tms_sprite_horiz(context); | |
4013 TMS_CHECK_LIMIT | |
4014 case 145: | |
4015 external_slot(context); | |
4016 TMS_CHECK_LIMIT | |
4017 case 146: | |
4018 external_slot(context); | |
4019 TMS_CHECK_LIMIT | |
4020 case 147: | |
4021 external_slot(context); | |
4022 context->hslot = 233; | |
4023 context->cycles += MCLKS_SLOT_H32; | |
4024 if (context->cycles >= target_cycles) { return; } | |
4025 case 233: | |
4026 external_slot(context); | |
4027 TMS_CHECK_LIMIT | |
4028 case 234: | |
4029 tms_sprite_name(context); | |
4030 TMS_CHECK_LIMIT | |
4031 case 235: | |
4032 tms_sprite_tag(context); | |
4033 TMS_CHECK_LIMIT | |
4034 case 236: | |
4035 tms_sprite_pattern1(context); | |
4036 TMS_CHECK_LIMIT | |
4037 case 237: | |
4038 tms_sprite_pattern2(context); | |
4039 TMS_CHECK_LIMIT | |
4040 TMS_SPRITE_BLOCK(238) | |
4041 case 244: | |
4042 tms_sprite_clock(context, 0); | |
4043 tms_sprite_clock(context, 1); | |
4044 external_slot(context); | |
4045 TMS_CHECK_LIMIT | |
4046 case 245: | |
4047 tms_sprite_clock(context, 0); | |
4048 tms_sprite_clock(context, 1); | |
4049 external_slot(context); | |
4050 TMS_CHECK_LIMIT | |
4051 case 246: | |
4052 tms_sprite_clock(context, 0); | |
4053 tms_sprite_clock(context, 1); | |
4054 external_slot(context); | |
4055 TMS_CHECK_LIMIT | |
4056 case 247: | |
4057 tms_sprite_clock(context, 0); | |
4058 tms_sprite_clock(context, 1); | |
4059 external_slot(context); | |
4060 vdp_advance_line(context); | |
4061 context->sprite_index = context->sprite_draws = 0; | |
4062 if (context->vcounter == 192) { | |
4063 context->state = INACTIVE; | |
4064 return; | |
4065 } | |
4066 TMS_CHECK_LIMIT | |
4067 TMS_SPRITE_SCAN_SLOT(248) | |
4068 TMS_SPRITE_SCAN_SLOT(249) | |
4069 TMS_SPRITE_SCAN_SLOT(250) | |
4070 TMS_SPRITE_SCAN_SLOT(251) | |
4071 TMS_SPRITE_SCAN_SLOT(252) | |
4072 TMS_SPRITE_SCAN_SLOT(253) | |
4073 TMS_SPRITE_SCAN_SLOT(254) | |
4074 TMS_SPRITE_SCAN_SLOT(255) | |
4075 } | |
4076 default: | |
4077 context->hslot++; | |
4078 context->cycles += MCLKS_SLOT_H32; | |
4079 } | |
4080 } | |
4081 | |
4082 #define TMS_CHECK_LIMIT_SKIP context->hslot+=2; context->cycles += MCLKS_SLOT_H32; if (context->cycles >= target_cycles) { return; } | |
4083 #define TMS_TEXT_BLOCK(slot) \ | |
4084 case slot:\ | |
4085 tms_fetch_pattern_name(context);\ | |
4086 TMS_CHECK_LIMIT \ | |
4087 case slot+1:\ | |
4088 external_slot(context);\ | |
4089 TMS_CHECK_LIMIT_SKIP \ | |
4090 case slot+3:\ | |
4091 tms_fetch_pattern_value(context);\ | |
4092 TMS_CHECK_LIMIT | |
4093 | |
4094 static void vdp_tms_text(vdp_context * context, uint32_t target_cycles) | |
4095 { | |
4096 switch (context->hslot) | |
4097 { | |
4098 for (;;) | |
4099 { | |
4100 TMS_TEXT_BLOCK(0) | |
4101 TMS_TEXT_BLOCK(4) | |
4102 TMS_TEXT_BLOCK(8) | |
4103 TMS_TEXT_BLOCK(12) | |
4104 TMS_TEXT_BLOCK(16) | |
4105 TMS_TEXT_BLOCK(20) | |
4106 TMS_TEXT_BLOCK(24) | |
4107 TMS_TEXT_BLOCK(28) | |
4108 TMS_TEXT_BLOCK(32) | |
4109 TMS_TEXT_BLOCK(36) | |
4110 TMS_TEXT_BLOCK(40) | |
4111 TMS_TEXT_BLOCK(44) | |
4112 TMS_TEXT_BLOCK(48) | |
4113 TMS_TEXT_BLOCK(52) | |
4114 TMS_TEXT_BLOCK(56) | |
4115 TMS_TEXT_BLOCK(60) | |
4116 TMS_TEXT_BLOCK(64) | |
4117 TMS_TEXT_BLOCK(68) | |
4118 TMS_TEXT_BLOCK(72) | |
4119 TMS_TEXT_BLOCK(76) | |
4120 TMS_TEXT_BLOCK(80) | |
4121 TMS_TEXT_BLOCK(84) | |
4122 TMS_TEXT_BLOCK(88) | |
4123 TMS_TEXT_BLOCK(92) | |
4124 TMS_TEXT_BLOCK(96) | |
4125 TMS_TEXT_BLOCK(100) | |
4126 TMS_TEXT_BLOCK(104) | |
4127 TMS_TEXT_BLOCK(108) | |
4128 TMS_TEXT_BLOCK(112) | |
4129 TMS_TEXT_BLOCK(116) | |
4130 TMS_TEXT_BLOCK(120) | |
4131 TMS_TEXT_BLOCK(124) | |
4132 TMS_TEXT_BLOCK(128) | |
4133 TMS_TEXT_BLOCK(132) | |
4134 TMS_TEXT_BLOCK(136) | |
4135 TMS_TEXT_BLOCK(140) | |
4136 TMS_TEXT_BLOCK(144) | |
4137 TMS_TEXT_BLOCK(148) | |
4138 TMS_TEXT_BLOCK(152) | |
4139 TMS_TEXT_BLOCK(156) | |
4140 default: | |
4141 while (context->hslot < 179) | |
4142 { | |
4143 external_slot(context); | |
4144 TMS_CHECK_LIMIT | |
4145 } | |
4146 if (context->hslot == 179) { | |
4147 external_slot(context); | |
4148 context->hslot = 233; | |
4149 context->cycles += MCLKS_SLOT_H32; | |
4150 if (context->cycles >= target_cycles) { return; } | |
4151 } | |
4152 while (context->hslot > 179) { | |
4153 if (context->hslot >= 233) { | |
4154 external_slot(context); | |
4155 if (context->hslot + 1 == LINE_CHANGE_MODE4) { | |
4156 vdp_advance_line(context); | |
4157 } | |
4158 } | |
4159 TMS_CHECK_LIMIT | |
4160 } | |
4161 } | |
4162 } | |
4163 } | |
4164 | |
3423 static void inactive_test_output(vdp_context *context, uint8_t is_h40, uint8_t test_layer) | 4165 static void inactive_test_output(vdp_context *context, uint8_t is_h40, uint8_t test_layer) |
3424 { | 4166 { |
3425 uint8_t max_slot = is_h40 ? 169 : 136; | 4167 uint8_t max_slot = is_h40 ? 169 : 136; |
3426 if (context->hslot > max_slot) { | 4168 if (context->hslot > max_slot) { |
3427 return; | 4169 return; |
3521 vint_line = context->inactive_start + 1; | 4263 vint_line = context->inactive_start + 1; |
3522 vint_slot = VINT_SLOT_MODE4; | 4264 vint_slot = VINT_SLOT_MODE4; |
3523 line_change = LINE_CHANGE_MODE4; | 4265 line_change = LINE_CHANGE_MODE4; |
3524 jump_start = 147; | 4266 jump_start = 147; |
3525 jump_dest = 233; | 4267 jump_dest = 233; |
3526 if (context->regs[REG_MODE_1] & BIT_MODE_4) { | 4268 if (context->regs[REG_MODE_1] & BIT_MODE_4 || context->type != VDP_GENESIS) { |
3527 active_line = 0x1FF; | 4269 active_line = 0x1FF; |
3528 } else { | 4270 } else { |
3529 //never active unless either mode 4 or mode 5 is turned on | 4271 //never active unless either mode 4 or mode 5 is turned on |
3530 active_line = 0x200; | 4272 active_line = 0x200; |
3531 } | 4273 } |
3691 if (is_h40) { | 4433 if (is_h40) { |
3692 vdp_h40(context, target_cycles); | 4434 vdp_h40(context, target_cycles); |
3693 } else { | 4435 } else { |
3694 vdp_h32(context, target_cycles); | 4436 vdp_h32(context, target_cycles); |
3695 } | 4437 } |
4438 } else if (context->regs[REG_MODE_1] & BIT_MODE_4) { | |
4439 vdp_h32_mode4(context, target_cycles); | |
4440 } else if (context->regs[REG_MODE_2] & BIT_M1) { | |
4441 vdp_tms_text(context, target_cycles); | |
3696 } else { | 4442 } else { |
3697 vdp_h32_mode4(context, target_cycles); | 4443 vdp_tms_graphics(context, target_cycles); |
3698 } | 4444 } |
3699 } else { | 4445 } else { |
3700 vdp_inactive(context, target_cycles, is_h40, mode_5); | 4446 vdp_inactive(context, target_cycles, is_h40, mode_5); |
3701 } | 4447 } |
3702 } | 4448 } |