comparison vdp.c @ 1692:5dacaef602a7 segacd

Merge from default
author Michael Pavone <pavone@retrodev.com>
date Sat, 05 Jan 2019 00:58:08 -0800
parents 3128d4e0bc68
children 8f2e78db0872
comparison
equal deleted inserted replaced
1504:95b3a1a8b26c 1692:5dacaef602a7
3 This file is part of BlastEm. 3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. 4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5 */ 5 */
6 #include "vdp.h" 6 #include "vdp.h"
7 #include "blastem.h" 7 #include "blastem.h"
8 #include "genesis.h"
9 #include <stdlib.h> 8 #include <stdlib.h>
10 #include <string.h> 9 #include <string.h>
11 #include "render.h" 10 #include "render.h"
12 #include "util.h" 11 #include "util.h"
13 12
17 #define BUF_BIT_PRIORITY 0x40 16 #define BUF_BIT_PRIORITY 0x40
18 #define MAP_BIT_PRIORITY 0x8000 17 #define MAP_BIT_PRIORITY 0x8000
19 #define MAP_BIT_H_FLIP 0x800 18 #define MAP_BIT_H_FLIP 0x800
20 #define MAP_BIT_V_FLIP 0x1000 19 #define MAP_BIT_V_FLIP 0x1000
21 20
22 #define SCROLL_BUFFER_SIZE 32
23 #define SCROLL_BUFFER_MASK (SCROLL_BUFFER_SIZE-1) 21 #define SCROLL_BUFFER_MASK (SCROLL_BUFFER_SIZE-1)
24 #define SCROLL_BUFFER_DRAW (SCROLL_BUFFER_SIZE/2) 22 #define SCROLL_BUFFER_DRAW (SCROLL_BUFFER_SIZE/2)
25 23
26 #define MCLKS_SLOT_H40 16 24 #define MCLKS_SLOT_H40 16
27 #define MCLKS_SLOT_H32 20 25 #define MCLKS_SLOT_H32 20
136 } 134 }
137 } 135 }
138 136
139 static uint8_t color_map_init_done; 137 static uint8_t color_map_init_done;
140 138
141 void init_vdp_context(vdp_context * context, uint8_t region_pal) 139 vdp_context *init_vdp_context(uint8_t region_pal)
142 { 140 {
143 memset(context, 0, sizeof(*context)); 141 vdp_context *context = calloc(1, sizeof(vdp_context) + VRAM_SIZE);
144 context->vdpmem = malloc(VRAM_SIZE);
145 memset(context->vdpmem, 0, VRAM_SIZE);
146 /*
147 */
148 if (headless) { 142 if (headless) {
149 context->output = malloc(LINEBUF_SIZE * sizeof(uint32_t)); 143 context->output = malloc(LINEBUF_SIZE * sizeof(uint32_t));
150 context->output_pitch = 0; 144 context->output_pitch = 0;
151 } else { 145 } else {
152 context->cur_buffer = FRAMEBUFFER_ODD; 146 context->cur_buffer = FRAMEBUFFER_ODD;
153 context->fb = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch); 147 context->fb = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch);
154 } 148 }
155 context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2);
156 memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2);
157 context->tmp_buf_a = context->linebuf + LINEBUF_SIZE;
158 context->tmp_buf_b = context->tmp_buf_a + SCROLL_BUFFER_SIZE;
159 context->sprite_draws = MAX_DRAWS; 149 context->sprite_draws = MAX_DRAWS;
160 context->fifo_write = 0; 150 context->fifo_write = 0;
161 context->fifo_read = -1; 151 context->fifo_read = -1;
162 context->regs[REG_HINT] = context->hint_counter = 0xFF; 152 context->regs[REG_HINT] = context->hint_counter = 0xFF;
163 153
248 } 238 }
249 update_video_params(context); 239 update_video_params(context);
250 if (!headless) { 240 if (!headless) {
251 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * context->border_top); 241 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * context->border_top);
252 } 242 }
243 return context;
253 } 244 }
254 245
255 void vdp_free(vdp_context *context) 246 void vdp_free(vdp_context *context)
256 { 247 {
257 free(context->vdpmem);
258 free(context->linebuf);
259 free(context); 248 free(context);
260 } 249 }
261 250
262 static int is_refresh(vdp_context * context, uint32_t slot) 251 static int is_refresh(vdp_context * context, uint32_t slot)
263 { 252 {
526 context->regs[REG_DMASRC_L], 515 context->regs[REG_DMASRC_L],
527 context->regs[REG_DMASRC_M], 516 context->regs[REG_DMASRC_M],
528 context->regs[REG_DMASRC_H], 517 context->regs[REG_DMASRC_H],
529 context->regs[REG_DMASRC_H] << 17 | context->regs[REG_DMASRC_M] << 9 | context->regs[REG_DMASRC_L] << 1, 518 context->regs[REG_DMASRC_H] << 17 | context->regs[REG_DMASRC_M] << 9 | context->regs[REG_DMASRC_L] << 1,
530 src_types[context->regs[REG_DMASRC_H] >> 6 & 3]); 519 src_types[context->regs[REG_DMASRC_H] >> 6 & 3]);
520 uint8_t old_flags = context->flags;
521 uint8_t old_flags2 = context->flags2;
531 printf("\n**Internal Group**\n" 522 printf("\n**Internal Group**\n"
532 "Address: %X\n" 523 "Address: %X\n"
533 "CD: %X - %s\n" 524 "CD: %X - %s\n"
534 "Pending: %s\n" 525 "Pending: %s\n"
535 "VCounter: %d\n" 526 "VCounter: %d\n"
539 "Status: %X\n", 530 "Status: %X\n",
540 context->address, context->cd, cd_name(context->cd), 531 context->address, context->cd, cd_name(context->cd),
541 (context->flags & FLAG_PENDING) ? "word" : (context->flags2 & FLAG2_BYTE_PENDING) ? "byte" : "none", 532 (context->flags & FLAG_PENDING) ? "word" : (context->flags2 & FLAG2_BYTE_PENDING) ? "byte" : "none",
542 context->vcounter, context->hslot*2, (context->flags2 & FLAG2_VINT_PENDING) ? "true" : "false", 533 context->vcounter, context->hslot*2, (context->flags2 & FLAG2_VINT_PENDING) ? "true" : "false",
543 (context->flags2 & FLAG2_HINT_PENDING) ? "true" : "false", vdp_control_port_read(context)); 534 (context->flags2 & FLAG2_HINT_PENDING) ? "true" : "false", vdp_control_port_read(context));
544 535 //restore flags as calling vdp_control_port_read can change them
545 //TODO: Window Group, DMA Group 536 context->flags = old_flags;
537 context->flags2 = old_flags2;
546 } 538 }
547 539
548 static uint8_t is_active(vdp_context *context) 540 static uint8_t is_active(vdp_context *context)
549 { 541 {
550 return context->state != INACTIVE && (context->regs[REG_MODE_2] & BIT_DISP_EN) != 0; 542 return context->state != INACTIVE && (context->regs[REG_MODE_2] & BIT_DISP_EN) != 0;
776 #define BG_START_SLOT 6 768 #define BG_START_SLOT 6
777 769
778 static void update_color_map(vdp_context *context, uint16_t index, uint16_t value) 770 static void update_color_map(vdp_context *context, uint16_t index, uint16_t value)
779 { 771 {
780 context->colors[index] = color_map[value & CRAM_BITS]; 772 context->colors[index] = color_map[value & CRAM_BITS];
781 context->colors[index + CRAM_SIZE] = color_map[(value & CRAM_BITS) | FBUF_SHADOW]; 773 context->colors[index + SHADOW_OFFSET] = color_map[(value & CRAM_BITS) | FBUF_SHADOW];
782 context->colors[index + CRAM_SIZE*2] = color_map[(value & CRAM_BITS) | FBUF_HILIGHT]; 774 context->colors[index + HIGHLIGHT_OFFSET] = color_map[(value & CRAM_BITS) | FBUF_HILIGHT];
783 context->colors[index + CRAM_SIZE*3] = color_map[(value & CRAM_BITS) | FBUF_MODE4]; 775 context->colors[index + MODE4_OFFSET] = color_map[(value & CRAM_BITS) | FBUF_MODE4];
784 } 776 }
785 777
786 void write_cram_internal(vdp_context * context, uint16_t addr, uint16_t value) 778 void write_cram_internal(vdp_context * context, uint16_t addr, uint16_t value)
787 { 779 {
788 context->cram[addr] = value; 780 context->cram[addr] = value;
804 context->vcounter < context->inactive_start + context->border_bot 796 context->vcounter < context->inactive_start + context->border_bot
805 || context->vcounter > 0x200 - context->border_top 797 || context->vcounter > 0x200 - context->border_top
806 )) { 798 )) {
807 uint8_t bg_end_slot = BG_START_SLOT + (context->regs[REG_MODE_4] & BIT_H40) ? LINEBUF_SIZE/2 : (256+HORIZ_BORDER)/2; 799 uint8_t bg_end_slot = BG_START_SLOT + (context->regs[REG_MODE_4] & BIT_H40) ? LINEBUF_SIZE/2 : (256+HORIZ_BORDER)/2;
808 if (context->hslot < bg_end_slot) { 800 if (context->hslot < bg_end_slot) {
809 uint32_t color = (context->regs[REG_MODE_2] & BIT_MODE_5) ? context->colors[addr] : context->colors[addr + CRAM_SIZE*3]; 801 uint32_t color = (context->regs[REG_MODE_2] & BIT_MODE_5) ? context->colors[addr] : context->colors[addr + MODE4_OFFSET];
810 context->output[(context->hslot - BG_START_SLOT)*2 + 1] = color; 802 context->output[(context->hslot - BG_START_SLOT)*2 + 1] = color;
811 } 803 }
812 } 804 }
813 } 805 }
814 806
873 address = mode4_address_map[address & 0x3FFF]; 865 address = mode4_address_map[address & 0x3FFF];
874 } 866 }
875 context->vdpmem[address] = value; 867 context->vdpmem[address] = value;
876 } 868 }
877 869
870 #define DMA_FILL 0x80
871 #define DMA_COPY 0xC0
872 #define DMA_TYPE_MASK 0xC0
878 static void external_slot(vdp_context * context) 873 static void external_slot(vdp_context * context)
879 { 874 {
880 if ((context->flags & FLAG_DMA_RUN) && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80 && context->fifo_read < 0) { 875 if ((context->flags & FLAG_DMA_RUN) && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_FILL && context->fifo_read < 0) {
881 context->fifo_read = (context->fifo_write-1) & (FIFO_SIZE-1); 876 context->fifo_read = (context->fifo_write-1) & (FIFO_SIZE-1);
882 fifo_entry * cur = context->fifo + context->fifo_read; 877 fifo_entry * cur = context->fifo + context->fifo_read;
883 cur->cycle = context->cycles; 878 cur->cycle = context->cycles;
884 cur->address = context->address; 879 cur->address = context->address;
885 cur->partial = 2; 880 cur->partial = 1;
886 vdp_advance_dma(context); 881 vdp_advance_dma(context);
887 } 882 }
888 fifo_entry * start = context->fifo + context->fifo_read; 883 fifo_entry * start = context->fifo + context->fifo_read;
889 if (context->fifo_read >= 0 && start->cycle <= context->cycles) { 884 if (context->fifo_read >= 0 && start->cycle <= context->cycles) {
890 switch (start->cd & 0xF) 885 switch (start->cd & 0xF)
891 { 886 {
892 case VRAM_WRITE: 887 case VRAM_WRITE:
893 if ((context->regs[REG_MODE_2] & (BIT_128K_VRAM|BIT_MODE_5)) == (BIT_128K_VRAM|BIT_MODE_5)) { 888 if ((context->regs[REG_MODE_2] & (BIT_128K_VRAM|BIT_MODE_5)) == (BIT_128K_VRAM|BIT_MODE_5)) {
894 vdp_check_update_sat(context, start->address, start->value); 889 vdp_check_update_sat(context, start->address, start->value);
895 write_vram_word(context, start->address, start->value); 890 write_vram_word(context, start->address, start->value);
896 } else if (start->partial) { 891 } else {
897 //printf("VRAM Write: %X to %X at %d (line %d, slot %d)\n", start->value, start->address ^ 1, context->cycles, context->cycles/MCLKS_LINE, (context->cycles%MCLKS_LINE)/16); 892 uint8_t byte = start->partial == 1 ? start->value >> 8 : start->value;
898 uint8_t byte = start->partial == 2 ? start->value >> 8 : start->value; 893 vdp_check_update_sat_byte(context, start->address ^ 1, byte);
899 if (start->partial > 1) {
900 vdp_check_update_sat_byte(context, start->address ^ 1, byte);
901 }
902 write_vram_byte(context, start->address ^ 1, byte); 894 write_vram_byte(context, start->address ^ 1, byte);
903 } else { 895 if (!start->partial) {
904 //printf("VRAM Write High: %X to %X at %d (line %d, slot %d)\n", start->value >> 8, start->address, context->cycles, context->cycles/MCLKS_LINE, (context->cycles%MCLKS_LINE)/16); 896 start->address = start->address ^ 1;
905 vdp_check_update_sat(context, start->address, start->value); 897 start->partial = 1;
906 write_vram_byte(context, start->address, start->value >> 8); 898 //skip auto-increment and removal of entry from fifo
907 start->partial = 1; 899 return;
908 //skip auto-increment and removal of entry from fifo 900 }
909 return;
910 } 901 }
911 break; 902 break;
912 case CRAM_WRITE: { 903 case CRAM_WRITE: {
913 //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1)); 904 //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1));
914 if (start->partial == 3) { 905 if (start->partial == 3) {
919 uint16_t address = (context->regs[REG_MODE_2] & BIT_MODE_5) ? start->address >> 1 & (CRAM_SIZE-1) : start->address & 0x1F; 910 uint16_t address = (context->regs[REG_MODE_2] & BIT_MODE_5) ? start->address >> 1 & (CRAM_SIZE-1) : start->address & 0x1F;
920 val = (context->cram[address] & 0xFF00) | start->value; 911 val = (context->cram[address] & 0xFF00) | start->value;
921 } 912 }
922 write_cram(context, start->address, val); 913 write_cram(context, start->address, val);
923 } else { 914 } else {
924 write_cram(context, start->address, start->partial == 2 ? context->fifo[context->fifo_write].value : start->value); 915 write_cram(context, start->address, start->partial ? context->fifo[context->fifo_write].value : start->value);
925 } 916 }
926 break; 917 break;
927 } 918 }
928 case VSRAM_WRITE: 919 case VSRAM_WRITE:
929 if (((start->address/2) & 63) < VSRAM_SIZE) { 920 if (((start->address/2) & 63) < VSRAM_SIZE) {
935 } else { 926 } else {
936 context->vsram[(start->address/2) & 63] &= 0xFF00; 927 context->vsram[(start->address/2) & 63] &= 0xFF00;
937 context->vsram[(start->address/2) & 63] |= start->value; 928 context->vsram[(start->address/2) & 63] |= start->value;
938 } 929 }
939 } else { 930 } else {
940 context->vsram[(start->address/2) & 63] = start->partial == 2 ? context->fifo[context->fifo_write].value : start->value; 931 context->vsram[(start->address/2) & 63] = start->partial ? context->fifo[context->fifo_write].value : start->value;
941 } 932 }
942 } 933 }
943 934
944 break; 935 break;
945 } 936 }
946 context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1); 937 context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1);
947 if (context->fifo_read == context->fifo_write) { 938 if (context->fifo_read == context->fifo_write) {
948 if ((context->cd & 0x20) && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { 939 if ((context->cd & 0x20) && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_FILL) {
949 context->flags |= FLAG_DMA_RUN; 940 context->flags |= FLAG_DMA_RUN;
950 } 941 }
951 context->fifo_read = -1; 942 context->fifo_read = -1;
952 } 943 }
953 } else if ((context->flags & FLAG_DMA_RUN) && (context->regs[REG_DMASRC_H] & 0xC0) == 0xC0) { 944 } else if ((context->flags & FLAG_DMA_RUN) && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_COPY) {
954 if (context->flags & FLAG_READ_FETCHED) { 945 if (context->flags & FLAG_READ_FETCHED) {
955 write_vram_byte(context, context->address ^ 1, context->prefetch); 946 write_vram_byte(context, context->address ^ 1, context->prefetch);
956 947
957 //Update DMA state 948 //Update DMA state
958 vdp_advance_dma(context); 949 vdp_advance_dma(context);
1215 if (col & MAP_BIT_V_FLIP) { 1206 if (col & MAP_BIT_V_FLIP) {
1216 address += vflip_base - 4 * context->v_offset; 1207 address += vflip_base - 4 * context->v_offset;
1217 } else { 1208 } else {
1218 address += 4 * context->v_offset; 1209 address += 4 * context->v_offset;
1219 } 1210 }
1220 uint16_t pal_priority = (col >> 9) & 0x70; 1211 uint8_t pal_priority = (col >> 9) & 0x70;
1221 int32_t dir; 1212 uint32_t bits = *((uint32_t *)(&context->vdpmem[address]));
1222 if (col & MAP_BIT_H_FLIP) { 1213 if (col & MAP_BIT_H_FLIP) {
1223 offset += 7; 1214 uint32_t shift = 28;
1224 offset &= SCROLL_BUFFER_MASK; 1215 for (int i = 0; i < 4; i++)
1225 dir = -1; 1216 {
1226 } else { 1217 uint8_t right = pal_priority | ((bits >> shift) & 0xF);
1227 dir = 1; 1218 shift -= 4;
1228 } 1219 tmp_buf[offset++] = pal_priority | ((bits >> shift) & 0xF);
1229 for (uint32_t i=0; i < 4; i++, address++) 1220 shift -= 4;
1230 { 1221 offset &= SCROLL_BUFFER_MASK;
1231 tmp_buf[offset] = pal_priority | (context->vdpmem[address] >> 4); 1222 tmp_buf[offset++] = right;
1232 offset += dir; 1223 offset &= SCROLL_BUFFER_MASK;
1233 offset &= SCROLL_BUFFER_MASK; 1224 }
1234 tmp_buf[offset] = pal_priority | (context->vdpmem[address] & 0xF); 1225 } else {
1235 offset += dir; 1226 for (int i = 0; i < 4; i++)
1236 offset &= SCROLL_BUFFER_MASK; 1227 {
1228 uint8_t right = pal_priority | (bits & 0xF);
1229 bits >>= 4;
1230 tmp_buf[offset++] = pal_priority | (bits & 0xF);
1231 offset &= SCROLL_BUFFER_MASK;
1232 bits >>= 4;
1233 tmp_buf[offset++] = right;
1234 offset &= SCROLL_BUFFER_MASK;
1235 }
1237 } 1236 }
1238 } 1237 }
1239 1238
1240 static void render_map_1(vdp_context * context) 1239 static void render_map_1(vdp_context * context)
1241 { 1240 {
1270 uint32_t address = mode4_address_map[((context->col_1 & 0x1FF) * 32) + vscroll * 4]; 1269 uint32_t address = mode4_address_map[((context->col_1 & 0x1FF) * 32) + vscroll * 4];
1271 context->fetch_tmp[0] = context->vdpmem[address]; 1270 context->fetch_tmp[0] = context->vdpmem[address];
1272 context->fetch_tmp[1] = context->vdpmem[address+1]; 1271 context->fetch_tmp[1] = context->vdpmem[address+1];
1273 } 1272 }
1274 1273
1274 static uint8_t composite_normal(vdp_context *context, uint8_t *debug_dst, uint8_t sprite, uint8_t plane_a, uint8_t plane_b, uint8_t bg_index)
1275 {
1276 uint8_t pixel = bg_index;
1277 uint8_t src = DBG_SRC_BG;
1278 if (plane_b & 0xF) {
1279 pixel = plane_b;
1280 src = DBG_SRC_B;
1281 }
1282 if (plane_a & 0xF && (plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) {
1283 pixel = plane_a;
1284 src = DBG_SRC_A;
1285 }
1286 if (sprite & 0xF && (sprite & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) {
1287 pixel = sprite;
1288 src = DBG_SRC_S;
1289 }
1290 *debug_dst = src;
1291 return pixel;
1292 }
1293 typedef struct {
1294 uint8_t index, intensity;
1295 } sh_pixel;
1296
1297 static sh_pixel composite_highlight(vdp_context *context, uint8_t *debug_dst, uint8_t sprite, uint8_t plane_a, uint8_t plane_b, uint8_t bg_index)
1298 {
1299 uint8_t pixel = bg_index;
1300 uint8_t src = DBG_SRC_BG;
1301 uint8_t intensity = 0;
1302 if (plane_b & 0xF) {
1303 pixel = plane_b;
1304 src = DBG_SRC_B;
1305 }
1306 intensity = plane_b & BUF_BIT_PRIORITY;
1307 if (plane_a & 0xF && (plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) {
1308 pixel = plane_a;
1309 src = DBG_SRC_A;
1310 }
1311 intensity |= plane_a & BUF_BIT_PRIORITY;
1312 if (sprite & 0xF && (sprite & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) {
1313 if ((sprite & 0x3F) == 0x3E) {
1314 intensity += BUF_BIT_PRIORITY;
1315 } else if ((sprite & 0x3F) == 0x3F) {
1316 intensity = 0;
1317 } else {
1318 pixel = sprite;
1319 src = DBG_SRC_S;
1320 if ((pixel & 0xF) == 0xE) {
1321 intensity = BUF_BIT_PRIORITY;
1322 } else {
1323 intensity |= pixel & BUF_BIT_PRIORITY;
1324 }
1325 }
1326 }
1327 *debug_dst = src;
1328 return (sh_pixel){.index = pixel, .intensity = intensity};
1329 }
1330
1331 static void render_normal(vdp_context *context, int32_t col, uint32_t *dst, uint8_t *debug_dst, int plane_a_off, int plane_b_off)
1332 {
1333 int start = 0;
1334 if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1335 uint32_t bgcolor = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
1336 for (int i = 0; i < 8; ++i)
1337 {
1338 *(dst++) = bgcolor;
1339 *(debug_dst++) = DBG_SRC_BG;
1340 }
1341 start = 8;
1342 }
1343 uint8_t *sprite_buf = context->linebuf + col * 8 + start;
1344 for (int i = start; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1345 {
1346 uint8_t sprite, plane_a, plane_b;
1347 plane_a = context->tmp_buf_a[plane_a_off & SCROLL_BUFFER_MASK];
1348 plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1349 sprite = *sprite_buf;
1350 uint8_t pixel = composite_normal(context, debug_dst, sprite, plane_a, plane_b, context->regs[REG_BG_COLOR]);
1351 debug_dst++;
1352 *(dst++) = context->colors[pixel & 0x3F];
1353 }
1354 }
1355
1356 static void render_highlight(vdp_context *context, int32_t col, uint32_t *dst, uint8_t *debug_dst, int plane_a_off, int plane_b_off)
1357 {
1358 int start = 0;
1359 if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1360 uint32_t bgcolor = context->colors[SHADOW_OFFSET + (context->regs[REG_BG_COLOR] & 0x3F)];
1361 for (int i = 0; i < 8; ++i)
1362 {
1363 *(dst++) = bgcolor;
1364 *(debug_dst++) = DBG_SRC_BG | DBG_SHADOW;
1365 }
1366 start = 8;
1367 }
1368 uint8_t *sprite_buf = context->linebuf + col * 8 + start;
1369 for (int i = start; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1370 {
1371 uint8_t sprite, plane_a, plane_b;
1372 plane_a = context->tmp_buf_a[plane_a_off & SCROLL_BUFFER_MASK];
1373 plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1374 sprite = *sprite_buf;
1375 sh_pixel pixel = composite_highlight(context, debug_dst, sprite, plane_a, plane_b, context->regs[REG_BG_COLOR]);
1376 uint32_t *colors;
1377 if (pixel.intensity == BUF_BIT_PRIORITY << 1) {
1378 colors = context->colors + HIGHLIGHT_OFFSET;
1379 } else if (pixel.intensity) {
1380 colors = context->colors;
1381 } else {
1382 colors = context->colors + SHADOW_OFFSET;
1383 }
1384 debug_dst++;
1385 *(dst++) = colors[pixel.index & 0x3F];
1386 }
1387 }
1388
1389 static void render_testreg(vdp_context *context, int32_t col, uint32_t *dst, uint8_t *debug_dst, int plane_a_off, int plane_b_off, uint8_t output_disabled, uint8_t test_layer)
1390 {
1391 if (output_disabled) {
1392 switch (test_layer)
1393 {
1394 case 0:
1395 for (int i = 0; i < 16; i++)
1396 {
1397 *(dst++) = 0x3F; //TODO: confirm this on hardware
1398 *(debug_dst++) = DBG_SRC_BG;
1399 }
1400 break;
1401 case 1: {
1402 uint8_t *sprite_buf = context->linebuf + col * 8;
1403 for (int i = 0; i < 16; i++)
1404 {
1405 *(dst++) = context->colors[*(sprite_buf++) & 0x3F];
1406 *(debug_dst++) = DBG_SRC_S;
1407 }
1408 break;
1409 }
1410 case 2:
1411 for (int i = 0; i < 16; i++)
1412 {
1413 *(dst++) = context->colors[context->tmp_buf_a[(plane_a_off++) & SCROLL_BUFFER_MASK] & 0x3F];
1414 *(debug_dst++) = DBG_SRC_A;
1415 }
1416 break;
1417 case 3:
1418 for (int i = 0; i < 16; i++)
1419 {
1420 *(dst++) = context->colors[context->tmp_buf_b[(plane_b_off++) & SCROLL_BUFFER_MASK] & 0x3F];
1421 *(debug_dst++) = DBG_SRC_B;
1422 }
1423 break;
1424 }
1425 } else {
1426 int start = 0;
1427 uint8_t *sprite_buf = context->linebuf + col * 8;
1428 if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1429 //TODO: Confirm how test register interacts with column 0 blanking
1430 uint8_t pixel = context->regs[REG_BG_COLOR] & 0x3F;
1431 uint8_t src = DBG_SRC_BG;
1432 for (int i = 0; i < 8; ++i)
1433 {
1434 switch (test_layer)
1435 {
1436 case 1:
1437 pixel &= sprite_buf[i];
1438 if (pixel) {
1439 src = DBG_SRC_S;
1440 }
1441 break;
1442 case 2:
1443 pixel &= context->tmp_buf_a[(plane_a_off + i) & SCROLL_BUFFER_MASK];
1444 if (pixel) {
1445 src = DBG_SRC_A;
1446 }
1447 break;
1448 case 3:
1449 pixel &= context->tmp_buf_b[(plane_b_off + i) & SCROLL_BUFFER_MASK];
1450 if (pixel) {
1451 src = DBG_SRC_B;
1452 }
1453 break;
1454 }
1455
1456 *(dst++) = context->colors[pixel & 0x3F];
1457 *(debug_dst++) = src;
1458 }
1459 plane_a_off += 8;
1460 plane_b_off += 8;
1461 sprite_buf += 8;
1462 start = 8;
1463 }
1464 for (int i = start; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1465 {
1466 uint8_t sprite, plane_a, plane_b;
1467 plane_a = context->tmp_buf_a[plane_a_off & SCROLL_BUFFER_MASK];
1468 plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1469 sprite = *sprite_buf;
1470 uint8_t pixel = composite_normal(context, debug_dst, sprite, plane_a, plane_b, 0x3F);
1471 switch (test_layer)
1472 {
1473 case 1:
1474 pixel &= sprite;
1475 if (pixel) {
1476 *debug_dst = DBG_SRC_S;
1477 }
1478 break;
1479 case 2:
1480 pixel &= plane_a;
1481 if (pixel) {
1482 *debug_dst = DBG_SRC_A;
1483 }
1484 break;
1485 case 3:
1486 pixel &= plane_b;
1487 if (pixel) {
1488 *debug_dst = DBG_SRC_B;
1489 }
1490 break;
1491 }
1492 debug_dst++;
1493 *(dst++) = context->colors[pixel & 0x3F];
1494 }
1495 }
1496 }
1497
1498 static void render_testreg_highlight(vdp_context *context, int32_t col, uint32_t *dst, uint8_t *debug_dst, int plane_a_off, int plane_b_off, uint8_t output_disabled, uint8_t test_layer)
1499 {
1500 int start = 0;
1501 uint8_t *sprite_buf = context->linebuf + col * 8;
1502 if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1503 //TODO: Confirm how test register interacts with column 0 blanking
1504 uint8_t pixel = context->regs[REG_BG_COLOR] & 0x3F;
1505 uint8_t src = DBG_SRC_BG | DBG_SHADOW;
1506 for (int i = 0; i < 8; ++i)
1507 {
1508 switch (test_layer)
1509 {
1510 case 1:
1511 pixel &= sprite_buf[i];
1512 if (pixel) {
1513 src = DBG_SRC_S | DBG_SHADOW;
1514 }
1515 break;
1516 case 2:
1517 pixel &= context->tmp_buf_a[(plane_a_off + i) & SCROLL_BUFFER_MASK];
1518 if (pixel) {
1519 src = DBG_SRC_A | DBG_SHADOW;
1520 }
1521 break;
1522 case 3:
1523 pixel &= context->tmp_buf_b[(plane_b_off + i) & SCROLL_BUFFER_MASK];
1524 if (pixel) {
1525 src = DBG_SRC_B | DBG_SHADOW;
1526 }
1527 break;
1528 }
1529
1530 *(dst++) = context->colors[SHADOW_OFFSET + (pixel & 0x3F)];
1531 *(debug_dst++) = src;
1532 }
1533 plane_a_off += 8;
1534 plane_b_off += 8;
1535 sprite_buf += 8;
1536 start = 8;
1537 }
1538 for (int i = start; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1539 {
1540 uint8_t sprite, plane_a, plane_b;
1541 plane_a = context->tmp_buf_a[plane_a_off & SCROLL_BUFFER_MASK];
1542 plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1543 sprite = *sprite_buf;
1544 sh_pixel pixel = composite_highlight(context, debug_dst, sprite, plane_a, plane_b, 0x3F);
1545 uint32_t *colors;
1546 if (pixel.intensity == BUF_BIT_PRIORITY << 1) {
1547 colors = context->colors + HIGHLIGHT_OFFSET;
1548 } else if (pixel.intensity) {
1549 colors = context->colors;
1550 } else {
1551 colors = context->colors + SHADOW_OFFSET;
1552 }
1553 if (output_disabled) {
1554 pixel.index = 0x3F;
1555 }
1556 switch (test_layer)
1557 {
1558 case 1:
1559 pixel.index &= sprite;
1560 if (pixel.index) {
1561 *debug_dst = DBG_SRC_S;
1562 }
1563 break;
1564 case 2:
1565 pixel.index &= plane_a;
1566 if (pixel.index) {
1567 *debug_dst = DBG_SRC_A;
1568 }
1569 break;
1570 case 3:
1571 pixel.index &= plane_b;
1572 if (pixel.index) {
1573 *debug_dst = DBG_SRC_B;
1574 }
1575 break;
1576 }
1577 debug_dst++;
1578 *(dst++) = colors[pixel.index & 0x3F];
1579 }
1580 }
1581
1275 static void render_map_output(uint32_t line, int32_t col, vdp_context * context) 1582 static void render_map_output(uint32_t line, int32_t col, vdp_context * context)
1276 { 1583 {
1277 uint32_t *dst; 1584 uint32_t *dst;
1585 uint8_t *debug_dst;
1278 uint8_t output_disabled = (context->test_port & TEST_BIT_DISABLE) != 0; 1586 uint8_t output_disabled = (context->test_port & TEST_BIT_DISABLE) != 0;
1279 uint8_t test_layer = context->test_port >> 7 & 3; 1587 uint8_t test_layer = context->test_port >> 7 & 3;
1280 if (context->state == PREPARING && !test_layer) { 1588 if (context->state == PREPARING && !test_layer) {
1281 if (col) { 1589 if (col) {
1282 col -= 2; 1590 col -= 2;
1299 context->done_output = dst; 1607 context->done_output = dst;
1300 return; 1608 return;
1301 } 1609 }
1302 line &= 0xFF; 1610 line &= 0xFF;
1303 render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context); 1611 render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context);
1304 uint8_t *sprite_buf, *plane_a, *plane_b; 1612 uint8_t *sprite_buf;
1613 uint8_t sprite, plane_a, plane_b;
1305 int plane_a_off, plane_b_off; 1614 int plane_a_off, plane_b_off;
1306 if (col) 1615 if (col)
1307 { 1616 {
1308 col-=2; 1617 col-=2;
1309 dst = context->output + BORDER_LEFT + col * 8; 1618 dst = context->output + BORDER_LEFT + col * 8;
1310 if (context->debug < 2) { 1619 debug_dst = context->layer_debug_buf + BORDER_LEFT + col * 8;
1311 sprite_buf = context->linebuf + col * 8; 1620
1312 uint8_t a_src, src; 1621
1313 if (context->flags & FLAG_WINDOW) { 1622 uint8_t a_src, src;
1314 plane_a_off = context->buf_a_off; 1623 if (context->flags & FLAG_WINDOW) {
1315 a_src = DBG_SRC_W; 1624 plane_a_off = context->buf_a_off;
1625 a_src = DBG_SRC_W;
1626 } else {
1627 plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF);
1628 a_src = DBG_SRC_A;
1629 }
1630 plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF);
1631 //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7));
1632
1633 if (context->regs[REG_MODE_4] & BIT_HILIGHT) {
1634 if (output_disabled || test_layer) {
1635 render_testreg_highlight(context, col, dst, debug_dst, plane_a_off, plane_b_off, output_disabled, test_layer);
1316 } else { 1636 } else {
1317 plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF); 1637 render_highlight(context, col, dst, debug_dst, plane_a_off, plane_b_off);
1318 a_src = DBG_SRC_A; 1638 }
1319 } 1639 } else {
1320 plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF); 1640 if (output_disabled || test_layer) {
1321 //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7)); 1641 render_testreg(context, col, dst, debug_dst, plane_a_off, plane_b_off, output_disabled, test_layer);
1322
1323 if (context->regs[REG_MODE_4] & BIT_HILIGHT) {
1324 for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) {
1325 plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK);
1326 plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK);
1327 uint8_t pixel = context->regs[REG_BG_COLOR];
1328 uint32_t *colors = context->colors;
1329 src = DBG_SRC_BG;
1330 if (*plane_b & 0xF) {
1331 pixel = *plane_b;
1332 src = DBG_SRC_B;
1333 }
1334 uint8_t intensity = *plane_b & BUF_BIT_PRIORITY;
1335 if (*plane_a & 0xF && (*plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) {
1336 pixel = *plane_a;
1337 src = a_src;
1338 }
1339 intensity |= *plane_a & BUF_BIT_PRIORITY;
1340 if (*sprite_buf & 0xF && (*sprite_buf & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) {
1341 if ((*sprite_buf & 0x3F) == 0x3E) {
1342 intensity += BUF_BIT_PRIORITY;
1343 } else if ((*sprite_buf & 0x3F) == 0x3F) {
1344 intensity = 0;
1345 } else {
1346 pixel = *sprite_buf;
1347 src = DBG_SRC_S;
1348 if ((pixel & 0xF) == 0xE) {
1349 intensity = BUF_BIT_PRIORITY;
1350 } else {
1351 intensity |= pixel & BUF_BIT_PRIORITY;
1352 }
1353 }
1354 }
1355 if (output_disabled) {
1356 pixel = 0x3F;
1357 }
1358 if (!intensity) {
1359 src |= DBG_SHADOW;
1360 colors += CRAM_SIZE;
1361 } else if (intensity == BUF_BIT_PRIORITY*2) {
1362 src |= DBG_HILIGHT;
1363 colors += CRAM_SIZE*2;
1364 }
1365 //TODO: Verify how test register stuff interacts with shadow/highlight
1366 //TODO: Simulate CRAM corruption from bus fight
1367 switch (test_layer)
1368 {
1369 case 1:
1370 pixel &= *sprite_buf;
1371 if (output_disabled && pixel) {
1372 src = DBG_SRC_S;
1373 }
1374 break;
1375 case 2:
1376 pixel &= *plane_a;
1377 if (output_disabled && pixel) {
1378 src = DBG_SRC_A;
1379 }
1380 break;
1381 case 3:
1382 pixel &= *plane_b;
1383 if (output_disabled && pixel) {
1384 src = DBG_SRC_B;
1385 }
1386 break;
1387 }
1388
1389 uint32_t outpixel;
1390 if (context->debug) {
1391 outpixel = context->debugcolors[src];
1392 } else {
1393 outpixel = colors[pixel & 0x3F];
1394 }
1395 *(dst++) = outpixel;
1396 }
1397 } else { 1642 } else {
1398 for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) { 1643 render_normal(context, col, dst, debug_dst, plane_a_off, plane_b_off);
1399 plane_a = context->tmp_buf_a + (plane_a_off & SCROLL_BUFFER_MASK); 1644 }
1400 plane_b = context->tmp_buf_b + (plane_b_off & SCROLL_BUFFER_MASK); 1645 }
1401 uint8_t pixel = context->regs[REG_BG_COLOR]; 1646 dst += 16;
1402 src = DBG_SRC_BG;
1403 if (output_disabled) {
1404 pixel = 0x3F;
1405 } else {
1406 if (*plane_b & 0xF) {
1407 pixel = *plane_b;
1408 src = DBG_SRC_B;
1409 }
1410 if (*plane_a & 0xF && (*plane_a & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) {
1411 pixel = *plane_a;
1412 src = a_src;
1413 }
1414 if (*sprite_buf & 0xF && (*sprite_buf & BUF_BIT_PRIORITY) >= (pixel & BUF_BIT_PRIORITY)) {
1415 pixel = *sprite_buf;
1416 src = DBG_SRC_S;
1417 }
1418 }
1419 //TODO: Simulate CRAM corruption from bus fight
1420 switch (test_layer)
1421 {
1422 case 1:
1423 pixel &= *sprite_buf;
1424 if (output_disabled && pixel) {
1425 src = DBG_SRC_S;
1426 }
1427 break;
1428 case 2:
1429 pixel &= *plane_a;
1430 if (output_disabled && pixel) {
1431 src = DBG_SRC_A;
1432 }
1433 break;
1434 case 3:
1435 pixel &= *plane_b;
1436 if (output_disabled && pixel) {
1437 src = DBG_SRC_B;
1438 }
1439 break;
1440 }
1441 uint32_t outpixel;
1442 if (context->debug) {
1443 outpixel = context->debugcolors[src];
1444 } else {
1445 outpixel = context->colors[pixel & 0x3F];
1446 }
1447 *(dst++) = outpixel;
1448 }
1449 }
1450 } else if (context->debug == 2) {
1451 if (col < 32) {
1452 *(dst++) = context->colors[col * 2];
1453 *(dst++) = context->colors[col * 2];
1454 *(dst++) = context->colors[col * 2];
1455 *(dst++) = context->colors[col * 2];
1456 *(dst++) = context->colors[col * 2 + 1];
1457 *(dst++) = context->colors[col * 2 + 1];
1458 *(dst++) = context->colors[col * 2 + 1];
1459 *(dst++) = context->colors[col * 2 + 1];
1460 *(dst++) = context->colors[col * 2 + 2];
1461 *(dst++) = context->colors[col * 2 + 2];
1462 *(dst++) = context->colors[col * 2 + 2];
1463 *(dst++) = context->colors[col * 2 + 2];
1464 *(dst++) = context->colors[col * 2 + 3];
1465 *(dst++) = context->colors[col * 2 + 3];
1466 *(dst++) = context->colors[col * 2 + 3];
1467 *(dst++) = context->colors[col * 2 + 3];
1468 } else if (col == 32 || line >= 192) {
1469 for (int32_t i = 0; i < 16; i ++) {
1470 *(dst++) = 0;
1471 }
1472 } else {
1473 for (int32_t i = 0; i < 16; i ++) {
1474 *(dst++) = context->colors[line / 3 + (col - 34) * 0x20];
1475 }
1476 }
1477 } else {
1478 uint32_t base = (context->debug - 3) * 0x200;
1479 uint32_t cell = base + (line / 8) * (context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32) + col;
1480 uint32_t address = (cell * 32 + (line % 8) * 4) & 0xFFFF;
1481 for (int32_t i = 0; i < 4; i ++) {
1482 *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] >> 4)];
1483 *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] & 0xF)];
1484 address++;
1485 }
1486 cell++;
1487 address = (cell * 32 + (line % 8) * 4) & 0xFFFF;
1488 for (int32_t i = 0; i < 4; i ++) {
1489 *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] >> 4)];
1490 *(dst++) = context->colors[(context->debug_pal << 4) | (context->vdpmem[address] & 0xF)];
1491 address++;
1492 }
1493 }
1494 } else { 1647 } else {
1495 dst = context->output; 1648 dst = context->output;
1649 debug_dst = context->layer_debug_buf;
1496 uint8_t pixel = context->regs[REG_BG_COLOR] & 0x3F; 1650 uint8_t pixel = context->regs[REG_BG_COLOR] & 0x3F;
1497 if (output_disabled) { 1651 if (output_disabled) {
1498 pixel = 0x3F; 1652 pixel = 0x3F;
1499 } 1653 }
1500 uint32_t bg_color = context->colors[pixel]; 1654 uint32_t bg_color = context->colors[pixel];
1501 if (test_layer) { 1655 if (test_layer) {
1502 switch(test_layer) 1656 switch(test_layer)
1503 { 1657 {
1504 case 1: 1658 case 1:
1505 bg_color = context->colors[0]; 1659 bg_color = context->colors[0];
1506 for (int i = 0; i < BORDER_LEFT; i++, dst++) 1660 for (int i = 0; i < BORDER_LEFT; i++, dst++, debug_dst++)
1507 { 1661 {
1508 *dst = bg_color; 1662 *dst = bg_color;
1663 *debug_dst = DBG_SRC_BG;
1664
1509 } 1665 }
1510 break; 1666 break;
1511 case 2: { 1667 case 2: {
1512 //plane A 1668 //plane A
1513 //TODO: Deal with Window layer 1669 //TODO: Deal with Window layer
1514 int i; 1670 int i;
1515 i = 0; 1671 i = 0;
1516 uint8_t buf_off = context->buf_a_off - (context->hscroll_a & 0xF) + (16 - BORDER_LEFT); 1672 uint8_t buf_off = context->buf_a_off - (context->hscroll_a & 0xF) + (16 - BORDER_LEFT);
1517 //uint8_t *src = context->tmp_buf_a + ((context->buf_a_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_a & 0xF))) & SCROLL_BUFFER_MASK); 1673 //uint8_t *src = context->tmp_buf_a + ((context->buf_a_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_a & 0xF))) & SCROLL_BUFFER_MASK);
1518 for (; i < BORDER_LEFT; buf_off++, i++, dst++) 1674 for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++)
1519 { 1675 {
1520 *dst = context->colors[context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK]]; 1676 *dst = context->colors[context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK]];
1677 *debug_dst = DBG_SRC_A;
1521 } 1678 }
1522 break; 1679 break;
1523 } 1680 }
1524 case 3: { 1681 case 3: {
1525 //plane B 1682 //plane B
1526 int i; 1683 int i;
1527 i = 0; 1684 i = 0;
1528 uint8_t buf_off = context->buf_b_off - (context->hscroll_b & 0xF) + (16 - BORDER_LEFT); 1685 uint8_t buf_off = context->buf_b_off - (context->hscroll_b & 0xF) + (16 - BORDER_LEFT);
1529 //uint8_t *src = context->tmp_buf_b + ((context->buf_b_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_b & 0xF))) & SCROLL_BUFFER_MASK); 1686 //uint8_t *src = context->tmp_buf_b + ((context->buf_b_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_b & 0xF))) & SCROLL_BUFFER_MASK);
1530 for (; i < BORDER_LEFT; buf_off++, i++, dst++) 1687 for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++)
1531 { 1688 {
1532 *dst = context->colors[context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK]]; 1689 *dst = context->colors[context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK]];
1690 *debug_dst = DBG_SRC_B;
1533 } 1691 }
1534 break; 1692 break;
1535 } 1693 }
1536 } 1694 }
1537 } else { 1695 } else {
1538 for (int i = 0; i < BORDER_LEFT; i++, dst++) 1696 for (int i = 0; i < BORDER_LEFT; i++, dst++, debug_dst++)
1539 { 1697 {
1540 *dst = bg_color; 1698 *dst = bg_color;
1699 *debug_dst = DBG_SRC_BG;
1541 } 1700 }
1542 } 1701 }
1543 } 1702 }
1544 context->done_output = dst; 1703 context->done_output = dst;
1545 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; 1704 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
1584 { 1743 {
1585 *dst = (pixels >> i & 0xF) | pal_priority; 1744 *dst = (pixels >> i & 0xF) | pal_priority;
1586 } 1745 }
1587 context->buf_a_off = (context->buf_a_off + 8) & 15; 1746 context->buf_a_off = (context->buf_a_off + 8) & 15;
1588 1747
1589 uint8_t bgcolor = 0x10 | (context->regs[REG_BG_COLOR] & 0xF) + CRAM_SIZE*3; 1748 uint8_t bgcolor = 0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET;
1590 uint32_t *dst = context->output + col * 8 + BORDER_LEFT; 1749 uint32_t *dst = context->output + col * 8 + BORDER_LEFT;
1750 uint8_t *debug_dst = context->layer_debug_buf + col * 8 + BORDER_LEFT;
1591 if (context->state == PREPARING) { 1751 if (context->state == PREPARING) {
1592 for (int i = 0; i < 16; i++) 1752 for (int i = 0; i < 16; i++)
1593 { 1753 {
1594 *(dst++) = context->colors[bgcolor]; 1754 *(dst++) = context->colors[bgcolor];
1595 } 1755 }
1596 context->done_output = dst; 1756 context->done_output = dst;
1597 return; 1757 return;
1598 } 1758 }
1599 if (context->debug < 2) { 1759
1600 if (col || !(context->regs[REG_MODE_1] & BIT_COL0_MASK)) { 1760 if (col || !(context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1601 uint8_t *sprite_src = context->linebuf + col * 8; 1761 uint8_t *sprite_src = context->linebuf + col * 8;
1602 if (context->regs[REG_MODE_1] & BIT_SPRITE_8PX) { 1762 if (context->regs[REG_MODE_1] & BIT_SPRITE_8PX) {
1603 sprite_src += 8; 1763 sprite_src += 8;
1604 } 1764 }
1605 for (int i = 0; i < 8; i++, sprite_src++) 1765 for (int i = 0; i < 8; i++, sprite_src++)
1606 { 1766 {
1607 uint8_t *bg_src = context->tmp_buf_a + ((8 + i + col * 8 - (context->hscroll_a & 0x7)) & 15); 1767 uint8_t *bg_src = context->tmp_buf_a + ((8 + i + col * 8 - (context->hscroll_a & 0x7)) & 15);
1608 if ((*bg_src & 0x4F) > 0x40 || !*sprite_src) { 1768 if ((*bg_src & 0x4F) > 0x40 || !*sprite_src) {
1609 //background plane has priority and is opaque or sprite layer is transparent 1769 //background plane has priority and is opaque or sprite layer is transparent
1610 if (context->debug) { 1770 *(dst++) = context->colors[(*bg_src & 0x1F) + MODE4_OFFSET];
1611 *(dst++) = context->debugcolors[DBG_SRC_A]; 1771 *(debug_dst++) = DBG_SRC_A;
1612 } else { 1772 } else {
1613 *(dst++) = context->colors[(*bg_src & 0x1F) + CRAM_SIZE*3]; 1773 //sprite layer is opaque and not covered by high priority BG pixels
1614 } 1774 *(dst++) = context->colors[*sprite_src | 0x10 + MODE4_OFFSET];
1615 } else { 1775 *(debug_dst++) = DBG_SRC_S;
1616 //sprite layer is opaque and not covered by high priority BG pixels 1776 }
1617 if (context->debug) { 1777 }
1618 *(dst++) = context->debugcolors[DBG_SRC_S]; 1778 } else {
1619 } else {
1620 *(dst++) = context->colors[*sprite_src | 0x10 + CRAM_SIZE*3];
1621 }
1622 }
1623 }
1624 } else {
1625 for (int i = 0; i < 8; i++)
1626 {
1627 *(dst++) = context->colors[bgcolor];
1628 }
1629 }
1630 } else if (context->debug == 2) {
1631 for (int i = 0; i < 8; i++) 1779 for (int i = 0; i < 8; i++)
1632 { 1780 {
1633 *(dst++) = context->colors[CRAM_SIZE*3 + col]; 1781 *(dst++) = context->colors[bgcolor];
1634 } 1782 *(debug_dst++) = DBG_SRC_BG;
1635 } else {
1636 uint32_t cell = (line / 8) * 32 + col;
1637 uint32_t address = cell * 32 + (line % 8) * 4;
1638 uint32_t m4_address = mode4_address_map[address & 0x3FFF];
1639 uint32_t pixel = planar_to_chunky[context->vdpmem[m4_address]] << 1;
1640 pixel |= planar_to_chunky[context->vdpmem[m4_address + 1]];
1641 m4_address = mode4_address_map[(address + 2) & 0x3FFF];
1642 pixel |= planar_to_chunky[context->vdpmem[m4_address]] << 3;
1643 pixel |= planar_to_chunky[context->vdpmem[m4_address + 1]] << 2;
1644 if (context->debug_pal < 2) {
1645 for (int i = 28; i >= 0; i -= 4)
1646 {
1647 *(dst++) = context->colors[CRAM_SIZE*3 | (context->debug_pal << 4) | (pixel >> i & 0xF)];
1648 }
1649 } else {
1650 for (int i = 28; i >= 0; i -= 4)
1651 {
1652 uint8_t value = (pixel >> i & 0xF) * 17;
1653 if (context->debug_pal == 3) {
1654 value = 255 - value;
1655 }
1656 *(dst++) = render_map_color(value, value, value);
1657 }
1658 } 1783 }
1659 } 1784 }
1660 context->done_output = dst; 1785 context->done_output = dst;
1661 } 1786 }
1662 1787
1672 printf("Line %d took %d cycles\n", context->vcounter, diff); 1797 printf("Line %d took %d cycles\n", context->vcounter, diff);
1673 } 1798 }
1674 } 1799 }
1675 last_line = context->cycles; 1800 last_line = context->cycles;
1676 #endif 1801 #endif
1677 context->vcounter++; 1802 uint16_t jump_start, jump_end;
1678
1679 uint8_t is_mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; 1803 uint8_t is_mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
1680 if (is_mode_5) { 1804 if (is_mode_5) {
1681 if (context->flags2 & FLAG2_REGION_PAL) { 1805 if (context->flags2 & FLAG2_REGION_PAL) {
1682 if (context->regs[REG_MODE_2] & BIT_PAL) { 1806 if (context->regs[REG_MODE_2] & BIT_PAL) {
1683 if (context->vcounter == 0x10B) { 1807 jump_start = 0x10B;
1684 context->vcounter = 0x1D2; 1808 jump_end = 0x1D2;
1685 } 1809 } else {
1686 } else if (context->vcounter == 0x103){ 1810 jump_start = 0x103;
1687 context->vcounter = 0x1CA; 1811 jump_end = 0x1CA;
1688 } 1812 }
1689 } else { 1813 } else if (context->regs[REG_MODE_2] & BIT_PAL) {
1690 if (context->regs[REG_MODE_2] & BIT_PAL) { 1814 jump_start = 0x100;
1691 if (context->vcounter == 0x100) { 1815 jump_end = 0x1FA;
1692 context->vcounter = 0x1FA; 1816 } else {
1693 } 1817 jump_start = 0xEB;
1694 } else if (context->vcounter == 0xEB) { 1818 jump_end = 0x1E5;
1695 context->vcounter = 0x1E5; 1819 }
1696 } 1820 } else {
1697 } 1821 jump_start = 0xDB;
1698 } else if (context->vcounter == 0xDB) { 1822 jump_end = 0x1D5;
1699 context->vcounter = 0x1D5; 1823 }
1700 } 1824
1701 context->vcounter &= 0x1FF; 1825 if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM | 1 << VDP_DEBUG_COMPOSITE)) {
1826 uint32_t line = context->vcounter;
1827 if (line >= jump_end) {
1828 line -= jump_end - jump_start;
1829 }
1830 uint32_t total_lines = (context->flags2 & FLAG2_REGION_PAL) ? 313 : 262;
1831
1832 if (total_lines - line <= context->border_top) {
1833 line -= total_lines - context->border_top;
1834 } else {
1835 line += context->border_top;
1836 }
1837 if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) {
1838 uint32_t *fb = context->debug_fbs[VDP_DEBUG_CRAM] + context->debug_fb_pitch[VDP_DEBUG_CRAM] * line / sizeof(uint32_t);
1839 for (int i = 0; i < 64; i++)
1840 {
1841 for (int x = 0; x < 8; x++)
1842 {
1843 *(fb++) = context->colors[i];
1844 }
1845 }
1846 }
1847 if (
1848 context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE)
1849 && line < (context->inactive_start + context->border_bot + context->border_top)
1850 ) {
1851 uint32_t *fb = context->debug_fbs[VDP_DEBUG_COMPOSITE] + context->debug_fb_pitch[VDP_DEBUG_COMPOSITE] * line / sizeof(uint32_t);
1852 for (int i = 0; i < LINEBUF_SIZE; i++)
1853 {
1854 *(fb++) = context->debugcolors[context->layer_debug_buf[i]];
1855 }
1856 }
1857 }
1858
1859 context->vcounter++;
1860 if (context->vcounter == jump_start) {
1861 context->vcounter = jump_end;
1862 } else {
1863 context->vcounter &= 0x1FF;
1864 }
1702 if (context->state == PREPARING) { 1865 if (context->state == PREPARING) {
1703 context->state = ACTIVE; 1866 context->state = ACTIVE;
1704 } 1867 }
1705 if (context->vcounter == 0x1FF) { 1868 if (context->vcounter == 0x1FF) {
1706 context->flags2 &= ~FLAG2_PAUSE; 1869 context->flags2 &= ~FLAG2_PAUSE;
1715 context->pending_hint_start = context->cycles; 1878 context->pending_hint_start = context->cycles;
1716 context->hint_counter = context->regs[REG_HINT]; 1879 context->hint_counter = context->regs[REG_HINT];
1717 } 1880 }
1718 } 1881 }
1719 1882
1883 static void vdp_update_per_frame_debug(vdp_context *context)
1884 {
1885 if (context->enabled_debuggers & (1 << VDP_DEBUG_PLANE)) {
1886 uint32_t pitch;
1887 uint32_t *fb = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_PLANE], &pitch);
1888 uint16_t hscroll_mask;
1889 uint16_t v_mul;
1890 uint16_t vscroll_mask = 0x1F | (context->regs[REG_SCROLL] & 0x30) << 1;
1891 switch(context->regs[REG_SCROLL] & 0x3)
1892 {
1893 case 0:
1894 hscroll_mask = 0x1F;
1895 v_mul = 64;
1896 break;
1897 case 0x1:
1898 hscroll_mask = 0x3F;
1899 v_mul = 128;
1900 break;
1901 case 0x2:
1902 //TODO: Verify this behavior
1903 hscroll_mask = 0x1F;
1904 v_mul = 0;
1905 break;
1906 case 0x3:
1907 hscroll_mask = 0x7F;
1908 v_mul = 256;
1909 break;
1910 }
1911 uint16_t table_address;
1912 switch(context->debug_modes[VDP_DEBUG_PLANE] % 3)
1913 {
1914 case 0:
1915 table_address = context->regs[REG_SCROLL_A] << 10 & 0xE000;
1916 break;
1917 case 1:
1918 table_address = context->regs[REG_SCROLL_B] << 13 & 0xE000;
1919 break;
1920 case 2:
1921 table_address = context->regs[REG_WINDOW] << 10;
1922 if (context->regs[REG_MODE_4] & BIT_H40) {
1923 table_address &= 0xF000;
1924 v_mul = 128;
1925 hscroll_mask = 0x3F;
1926 } else {
1927 table_address &= 0xF800;
1928 v_mul = 64;
1929 hscroll_mask = 0x1F;
1930 }
1931 vscroll_mask = 0x1F;
1932 break;
1933 }
1934 uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR & 0x3F]];
1935 for (uint16_t row = 0; row < 128; row++)
1936 {
1937 uint16_t row_address = table_address + (row & vscroll_mask) * v_mul;
1938 for (uint16_t col = 0; col < 128; col++)
1939 {
1940 uint16_t address = row_address + (col & hscroll_mask) * 2;
1941 //pccv hnnn nnnn nnnn
1942 //
1943 uint16_t entry = context->vdpmem[address] << 8 | context->vdpmem[address + 1];
1944 uint8_t pal = entry >> 9 & 0x30;
1945
1946 uint32_t *dst = fb + (row * pitch * 8 / sizeof(uint32_t)) + col * 8;
1947 address = (entry & 0x7FF) * 32;
1948 int y_diff = 4;
1949 if (entry & 0x1000) {
1950 y_diff = -4;
1951 address += 7 * 4;
1952 }
1953 int x_diff = 1;
1954 if (entry & 0x800) {
1955 x_diff = -1;
1956 address += 3;
1957 }
1958 for (int y = 0; y < 8; y++)
1959 {
1960 uint16_t trow_address = address;
1961 uint32_t *row_dst = dst;
1962 for (int x = 0; x < 4; x++)
1963 {
1964 uint8_t byte = context->vdpmem[trow_address];
1965 trow_address += x_diff;
1966 uint8_t left, right;
1967 if (x_diff > 0) {
1968 left = byte >> 4;
1969 right = byte & 0xF;
1970 } else {
1971 left = byte & 0xF;
1972 right = byte >> 4;
1973 }
1974 *(row_dst++) = left ? context->colors[left|pal] : bg_color;
1975 *(row_dst++) = right ? context->colors[right|pal] : bg_color;
1976 }
1977 address += y_diff;
1978 dst += pitch / sizeof(uint32_t);
1979 }
1980 }
1981 }
1982 render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_PLANE], 1024);
1983 }
1984
1985 if (context->enabled_debuggers & (1 << VDP_DEBUG_VRAM)) {
1986 uint32_t pitch;
1987 uint32_t *fb = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_VRAM], &pitch);
1988
1989 uint8_t pal = (context->debug_modes[VDP_DEBUG_VRAM] % 4) << 4;
1990 for (int y = 0; y < 512; y++)
1991 {
1992 uint32_t *line = fb + y * pitch / sizeof(uint32_t);
1993 int row = y >> 4;
1994 int yoff = y >> 1 & 7;
1995 for (int col = 0; col < 64; col++)
1996 {
1997 uint16_t address = (row * 64 + col) * 32 + yoff * 4;
1998 for (int x = 0; x < 4; x++)
1999 {
2000 uint8_t byte = context->vdpmem[address++];
2001 uint8_t left = byte >> 4 | pal;
2002 uint8_t right = byte & 0xF | pal;
2003 *(line++) = context->colors[left];
2004 *(line++) = context->colors[left];
2005 *(line++) = context->colors[right];
2006 *(line++) = context->colors[right];
2007 }
2008 }
2009 }
2010
2011 render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_VRAM], 1024);
2012 }
2013
2014 if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) {
2015 uint32_t starting_line = 512 - 32*4;
2016 uint32_t *line = context->debug_fbs[VDP_DEBUG_CRAM]
2017 + context->debug_fb_pitch[VDP_DEBUG_CRAM] * starting_line / sizeof(uint32_t);
2018 for (int pal = 0; pal < 4; pal ++)
2019 {
2020 uint32_t *cur;
2021 for (int y = 0; y < 31; y++)
2022 {
2023 cur = line;
2024 for (int offset = 0; offset < 16; offset++)
2025 {
2026 for (int x = 0; x < 31; x++)
2027 {
2028 *(cur++) = context->colors[pal * 16 + offset];
2029 }
2030 *(cur++) = 0xFF000000;
2031 }
2032 line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t);
2033 }
2034 cur = line;
2035 for (int x = 0; x < 512; x++)
2036 {
2037 *(cur++) = 0xFF000000;
2038 }
2039 line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t);
2040 }
2041 render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_CRAM], 512);
2042 context->debug_fbs[VDP_DEBUG_CRAM] = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_CRAM], &context->debug_fb_pitch[VDP_DEBUG_CRAM]);
2043 }
2044 if (context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE)) {
2045 render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_COMPOSITE], LINEBUF_SIZE);
2046 context->debug_fbs[VDP_DEBUG_COMPOSITE] = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_COMPOSITE], &context->debug_fb_pitch[VDP_DEBUG_COMPOSITE]);
2047 }
2048 }
2049
2050 void vdp_force_update_framebuffer(vdp_context *context)
2051 {
2052 uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL)
2053 ? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL
2054 : 224 + BORDER_TOP_V28 + BORDER_BOT_V28;
2055
2056 uint16_t to_fill = lines_max - context->output_lines;
2057 memset(
2058 ((char *)context->fb) + context->output_pitch * context->output_lines,
2059 0,
2060 to_fill * context->output_pitch
2061 );
2062 render_framebuffer_updated(context->cur_buffer, context->h40_lines > context->output_lines / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER));
2063 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch);
2064 vdp_update_per_frame_debug(context);
2065 }
2066
1720 static void advance_output_line(vdp_context *context) 2067 static void advance_output_line(vdp_context *context)
1721 { 2068 {
1722 if (headless) { 2069 if (headless) {
1723 if (context->vcounter == context->inactive_start) { 2070 if (context->vcounter == context->inactive_start) {
1724 context->frame++; 2071 context->frame++;
1731 2078
1732 if (context->output_lines == lines_max) { 2079 if (context->output_lines == lines_max) {
1733 render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER)); 2080 render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER));
1734 context->cur_buffer = context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD; 2081 context->cur_buffer = context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD;
1735 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch); 2082 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch);
2083 vdp_update_per_frame_debug(context);
1736 context->h40_lines = 0; 2084 context->h40_lines = 0;
1737 context->frame++; 2085 context->frame++;
1738 context->output_lines = 0; 2086 context->output_lines = 0;
1739 } 2087 }
1740 uint32_t output_line = context->vcounter; 2088 uint32_t output_line = context->vcounter;
2040 fetch_sprite_cells_mode4(context);\ 2388 fetch_sprite_cells_mode4(context);\
2041 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 2))\ 2389 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 2))\
2042 case CALC_SLOT(slot, 3):\ 2390 case CALC_SLOT(slot, 3):\
2043 if ((slot + 3) == 140) {\ 2391 if ((slot + 3) == 140) {\
2044 uint32_t *dst = context->output + BORDER_LEFT + 256 + 8;\ 2392 uint32_t *dst = context->output + BORDER_LEFT + 256 + 8;\
2045 uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + CRAM_SIZE*3];\ 2393 uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET];\
2046 for (int i = 0; i < BORDER_RIGHT-8; i++, dst++)\ 2394 for (int i = 0; i < BORDER_RIGHT-8; i++, dst++)\
2047 {\ 2395 {\
2048 *dst = bgcolor;\ 2396 *dst = bgcolor;\
2049 }\ 2397 }\
2050 context->done_output = dst;\ 2398 context->done_output = dst;\
2560 scan_sprite_table_mode4(context); 2908 scan_sprite_table_mode4(context);
2561 CHECK_LIMIT 2909 CHECK_LIMIT
2562 case 0: { 2910 case 0: {
2563 scan_sprite_table_mode4(context); 2911 scan_sprite_table_mode4(context);
2564 uint32_t *dst = context->output;; 2912 uint32_t *dst = context->output;;
2565 uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + CRAM_SIZE*3]; 2913 uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET];
2566 for (int i = 0; i < BORDER_LEFT-8; i++, dst++) 2914 for (int i = 0; i < BORDER_LEFT-8; i++, dst++)
2567 { 2915 {
2568 *dst = bgcolor; 2916 *dst = bgcolor;
2569 } 2917 }
2570 context->done_output = dst; 2918 context->done_output = dst;
2582 case 4: { 2930 case 4: {
2583 scan_sprite_table_mode4(context); 2931 scan_sprite_table_mode4(context);
2584 context->buf_a_off = 8; 2932 context->buf_a_off = 8;
2585 memset(context->tmp_buf_a, 0, 8); 2933 memset(context->tmp_buf_a, 0, 8);
2586 uint32_t *dst = context->output + BORDER_LEFT - 8; 2934 uint32_t *dst = context->output + BORDER_LEFT - 8;
2587 uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + CRAM_SIZE*3]; 2935 uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET];
2588 for (int i = 0; i < 8; i++, dst++) 2936 for (int i = 0; i < 8; i++, dst++)
2589 { 2937 {
2590 *dst = bgcolor; 2938 *dst = bgcolor;
2591 } 2939 }
2592 context->done_output = dst; 2940 context->done_output = dst;
2638 //set things up for sprite rendering in the next slot 2986 //set things up for sprite rendering in the next slot
2639 memset(context->linebuf, 0, LINEBUF_SIZE); 2987 memset(context->linebuf, 0, LINEBUF_SIZE);
2640 context->cur_slot = context->sprite_index = MAX_DRAWS_H32_MODE4-1; 2988 context->cur_slot = context->sprite_index = MAX_DRAWS_H32_MODE4-1;
2641 context->sprite_draws = MAX_DRAWS_H32_MODE4; 2989 context->sprite_draws = MAX_DRAWS_H32_MODE4;
2642 uint32_t *dst = context->output + BORDER_LEFT + 256; 2990 uint32_t *dst = context->output + BORDER_LEFT + 256;
2643 uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + CRAM_SIZE*3]; 2991 uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET];
2644 for (int i = 0; i < 8; i++, dst++) 2992 for (int i = 0; i < 8; i++, dst++)
2645 { 2993 {
2646 *dst = bgcolor; 2994 *dst = bgcolor;
2647 } 2995 }
2648 context->done_output = dst; 2996 context->done_output = dst;
2761 } else { 3109 } else {
2762 //never active unless either mode 4 or mode 5 is turned on 3110 //never active unless either mode 4 or mode 5 is turned on
2763 active_line = 0x200; 3111 active_line = 0x200;
2764 } 3112 }
2765 } 3113 }
2766 uint32_t *dst = ( 3114 uint32_t *dst;
2767 context->vcounter < context->inactive_start + context->border_bot 3115 uint8_t *debug_dst;
2768 || context->vcounter >= 0x200 - context->border_top 3116 if (
2769 ) && context->hslot >= BG_START_SLOT && context->hslot < bg_end_slot 3117 (
2770 ? context->output + 2 * (context->hslot - BG_START_SLOT) 3118 context->vcounter < context->inactive_start + context->border_bot
2771 : NULL; 3119 || context->vcounter >= 0x200 - context->border_top
3120 ) && context->hslot >= BG_START_SLOT && context->hslot < bg_end_slot
3121 ) {
3122 dst = context->output + 2 * (context->hslot - BG_START_SLOT);
3123 debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT);
3124 } else {
3125 dst = NULL;
3126 }
2772 3127
2773 if ( 3128 if (
2774 !dst && context->vcounter == context->inactive_start + context->border_bot 3129 !dst && context->vcounter == context->inactive_start + context->border_bot
2775 && context->hslot >= line_change && context->hslot < bg_end_slot 3130 && context->hslot >= line_change && context->hslot < bg_end_slot
2776 ) { 3131 ) {
2777 dst = context->output + 2 * (context->hslot - BG_START_SLOT); 3132 dst = context->output + 2 * (context->hslot - BG_START_SLOT);
3133 debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT);
2778 } 3134 }
2779 3135
2780 uint8_t test_layer = context->test_port >> 7 & 3; 3136 uint8_t test_layer = context->test_port >> 7 & 3;
2781 if (test_layer) { 3137 if (test_layer) {
2782 dst = NULL; 3138 dst = NULL;
2788 if (context->hslot == BG_START_SLOT && !test_layer && ( 3144 if (context->hslot == BG_START_SLOT && !test_layer && (
2789 context->vcounter < context->inactive_start + context->border_bot 3145 context->vcounter < context->inactive_start + context->border_bot
2790 || context->vcounter >= 0x200 - context->border_top 3146 || context->vcounter >= 0x200 - context->border_top
2791 )) { 3147 )) {
2792 dst = context->output + (context->hslot - BG_START_SLOT) * 2; 3148 dst = context->output + (context->hslot - BG_START_SLOT) * 2;
3149 debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT);
2793 } else if (context->hslot == bg_end_slot) { 3150 } else if (context->hslot == bg_end_slot) {
2794 advance_output_line(context); 3151 advance_output_line(context);
2795 dst = NULL; 3152 dst = NULL;
2796 } 3153 }
2797 //this will need some tweaking to properly interact with 128K mode, 3154 //this will need some tweaking to properly interact with 128K mode,
2844 3201
2845 if (dst) { 3202 if (dst) {
2846 if (mode_5) { 3203 if (mode_5) {
2847 bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; 3204 bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
2848 } else if (context->regs[REG_MODE_1] & BIT_MODE_4) { 3205 } else if (context->regs[REG_MODE_1] & BIT_MODE_4) {
2849 bg_color = context->colors[CRAM_SIZE * 3 + 0x10 + (context->regs[REG_BG_COLOR] & 0xF)]; 3206 bg_color = context->colors[MODE4_OFFSET + 0x10 + (context->regs[REG_BG_COLOR] & 0xF)];
2850 } 3207 }
2851 if (dst >= context->done_output) { 3208 if (dst >= context->done_output) {
2852 *(dst++) = bg_color; 3209 *(dst++) = bg_color;
3210 *(debug_dst++) = DBG_SRC_BG;
2853 } else { 3211 } else {
2854 dst++; 3212 dst++;
3213 debug_dst++;
2855 } 3214 }
2856 if (dst >= context->done_output) { 3215 if (dst >= context->done_output) {
2857 *(dst++) = bg_color; 3216 *(dst++) = bg_color;
3217 *(debug_dst++) = DBG_SRC_BG;
2858 context->done_output = dst; 3218 context->done_output = dst;
2859 } else { 3219 } else {
2860 dst++; 3220 dst++;
3221 debug_dst++;
2861 } 3222 }
2862 if (context->hslot == (bg_end_slot-1)) { 3223 if (context->hslot == (bg_end_slot-1)) {
2863 *(dst++) = bg_color; 3224 *(dst++) = bg_color;
3225 *(debug_dst++) = DBG_SRC_BG;
2864 context->done_output = dst; 3226 context->done_output = dst;
2865 } 3227 }
2866 } 3228 }
2867 3229
2868 if (!is_refresh(context, context->hslot)) { 3230 if (!is_refresh(context, context->hslot)) {
2947 if (!dmalen) { 3309 if (!dmalen) {
2948 dmalen = 0x10000; 3310 dmalen = 0x10000;
2949 } 3311 }
2950 uint32_t min_dma_complete = dmalen * (context->regs[REG_MODE_4] & BIT_H40 ? 16 : 20); 3312 uint32_t min_dma_complete = dmalen * (context->regs[REG_MODE_4] & BIT_H40 ? 16 : 20);
2951 if ( 3313 if (
2952 (context->regs[REG_DMASRC_H] & 0xC0) == 0xC0 3314 (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_COPY
2953 || (((context->cd & 0xF) == VRAM_WRITE) && !(context->regs[REG_MODE_2] & BIT_128K_VRAM))) { 3315 || (((context->cd & 0xF) == VRAM_WRITE) && !(context->regs[REG_MODE_2] & BIT_128K_VRAM))) {
2954 //DMA copies take twice as long to complete since they require a read and a write 3316 //DMA copies take twice as long to complete since they require a read and a write
2955 //DMA Fills and transfers to VRAM also take twice as long as it requires 2 writes for a single word 3317 //DMA Fills and transfers to VRAM also take twice as long as it requires 2 writes for a single word
2956 //unless 128KB mode is enabled 3318 //unless 128KB mode is enabled
2957 min_dma_complete *= 2; 3319 min_dma_complete *= 2;
3023 context->flags &= ~FLAG_READ_FETCHED; 3385 context->flags &= ~FLAG_READ_FETCHED;
3024 context->flags2 &= ~FLAG2_READ_PENDING; 3386 context->flags2 &= ~FLAG2_READ_PENDING;
3025 //printf("New Address: %X, New CD: %X\n", context->address, context->cd); 3387 //printf("New Address: %X, New CD: %X\n", context->address, context->cd);
3026 if (context->cd & 0x20) { 3388 if (context->cd & 0x20) {
3027 // 3389 //
3028 if((context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { 3390 if((context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) != DMA_FILL) {
3029 //DMA copy or 68K -> VDP, transfer starts immediately 3391 //DMA copy or 68K -> VDP, transfer starts immediately
3030 //printf("DMA start (length: %X) at cycle %d, frame: %d, vcounter: %d, hslot: %d\n", (context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L], context->cycles, context->frame, context->vcounter, context->hslot); 3392 //printf("DMA start (length: %X) at cycle %d, frame: %d, vcounter: %d, hslot: %d\n", (context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L], context->cycles, context->frame, context->vcounter, context->hslot);
3031 if (!(context->regs[REG_DMASRC_H] & 0x80)) { 3393 if (!(context->regs[REG_DMASRC_H] & 0x80)) {
3032 //printf("DMA Address: %X, New CD: %X, Source: %X, Length: %X\n", context->address, context->cd, (context->regs[REG_DMASRC_H] << 17) | (context->regs[REG_DMASRC_M] << 9) | (context->regs[REG_DMASRC_L] << 1), context->regs[REG_DMALEN_H] << 8 | context->regs[REG_DMALEN_L]); 3394 //printf("DMA Address: %X, New CD: %X, Source: %X, Length: %X\n", context->address, context->cd, (context->regs[REG_DMASRC_H] << 17) | (context->regs[REG_DMASRC_M] << 9) | (context->regs[REG_DMASRC_L] << 1), context->regs[REG_DMALEN_H] << 8 | context->regs[REG_DMALEN_L]);
3033 //68K -> VDP DMA takes a few slots to actually start reading even though it acquires the bus immediately 3395 //68K -> VDP DMA takes a few slots to actually start reading even though it acquires the bus immediately
3104 } 3466 }
3105 3467
3106 int vdp_data_port_write(vdp_context * context, uint16_t value) 3468 int vdp_data_port_write(vdp_context * context, uint16_t value)
3107 { 3469 {
3108 //printf("data port write: %X at %d\n", value, context->cycles); 3470 //printf("data port write: %X at %d\n", value, context->cycles);
3109 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { 3471 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) != DMA_FILL) {
3110 return -1; 3472 return -1;
3111 } 3473 }
3112 if (context->flags & FLAG_PENDING) { 3474 if (context->flags & FLAG_PENDING) {
3113 context->flags &= ~FLAG_PENDING; 3475 context->flags &= ~FLAG_PENDING;
3114 //Should these be cleared here? 3476 //Should these be cleared here?
3116 context->flags2 &= ~FLAG2_READ_PENDING; 3478 context->flags2 &= ~FLAG2_READ_PENDING;
3117 } 3479 }
3118 /*if (context->fifo_cur == context->fifo_end) { 3480 /*if (context->fifo_cur == context->fifo_end) {
3119 printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles); 3481 printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles);
3120 }*/ 3482 }*/
3121 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { 3483 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_FILL) {
3122 context->flags &= ~FLAG_DMA_RUN; 3484 context->flags &= ~FLAG_DMA_RUN;
3123 } 3485 }
3124 while (context->fifo_write == context->fifo_read) { 3486 while (context->fifo_write == context->fifo_read) {
3125 vdp_run_context_full(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); 3487 vdp_run_context_full(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20));
3126 } 3488 }
3152 } 3514 }
3153 context->flags2 &= ~FLAG2_BYTE_PENDING; 3515 context->flags2 &= ~FLAG2_BYTE_PENDING;
3154 /*if (context->fifo_cur == context->fifo_end) { 3516 /*if (context->fifo_cur == context->fifo_end) {
3155 printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles); 3517 printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles);
3156 }*/ 3518 }*/
3157 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { 3519 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_FILL) {
3158 context->flags &= ~FLAG_DMA_RUN; 3520 context->flags &= ~FLAG_DMA_RUN;
3159 } 3521 }
3160 while (context->fifo_write == context->fifo_read) { 3522 while (context->fifo_write == context->fifo_read) {
3161 vdp_run_context_full(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); 3523 vdp_run_context_full(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20));
3162 } 3524 }
3719 context->cycles = load_int32(buf); 4081 context->cycles = load_int32(buf);
3720 context->pending_vint_start = load_int32(buf); 4082 context->pending_vint_start = load_int32(buf);
3721 context->pending_hint_start = load_int32(buf); 4083 context->pending_hint_start = load_int32(buf);
3722 update_video_params(context); 4084 update_video_params(context);
3723 } 4085 }
4086
4087 static vdp_context *current_vdp;
4088 static void vdp_debug_window_close(uint8_t which)
4089 {
4090 //TODO: remove need for current_vdp global, and find the VDP via current_system instead
4091 for (int i = 0; i < VDP_NUM_DEBUG_TYPES; i++)
4092 {
4093 if (current_vdp->enabled_debuggers & (1 << i) && which == current_vdp->debug_fb_indices[i]) {
4094 vdp_toggle_debug_view(current_vdp, i);
4095 break;
4096 }
4097 }
4098 }
4099
4100 void vdp_toggle_debug_view(vdp_context *context, uint8_t debug_type)
4101 {
4102 if (context->enabled_debuggers & 1 << debug_type) {
4103 render_destroy_window(context->debug_fb_indices[debug_type]);
4104 context->enabled_debuggers &= ~(1 << debug_type);
4105 } else {
4106 uint32_t width,height;
4107 uint8_t fetch_immediately = 0;
4108 char *caption;
4109 switch(debug_type)
4110 {
4111 case VDP_DEBUG_PLANE:
4112 caption = "BlastEm - VDP Plane Debugger";
4113 width = height = 1024;
4114 break;
4115 case VDP_DEBUG_VRAM:
4116 caption = "BlastEm - VDP VRAM Debugger";
4117 width = 1024;
4118 height = 512;
4119 break;
4120 case VDP_DEBUG_CRAM:
4121 caption = "BlastEm - VDP CRAM Debugger";
4122 width = 512;
4123 height = 512;
4124 fetch_immediately = 1;
4125 break;
4126 case VDP_DEBUG_COMPOSITE:
4127 caption = "BlastEm - VDP Plane Composition Debugger";
4128 width = LINEBUF_SIZE;
4129 height = context->inactive_start + context->border_top + context->border_bot;
4130 fetch_immediately = 1;
4131 break;
4132 default:
4133 return;
4134 }
4135 current_vdp = context;
4136 context->debug_fb_indices[debug_type] = render_create_window(caption, width, height, vdp_debug_window_close);
4137 if (context->debug_fb_indices[debug_type]) {
4138 context->enabled_debuggers |= 1 << debug_type;
4139 }
4140 if (fetch_immediately) {
4141 context->debug_fbs[debug_type] = render_get_framebuffer(context->debug_fb_indices[debug_type], &context->debug_fb_pitch[debug_type]);
4142 }
4143 }
4144 }
4145
4146 void vdp_inc_debug_mode(vdp_context *context)
4147 {
4148 uint8_t active = render_get_active_framebuffer();
4149 if (active < FRAMEBUFFER_USER_START) {
4150 return;
4151 }
4152 for (int i = 0; i < VDP_NUM_DEBUG_TYPES; i++)
4153 {
4154 if (context->enabled_debuggers & (1 << i) && context->debug_fb_indices[i] == active) {
4155 context->debug_modes[i]++;
4156 return;
4157 }
4158 }
4159 }