Mercurial > repos > blastem
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 } |