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 }