comparison vdp.c @ 1120:e9369d6f0101

Somewhat broken implementation of Mode 4
author Michael Pavone <pavone@retrodev.com>
date Tue, 27 Dec 2016 11:31:17 -0800
parents 928a65750345
children 1913f9c28003
comparison
equal deleted inserted replaced
1119:55ea7f9a4e92 1120:e9369d6f0101
11 #include "render.h" 11 #include "render.h"
12 #include "util.h" 12 #include "util.h"
13 13
14 #define NTSC_INACTIVE_START 224 14 #define NTSC_INACTIVE_START 224
15 #define PAL_INACTIVE_START 240 15 #define PAL_INACTIVE_START 240
16 #define MODE4_INACTIVE_START 192
16 #define BUF_BIT_PRIORITY 0x40 17 #define BUF_BIT_PRIORITY 0x40
17 #define MAP_BIT_PRIORITY 0x8000 18 #define MAP_BIT_PRIORITY 0x8000
18 #define MAP_BIT_H_FLIP 0x800 19 #define MAP_BIT_H_FLIP 0x800
19 #define MAP_BIT_V_FLIP 0x1000 20 #define MAP_BIT_V_FLIP 0x1000
20 21
37 #define LINE_CHANGE_H32 132 38 #define LINE_CHANGE_H32 132
38 #define VBLANK_START_H40 (LINE_CHANGE_H40+2) 39 #define VBLANK_START_H40 (LINE_CHANGE_H40+2)
39 #define VBLANK_START_H32 (LINE_CHANGE_H32+2) 40 #define VBLANK_START_H32 (LINE_CHANGE_H32+2)
40 #define FIFO_LATENCY 3 41 #define FIFO_LATENCY 3
41 42
42 int32_t color_map[1 << 12]; 43 static int32_t color_map[1 << 12];
44 static uint16_t mode4_address_map[0x4000];
45 static uint32_t planar_to_chunky[256];
43 static uint8_t levels[] = {0, 27, 49, 71, 87, 103, 119, 130, 146, 157, 174, 190, 206, 228, 255}; 46 static uint8_t levels[] = {0, 27, 49, 71, 87, 103, 119, 130, 146, 157, 174, 190, 206, 228, 255};
44 47
45 static uint8_t debug_base[][3] = { 48 static uint8_t debug_base[][3] = {
46 {127, 127, 127}, //BG 49 {127, 127, 127}, //BG
47 {0, 0, 127}, //A 50 {0, 0, 127}, //A
83 r = levels[(color >> 1) & 0x7]; 86 r = levels[(color >> 1) & 0x7];
84 } else if(color & FBUF_HILIGHT) { 87 } else if(color & FBUF_HILIGHT) {
85 b = levels[((color >> 9) & 0x7) + 7]; 88 b = levels[((color >> 9) & 0x7) + 7];
86 g = levels[((color >> 5) & 0x7) + 7]; 89 g = levels[((color >> 5) & 0x7) + 7];
87 r = levels[((color >> 1) & 0x7) + 7]; 90 r = levels[((color >> 1) & 0x7) + 7];
91 } else if(color & FBUF_MODE4) {
92 b = levels[color >> 3 & 0xC];
93 g = levels[(color >> 2 & 0x8) | (color >> 1 & 0x4)];
94 r = levels[color << 1 & 0xC];
88 } else { 95 } else {
89 b = levels[(color >> 8) & 0xE]; 96 b = levels[(color >> 8) & 0xE];
90 g = levels[(color >> 4) & 0xE]; 97 g = levels[(color >> 4) & 0xE];
91 r = levels[color & 0xE]; 98 r = levels[color & 0xE];
92 } 99 }
93 color_map[color] = render_map_color(r, g, b); 100 color_map[color] = render_map_color(r, g, b);
101 }
102 for (uint16_t mode4_addr = 0; mode4_addr < 0x4000; mode4_addr++)
103 {
104 uint16_t mode5_addr = mode4_addr & 0x3DFD;
105 mode5_addr |= mode4_addr << 8 & 0x200;
106 mode5_addr |= mode4_addr >> 8 & 2;
107 mode4_address_map[mode4_addr] = mode5_addr;
108 }
109 for (uint32_t planar = 0; planar < 256; planar++)
110 {
111 uint32_t chunky = 0;
112 for (int bit = 7; bit >= 0; bit--)
113 {
114 chunky = chunky << 4;
115 chunky |= planar >> bit & 1;
116 }
117 planar_to_chunky[planar] = chunky;
94 } 118 }
95 color_map_init_done = 1; 119 color_map_init_done = 1;
96 } 120 }
97 for (uint8_t color = 0; color < (1 << (3 + 1 + 1 + 1)); color++) 121 for (uint8_t color = 0; color < (1 << (3 + 1 + 1 + 1)); color++)
98 { 122 {
192 context->flags2 |= FLAG2_SPRITE_COLLIDE; 216 context->flags2 |= FLAG2_SPRITE_COLLIDE;
193 } 217 }
194 } 218 }
195 x += dir; 219 x += dir;
196 } 220 }
221 }
222 }
223
224 static void fetch_sprite_cells_mode4(vdp_context * context)
225 {
226 if (context->cur_slot >= context->sprite_draws) {
227 sprite_draw * d = context->sprite_draw_list + context->cur_slot;
228 uint32_t address = mode4_address_map[d->address & 0x3FFF];
229 context->fetch_tmp[0] = context->vdpmem[address];
230 context->fetch_tmp[1] = context->vdpmem[address + 1];
231 }
232 }
233
234 static void render_sprite_cells_mode4(vdp_context * context)
235 {
236 if (context->cur_slot >= context->sprite_draws) {
237 sprite_draw * d = context->sprite_draw_list + context->cur_slot;
238 uint32_t pixels = planar_to_chunky[context->fetch_tmp[0]] << 1;
239 pixels |= planar_to_chunky[context->fetch_tmp[1]];
240 uint32_t address = mode4_address_map[(d->address + 2) & 0x3FFF];
241 pixels |= planar_to_chunky[context->vdpmem[address]] << 3;
242 pixels |= planar_to_chunky[context->vdpmem[address + 1]] << 2;
243 int x = d->x_pos & 0xFF;
244 for (int i = 28; i >= 0; i -= 4, x++)
245 {
246 if (context->linebuf[x]) {
247 context->flags2 |= FLAG2_SPRITE_COLLIDE;
248 } else {
249 context->linebuf[x] = pixels >> i & 0xF;
250 }
251 }
252 context->cur_slot--;
197 } 253 }
198 } 254 }
199 255
200 void vdp_print_sprite_table(vdp_context * context) 256 void vdp_print_sprite_table(vdp_context * context)
201 { 257 {
405 context->sprite_index = context->sat_cache[address+3] & 0x7F; 461 context->sprite_index = context->sat_cache[address+3] & 0x7F;
406 } 462 }
407 } 463 }
408 } 464 }
409 465
466 static void scan_sprite_table_mode4(uint32_t line, vdp_context * context)
467 {
468 if (context->sprite_index < MAX_SPRITES_FRAME_H32 && context->slot_counter) {
469 line += 1;
470 line &= 0xFF;
471
472 uint32_t y = context->sat_cache[context->sprite_index];
473 uint32_t size = (context->regs[REG_MODE_2] & BIT_SPRITE_SZ) ? 16 : 8;
474 if (y <= line && line < (y + size)) {
475 context->sprite_info_list[--(context->slot_counter)].size = size;
476 context->sprite_info_list[context->slot_counter].index = context->sprite_index;
477 context->sprite_info_list[context->slot_counter].y = y;
478 }
479 context->sprite_index++;
480
481 if (context->sprite_index < MAX_SPRITES_FRAME_H32 && context->slot_counter) {
482 y = context->sat_cache[context->sprite_index];
483 if (y <= line && line < (y + size)) {
484 context->sprite_info_list[--(context->slot_counter)].size = size;
485 context->sprite_info_list[context->slot_counter].index = context->sprite_index;
486 context->sprite_info_list[context->slot_counter].y = y;
487 }
488 context->sprite_index++;
489 }
490
491 }
492 }
493
410 static void read_sprite_x(uint32_t line, vdp_context * context) 494 static void read_sprite_x(uint32_t line, vdp_context * context)
411 { 495 {
412 if (context->cur_slot >= context->slot_counter) { 496 if (context->cur_slot >= context->slot_counter) {
413 if (context->sprite_draws) { 497 if (context->sprite_draws) {
414 line += 1; 498 line += 1;
482 context->flags |= FLAG_DOT_OFLOW; 566 context->flags |= FLAG_DOT_OFLOW;
483 } 567 }
484 } 568 }
485 } 569 }
486 570
487 static void write_cram(vdp_context * context, uint16_t address, uint16_t value) 571 static void read_sprite_x_mode4(uint32_t line, vdp_context * context)
488 { 572 {
489 uint16_t addr = (address/2) & (CRAM_SIZE-1); 573 if (context->cur_slot >= context->slot_counter) {
490 context->cram[addr] = value; 574 if (context->sprite_draws) {
491 context->colors[addr] = color_map[value & 0xEEE]; 575 line += 1;
492 context->colors[addr + CRAM_SIZE] = color_map[(value & 0xEEE) | FBUF_SHADOW]; 576 line &= 0xFF;
493 context->colors[addr + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT]; 577
578 uint32_t address = (context->regs[REG_SAT] << 7 & 0x3F00) + 0x80 + context->sprite_info_list[context->cur_slot].index * 2;
579 address = mode4_address_map[address];
580 --context->sprite_draws;
581 uint32_t tile_address = context->vdpmem[address + 1] * 32 + (context->regs[REG_STILE_BASE] << 11 & 0x2000);
582 tile_address += (line - context->sprite_info_list[context->cur_slot].y)* 4;
583 context->sprite_draw_list[context->sprite_draws].x_pos = context->vdpmem[address];
584 context->sprite_draw_list[context->sprite_draws].address = tile_address;
585 context->cur_slot--;
586 } else {
587 context->flags |= FLAG_DOT_OFLOW;
588 }
589 }
494 } 590 }
495 591
496 #define CRAM_BITS 0xEEE 592 #define CRAM_BITS 0xEEE
497 #define VSRAM_BITS 0x7FF 593 #define VSRAM_BITS 0x7FF
498 #define VSRAM_DIRTY_BITS 0xF800 594 #define VSRAM_DIRTY_BITS 0xF800
595
596 void write_cram(vdp_context * context, uint16_t address, uint16_t value)
597 {
598 uint16_t addr;
599 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
600 addr = (address/2) & (CRAM_SIZE-1);
601 } else {
602 addr = address & 0x1F;
603 value = (value << 1 & 0xE) | (value << 2 & 0xE0) | (value & 0xE00);
604 }
605 context->cram[addr] = value;
606 context->colors[addr] = color_map[value & CRAM_BITS];
607 context->colors[addr + CRAM_SIZE] = color_map[(value & CRAM_BITS) | FBUF_SHADOW];
608 context->colors[addr + CRAM_SIZE*2] = color_map[(value & CRAM_BITS) | FBUF_HILIGHT];
609 context->colors[addr + CRAM_SIZE*3] = color_map[(value & CRAM_BITS) | FBUF_MODE4];
610 }
499 611
500 static void vdp_advance_dma(vdp_context * context) 612 static void vdp_advance_dma(vdp_context * context)
501 { 613 {
502 context->regs[REG_DMASRC_L] += 1; 614 context->regs[REG_DMASRC_L] += 1;
503 if (!context->regs[REG_DMASRC_L]) { 615 if (!context->regs[REG_DMASRC_L]) {
513 } 625 }
514 } 626 }
515 627
516 void write_vram_byte(vdp_context *context, uint16_t address, uint8_t value) 628 void write_vram_byte(vdp_context *context, uint16_t address, uint8_t value)
517 { 629 {
518 if (!(address & 4)) { 630 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
519 uint16_t sat_address = (context->regs[REG_SAT] & 0x7F) << 9; 631 if (!(address & 4)) {
520 if(address >= sat_address && address < (sat_address + SAT_CACHE_SIZE*2)) { 632 uint16_t sat_address = (context->regs[REG_SAT] & 0x7F) << 9;
521 uint16_t cache_address = address - sat_address; 633 if(address >= sat_address && address < (sat_address + SAT_CACHE_SIZE*2)) {
522 cache_address = (cache_address & 3) | (cache_address >> 1 & 0x1FC); 634 uint16_t cache_address = address - sat_address;
523 context->sat_cache[cache_address] = value; 635 cache_address = (cache_address & 3) | (cache_address >> 1 & 0x1FC);
524 } 636 context->sat_cache[cache_address] = value;
637 }
638 }
639 } else {
640 if (!(address & 0xC0)) {
641 uint16_t sat_address = context->regs[REG_SAT] << 7 & 0x3F00;
642 if (address >= sat_address && address < (sat_address + 0x40)) {
643 context->sat_cache[address-sat_address] = value;
644 }
645 }
646 address = mode4_address_map[address & 0x3FFF];
525 } 647 }
526 context->vdpmem[address] = value; 648 context->vdpmem[address] = value;
527 } 649 }
528 650
529 static void external_slot(vdp_context * context) 651 static void external_slot(vdp_context * context)
554 break; 676 break;
555 case CRAM_WRITE: { 677 case CRAM_WRITE: {
556 //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1)); 678 //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1));
557 if (start->partial == 1) { 679 if (start->partial == 1) {
558 uint16_t val; 680 uint16_t val;
559 if (start->address & 1) { 681 if ((start->address & 1) && (context->regs[REG_MODE_2] & BIT_MODE_5)) {
560 val = (context->cram[start->address >> 1 & (CRAM_SIZE-1)] & 0xFF) | start->value << 8; 682 val = (context->cram[start->address >> 1 & (CRAM_SIZE-1)] & 0xFF) | start->value << 8;
561 } else { 683 } else {
562 val = (context->cram[start->address >> 1 & (CRAM_SIZE-1)] & 0xFF00) | start->value; 684 uint16_t address = (context->regs[REG_MODE_2] & BIT_MODE_5) ? start->address >> 1 & (CRAM_SIZE-1) : start->address & 0x1F;
685 val = (context->cram[address] & 0xFF00) | start->value;
563 } 686 }
564 write_cram(context, start->address, val); 687 write_cram(context, start->address, val);
565 } else { 688 } else {
566 write_cram(context, start->address, start->partial == 2 ? context->fifo[context->fifo_write].value : start->value); 689 write_cram(context, start->address, start->partial == 2 ? context->fifo[context->fifo_write].value : start->value);
567 } 690 }
833 static void read_map_scroll_b(uint16_t column, uint32_t line, vdp_context * context) 956 static void read_map_scroll_b(uint16_t column, uint32_t line, vdp_context * context)
834 { 957 {
835 read_map_scroll(column, 1, line, (context->regs[REG_SCROLL_B] & 0x7) << 13, context->hscroll_b, context); 958 read_map_scroll(column, 1, line, (context->regs[REG_SCROLL_B] & 0x7) << 13, context->hscroll_b, context);
836 } 959 }
837 960
961 static void read_map_mode4(uint16_t column, uint32_t line, vdp_context * context)
962 {
963 uint32_t address = (context->regs[REG_SCROLL_A] & 0xE) << 10;
964 //add row
965 uint32_t vscroll = line;
966 if (column < 24 || !(context->regs[REG_MODE_1] & BIT_VSCRL_LOCK)) {
967 vscroll += context->regs[REG_Y_SCROLL];
968 }
969 if (vscroll > 223) {
970 vscroll -= 224;
971 }
972 address += (vscroll >> 3) * 2 * 32;
973 //add column
974 address += (((column << 3) + context->hscroll_a) >> 3) * 2;
975 //adjust for weird VRAM mapping in Mode 4
976 address = mode4_address_map[address];
977 context->col_1 = (context->vdpmem[address] << 8) | context->vdpmem[address+1];
978 }
979
838 static void render_map(uint16_t col, uint8_t * tmp_buf, uint8_t offset, vdp_context * context) 980 static void render_map(uint16_t col, uint8_t * tmp_buf, uint8_t offset, vdp_context * context)
839 { 981 {
840 uint16_t address; 982 uint16_t address;
841 uint16_t vflip_base; 983 uint16_t vflip_base;
842 if (context->double_res) { 984 if (context->double_res) {
882 } 1024 }
883 1025
884 static void render_map_3(vdp_context * context) 1026 static void render_map_3(vdp_context * context)
885 { 1027 {
886 render_map(context->col_1, context->tmp_buf_b, context->buf_b_off, context); 1028 render_map(context->col_1, context->tmp_buf_b, context->buf_b_off, context);
1029 }
1030
1031 static void fetch_map_mode4(uint16_t col, uint32_t line, vdp_context *context)
1032 {
1033 //calculate pixel row to fetch
1034 uint32_t vscroll = line;
1035 if (col < 24 || !(context->regs[REG_MODE_1] & BIT_VSCRL_LOCK)) {
1036 vscroll += context->regs[REG_Y_SCROLL];
1037 }
1038 if (vscroll > 223) {
1039 vscroll -= 224;
1040 }
1041 vscroll &= 7;
1042 if (context->col_1 & 0x400) {
1043 vscroll = 7 - vscroll;
1044 }
1045
1046 uint32_t address = mode4_address_map[((context->col_1 & 0x1FF) * 32) + vscroll * 4];
1047 context->fetch_tmp[0] = context->vdpmem[address];
1048 context->fetch_tmp[1] = context->vdpmem[address+1];
887 } 1049 }
888 1050
889 static void render_map_output(uint32_t line, int32_t col, vdp_context * context) 1051 static void render_map_output(uint32_t line, int32_t col, vdp_context * context)
890 { 1052 {
891 if (line >= 240) { 1053 if (line >= 240) {
1034 } 1196 }
1035 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; 1197 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
1036 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; 1198 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
1037 } 1199 }
1038 1200
1201 static void render_map_mode4(uint32_t line, int32_t col, vdp_context * context)
1202 {
1203 uint32_t vscroll = line;
1204 if (col < 24 || !(context->regs[REG_MODE_1] & BIT_VSCRL_LOCK)) {
1205 vscroll += context->regs[REG_Y_SCROLL];
1206 }
1207 if (vscroll > 223) {
1208 vscroll -= 224;
1209 }
1210 vscroll &= 7;
1211 if (context->col_1 & 0x400) {
1212 //vflip
1213 vscroll = 7 - vscroll;
1214 }
1215
1216 uint32_t pixels = planar_to_chunky[context->fetch_tmp[0]] << 1;
1217 pixels |= planar_to_chunky[context->fetch_tmp[1]];
1218
1219 uint32_t address = mode4_address_map[((context->col_1 & 0x1FF) * 32) + vscroll * 4 + 2];
1220 pixels |= planar_to_chunky[context->vdpmem[address]] << 3;
1221 pixels |= planar_to_chunky[context->vdpmem[address+1]] << 2;
1222
1223 int i, i_inc, i_limit;
1224 if (context->col_1 & 0x200) {
1225 //hflip
1226 i = 0;
1227 i_inc = 4;
1228 i_limit = 32;
1229 } else {
1230 i = 28;
1231 i_inc = -4;
1232 i_limit = -4;
1233 }
1234 uint8_t pal_priority = (context->col_1 >> 7 & 0x10) | (context->col_1 >> 6 & 0x40);
1235 for (uint8_t *dst = context->tmp_buf_a + context->buf_a_off; i != i_limit; i += i_inc, dst++)
1236 {
1237 *dst = (pixels >> i & 0xF) | pal_priority;
1238 }
1239 context->buf_a_off = (context->buf_a_off + 8) & 15;
1240
1241 uint8_t bgcolor = 0x10 | (context->regs[REG_BG_COLOR] & 0xF) + CRAM_SIZE*3;
1242 uint32_t *dst = context->output + col * 8;
1243 if (context->debug < 2) {
1244 if (col || !(context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1245 uint8_t *sprite_src = context->linebuf + col * 8;
1246 if (context->regs[REG_MODE_1] & BIT_SPRITE_8PX) {
1247 sprite_src += 8;
1248 }
1249 uint8_t *bg_src = context->tmp_buf_a + (((col & 1) * 8 + (context->hscroll_a & 0x7)) & 0x15);
1250 for (int i = 0; i < 8; i++, bg_src++, sprite_src++)
1251 {
1252 if ((*bg_src & 0x4F) > 0x40) {
1253 //background plane has priority and is opaque
1254 if (context->debug) {
1255 *(dst++) = context->debugcolors[DBG_SRC_A];
1256 } else {
1257 *(dst++) = context->colors[(*bg_src & 0x1F) + CRAM_SIZE*3];
1258 }
1259
1260 } else if (*sprite_src) {
1261 //sprite layer is opaque
1262 if (context->debug) {
1263 *(dst++) = context->debugcolors[DBG_SRC_S];
1264 } else {
1265 *(dst++) = context->colors[*sprite_src | 0x10 + CRAM_SIZE*3];
1266 }
1267 } else if (*bg_src & 0xF) {
1268 //background plane is opaque
1269 if (context->debug) {
1270 *(dst++) = context->debugcolors[DBG_SRC_A];
1271 } else {
1272 *(dst++) = context->colors[(*bg_src & 0x1F) + CRAM_SIZE*3];
1273 }
1274 } else {
1275 if (context->debug) {
1276 *(dst++) = context->debugcolors[DBG_SRC_BG];
1277 } else {
1278 *(dst++) = context->colors[bgcolor];
1279 }
1280 }
1281 }
1282 } else {
1283 for (int i = 0; i < 8; i++)
1284 {
1285 *(dst++) = context->colors[bgcolor];
1286 }
1287 }
1288 } else if (context->debug == 2) {
1289 for (int i = 0; i < 8; i++)
1290 {
1291 *(dst++) = context->colors[CRAM_SIZE*3 + col];
1292 }
1293 } else {
1294 uint32_t cell = (line / 8) * 32 + col;
1295 uint32_t address = cell * 32 + (line % 8) * 4;
1296 uint32_t m4_address = mode4_address_map[address & 0x3FFF];
1297 uint32_t pixel = planar_to_chunky[context->vdpmem[m4_address]] << 1;
1298 pixel |= planar_to_chunky[context->vdpmem[m4_address + 1]];
1299 m4_address = mode4_address_map[(address + 2) & 0x3FFF];
1300 pixel |= planar_to_chunky[context->vdpmem[m4_address]] << 3;
1301 pixel |= planar_to_chunky[context->vdpmem[m4_address + 1]] << 2;
1302 if (context->debug_pal < 2) {
1303 for (int i = 28; i >= 0; i -= 4)
1304 {
1305 *(dst++) = context->colors[CRAM_SIZE*3 | (context->debug_pal << 4) | (pixel >> i & 0xF)];
1306 }
1307 } else {
1308 for (int i = 28; i >= 0; i -= 4)
1309 {
1310 uint8_t value = (pixel >> i & 0xF) * 17;
1311 if (context->debug_pal == 3) {
1312 value = 255 - value;
1313 }
1314 *(dst++) = render_map_color(value, value, value);
1315 }
1316 }
1317 }
1318 }
1319
1039 static uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19}; 1320 static uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19};
1040 1321
1041 static void vdp_advance_line(vdp_context *context) 1322 static void vdp_advance_line(vdp_context *context)
1042 { 1323 {
1043 context->vcounter++; 1324 context->vcounter++;
1137 render_map_3(context);\ 1418 render_map_3(context);\
1138 CHECK_LIMIT\ 1419 CHECK_LIMIT\
1139 case (startcyc+7):\ 1420 case (startcyc+7):\
1140 render_map_output(context->vcounter, column, context);\ 1421 render_map_output(context->vcounter, column, context);\
1141 CHECK_LIMIT 1422 CHECK_LIMIT
1423
1424 #define COLUMN_RENDER_BLOCK_MODE4(column, startcyc) \
1425 case startcyc:\
1426 read_map_mode4(column, context->vcounter, context);\
1427 CHECK_LIMIT\
1428 case ((startcyc+1)&0xFF):\
1429 if (column & 1) {\
1430 read_sprite_x_mode4(context->vcounter, context);\
1431 } else {\
1432 external_slot(context);\
1433 }\
1434 CHECK_LIMIT\
1435 case ((startcyc+2)&0xFF):\
1436 fetch_map_mode4(column, context->vcounter, context);\
1437 CHECK_LIMIT\
1438 case ((startcyc+3)&0xFF):\
1439 render_map_mode4(context->vcounter, column, context);\
1440 CHECK_LIMIT
1441
1442 #define COLUMN_RENDER_BLOCK_REFRESH_MODE4(column, startcyc) \
1443 case startcyc:\
1444 read_map_mode4(column, context->vcounter, context);\
1445 CHECK_LIMIT\
1446 case (startcyc+1):\
1447 /* refresh, no don't run dma src */\
1448 context->hslot++;\
1449 context->cycles += slot_cycles;\
1450 CHECK_ONLY\
1451 case (startcyc+2):\
1452 fetch_map_mode4(column, context->vcounter, context);\
1453 CHECK_LIMIT\
1454 case (startcyc+3):\
1455 render_map_mode4(context->vcounter, column, context);\
1456 CHECK_LIMIT
1142 1457
1143 #define SPRITE_RENDER_H40(slot) \ 1458 #define SPRITE_RENDER_H40(slot) \
1144 case slot:\ 1459 case slot:\
1145 render_sprite_cells( context);\ 1460 render_sprite_cells( context);\
1146 scan_sprite_table(context->vcounter, context);\ 1461 scan_sprite_table(context->vcounter, context);\
1168 } else {\ 1483 } else {\
1169 context->hslot++;\ 1484 context->hslot++;\
1170 }\ 1485 }\
1171 context->cycles += slot_cycles;\ 1486 context->cycles += slot_cycles;\
1172 CHECK_ONLY 1487 CHECK_ONLY
1173 1488
1489 #define SPRITE_RENDER_H32_MODE4(slot) \
1490 case slot:\
1491 fetch_sprite_cells_mode4(context);\
1492 scan_sprite_table(context->vcounter, context);\
1493 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \
1494 if (slot == 147) {\
1495 context->hslot = 233;\
1496 } else {\
1497 context->hslot++;\
1498 }\
1499 context->cycles += slot_cycles;\
1500 CHECK_ONLY\
1501 case (slot == 147 ? 233 : slot+1):\
1502 render_sprite_cells_mode4(context);\
1503 scan_sprite_table(context->vcounter, context);\
1504 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \
1505 if (slot == 147) {\
1506 context->hslot = 233;\
1507 } else {\
1508 context->hslot++;\
1509 }\
1510 context->cycles += slot_cycles;\
1511 CHECK_ONLY
1174 1512
1175 static void vdp_h40(vdp_context * context, uint32_t target_cycles) 1513 static void vdp_h40(vdp_context * context, uint32_t target_cycles)
1176 { 1514 {
1177 uint16_t address; 1515 uint16_t address;
1178 uint32_t mask; 1516 uint32_t mask;
1476 context->hslot++; 1814 context->hslot++;
1477 context->cycles += MCLKS_SLOT_H32; 1815 context->cycles += MCLKS_SLOT_H32;
1478 } 1816 }
1479 } 1817 }
1480 1818
1819 static void vdp_h32_mode4(vdp_context * context, uint32_t target_cycles)
1820 {
1821 uint16_t address;
1822 uint32_t mask;
1823 uint32_t const slot_cycles = MCLKS_SLOT_H32;
1824 switch(context->hslot)
1825 {
1826 for (;;)
1827 {
1828 //sprite attribute table scan starts
1829 case 132:
1830 context->sprite_index = 0x80;
1831 //in theory, Mode 4 should only allow 8 sprites per line, but if we assume that thee
1832 //Genesis VDP uses the SAT cache for sprite scans in Mode 4 like it does in Mode 5,
1833 //there should be enough bandwidth for 16 like in Mode 5 (though only 128 pixels rather than 256)
1834 context->slot_counter = MAX_SPRITES_LINE_H32;
1835 fetch_sprite_cells_mode4(context);
1836 scan_sprite_table_mode4(context->vcounter, context);
1837 CHECK_LIMIT
1838 case 133:
1839 render_sprite_cells_mode4(context);
1840 scan_sprite_table_mode4(context->vcounter, context);
1841 CHECK_LIMIT
1842 SPRITE_RENDER_H32_MODE4(134)
1843 SPRITE_RENDER_H32_MODE4(136)
1844 SPRITE_RENDER_H32_MODE4(138)
1845 SPRITE_RENDER_H32_MODE4(140)
1846 case 142:
1847 external_slot(context);
1848 CHECK_LIMIT
1849 SPRITE_RENDER_H32_MODE4(143)
1850 SPRITE_RENDER_H32_MODE4(145)
1851 SPRITE_RENDER_H32_MODE4(147)
1852 //HSYNC start @233
1853 SPRITE_RENDER_H32_MODE4(234)
1854 SPRITE_RENDER_H32_MODE4(236)
1855 SPRITE_RENDER_H32_MODE4(238)
1856 case 240:
1857 external_slot(context);
1858 CHECK_LIMIT
1859 case 241:
1860 if (context->regs[REG_MODE_1] & BIT_HSCRL_LOCK && context->vcounter < 16) {
1861 context->hscroll_a = 0;
1862 } else {
1863 context->hscroll_a = context->regs[REG_X_SCROLL];
1864 }
1865 CHECK_LIMIT
1866 SPRITE_RENDER_H32_MODE4(242)
1867 SPRITE_RENDER_H32_MODE4(244)
1868 //!HSYNC high
1869 case 246:
1870 external_slot(context);
1871 CHECK_LIMIT
1872 case 247:
1873 fetch_sprite_cells_mode4(context);
1874 scan_sprite_table_mode4(context->vcounter, context);
1875 CHECK_LIMIT
1876 case 248:
1877 external_slot(context);
1878 scan_sprite_table_mode4(context->vcounter, context);//Just a guess
1879 CHECK_LIMIT
1880 case 249:
1881 external_slot(context);
1882 scan_sprite_table_mode4(context->vcounter, context);//Just a guess
1883 CHECK_LIMIT
1884 case 250:
1885 external_slot(context);
1886 CHECK_LIMIT
1887 case 251:
1888 render_sprite_cells_mode4(context);
1889 scan_sprite_table_mode4(context->vcounter, context);
1890 CHECK_LIMIT
1891 case 252:
1892 external_slot(context);
1893 scan_sprite_table_mode4(context->vcounter, context);//Just a guess
1894 CHECK_LIMIT
1895 case 253:
1896 external_slot(context);
1897 scan_sprite_table_mode4(context->vcounter, context);//Just a guess
1898 //reverse context slot counter so it counts the number of sprite slots
1899 //filled rather than the number of available slots
1900 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter;
1901 context->cur_slot = MAX_SPRITES_LINE_H32-1;
1902 context->sprite_draws = MAX_DRAWS_H32_MODE4;
1903 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED);
1904 CHECK_LIMIT
1905 COLUMN_RENDER_BLOCK_MODE4(0, 254)
1906 COLUMN_RENDER_BLOCK_MODE4(1, 2)
1907 COLUMN_RENDER_BLOCK_MODE4(2, 6)
1908 COLUMN_RENDER_BLOCK_MODE4(3, 10)
1909 COLUMN_RENDER_BLOCK_MODE4(4, 14)
1910 COLUMN_RENDER_BLOCK_MODE4(5, 18)
1911 COLUMN_RENDER_BLOCK_REFRESH_MODE4(6, 22)
1912 COLUMN_RENDER_BLOCK_MODE4(7, 26)
1913 COLUMN_RENDER_BLOCK_MODE4(8, 30)
1914 COLUMN_RENDER_BLOCK_MODE4(9, 34)
1915 COLUMN_RENDER_BLOCK_MODE4(10, 38)
1916 COLUMN_RENDER_BLOCK_MODE4(11, 42)
1917 COLUMN_RENDER_BLOCK_MODE4(12, 46)
1918 COLUMN_RENDER_BLOCK_MODE4(13, 50)
1919 COLUMN_RENDER_BLOCK_REFRESH_MODE4(14, 54)
1920 COLUMN_RENDER_BLOCK_MODE4(15, 58)
1921 COLUMN_RENDER_BLOCK_MODE4(16, 62)
1922 COLUMN_RENDER_BLOCK_MODE4(17, 66)
1923 COLUMN_RENDER_BLOCK_MODE4(18, 70)
1924 COLUMN_RENDER_BLOCK_MODE4(19, 74)
1925 COLUMN_RENDER_BLOCK_MODE4(20, 78)
1926 COLUMN_RENDER_BLOCK_MODE4(21, 82)
1927 COLUMN_RENDER_BLOCK_REFRESH_MODE4(22, 86)
1928 COLUMN_RENDER_BLOCK_MODE4(23, 90)
1929 COLUMN_RENDER_BLOCK_MODE4(24, 94)
1930 COLUMN_RENDER_BLOCK_MODE4(25, 98)
1931 COLUMN_RENDER_BLOCK_MODE4(26, 102)
1932 COLUMN_RENDER_BLOCK_MODE4(27, 106)
1933 COLUMN_RENDER_BLOCK_MODE4(28, 110)
1934 COLUMN_RENDER_BLOCK_MODE4(29, 114)
1935 COLUMN_RENDER_BLOCK_REFRESH_MODE4(30, 118)
1936 COLUMN_RENDER_BLOCK_MODE4(31, 122)
1937 case 126:
1938 external_slot(context);
1939 CHECK_LIMIT
1940 case 127:
1941 external_slot(context);
1942 CHECK_LIMIT
1943 //sprite render to line buffer starts
1944 case 128:
1945 context->cur_slot = MAX_DRAWS_H32_MODE4-1;
1946 memset(context->linebuf, 0, LINEBUF_SIZE);
1947 fetch_sprite_cells_mode4(context);
1948 CHECK_LIMIT
1949 case 129:
1950 render_sprite_cells_mode4(context);
1951 CHECK_LIMIT
1952 case 130:
1953 fetch_sprite_cells_mode4(context);
1954 CHECK_LIMIT
1955 case 131:
1956 render_sprite_cells_mode4(context);
1957 vdp_advance_line(context);
1958 if (context->vcounter == MODE4_INACTIVE_START) {
1959 context->hslot++;
1960 context->cycles += slot_cycles;
1961 return;
1962 }
1963 CHECK_LIMIT
1964 }
1965 default:
1966 context->hslot++;
1967 context->cycles += MCLKS_SLOT_H32;
1968 }
1969 }
1970
1481 void latch_mode(vdp_context * context) 1971 void latch_mode(vdp_context * context)
1482 { 1972 {
1483 context->latched_mode = context->regs[REG_MODE_2] & BIT_PAL; 1973 context->latched_mode = context->regs[REG_MODE_2] & BIT_PAL;
1484 } 1974 }
1485 1975
1507 1997
1508 void vdp_run_context(vdp_context * context, uint32_t target_cycles) 1998 void vdp_run_context(vdp_context * context, uint32_t target_cycles)
1509 { 1999 {
1510 while(context->cycles < target_cycles) 2000 while(context->cycles < target_cycles)
1511 { 2001 {
1512 uint32_t inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START;
1513 //line 0x1FF is basically active even though it's not displayed
1514 uint8_t active_slot = context->vcounter < inactive_start || context->vcounter == 0x1FF;
1515 uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; 2002 uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40;
1516 if (context->regs[REG_MODE_2] & DISPLAY_ENABLE && active_slot) { 2003 uint8_t active_slot, mode_5;
1517 if (is_h40) { 2004 uint32_t inactive_start;
1518 vdp_h40(context, target_cycles); 2005 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
2006 //Mode 5 selected
2007 mode_5 = 1;
2008 inactive_start = context->latched_mode & BIT_PAL ? PAL_INACTIVE_START : NTSC_INACTIVE_START;
2009 //line 0x1FF is basically active even though it's not displayed
2010 active_slot = (context->vcounter < inactive_start || context->vcounter == 0x1FF) && (context->regs[REG_MODE_2] & DISPLAY_ENABLE);
2011 } else {
2012 mode_5 = 0;
2013 inactive_start = MODE4_INACTIVE_START;
2014 //display is effectively disabled if neither mode 5 nor mode 4 are selected
2015 active_slot = context->vcounter < inactive_start && (context->regs[REG_MODE_2] & DISPLAY_ENABLE) && (context->regs[REG_MODE_1] & BIT_MODE_4);
2016 }
2017
2018 if (active_slot) {
2019 if (mode_5) {
2020 if (is_h40) {
2021 vdp_h40(context, target_cycles);
2022 } else {
2023 vdp_h32(context, target_cycles);
2024 }
1519 } else { 2025 } else {
1520 vdp_h32(context, target_cycles); 2026 vdp_h32_mode4(context, target_cycles);
1521 } 2027 }
1522 } else { 2028 } else {
1523 if (is_h40) { 2029 if (is_h40) {
1524 if (context->hslot == 161) { 2030 if (context->hslot == 161) {
1525 context->cur_slot = MAX_DRAWS-1; 2031 context->cur_slot = MAX_DRAWS-1;
1656 } else { 2162 } else {
1657 //printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd); 2163 //printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd);
1658 } 2164 }
1659 } 2165 }
1660 } else { 2166 } else {
2167 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
1661 if ((value & 0xC000) == 0x8000) { 2168 if ((value & 0xC000) == 0x8000) {
1662 //Register write 2169 //Register write
1663 uint8_t reg = (value >> 8) & 0x1F; 2170 uint8_t reg = (value >> 8) & 0x1F;
1664 if (reg < (context->regs[REG_MODE_2] & BIT_MODE_5 ? VDP_REGS : 0xA)) { 2171 if (reg < (mode_5 ? VDP_REGS : 0xA)) {
1665 //printf("register %d set to %X\n", reg, value & 0xFF); 2172 //printf("register %d set to %X\n", reg, value & 0xFF);
1666 if (reg == REG_MODE_1 && (value & BIT_HVC_LATCH) && !(context->regs[reg] & BIT_HVC_LATCH)) { 2173 if (reg == REG_MODE_1 && (value & BIT_HVC_LATCH) && !(context->regs[reg] & BIT_HVC_LATCH)) {
1667 context->hv_latch = vdp_hv_counter_read(context); 2174 context->hv_latch = vdp_hv_counter_read(context);
1668 } 2175 }
1669 if (reg == REG_BG_COLOR) { 2176 if (reg == REG_BG_COLOR) {
1679 context->flags2 &= ~FLAG2_EVEN_FIELD; 2186 context->flags2 &= ~FLAG2_EVEN_FIELD;
1680 } 2187 }
1681 } 2188 }
1682 context->cd &= 0x3C; 2189 context->cd &= 0x3C;
1683 } 2190 }
1684 } else { 2191 } else if (mode_5) {
1685 context->flags |= FLAG_PENDING; 2192 context->flags |= FLAG_PENDING;
1686 context->address = (context->address &0xC000) | (value & 0x3FFF); 2193 context->address = (context->address &0xC000) | (value & 0x3FFF);
1687 context->cd = (context->cd &0x3C) | (value >> 14); 2194 context->cd = (context->cd &0x3C) | (value >> 14);
1688 //Should these be taken care of here or after the second write? 2195 //Should these be taken care of here or after the second write?
1689 //context->flags &= ~FLAG_READ_FETCHED; 2196 //context->flags &= ~FLAG_READ_FETCHED;
1690 //context->flags2 &= ~FLAG2_READ_PENDING; 2197 //context->flags2 &= ~FLAG2_READ_PENDING;
2198 } else {
2199 context->address = value & 0x3FFF;
2200 context->cd = value >> 14;
2201 context->flags &= ~FLAG_READ_FETCHED;
2202 context->flags2 &= ~FLAG2_READ_PENDING;
1691 } 2203 }
1692 } 2204 }
1693 return 0; 2205 return 0;
1694 } 2206 }
1695 2207
1736 if (context->fifo_read < 0) { 2248 if (context->fifo_read < 0) {
1737 context->fifo_read = context->fifo_write; 2249 context->fifo_read = context->fifo_write;
1738 } 2250 }
1739 context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1); 2251 context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1);
1740 context->address += context->regs[REG_AUTOINC]; 2252 context->address += context->regs[REG_AUTOINC];
2253 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) {
2254 context->address++;
2255 }
1741 return 0; 2256 return 0;
1742 } 2257 }
1743 2258
1744 void vdp_data_port_write_pbc(vdp_context * context, uint8_t value) 2259 void vdp_data_port_write_pbc(vdp_context * context, uint8_t value)
1745 { 2260 {
1767 if (context->fifo_read < 0) { 2282 if (context->fifo_read < 0) {
1768 context->fifo_read = context->fifo_write; 2283 context->fifo_read = context->fifo_write;
1769 } 2284 }
1770 context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1); 2285 context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1);
1771 context->address += context->regs[REG_AUTOINC]; 2286 context->address += context->regs[REG_AUTOINC];
2287 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) {
2288 context->address++;
2289 }
1772 } 2290 }
1773 2291
1774 void vdp_test_port_write(vdp_context * context, uint16_t value) 2292 void vdp_test_port_write(vdp_context * context, uint16_t value)
1775 { 2293 {
1776 //TODO: implement test register 2294 //TODO: implement test register