comparison vdp.c @ 2053:3414a4423de1 segacd

Merge from default
author Michael Pavone <pavone@retrodev.com>
date Sat, 15 Jan 2022 13:15:21 -0800
parents a61b47d5489e
children c5d0edf1d7e7
comparison
equal deleted inserted replaced
1692:5dacaef602a7 2053:3414a4423de1
7 #include "blastem.h" 7 #include "blastem.h"
8 #include <stdlib.h> 8 #include <stdlib.h>
9 #include <string.h> 9 #include <string.h>
10 #include "render.h" 10 #include "render.h"
11 #include "util.h" 11 #include "util.h"
12 #include "event_log.h"
13 #include "terminal.h"
12 14
13 #define NTSC_INACTIVE_START 224 15 #define NTSC_INACTIVE_START 224
14 #define PAL_INACTIVE_START 240 16 #define PAL_INACTIVE_START 240
15 #define MODE4_INACTIVE_START 192 17 #define MODE4_INACTIVE_START 192
16 #define BUF_BIT_PRIORITY 0x40 18 #define BUF_BIT_PRIORITY 0x40
49 #define BORDER_BOT_V28 8 51 #define BORDER_BOT_V28 8
50 #define BORDER_BOT_V24_PAL 48 52 #define BORDER_BOT_V24_PAL 48
51 #define BORDER_BOT_V28_PAL 32 53 #define BORDER_BOT_V28_PAL 32
52 #define BORDER_BOT_V30_PAL 24 54 #define BORDER_BOT_V30_PAL 24
53 55
54 #define INVALID_LINE 0x200
55
56 enum { 56 enum {
57 INACTIVE = 0, 57 INACTIVE = 0,
58 PREPARING, //used for line 0x1FF 58 PREPARING, //used for line 0x1FF
59 ACTIVE 59 ACTIVE
60 }; 60 };
70 {127, 0, 0}, //Window 70 {127, 0, 0}, //Window
71 {0, 127, 0}, //B 71 {0, 127, 0}, //B
72 {127, 0, 127} //Sprites 72 {127, 0, 127} //Sprites
73 }; 73 };
74 74
75 static uint32_t calc_crop(uint32_t crop, uint32_t border)
76 {
77 return crop >= border ? 0 : border - crop;
78 }
79
75 static void update_video_params(vdp_context *context) 80 static void update_video_params(vdp_context *context)
76 { 81 {
82 uint32_t top_crop = render_overscan_top();
83 uint32_t bot_crop = render_overscan_bot();
84 uint32_t border_top;
77 if (context->regs[REG_MODE_2] & BIT_MODE_5) { 85 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
78 if (context->regs[REG_MODE_2] & BIT_PAL) { 86 if (context->regs[REG_MODE_2] & BIT_PAL) {
79 if (context->flags2 & FLAG2_REGION_PAL) { 87 if (context->flags2 & FLAG2_REGION_PAL) {
80 context->inactive_start = PAL_INACTIVE_START; 88 context->inactive_start = PAL_INACTIVE_START;
81 context->border_top = BORDER_TOP_V30_PAL; 89 border_top = BORDER_TOP_V30_PAL;
82 context->border_bot = BORDER_BOT_V30_PAL; 90 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V30_PAL);
83 } else { 91 } else {
84 //the behavior here is rather weird and needs more investigation 92 //the behavior here is rather weird and needs more investigation
85 context->inactive_start = 0xF0; 93 context->inactive_start = 0xF0;
86 context->border_top = 1; 94 border_top = 1;
87 context->border_bot = 3; 95 context->border_bot = calc_crop(bot_crop, 3);
88 } 96 }
89 } else { 97 } else {
90 context->inactive_start = NTSC_INACTIVE_START; 98 context->inactive_start = NTSC_INACTIVE_START;
91 if (context->flags2 & FLAG2_REGION_PAL) { 99 if (context->flags2 & FLAG2_REGION_PAL) {
92 context->border_top = BORDER_TOP_V28_PAL; 100 border_top = BORDER_TOP_V28_PAL;
93 context->border_bot = BORDER_BOT_V28_PAL; 101 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V28_PAL);
94 } else { 102 } else {
95 context->border_top = BORDER_TOP_V28; 103 border_top = BORDER_TOP_V28;
96 context->border_bot = BORDER_TOP_V28; 104 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V28);
97 } 105 }
98 } 106 }
99 if (context->regs[REG_MODE_4] & BIT_H40) { 107 if (context->regs[REG_MODE_4] & BIT_H40) {
100 context->max_sprites_frame = MAX_SPRITES_FRAME; 108 context->max_sprites_frame = MAX_SPRITES_FRAME;
101 context->max_sprites_line = MAX_SPRITES_LINE; 109 context->max_sprites_line = MAX_SPRITES_LINE;
112 } 120 }
113 } 121 }
114 } else { 122 } else {
115 context->inactive_start = MODE4_INACTIVE_START; 123 context->inactive_start = MODE4_INACTIVE_START;
116 if (context->flags2 & FLAG2_REGION_PAL) { 124 if (context->flags2 & FLAG2_REGION_PAL) {
117 context->border_top = BORDER_TOP_V24_PAL; 125 border_top = BORDER_TOP_V24_PAL;
118 context->border_bot = BORDER_BOT_V24_PAL; 126 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V24_PAL);
119 } else { 127 } else {
120 context->border_top = BORDER_TOP_V24; 128 border_top = BORDER_TOP_V24;
121 context->border_bot = BORDER_BOT_V24; 129 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V24);
122 } 130 }
123 if (!(context->regs[REG_MODE_1] & BIT_MODE_4)){ 131 if (!(context->regs[REG_MODE_1] & BIT_MODE_4)){
124 context->state = INACTIVE; 132 context->state = INACTIVE;
125 } else if (context->state == INACTIVE) { 133 } else if (context->state == INACTIVE) {
126 //Undo forced INACTIVE state due to neither Mode 4 nor Mode 5 being active 134 //Undo forced INACTIVE state due to neither Mode 4 nor Mode 5 being active
130 else if (context->vcounter == 0x1FF) { 138 else if (context->vcounter == 0x1FF) {
131 context->state = PREPARING; 139 context->state = PREPARING;
132 } 140 }
133 } 141 }
134 } 142 }
143 context->border_top = calc_crop(top_crop, border_top);
144 context->top_offset = border_top - context->border_top;
135 } 145 }
136 146
137 static uint8_t color_map_init_done; 147 static uint8_t color_map_init_done;
138 148
139 vdp_context *init_vdp_context(uint8_t region_pal) 149 vdp_context *init_vdp_context(uint8_t region_pal, uint8_t has_max_vsram)
140 { 150 {
141 vdp_context *context = calloc(1, sizeof(vdp_context) + VRAM_SIZE); 151 vdp_context *context = calloc(1, sizeof(vdp_context) + VRAM_SIZE);
142 if (headless) { 152 if (headless) {
143 context->output = malloc(LINEBUF_SIZE * sizeof(uint32_t)); 153 context->fb = malloc(512 * LINEBUF_SIZE * sizeof(uint32_t));
144 context->output_pitch = 0; 154 context->output_pitch = LINEBUF_SIZE * sizeof(uint32_t);
145 } else { 155 } else {
146 context->cur_buffer = FRAMEBUFFER_ODD; 156 context->cur_buffer = FRAMEBUFFER_ODD;
147 context->fb = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch); 157 context->fb = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch);
148 } 158 }
149 context->sprite_draws = MAX_DRAWS; 159 context->sprite_draws = MAX_SPRITES_LINE;
150 context->fifo_write = 0; 160 context->fifo_write = 0;
151 context->fifo_read = -1; 161 context->fifo_read = -1;
152 context->regs[REG_HINT] = context->hint_counter = 0xFF; 162 context->regs[REG_HINT] = context->hint_counter = 0xFF;
163 context->vsram_size = has_max_vsram ? MAX_VSRAM_SIZE : MIN_VSRAM_SIZE;
153 164
154 if (!color_map_init_done) { 165 if (!color_map_init_done) {
155 uint8_t b,g,r; 166 uint8_t b,g,r;
156 for (uint16_t color = 0; color < (1 << 12); color++) { 167 for (uint16_t color = 0; color < (1 << 12); color++) {
157 if (color & FBUF_SHADOW) { 168 if (color & FBUF_SHADOW) {
235 } 246 }
236 if (region_pal) { 247 if (region_pal) {
237 context->flags2 |= FLAG2_REGION_PAL; 248 context->flags2 |= FLAG2_REGION_PAL;
238 } 249 }
239 update_video_params(context); 250 update_video_params(context);
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);
242 }
243 return context; 252 return context;
244 } 253 }
245 254
246 void vdp_free(vdp_context *context) 255 void vdp_free(vdp_context *context)
247 { 256 {
257 if (headless) {
258 free(context->fb);
259 }
260 for (int i = 0; i < VDP_NUM_DEBUG_TYPES; i++)
261 {
262 if (context->enabled_debuggers & (1 << i)) {
263 vdp_toggle_debug_view(context, i);
264 }
265 }
248 free(context); 266 free(context);
249 } 267 }
250 268
251 static int is_refresh(vdp_context * context, uint32_t slot) 269 static int is_refresh(vdp_context * context, uint32_t slot)
252 { 270 {
269 } 287 }
270 } 288 }
271 289
272 static void render_sprite_cells(vdp_context * context) 290 static void render_sprite_cells(vdp_context * context)
273 { 291 {
292 if (context->cur_slot > MAX_SPRITES_LINE) {
293 context->cur_slot--;
294 return;
295 }
296 if (context->cur_slot < 0) {
297 return;
298 }
274 sprite_draw * d = context->sprite_draw_list + context->cur_slot; 299 sprite_draw * d = context->sprite_draw_list + context->cur_slot;
275 context->serial_address = d->address; 300 uint16_t address = d->address;
276 if (context->cur_slot >= context->sprite_draws) { 301 address += context->sprite_x_offset * d->height * 4;
277 302 context->serial_address = address;
278 uint16_t dir; 303 uint16_t dir;
279 int16_t x; 304 int16_t x;
280 if (d->h_flip) { 305 if (d->h_flip) {
281 x = d->x_pos + 7; 306 x = d->x_pos + 7 + 8 * (d->width - context->sprite_x_offset - 1);
282 dir = -1; 307 dir = -1;
283 } else { 308 } else {
284 x = d->x_pos; 309 x = d->x_pos + context->sprite_x_offset * 8;
285 dir = 1; 310 dir = 1;
286 } 311 }
287 //printf("Draw Slot %d of %d, Rendering sprite cell from %X to x: %d\n", context->cur_slot, context->sprite_draws, d->address, x); 312 if (d->x_pos) {
288 context->cur_slot--; 313 context->flags |= FLAG_CAN_MASK;
289 for (uint16_t address = d->address; address != ((d->address+4) & 0xFFFF); address++) { 314 if (!(context->flags & FLAG_MASKED)) {
290 if (x >= 0 && x < 320) { 315 x -= 128;
291 if (!(context->linebuf[x] & 0xF)) { 316 //printf("Draw Slot %d of %d, Rendering sprite cell from %X to x: %d\n", context->cur_slot, context->sprite_draws, d->address, x);
292 context->linebuf[x] = (context->vdpmem[address] >> 4) | d->pal_priority; 317 uint8_t collide = 0;
293 } else if (context->vdpmem[address] >> 4) { 318 if (x >= 8 && x < 312) {
294 context->flags2 |= FLAG2_SPRITE_COLLIDE; 319 //sprite is fully visible
295 } 320 for (; address != ((context->serial_address+4) & 0xFFFF); address++) {
296 } 321 uint8_t pixel = context->vdpmem[address] >> 4;
297 x += dir; 322 if (!(context->linebuf[x] & 0xF)) {
298 if (x >= 0 && x < 320) { 323 context->linebuf[x] = pixel | d->pal_priority;
299 if (!(context->linebuf[x] & 0xF)) { 324 } else {
300 context->linebuf[x] = (context->vdpmem[address] & 0xF) | d->pal_priority; 325 collide |= pixel;
301 } else if (context->vdpmem[address] & 0xF) { 326 }
302 context->flags2 |= FLAG2_SPRITE_COLLIDE; 327 x += dir;
303 } 328 pixel = context->vdpmem[address] & 0xF;
304 } 329 if (!(context->linebuf[x] & 0xF)) {
305 x += dir; 330 context->linebuf[x] = pixel | d->pal_priority;
306 } 331 } else {
307 } else { 332 collide |= pixel;
333 }
334 x += dir;
335 }
336 } else if (x > -8 && x < 327) {
337 //sprite is partially visible
338 for (; address != ((context->serial_address+4) & 0xFFFF); address++) {
339 if (x >= 0 && x < 320) {
340 uint8_t pixel = context->vdpmem[address] >> 4;
341 if (!(context->linebuf[x] & 0xF)) {
342 context->linebuf[x] = pixel | d->pal_priority;
343 } else {
344 collide |= pixel;
345 }
346 }
347 x += dir;
348 if (x >= 0 && x < 320) {
349 uint8_t pixel = context->vdpmem[address] & 0xF;
350 if (!(context->linebuf[x] & 0xF)) {
351 context->linebuf[x] = pixel | d->pal_priority;
352 } else {
353 collide |= pixel;
354 }
355 }
356 x += dir;
357 }
358 }
359 if (collide) {
360 context->flags2 |= FLAG2_SPRITE_COLLIDE;
361 }
362 }
363 } else if (context->flags & FLAG_CAN_MASK) {
364 context->flags |= FLAG_MASKED;
365 context->flags &= ~FLAG_CAN_MASK;
366 }
367
368 context->sprite_x_offset++;
369 if (context->sprite_x_offset == d->width) {
370 d->x_pos = 0;
371 context->sprite_x_offset = 0;
308 context->cur_slot--; 372 context->cur_slot--;
309 } 373 }
310 } 374 }
311 375
312 static void fetch_sprite_cells_mode4(vdp_context * context) 376 static void fetch_sprite_cells_mode4(vdp_context * context)
530 "Status: %X\n", 594 "Status: %X\n",
531 context->address, context->cd, cd_name(context->cd), 595 context->address, context->cd, cd_name(context->cd),
532 (context->flags & FLAG_PENDING) ? "word" : (context->flags2 & FLAG2_BYTE_PENDING) ? "byte" : "none", 596 (context->flags & FLAG_PENDING) ? "word" : (context->flags2 & FLAG2_BYTE_PENDING) ? "byte" : "none",
533 context->vcounter, context->hslot*2, (context->flags2 & FLAG2_VINT_PENDING) ? "true" : "false", 597 context->vcounter, context->hslot*2, (context->flags2 & FLAG2_VINT_PENDING) ? "true" : "false",
534 (context->flags2 & FLAG2_HINT_PENDING) ? "true" : "false", vdp_control_port_read(context)); 598 (context->flags2 & FLAG2_HINT_PENDING) ? "true" : "false", vdp_control_port_read(context));
599 printf("\nDebug Register: %X | Output disabled: %s, Force Layer: %d\n", context->test_port,
600 (context->test_port & TEST_BIT_DISABLE) ? "true" : "false", context->test_port >> 7 & 3
601 );
535 //restore flags as calling vdp_control_port_read can change them 602 //restore flags as calling vdp_control_port_read can change them
536 context->flags = old_flags; 603 context->flags = old_flags;
537 context->flags2 = old_flags2; 604 context->flags2 = old_flags2;
538 } 605 }
539 606
695 if (context->double_res) { 762 if (context->double_res) {
696 address = ((tileinfo & 0x3FF) << 6) + row * 4; 763 address = ((tileinfo & 0x3FF) << 6) + row * 4;
697 } else { 764 } else {
698 address = ((tileinfo & 0x7FF) << 5) + row * 4; 765 address = ((tileinfo & 0x7FF) << 5) + row * 4;
699 } 766 }
700 int16_t x = ((context->vdpmem[att_addr+ 2] & 0x3) << 8 | context->vdpmem[att_addr + 3]) & 0x1FF; 767 context->sprite_draws--;
701 if (x) { 768 context->sprite_draw_list[context->sprite_draws].x_pos = ((context->vdpmem[att_addr+ 2] & 0x3) << 8 | context->vdpmem[att_addr + 3]) & 0x1FF;
702 context->flags |= FLAG_CAN_MASK; 769 context->sprite_draw_list[context->sprite_draws].address = address;
703 } else if(context->flags & (FLAG_CAN_MASK | FLAG_DOT_OFLOW)) { 770 context->sprite_draw_list[context->sprite_draws].pal_priority = pal_priority;
704 context->flags |= FLAG_MASKED; 771 context->sprite_draw_list[context->sprite_draws].h_flip = (tileinfo & MAP_BIT_H_FLIP) ? 1 : 0;
705 } 772 context->sprite_draw_list[context->sprite_draws].width = width;
706 773 context->sprite_draw_list[context->sprite_draws].height = height;
707 context->flags &= ~FLAG_DOT_OFLOW;
708 int16_t i;
709 if (context->flags & FLAG_MASKED) {
710 for (i=0; i < width && context->sprite_draws; i++) {
711 --context->sprite_draws;
712 context->sprite_draw_list[context->sprite_draws].x_pos = -128;
713 context->sprite_draw_list[context->sprite_draws].address = address + i * height * 4;
714 }
715 } else {
716 x -= 128;
717 int16_t base_x = x;
718 int16_t dir;
719 if (tileinfo & MAP_BIT_H_FLIP) {
720 x += (width-1) * 8;
721 dir = -8;
722 } else {
723 dir = 8;
724 }
725 //printf("Sprite %d | x: %d, y: %d, width: %d, height: %d, pal_priority: %X, row: %d, tile addr: %X\n", context->sprite_info_list[context->cur_slot].index, x, context->sprite_info_list[context->cur_slot].y, width, height, pal_priority, row, address);
726 for (i=0; i < width && context->sprite_draws; i++, x += dir) {
727 --context->sprite_draws;
728 context->sprite_draw_list[context->sprite_draws].address = address + i * height * 4;
729 context->sprite_draw_list[context->sprite_draws].x_pos = x;
730 context->sprite_draw_list[context->sprite_draws].pal_priority = pal_priority;
731 context->sprite_draw_list[context->sprite_draws].h_flip = (tileinfo & MAP_BIT_H_FLIP) ? 1 : 0;
732 }
733 }
734 //Used to be i < width
735 //TODO: Confirm this is the right condition on hardware
736 if (!context->sprite_draws) {
737 context->flags |= FLAG_DOT_OFLOW;
738 }
739 } else {
740 context->flags |= FLAG_DOT_OFLOW;
741 } 774 }
742 } 775 }
743 context->cur_slot++; 776 context->cur_slot++;
744 } 777 }
745 778
790 addr = address & 0x1F; 823 addr = address & 0x1F;
791 value = (value << 1 & 0xE) | (value << 2 & 0xE0) | (value & 0xE00); 824 value = (value << 1 & 0xE) | (value << 2 & 0xE0) | (value & 0xE00);
792 } 825 }
793 write_cram_internal(context, addr, value); 826 write_cram_internal(context, addr, value);
794 827
795 if (context->hslot >= BG_START_SLOT && ( 828 if (context->output && context->hslot >= BG_START_SLOT && (
796 context->vcounter < context->inactive_start + context->border_bot 829 context->vcounter < context->inactive_start + context->border_bot
797 || context->vcounter > 0x200 - context->border_top 830 || context->vcounter > 0x200 - context->border_top
798 )) { 831 )) {
799 uint8_t bg_end_slot = BG_START_SLOT + (context->regs[REG_MODE_4] & BIT_H40) ? LINEBUF_SIZE/2 : (256+HORIZ_BORDER)/2; 832 uint8_t bg_end_slot = BG_START_SLOT + (context->regs[REG_MODE_4] & BIT_H40) ? LINEBUF_SIZE/2 : (256+HORIZ_BORDER)/2;
800 if (context->hslot < bg_end_slot) { 833 if (context->hslot < bg_end_slot) {
884 if (context->fifo_read >= 0 && start->cycle <= context->cycles) { 917 if (context->fifo_read >= 0 && start->cycle <= context->cycles) {
885 switch (start->cd & 0xF) 918 switch (start->cd & 0xF)
886 { 919 {
887 case VRAM_WRITE: 920 case VRAM_WRITE:
888 if ((context->regs[REG_MODE_2] & (BIT_128K_VRAM|BIT_MODE_5)) == (BIT_128K_VRAM|BIT_MODE_5)) { 921 if ((context->regs[REG_MODE_2] & (BIT_128K_VRAM|BIT_MODE_5)) == (BIT_128K_VRAM|BIT_MODE_5)) {
922 event_vram_word(context->cycles, start->address, start->value);
889 vdp_check_update_sat(context, start->address, start->value); 923 vdp_check_update_sat(context, start->address, start->value);
890 write_vram_word(context, start->address, start->value); 924 write_vram_word(context, start->address, start->value);
891 } else { 925 } else {
892 uint8_t byte = start->partial == 1 ? start->value >> 8 : start->value; 926 uint8_t byte = start->partial == 1 ? start->value >> 8 : start->value;
893 vdp_check_update_sat_byte(context, start->address ^ 1, byte); 927 uint32_t address = start->address ^ 1;
894 write_vram_byte(context, start->address ^ 1, byte); 928 event_vram_byte(context->cycles, start->address, byte, context->regs[REG_AUTOINC]);
929 vdp_check_update_sat_byte(context, address, byte);
930 write_vram_byte(context, address, byte);
895 if (!start->partial) { 931 if (!start->partial) {
896 start->address = start->address ^ 1; 932 start->address = address;
897 start->partial = 1; 933 start->partial = 1;
898 //skip auto-increment and removal of entry from fifo 934 //skip auto-increment and removal of entry from fifo
899 return; 935 return;
900 } 936 }
901 } 937 }
902 break; 938 break;
903 case CRAM_WRITE: { 939 case CRAM_WRITE: {
904 //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1)); 940 //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1));
941 uint16_t val;
905 if (start->partial == 3) { 942 if (start->partial == 3) {
906 uint16_t val;
907 if ((start->address & 1) && (context->regs[REG_MODE_2] & BIT_MODE_5)) { 943 if ((start->address & 1) && (context->regs[REG_MODE_2] & BIT_MODE_5)) {
908 val = (context->cram[start->address >> 1 & (CRAM_SIZE-1)] & 0xFF) | start->value << 8; 944 val = (context->cram[start->address >> 1 & (CRAM_SIZE-1)] & 0xFF) | start->value << 8;
909 } else { 945 } else {
910 uint16_t address = (context->regs[REG_MODE_2] & BIT_MODE_5) ? start->address >> 1 & (CRAM_SIZE-1) : start->address & 0x1F; 946 uint16_t address = (context->regs[REG_MODE_2] & BIT_MODE_5) ? start->address >> 1 & (CRAM_SIZE-1) : start->address & 0x1F;
911 val = (context->cram[address] & 0xFF00) | start->value; 947 val = (context->cram[address] & 0xFF00) | start->value;
912 } 948 }
913 write_cram(context, start->address, val);
914 } else { 949 } else {
915 write_cram(context, start->address, start->partial ? context->fifo[context->fifo_write].value : start->value); 950 val = start->partial ? context->fifo[context->fifo_write].value : start->value;
916 } 951 }
952 uint8_t buffer[3] = {start->address & 127, val >> 8, val};
953 event_log(EVENT_VDP_INTRAM, context->cycles, sizeof(buffer), buffer);
954 write_cram(context, start->address, val);
917 break; 955 break;
918 } 956 }
919 case VSRAM_WRITE: 957 case VSRAM_WRITE:
920 if (((start->address/2) & 63) < VSRAM_SIZE) { 958 if (((start->address/2) & 63) < context->vsram_size) {
921 //printf("VSRAM Write: %X to %X @ frame: %d, vcounter: %d, hslot: %d, cycle: %d\n", start->value, start->address, context->frame, context->vcounter, context->hslot, context->cycles); 959 //printf("VSRAM Write: %X to %X @ frame: %d, vcounter: %d, hslot: %d, cycle: %d\n", start->value, start->address, context->frame, context->vcounter, context->hslot, context->cycles);
922 if (start->partial == 3) { 960 if (start->partial == 3) {
923 if (start->address & 1) { 961 if (start->address & 1) {
924 context->vsram[(start->address/2) & 63] &= 0xFF; 962 context->vsram[(start->address/2) & 63] &= 0xFF;
925 context->vsram[(start->address/2) & 63] |= start->value << 8; 963 context->vsram[(start->address/2) & 63] |= start->value << 8;
928 context->vsram[(start->address/2) & 63] |= start->value; 966 context->vsram[(start->address/2) & 63] |= start->value;
929 } 967 }
930 } else { 968 } else {
931 context->vsram[(start->address/2) & 63] = start->partial ? context->fifo[context->fifo_write].value : start->value; 969 context->vsram[(start->address/2) & 63] = start->partial ? context->fifo[context->fifo_write].value : start->value;
932 } 970 }
971 uint8_t buffer[3] = {((start->address/2) & 63) + 128, context->vsram[(start->address/2) & 63] >> 8, context->vsram[(start->address/2) & 63]};
972 event_log(EVENT_VDP_INTRAM, context->cycles, sizeof(buffer), buffer);
933 } 973 }
934 974
935 break; 975 break;
936 } 976 }
937 context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1); 977 context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1);
952 } else { 992 } else {
953 context->prefetch = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1]; 993 context->prefetch = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1];
954 994
955 context->flags |= FLAG_READ_FETCHED; 995 context->flags |= FLAG_READ_FETCHED;
956 } 996 }
957 } else if (!(context->cd & 1) && !(context->flags & (FLAG_READ_FETCHED|FLAG_PENDING))) { 997 } else if (!(context->cd & 1) && !(context->flags & FLAG_READ_FETCHED)) {
958 switch(context->cd & 0xF) 998 switch(context->cd & 0xF)
959 { 999 {
960 case VRAM_READ: 1000 case VRAM_READ:
961 if (context->flags2 & FLAG2_READ_PENDING) { 1001 if (context->flags2 & FLAG2_READ_PENDING) {
962 context->prefetch |= context->vdpmem[context->address | 1]; 1002 context->prefetch |= context->vdpmem[context->address | 1];
989 //Should this happen after the prefetch or after the read? 1029 //Should this happen after the prefetch or after the read?
990 increment_address(context); 1030 increment_address(context);
991 break; 1031 break;
992 case VSRAM_READ: { 1032 case VSRAM_READ: {
993 uint16_t address = (context->address /2) & 63; 1033 uint16_t address = (context->address /2) & 63;
994 if (address >= VSRAM_SIZE) { 1034 if (address >= context->vsram_size) {
995 address = 0; 1035 address = 0;
996 } 1036 }
997 context->prefetch = context->vsram[address] & VSRAM_BITS; 1037 context->prefetch = context->vsram[address] & VSRAM_BITS;
998 context->prefetch |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS; 1038 context->prefetch |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS;
999 context->flags |= FLAG_READ_FETCHED; 1039 context->flags |= FLAG_READ_FETCHED;
1112 offset = address + line_offset + (((column - 1) * 2) & mask); 1152 offset = address + line_offset + (((column - 1) * 2) & mask);
1113 context->col_2 = (context->vdpmem[offset] << 8) | context->vdpmem[offset+1]; 1153 context->col_2 = (context->vdpmem[offset] << 8) | context->vdpmem[offset+1];
1114 context->v_offset = (line) & v_offset_mask; 1154 context->v_offset = (line) & v_offset_mask;
1115 context->flags |= FLAG_WINDOW; 1155 context->flags |= FLAG_WINDOW;
1116 return; 1156 return;
1117 } 1157 } else if (column == right_col) {
1118 context->flags &= ~FLAG_WINDOW; 1158 context->flags |= FLAG_WINDOW_EDGE;
1159 context->flags &= ~FLAG_WINDOW;
1160 } else {
1161 context->flags &= ~(FLAG_WINDOW_EDGE|FLAG_WINDOW);
1162 }
1119 } 1163 }
1120 //TODO: Verify behavior for 0x20 case 1164 //TODO: Verify behavior for 0x20 case
1121 uint16_t vscroll = 0xFF | (context->regs[REG_SCROLL] & 0x30) << 4; 1165 uint16_t vscroll = 0xFF | (context->regs[REG_SCROLL] & 0x30) << 4;
1122 if (context->double_res) { 1166 if (context->double_res) {
1123 vscroll <<= 1; 1167 vscroll <<= 1;
1125 } 1169 }
1126 vscroll &= context->vscroll_latch[vsram_off] + line; 1170 vscroll &= context->vscroll_latch[vsram_off] + line;
1127 context->v_offset = vscroll & v_offset_mask; 1171 context->v_offset = vscroll & v_offset_mask;
1128 //printf("%s | line %d, vsram: %d, vscroll: %d, v_offset: %d\n",(vsram_off ? "B" : "A"), line, context->vsram[context->regs[REG_MODE_3] & 0x4 ? column : 0], vscroll, context->v_offset); 1172 //printf("%s | line %d, vsram: %d, vscroll: %d, v_offset: %d\n",(vsram_off ? "B" : "A"), line, context->vsram[context->regs[REG_MODE_3] & 0x4 ? column : 0], vscroll, context->v_offset);
1129 vscroll >>= vscroll_shift; 1173 vscroll >>= vscroll_shift;
1130 uint16_t hscroll_mask; 1174 //TODO: Verify the behavior for a setting of 2
1131 uint16_t v_mul; 1175 static const uint16_t hscroll_masks[] = {0x1F, 0x3F, 0x1F, 0x7F};
1132 switch(context->regs[REG_SCROLL] & 0x3) 1176 static const uint16_t v_shifts[] = {6, 7, 16, 8};
1133 { 1177 uint16_t hscroll_mask = hscroll_masks[context->regs[REG_SCROLL] & 0x3];
1134 case 0: 1178 uint16_t v_shift = v_shifts[context->regs[REG_SCROLL] & 0x3];
1135 hscroll_mask = 0x1F;
1136 v_mul = 64;
1137 break;
1138 case 0x1:
1139 hscroll_mask = 0x3F;
1140 v_mul = 128;
1141 break;
1142 case 0x2:
1143 //TODO: Verify this behavior
1144 hscroll_mask = 0x1F;
1145 v_mul = 0;
1146 break;
1147 case 0x3:
1148 hscroll_mask = 0x7F;
1149 v_mul = 256;
1150 break;
1151 }
1152 uint16_t hscroll, offset; 1179 uint16_t hscroll, offset;
1153 for (int i = 0; i < 2; i++) { 1180 for (int i = 0; i < 2; i++) {
1154 hscroll = (column - 2 + i - ((hscroll_val/8) & 0xFFFE)) & hscroll_mask; 1181 hscroll = (column - 2 + i - ((hscroll_val/8) & 0xFFFE)) & hscroll_mask;
1155 offset = address + ((vscroll * v_mul + hscroll*2) & 0x1FFF); 1182 offset = address + (((vscroll << v_shift) + hscroll*2) & 0x1FFF);
1156 //printf("%s | line: %d, col: %d, x: %d, hs_mask %X, scr reg: %X, tbl addr: %X\n", (vsram_off ? "B" : "A"), line, (column-2+i), hscroll, hscroll_mask, context->regs[REG_SCROLL], offset); 1183 //printf("%s | line: %d, col: %d, x: %d, hs_mask %X, scr reg: %X, tbl addr: %X\n", (vsram_off ? "B" : "A"), line, (column-2+i), hscroll, hscroll_mask, context->regs[REG_SCROLL], offset);
1157 uint16_t col_val = (context->vdpmem[offset] << 8) | context->vdpmem[offset+1]; 1184 uint16_t col_val = (context->vdpmem[offset] << 8) | context->vdpmem[offset+1];
1158 if (i) { 1185 if (i) {
1159 context->col_2 = col_val; 1186 context->col_2 = col_val;
1160 } else { 1187 } else {
1208 } else { 1235 } else {
1209 address += 4 * context->v_offset; 1236 address += 4 * context->v_offset;
1210 } 1237 }
1211 uint8_t pal_priority = (col >> 9) & 0x70; 1238 uint8_t pal_priority = (col >> 9) & 0x70;
1212 uint32_t bits = *((uint32_t *)(&context->vdpmem[address])); 1239 uint32_t bits = *((uint32_t *)(&context->vdpmem[address]));
1240 tmp_buf += offset;
1213 if (col & MAP_BIT_H_FLIP) { 1241 if (col & MAP_BIT_H_FLIP) {
1214 uint32_t shift = 28; 1242 uint32_t shift = 28;
1215 for (int i = 0; i < 4; i++) 1243 for (int i = 0; i < 4; i++)
1216 { 1244 {
1217 uint8_t right = pal_priority | ((bits >> shift) & 0xF); 1245 uint8_t right = pal_priority | ((bits >> shift) & 0xF);
1218 shift -= 4; 1246 shift -= 4;
1219 tmp_buf[offset++] = pal_priority | ((bits >> shift) & 0xF); 1247 *(tmp_buf++) = pal_priority | ((bits >> shift) & 0xF);
1220 shift -= 4; 1248 shift -= 4;
1221 offset &= SCROLL_BUFFER_MASK; 1249 *(tmp_buf++) = right;
1222 tmp_buf[offset++] = right;
1223 offset &= SCROLL_BUFFER_MASK;
1224 } 1250 }
1225 } else { 1251 } else {
1226 for (int i = 0; i < 4; i++) 1252 for (int i = 0; i < 4; i++)
1227 { 1253 {
1228 uint8_t right = pal_priority | (bits & 0xF); 1254 uint8_t right = pal_priority | (bits & 0xF);
1229 bits >>= 4; 1255 bits >>= 4;
1230 tmp_buf[offset++] = pal_priority | (bits & 0xF); 1256 *(tmp_buf++) = pal_priority | (bits & 0xF);
1231 offset &= SCROLL_BUFFER_MASK;
1232 bits >>= 4; 1257 bits >>= 4;
1233 tmp_buf[offset++] = right; 1258 *(tmp_buf++) = right;
1234 offset &= SCROLL_BUFFER_MASK;
1235 } 1259 }
1236 } 1260 }
1237 } 1261 }
1238 1262
1239 static void render_map_1(vdp_context * context) 1263 static void render_map_1(vdp_context * context)
1326 } 1350 }
1327 *debug_dst = src; 1351 *debug_dst = src;
1328 return (sh_pixel){.index = pixel, .intensity = intensity}; 1352 return (sh_pixel){.index = pixel, .intensity = intensity};
1329 } 1353 }
1330 1354
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) 1355 static void render_normal(vdp_context *context, int32_t col, uint8_t *dst, uint8_t *debug_dst, uint8_t *buf_a, int plane_a_off, int plane_a_mask, int plane_b_off)
1356 {
1357 uint8_t *sprite_buf = context->linebuf + col * 8;
1358 if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1359 memset(dst, 0, 8);
1360 memset(debug_dst, DBG_SRC_BG, 8);
1361 dst += 8;
1362 debug_dst += 8;
1363 sprite_buf += 8;
1364 plane_a_off += 8;
1365 plane_b_off += 8;
1366 for (int i = 0; i < 8; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1367 {
1368 uint8_t sprite, plane_a, plane_b;
1369 plane_a = buf_a[plane_a_off & plane_a_mask];
1370 plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1371 *(dst++) = composite_normal(context, debug_dst, *sprite_buf, plane_a, plane_b, context->regs[REG_BG_COLOR]) & 0x3F;
1372 debug_dst++;
1373 }
1374 } else {
1375 for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1376 {
1377 uint8_t sprite, plane_a, plane_b;
1378 plane_a = buf_a[plane_a_off & plane_a_mask];
1379 plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1380 *(dst++) = composite_normal(context, debug_dst, *sprite_buf, plane_a, plane_b, context->regs[REG_BG_COLOR]) & 0x3F;
1381 debug_dst++;
1382 }
1383 }
1384 }
1385
1386 static void render_highlight(vdp_context *context, int32_t col, uint8_t *dst, uint8_t *debug_dst, uint8_t *buf_a, int plane_a_off, int plane_a_mask, int plane_b_off)
1332 { 1387 {
1333 int start = 0; 1388 int start = 0;
1334 if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) { 1389 if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1335 uint32_t bgcolor = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; 1390 memset(dst, SHADOW_OFFSET + (context->regs[REG_BG_COLOR] & 0x3F), 8);
1336 for (int i = 0; i < 8; ++i) 1391 memset(debug_dst, DBG_SRC_BG | DBG_SHADOW, 8);
1337 { 1392 dst += 8;
1338 *(dst++) = bgcolor; 1393 debug_dst += 8;
1339 *(debug_dst++) = DBG_SRC_BG;
1340 }
1341 start = 8; 1394 start = 8;
1342 } 1395 }
1343 uint8_t *sprite_buf = context->linebuf + col * 8 + start; 1396 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) 1397 for (int i = start; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1345 { 1398 {
1346 uint8_t sprite, plane_a, plane_b; 1399 uint8_t sprite, plane_a, plane_b;
1347 plane_a = context->tmp_buf_a[plane_a_off & SCROLL_BUFFER_MASK]; 1400 plane_a = buf_a[plane_a_off & plane_a_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]; 1401 plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1374 sprite = *sprite_buf; 1402 sprite = *sprite_buf;
1375 sh_pixel pixel = composite_highlight(context, debug_dst, sprite, plane_a, plane_b, context->regs[REG_BG_COLOR]); 1403 sh_pixel pixel = composite_highlight(context, debug_dst, sprite, plane_a, plane_b, context->regs[REG_BG_COLOR]);
1376 uint32_t *colors; 1404 uint8_t final_pixel;
1377 if (pixel.intensity == BUF_BIT_PRIORITY << 1) { 1405 if (pixel.intensity == BUF_BIT_PRIORITY << 1) {
1378 colors = context->colors + HIGHLIGHT_OFFSET; 1406 final_pixel = (pixel.index & 0x3F) + HIGHLIGHT_OFFSET;
1379 } else if (pixel.intensity) { 1407 } else if (pixel.intensity) {
1380 colors = context->colors; 1408 final_pixel = pixel.index & 0x3F;
1381 } else { 1409 } else {
1382 colors = context->colors + SHADOW_OFFSET; 1410 final_pixel = (pixel.index & 0x3F) + SHADOW_OFFSET;
1383 } 1411 }
1384 debug_dst++; 1412 debug_dst++;
1385 *(dst++) = colors[pixel.index & 0x3F]; 1413 *(dst++) = final_pixel;
1386 } 1414 }
1387 } 1415 }
1388 1416
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) 1417 static void render_testreg(vdp_context *context, int32_t col, uint8_t *dst, uint8_t *debug_dst, uint8_t *buf_a, int plane_a_off, int plane_a_mask, int plane_b_off, uint8_t output_disabled, uint8_t test_layer)
1390 { 1418 {
1391 if (output_disabled) { 1419 if (output_disabled) {
1392 switch (test_layer) 1420 switch (test_layer)
1393 { 1421 {
1394 case 0: 1422 case 0:
1400 break; 1428 break;
1401 case 1: { 1429 case 1: {
1402 uint8_t *sprite_buf = context->linebuf + col * 8; 1430 uint8_t *sprite_buf = context->linebuf + col * 8;
1403 for (int i = 0; i < 16; i++) 1431 for (int i = 0; i < 16; i++)
1404 { 1432 {
1405 *(dst++) = context->colors[*(sprite_buf++) & 0x3F]; 1433 *(dst++) = *(sprite_buf++) & 0x3F;
1406 *(debug_dst++) = DBG_SRC_S; 1434 *(debug_dst++) = DBG_SRC_S;
1407 } 1435 }
1408 break; 1436 break;
1409 } 1437 }
1410 case 2: 1438 case 2:
1411 for (int i = 0; i < 16; i++) 1439 for (int i = 0; i < 16; i++)
1412 { 1440 {
1413 *(dst++) = context->colors[context->tmp_buf_a[(plane_a_off++) & SCROLL_BUFFER_MASK] & 0x3F]; 1441 *(dst++) = buf_a[(plane_a_off++) & plane_a_mask] & 0x3F;
1414 *(debug_dst++) = DBG_SRC_A; 1442 *(debug_dst++) = DBG_SRC_A;
1415 } 1443 }
1416 break; 1444 break;
1417 case 3: 1445 case 3:
1418 for (int i = 0; i < 16; i++) 1446 for (int i = 0; i < 16; i++)
1419 { 1447 {
1420 *(dst++) = context->colors[context->tmp_buf_b[(plane_b_off++) & SCROLL_BUFFER_MASK] & 0x3F]; 1448 *(dst++) = context->tmp_buf_b[(plane_b_off++) & SCROLL_BUFFER_MASK] & 0x3F;
1421 *(debug_dst++) = DBG_SRC_B; 1449 *(debug_dst++) = DBG_SRC_B;
1422 } 1450 }
1423 break; 1451 break;
1424 } 1452 }
1425 } else { 1453 } else {
1426 int start = 0; 1454 int start = 0;
1427 uint8_t *sprite_buf = context->linebuf + col * 8; 1455 uint8_t *sprite_buf = context->linebuf + col * 8;
1428 if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) { 1456 if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1429 //TODO: Confirm how test register interacts with column 0 blanking 1457 //TODO: Confirm how test register interacts with column 0 blanking
1430 uint8_t pixel = context->regs[REG_BG_COLOR] & 0x3F; 1458 uint8_t pixel = 0x3F;
1431 uint8_t src = DBG_SRC_BG; 1459 uint8_t src = DBG_SRC_BG;
1432 for (int i = 0; i < 8; ++i) 1460 for (int i = 0; i < 8; ++i)
1433 { 1461 {
1434 switch (test_layer) 1462 switch (test_layer)
1435 { 1463 {
1438 if (pixel) { 1466 if (pixel) {
1439 src = DBG_SRC_S; 1467 src = DBG_SRC_S;
1440 } 1468 }
1441 break; 1469 break;
1442 case 2: 1470 case 2:
1443 pixel &= context->tmp_buf_a[(plane_a_off + i) & SCROLL_BUFFER_MASK]; 1471 pixel &= buf_a[(plane_a_off + i) & plane_a_mask];
1444 if (pixel) { 1472 if (pixel) {
1445 src = DBG_SRC_A; 1473 src = DBG_SRC_A;
1446 } 1474 }
1447 break; 1475 break;
1448 case 3: 1476 case 3:
1451 src = DBG_SRC_B; 1479 src = DBG_SRC_B;
1452 } 1480 }
1453 break; 1481 break;
1454 } 1482 }
1455 1483
1456 *(dst++) = context->colors[pixel & 0x3F]; 1484 *(dst++) = pixel;
1457 *(debug_dst++) = src; 1485 *(debug_dst++) = src;
1458 } 1486 }
1459 plane_a_off += 8; 1487 plane_a_off += 8;
1460 plane_b_off += 8; 1488 plane_b_off += 8;
1461 sprite_buf += 8; 1489 sprite_buf += 8;
1462 start = 8; 1490 start = 8;
1463 } 1491 }
1464 for (int i = start; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) 1492 for (int i = start; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1465 { 1493 {
1466 uint8_t sprite, plane_a, plane_b; 1494 uint8_t sprite, plane_a, plane_b;
1467 plane_a = context->tmp_buf_a[plane_a_off & SCROLL_BUFFER_MASK]; 1495 plane_a = buf_a[plane_a_off & plane_a_mask];
1468 plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK]; 1496 plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1469 sprite = *sprite_buf; 1497 sprite = *sprite_buf;
1470 uint8_t pixel = composite_normal(context, debug_dst, sprite, plane_a, plane_b, 0x3F); 1498 uint8_t pixel = composite_normal(context, debug_dst, sprite, plane_a, plane_b, 0x3F) & 0x3F;
1471 switch (test_layer) 1499 switch (test_layer)
1472 { 1500 {
1473 case 1: 1501 case 1:
1474 pixel &= sprite; 1502 pixel &= sprite;
1475 if (pixel) { 1503 if (pixel) {
1488 *debug_dst = DBG_SRC_B; 1516 *debug_dst = DBG_SRC_B;
1489 } 1517 }
1490 break; 1518 break;
1491 } 1519 }
1492 debug_dst++; 1520 debug_dst++;
1493 *(dst++) = context->colors[pixel & 0x3F]; 1521 *(dst++) = pixel;
1494 } 1522 }
1495 } 1523 }
1496 } 1524 }
1497 1525
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) 1526 static void render_testreg_highlight(vdp_context *context, int32_t col, uint8_t *dst, uint8_t *debug_dst, uint8_t *buf_a, int plane_a_off, int plane_a_mask, int plane_b_off, uint8_t output_disabled, uint8_t test_layer)
1499 { 1527 {
1500 int start = 0; 1528 int start = 0;
1501 uint8_t *sprite_buf = context->linebuf + col * 8; 1529 uint8_t *sprite_buf = context->linebuf + col * 8;
1502 if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) { 1530 if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1503 //TODO: Confirm how test register interacts with column 0 blanking 1531 //TODO: Confirm how test register interacts with column 0 blanking
1504 uint8_t pixel = context->regs[REG_BG_COLOR] & 0x3F; 1532 uint8_t pixel = 0x3F;
1505 uint8_t src = DBG_SRC_BG | DBG_SHADOW; 1533 uint8_t src = DBG_SRC_BG | DBG_SHADOW;
1506 for (int i = 0; i < 8; ++i) 1534 for (int i = 0; i < 8; ++i)
1507 { 1535 {
1508 switch (test_layer) 1536 switch (test_layer)
1509 { 1537 {
1512 if (pixel) { 1540 if (pixel) {
1513 src = DBG_SRC_S | DBG_SHADOW; 1541 src = DBG_SRC_S | DBG_SHADOW;
1514 } 1542 }
1515 break; 1543 break;
1516 case 2: 1544 case 2:
1517 pixel &= context->tmp_buf_a[(plane_a_off + i) & SCROLL_BUFFER_MASK]; 1545 pixel &= buf_a[(plane_a_off + i) & plane_a_mask];
1518 if (pixel) { 1546 if (pixel) {
1519 src = DBG_SRC_A | DBG_SHADOW; 1547 src = DBG_SRC_A | DBG_SHADOW;
1520 } 1548 }
1521 break; 1549 break;
1522 case 3: 1550 case 3:
1525 src = DBG_SRC_B | DBG_SHADOW; 1553 src = DBG_SRC_B | DBG_SHADOW;
1526 } 1554 }
1527 break; 1555 break;
1528 } 1556 }
1529 1557
1530 *(dst++) = context->colors[SHADOW_OFFSET + (pixel & 0x3F)]; 1558 *(dst++) = SHADOW_OFFSET + pixel;
1531 *(debug_dst++) = src; 1559 *(debug_dst++) = src;
1532 } 1560 }
1533 plane_a_off += 8; 1561 plane_a_off += 8;
1534 plane_b_off += 8; 1562 plane_b_off += 8;
1535 sprite_buf += 8; 1563 sprite_buf += 8;
1536 start = 8; 1564 start = 8;
1537 } 1565 }
1538 for (int i = start; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) 1566 for (int i = start; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1539 { 1567 {
1540 uint8_t sprite, plane_a, plane_b; 1568 uint8_t sprite, plane_a, plane_b;
1541 plane_a = context->tmp_buf_a[plane_a_off & SCROLL_BUFFER_MASK]; 1569 plane_a = buf_a[plane_a_off & plane_a_mask];
1542 plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK]; 1570 plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1543 sprite = *sprite_buf; 1571 sprite = *sprite_buf;
1544 sh_pixel pixel = composite_highlight(context, debug_dst, sprite, plane_a, plane_b, 0x3F); 1572 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) { 1573 if (output_disabled) {
1554 pixel.index = 0x3F; 1574 pixel.index = 0x3F;
1575 } else {
1576 pixel.index &= 0x3F;
1555 } 1577 }
1556 switch (test_layer) 1578 switch (test_layer)
1557 { 1579 {
1558 case 1: 1580 case 1:
1559 pixel.index &= sprite; 1581 pixel.index &= sprite;
1572 if (pixel.index) { 1594 if (pixel.index) {
1573 *debug_dst = DBG_SRC_B; 1595 *debug_dst = DBG_SRC_B;
1574 } 1596 }
1575 break; 1597 break;
1576 } 1598 }
1599 if (pixel.intensity == BUF_BIT_PRIORITY << 1) {
1600 pixel.index += HIGHLIGHT_OFFSET;
1601 } else if (!pixel.intensity) {
1602 pixel.index += SHADOW_OFFSET;
1603 }
1577 debug_dst++; 1604 debug_dst++;
1578 *(dst++) = colors[pixel.index & 0x3F]; 1605 *(dst++) = pixel.index;
1579 } 1606 }
1580 } 1607 }
1581 1608
1582 static void render_map_output(uint32_t line, int32_t col, vdp_context * context) 1609 static void render_map_output(uint32_t line, int32_t col, vdp_context * context)
1583 { 1610 {
1584 uint32_t *dst; 1611 uint8_t *dst;
1585 uint8_t *debug_dst; 1612 uint8_t *debug_dst;
1586 uint8_t output_disabled = (context->test_port & TEST_BIT_DISABLE) != 0; 1613 uint8_t output_disabled = (context->test_port & TEST_BIT_DISABLE) != 0;
1587 uint8_t test_layer = context->test_port >> 7 & 3; 1614 uint8_t test_layer = context->test_port >> 7 & 3;
1588 if (context->state == PREPARING && !test_layer) { 1615 if (context->state == PREPARING && !test_layer) {
1589 if (col) { 1616 if (col) {
1590 col -= 2; 1617 col -= 2;
1591 dst = context->output + BORDER_LEFT + col * 8; 1618 dst = context->compositebuf + BORDER_LEFT + col * 8;
1592 } else { 1619 } else {
1593 dst = context->output; 1620 dst = context->compositebuf;
1594 uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; 1621 uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
1595 for (int i = 0; i < BORDER_LEFT; i++, dst++) 1622 memset(dst, 0, BORDER_LEFT);
1596 { 1623 context->done_composite = dst + BORDER_LEFT;
1597 *dst = bg_color;
1598 }
1599 context->done_output = dst;
1600 return; 1624 return;
1601 } 1625 }
1602 uint32_t color = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; 1626 memset(dst, 0, 16);
1603 for (int i = 0; i < 16; i++) 1627 context->done_composite = dst + 16;
1604 {
1605 *(dst++) = color;
1606 }
1607 context->done_output = dst;
1608 return; 1628 return;
1609 } 1629 }
1610 line &= 0xFF; 1630 line &= 0xFF;
1611 render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context); 1631 render_map(context->col_2, context->tmp_buf_b, context->buf_b_off+8, context);
1612 uint8_t *sprite_buf; 1632 uint8_t *sprite_buf;
1613 uint8_t sprite, plane_a, plane_b; 1633 uint8_t sprite, plane_a, plane_b;
1614 int plane_a_off, plane_b_off; 1634 int plane_a_off, plane_b_off;
1615 if (col) 1635 if (col)
1616 { 1636 {
1617 col-=2; 1637 col-=2;
1618 dst = context->output + BORDER_LEFT + col * 8; 1638 dst = context->compositebuf + BORDER_LEFT + col * 8;
1619 debug_dst = context->layer_debug_buf + BORDER_LEFT + col * 8; 1639 debug_dst = context->layer_debug_buf + BORDER_LEFT + col * 8;
1620 1640
1621 1641
1622 uint8_t a_src, src; 1642 uint8_t a_src, src;
1643 uint8_t *buf_a;
1644 int plane_a_mask;
1623 if (context->flags & FLAG_WINDOW) { 1645 if (context->flags & FLAG_WINDOW) {
1624 plane_a_off = context->buf_a_off; 1646 plane_a_off = context->buf_a_off;
1647 buf_a = context->tmp_buf_a;
1625 a_src = DBG_SRC_W; 1648 a_src = DBG_SRC_W;
1649 plane_a_mask = SCROLL_BUFFER_MASK;
1626 } else { 1650 } else {
1627 plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF); 1651 if (context->flags & FLAG_WINDOW_EDGE) {
1652 buf_a = context->tmp_buf_a + context->buf_a_off;
1653 plane_a_mask = 15;
1654 plane_a_off = -context->hscroll_a_fine;
1655 } else {
1656 plane_a_off = context->buf_a_off - context->hscroll_a_fine;
1657 plane_a_mask = SCROLL_BUFFER_MASK;
1658 buf_a = context->tmp_buf_a;
1659 }
1628 a_src = DBG_SRC_A; 1660 a_src = DBG_SRC_A;
1629 } 1661 }
1630 plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF); 1662 plane_a_off &= plane_a_mask;
1663 plane_b_off = context->buf_b_off - context->hscroll_b_fine;
1631 //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7)); 1664 //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7));
1632 1665
1633 if (context->regs[REG_MODE_4] & BIT_HILIGHT) { 1666 if (context->regs[REG_MODE_4] & BIT_HILIGHT) {
1634 if (output_disabled || test_layer) { 1667 if (output_disabled || test_layer) {
1635 render_testreg_highlight(context, col, dst, debug_dst, plane_a_off, plane_b_off, output_disabled, test_layer); 1668 render_testreg_highlight(context, col, dst, debug_dst, buf_a, plane_a_off, plane_a_mask, plane_b_off, output_disabled, test_layer);
1636 } else { 1669 } else {
1637 render_highlight(context, col, dst, debug_dst, plane_a_off, plane_b_off); 1670 render_highlight(context, col, dst, debug_dst, buf_a, plane_a_off, plane_a_mask, plane_b_off);
1638 } 1671 }
1639 } else { 1672 } else {
1640 if (output_disabled || test_layer) { 1673 if (output_disabled || test_layer) {
1641 render_testreg(context, col, dst, debug_dst, plane_a_off, plane_b_off, output_disabled, test_layer); 1674 render_testreg(context, col, dst, debug_dst, buf_a, plane_a_off, plane_a_mask, plane_b_off, output_disabled, test_layer);
1642 } else { 1675 } else {
1643 render_normal(context, col, dst, debug_dst, plane_a_off, plane_b_off); 1676 render_normal(context, col, dst, debug_dst, buf_a, plane_a_off, plane_a_mask, plane_b_off);
1644 } 1677 }
1645 } 1678 }
1646 dst += 16; 1679 dst += 16;
1647 } else { 1680 } else {
1648 dst = context->output; 1681 dst = context->compositebuf;
1649 debug_dst = context->layer_debug_buf; 1682 debug_dst = context->layer_debug_buf;
1650 uint8_t pixel = context->regs[REG_BG_COLOR] & 0x3F; 1683 uint8_t pixel = 0;
1651 if (output_disabled) { 1684 if (output_disabled) {
1652 pixel = 0x3F; 1685 pixel = 0x3F;
1653 } 1686 }
1654 uint32_t bg_color = context->colors[pixel];
1655 if (test_layer) { 1687 if (test_layer) {
1656 switch(test_layer) 1688 switch(test_layer)
1657 { 1689 {
1658 case 1: 1690 case 1:
1659 bg_color = context->colors[0]; 1691 memset(dst, 0, BORDER_LEFT);
1660 for (int i = 0; i < BORDER_LEFT; i++, dst++, debug_dst++) 1692 memset(debug_dst, DBG_SRC_BG, BORDER_LEFT);
1661 { 1693 dst += BORDER_LEFT;
1662 *dst = bg_color;
1663 *debug_dst = DBG_SRC_BG;
1664
1665 }
1666 break; 1694 break;
1667 case 2: { 1695 case 2: {
1668 //plane A 1696 //plane A
1669 //TODO: Deal with Window layer 1697 //TODO: Deal with Window layer
1670 int i; 1698 int i;
1671 i = 0; 1699 i = 0;
1672 uint8_t buf_off = context->buf_a_off - (context->hscroll_a & 0xF) + (16 - BORDER_LEFT); 1700 uint8_t buf_off = context->buf_a_off - context->hscroll_a_fine + (16 - BORDER_LEFT);
1673 //uint8_t *src = context->tmp_buf_a + ((context->buf_a_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_a & 0xF))) & SCROLL_BUFFER_MASK); 1701 //uint8_t *src = context->tmp_buf_a + ((context->buf_a_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_a & 0xF))) & SCROLL_BUFFER_MASK);
1674 for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++) 1702 for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++)
1675 { 1703 {
1676 *dst = context->colors[context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK]]; 1704 *dst = context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK];
1677 *debug_dst = DBG_SRC_A; 1705 *debug_dst = DBG_SRC_A;
1678 } 1706 }
1679 break; 1707 break;
1680 } 1708 }
1681 case 3: { 1709 case 3: {
1682 //plane B 1710 //plane B
1683 int i; 1711 int i;
1684 i = 0; 1712 i = 0;
1685 uint8_t buf_off = context->buf_b_off - (context->hscroll_b & 0xF) + (16 - BORDER_LEFT); 1713 uint8_t buf_off = context->buf_b_off - context->hscroll_b_fine + (16 - BORDER_LEFT);
1686 //uint8_t *src = context->tmp_buf_b + ((context->buf_b_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_b & 0xF))) & SCROLL_BUFFER_MASK); 1714 //uint8_t *src = context->tmp_buf_b + ((context->buf_b_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_b & 0xF))) & SCROLL_BUFFER_MASK);
1687 for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++) 1715 for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++)
1688 { 1716 {
1689 *dst = context->colors[context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK]]; 1717 *dst = context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK];
1690 *debug_dst = DBG_SRC_B; 1718 *debug_dst = DBG_SRC_B;
1691 } 1719 }
1692 break; 1720 break;
1693 } 1721 }
1694 } 1722 }
1695 } else { 1723 } else {
1696 for (int i = 0; i < BORDER_LEFT; i++, dst++, debug_dst++) 1724 memset(dst, pixel, BORDER_LEFT);
1697 { 1725 memset(debug_dst, DBG_SRC_BG, BORDER_LEFT);
1698 *dst = bg_color; 1726 dst += BORDER_LEFT;
1699 *debug_dst = DBG_SRC_BG; 1727 }
1700 } 1728 }
1701 } 1729 context->done_composite = dst;
1702 }
1703 context->done_output = dst;
1704 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; 1730 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
1705 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; 1731 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
1706 } 1732 }
1707 1733
1708 static void render_map_mode4(uint32_t line, int32_t col, vdp_context * context) 1734 static void render_map_mode4(uint32_t line, int32_t col, vdp_context * context)
1743 { 1769 {
1744 *dst = (pixels >> i & 0xF) | pal_priority; 1770 *dst = (pixels >> i & 0xF) | pal_priority;
1745 } 1771 }
1746 context->buf_a_off = (context->buf_a_off + 8) & 15; 1772 context->buf_a_off = (context->buf_a_off + 8) & 15;
1747 1773
1748 uint8_t bgcolor = 0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET; 1774 uint8_t *dst = context->compositebuf + 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; 1775 uint8_t *debug_dst = context->layer_debug_buf + col * 8 + BORDER_LEFT;
1751 if (context->state == PREPARING) { 1776 if (context->state == PREPARING) {
1752 for (int i = 0; i < 16; i++) 1777 memset(dst, 0x10 + (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET, 8);
1753 { 1778 memset(debug_dst, DBG_SRC_BG, 8);
1754 *(dst++) = context->colors[bgcolor]; 1779 context->done_composite = dst + 8;
1755 }
1756 context->done_output = dst;
1757 return; 1780 return;
1758 } 1781 }
1759 1782
1760 if (col || !(context->regs[REG_MODE_1] & BIT_COL0_MASK)) { 1783 if (col || !(context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1761 uint8_t *sprite_src = context->linebuf + col * 8; 1784 uint8_t *sprite_src = context->linebuf + col * 8;
1765 for (int i = 0; i < 8; i++, sprite_src++) 1788 for (int i = 0; i < 8; i++, sprite_src++)
1766 { 1789 {
1767 uint8_t *bg_src = context->tmp_buf_a + ((8 + i + col * 8 - (context->hscroll_a & 0x7)) & 15); 1790 uint8_t *bg_src = context->tmp_buf_a + ((8 + i + col * 8 - (context->hscroll_a & 0x7)) & 15);
1768 if ((*bg_src & 0x4F) > 0x40 || !*sprite_src) { 1791 if ((*bg_src & 0x4F) > 0x40 || !*sprite_src) {
1769 //background plane has priority and is opaque or sprite layer is transparent 1792 //background plane has priority and is opaque or sprite layer is transparent
1770 *(dst++) = context->colors[(*bg_src & 0x1F) + MODE4_OFFSET]; 1793 uint8_t pixel = *bg_src & 0x1F;
1771 *(debug_dst++) = DBG_SRC_A; 1794 *(dst++) = pixel + MODE4_OFFSET;
1795 *(debug_dst++) = pixel ? DBG_SRC_A : DBG_SRC_BG;
1772 } else { 1796 } else {
1773 //sprite layer is opaque and not covered by high priority BG pixels 1797 //sprite layer is opaque and not covered by high priority BG pixels
1774 *(dst++) = context->colors[*sprite_src | 0x10 + MODE4_OFFSET]; 1798 *(dst++) = (*sprite_src | 0x10) + MODE4_OFFSET;
1775 *(debug_dst++) = DBG_SRC_S; 1799 *(debug_dst++) = DBG_SRC_S;
1776 } 1800 }
1777 } 1801 }
1778 } else { 1802 context->done_composite = dst;
1779 for (int i = 0; i < 8; i++) 1803 } else {
1780 { 1804 memset(dst, 0x10 + (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET, 8);
1781 *(dst++) = context->colors[bgcolor]; 1805 memset(debug_dst, DBG_SRC_BG, 8);
1782 *(debug_dst++) = DBG_SRC_BG; 1806 context->done_composite = dst + 8;
1783 } 1807 }
1784 }
1785 context->done_output = dst;
1786 } 1808 }
1787 1809
1788 static uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19}; 1810 static uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19};
1789 1811
1790 static void vdp_advance_line(vdp_context *context) 1812 static void vdp_advance_line(vdp_context *context)
1834 } else { 1856 } else {
1835 line += context->border_top; 1857 line += context->border_top;
1836 } 1858 }
1837 if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) { 1859 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); 1860 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++) 1861 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
1840 { 1862 for (int i = 0; i < 64; i++)
1841 for (int x = 0; x < 8; x++)
1842 { 1863 {
1843 *(fb++) = context->colors[i]; 1864 for (int x = 0; x < 8; x++)
1865 {
1866 *(fb++) = context->colors[i];
1867 }
1868 }
1869 } else {
1870 for (int i = MODE4_OFFSET; i < MODE4_OFFSET+32; i++)
1871 {
1872 for (int x = 0; x < 16; x++)
1873 {
1874 *(fb++) = context->colors[i];
1875 }
1844 } 1876 }
1845 } 1877 }
1846 } 1878 }
1847 if ( 1879 if (
1848 context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE) 1880 context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE)
2013 2045
2014 if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) { 2046 if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) {
2015 uint32_t starting_line = 512 - 32*4; 2047 uint32_t starting_line = 512 - 32*4;
2016 uint32_t *line = context->debug_fbs[VDP_DEBUG_CRAM] 2048 uint32_t *line = context->debug_fbs[VDP_DEBUG_CRAM]
2017 + context->debug_fb_pitch[VDP_DEBUG_CRAM] * starting_line / sizeof(uint32_t); 2049 + context->debug_fb_pitch[VDP_DEBUG_CRAM] * starting_line / sizeof(uint32_t);
2018 for (int pal = 0; pal < 4; pal ++) 2050 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
2019 { 2051 for (int pal = 0; pal < 4; pal ++)
2020 uint32_t *cur;
2021 for (int y = 0; y < 31; y++)
2022 { 2052 {
2053 uint32_t *cur;
2054 for (int y = 0; y < 31; y++)
2055 {
2056 cur = line;
2057 for (int offset = 0; offset < 16; offset++)
2058 {
2059 for (int x = 0; x < 31; x++)
2060 {
2061 *(cur++) = context->colors[pal * 16 + offset];
2062 }
2063 *(cur++) = 0xFF000000;
2064 }
2065 line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t);
2066 }
2023 cur = line; 2067 cur = line;
2024 for (int offset = 0; offset < 16; offset++) 2068 for (int x = 0; x < 512; x++)
2025 { 2069 {
2026 for (int x = 0; x < 31; x++) 2070 *(cur++) = 0xFF000000;
2071 }
2072 line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t);
2073 }
2074 } else {
2075 for (int pal = 0; pal < 2; pal ++)
2076 {
2077 uint32_t *cur;
2078 for (int y = 0; y < 31; y++)
2079 {
2080 cur = line;
2081 for (int offset = MODE4_OFFSET; offset < MODE4_OFFSET + 16; offset++)
2027 { 2082 {
2028 *(cur++) = context->colors[pal * 16 + offset]; 2083 for (int x = 0; x < 31; x++)
2084 {
2085 *(cur++) = context->colors[pal * 16 + offset];
2086 }
2087 *(cur++) = 0xFF000000;
2029 } 2088 }
2089 line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t);
2090 }
2091 cur = line;
2092 for (int x = 0; x < 512; x++)
2093 {
2030 *(cur++) = 0xFF000000; 2094 *(cur++) = 0xFF000000;
2031 } 2095 }
2032 line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t); 2096 line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t);
2033 } 2097 }
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 } 2098 }
2041 render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_CRAM], 512); 2099 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]); 2100 context->debug_fbs[VDP_DEBUG_CRAM] = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_CRAM], &context->debug_fb_pitch[VDP_DEBUG_CRAM]);
2043 } 2101 }
2044 if (context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE)) { 2102 if (context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE)) {
2047 } 2105 }
2048 } 2106 }
2049 2107
2050 void vdp_force_update_framebuffer(vdp_context *context) 2108 void vdp_force_update_framebuffer(vdp_context *context)
2051 { 2109 {
2052 uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL) 2110 if (!context->fb) {
2053 ? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL 2111 return;
2054 : 224 + BORDER_TOP_V28 + BORDER_BOT_V28; 2112 }
2113 uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top;
2055 2114
2056 uint16_t to_fill = lines_max - context->output_lines; 2115 uint16_t to_fill = lines_max - context->output_lines;
2057 memset( 2116 memset(
2058 ((char *)context->fb) + context->output_pitch * context->output_lines, 2117 ((char *)context->fb) + context->output_pitch * context->output_lines,
2059 0, 2118 0,
2064 vdp_update_per_frame_debug(context); 2123 vdp_update_per_frame_debug(context);
2065 } 2124 }
2066 2125
2067 static void advance_output_line(vdp_context *context) 2126 static void advance_output_line(vdp_context *context)
2068 { 2127 {
2069 if (headless) { 2128 //This function is kind of gross because of the need to deal with vertical border busting via mode changes
2070 if (context->vcounter == context->inactive_start) { 2129 uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top;
2071 context->frame++; 2130 uint32_t output_line = context->vcounter;
2072 } 2131 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) {
2073 context->vcounter &= 0x1FF; 2132 //vcounter increment occurs much later in Mode 4
2074 } else { 2133 output_line++;
2075 uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL) 2134 }
2076 ? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL 2135
2077 : 224 + BORDER_TOP_V28 + BORDER_BOT_V28; 2136 if (context->output_lines >= lines_max || (!context->pushed_frame && output_line == context->inactive_start + context->border_top)) {
2078 2137 //we've either filled up a full frame or we're at the bottom of screen in the current defined mode + border crop
2079 if (context->output_lines == lines_max) { 2138 if (!headless) {
2080 render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER)); 2139 render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER));
2081 context->cur_buffer = context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD; 2140 uint8_t is_even = context->flags2 & FLAG2_EVEN_FIELD;
2082 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch); 2141 if (context->vcounter <= context->inactive_start && (context->regs[REG_MODE_4] & BIT_INTERLACE)) {
2083 vdp_update_per_frame_debug(context); 2142 is_even = !is_even;
2084 context->h40_lines = 0; 2143 }
2085 context->frame++; 2144 context->cur_buffer = is_even ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD;
2145 context->pushed_frame = 1;
2146 context->fb = NULL;
2147 }
2148 vdp_update_per_frame_debug(context);
2149 context->h40_lines = 0;
2150 context->frame++;
2151 context->output_lines = 0;
2152 }
2153
2154 if (output_line < context->inactive_start + context->border_bot) {
2155 if (context->output_lines) {
2156 output_line = context->output_lines++;//context->border_top + context->vcounter;
2157 } else if (!output_line && !context->border_top) {
2158 //top border is completely cropped so we won't hit the case below
2159 output_line = 0;
2160 context->output_lines = 1;
2161 context->pushed_frame = 0;
2162 } else {
2163 context->output_lines = output_line + 1;
2164 }
2165 } else if (output_line >= 0x200 - context->border_top) {
2166 if (output_line == 0x200 - context->border_top) {
2167 //We're at the top of the display, force context->output_lines to be zero to avoid
2168 //potential screen rolling if the mode is changed at an inopportune time
2086 context->output_lines = 0; 2169 context->output_lines = 0;
2087 } 2170 context->pushed_frame = 0;
2088 uint32_t output_line = context->vcounter; 2171 }
2089 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) { 2172 output_line = context->output_lines++;//context->vcounter - (0x200 - context->border_top);
2090 //vcounter increment occurs much later in Mode 4 2173 } else {
2091 output_line++; 2174 context->output = NULL;
2092 } 2175 return;
2093 if (output_line < context->inactive_start + context->border_bot && context->output_lines > 0) { 2176 }
2094 output_line = context->output_lines++;//context->border_top + context->vcounter; 2177 if (!context->fb) {
2095 } else if (output_line >= 0x200 - context->border_top) { 2178 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch);
2096 if (output_line == 0x200 - context->border_top) { 2179 }
2097 //We're at the top of the display, force context->output_lines to be zero to avoid 2180 output_line += context->top_offset;
2098 //potential screen rolling if the mode is changed at an inopportune time 2181 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * output_line);
2099 context->output_lines = 0;
2100 }
2101 output_line = context->output_lines++;//context->vcounter - (0x200 - context->border_top);
2102 } else {
2103 output_line = INVALID_LINE;
2104 }
2105 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * output_line);
2106 context->done_output = context->output;
2107 #ifdef DEBUG_FB_FILL 2182 #ifdef DEBUG_FB_FILL
2108 for (int i = 0; i < LINEBUF_SIZE; i++) 2183 for (int i = 0; i < LINEBUF_SIZE; i++)
2109 { 2184 {
2110 context->output[i] = 0xFFFF00FF; 2185 context->output[i] = 0xFFFF00FF;
2111 } 2186 }
2112 #endif 2187 #endif
2113 if (output_line != INVALID_LINE && (context->regs[REG_MODE_4] & BIT_H40)) { 2188 if (context->output && (context->regs[REG_MODE_4] & BIT_H40)) {
2114 context->h40_lines++; 2189 context->h40_lines++;
2115 }
2116 } 2190 }
2117 } 2191 }
2118 2192
2119 void vdp_release_framebuffer(vdp_context *context) 2193 void vdp_release_framebuffer(vdp_context *context)
2120 { 2194 {
2121 render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER)); 2195 if (context->fb) {
2122 context->output = context->fb = NULL; 2196 render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER));
2197 context->output = context->fb = NULL;
2198 }
2123 } 2199 }
2124 2200
2125 void vdp_reacquire_framebuffer(vdp_context *context) 2201 void vdp_reacquire_framebuffer(vdp_context *context)
2126 { 2202 {
2127 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch); 2203 uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top;
2128 uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL)
2129 ? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL
2130 : 224 + BORDER_TOP_V28 + BORDER_BOT_V28;
2131 if (context->output_lines <= lines_max && context->output_lines > 0) { 2204 if (context->output_lines <= lines_max && context->output_lines > 0) {
2132 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * (context->output_lines - 1)); 2205 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch);
2133 } else { 2206 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * (context->output_lines - 1 + context->top_offset));
2134 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * INVALID_LINE); 2207 } else {
2208 context->output = NULL;
2135 } 2209 }
2136 } 2210 }
2137 2211
2138 static void render_border_garbage(vdp_context *context, uint32_t address, uint8_t *buf, uint8_t buf_off, uint16_t col) 2212 static void render_border_garbage(vdp_context *context, uint32_t address, uint8_t *buf, uint8_t buf_off, uint16_t col)
2139 { 2213 {
2146 } 2220 }
2147 } 2221 }
2148 2222
2149 static void draw_right_border(vdp_context *context) 2223 static void draw_right_border(vdp_context *context)
2150 { 2224 {
2151 uint32_t *dst = context->output + BORDER_LEFT + ((context->regs[REG_MODE_4] & BIT_H40) ? 320 : 256); 2225 uint8_t *dst = context->compositebuf + BORDER_LEFT + ((context->regs[REG_MODE_4] & BIT_H40) ? 320 : 256);
2152 uint8_t pixel = context->regs[REG_BG_COLOR] & 0x3F; 2226 uint8_t pixel = context->regs[REG_BG_COLOR] & 0x3F;
2153 if ((context->test_port & TEST_BIT_DISABLE) != 0) { 2227 if ((context->test_port & TEST_BIT_DISABLE) != 0) {
2154 pixel = 0x3F; 2228 pixel = 0x3F;
2155 } 2229 }
2156 uint32_t bg_color = context->colors[pixel];
2157 uint8_t test_layer = context->test_port >> 7 & 3; 2230 uint8_t test_layer = context->test_port >> 7 & 3;
2158 if (test_layer) { 2231 if (test_layer) {
2159 switch(test_layer) 2232 switch(test_layer)
2160 { 2233 {
2161 case 1: 2234 case 1:
2162 bg_color = context->colors[0]; 2235 memset(dst, 0, BORDER_RIGHT);
2163 for (int i = 0; i < BORDER_RIGHT; i++, dst++) 2236 dst += BORDER_RIGHT;
2164 {
2165 *dst = bg_color;
2166 }
2167 break; 2237 break;
2168 case 2: { 2238 case 2: {
2169 //plane A 2239 //plane A
2170 //TODO: Deal with Window layer 2240 //TODO: Deal with Window layer
2171 int i; 2241 int i;
2172 i = 0; 2242 i = 0;
2173 uint8_t buf_off = context->buf_a_off - (context->hscroll_a & 0xF); 2243 uint8_t buf_off = context->buf_a_off - context->hscroll_a_fine;
2174 //uint8_t *src = context->tmp_buf_a + ((context->buf_a_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_a & 0xF))) & SCROLL_BUFFER_MASK); 2244 //uint8_t *src = context->tmp_buf_a + ((context->buf_a_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_a & 0xF))) & SCROLL_BUFFER_MASK);
2175 for (; i < BORDER_RIGHT; buf_off++, i++, dst++) 2245 for (; i < BORDER_RIGHT; buf_off++, i++, dst++)
2176 { 2246 {
2177 *dst = context->colors[context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK] & 0x3F]; 2247 *dst = context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK] & 0x3F;
2178 } 2248 }
2179 break; 2249 break;
2180 } 2250 }
2181 case 3: { 2251 case 3: {
2182 //plane B 2252 //plane B
2184 i = 0; 2254 i = 0;
2185 uint8_t buf_off = context->buf_b_off - (context->hscroll_b & 0xF); 2255 uint8_t buf_off = context->buf_b_off - (context->hscroll_b & 0xF);
2186 //uint8_t *src = context->tmp_buf_b + ((context->buf_b_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_b & 0xF))) & SCROLL_BUFFER_MASK); 2256 //uint8_t *src = context->tmp_buf_b + ((context->buf_b_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_b & 0xF))) & SCROLL_BUFFER_MASK);
2187 for (; i < BORDER_RIGHT; buf_off++, i++, dst++) 2257 for (; i < BORDER_RIGHT; buf_off++, i++, dst++)
2188 { 2258 {
2189 *dst = context->colors[context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK] & 0x3F]; 2259 *dst = context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK] & 0x3F;
2190 } 2260 }
2191 break; 2261 break;
2192 } 2262 }
2193 } 2263 }
2194 } else { 2264 } else {
2195 for (int i = 0; i < BORDER_RIGHT; i++, dst++) 2265 memset(dst, 0, BORDER_RIGHT);
2196 { 2266 dst += BORDER_RIGHT;
2197 *dst = bg_color; 2267 }
2198 } 2268 context->done_composite = dst;
2199 }
2200 context->done_output = dst;
2201 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; 2269 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
2202 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; 2270 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
2203 } 2271 }
2204 2272
2205 #define CHECK_ONLY if (context->cycles >= target_cycles) { return; } 2273 #define CHECK_ONLY if (context->cycles >= target_cycles) { return; }
2206 #define CHECK_LIMIT if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } context->hslot++; context->cycles += slot_cycles; CHECK_ONLY 2274 #define CHECK_LIMIT if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } context->hslot++; context->cycles += slot_cycles; CHECK_ONLY
2275 #define OUTPUT_PIXEL(slot) if ((slot) >= BG_START_SLOT) {\
2276 uint8_t *src = context->compositebuf + ((slot) - BG_START_SLOT) *2;\
2277 uint32_t *dst = context->output + ((slot) - BG_START_SLOT) *2;\
2278 if ((*src & 0x3F) | test_layer) {\
2279 *(dst++) = context->colors[*(src++)];\
2280 } else {\
2281 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];\
2282 }\
2283 if ((*src & 0x3F) | test_layer) {\
2284 *(dst++) = context->colors[*(src++)];\
2285 } else {\
2286 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];\
2287 }\
2288 }
2289
2290 #define OUTPUT_PIXEL_H40(slot) if (slot <= (BG_START_SLOT + LINEBUF_SIZE/2)) {\
2291 uint8_t *src = context->compositebuf + (slot - BG_START_SLOT) *2;\
2292 uint32_t *dst = context->output + (slot - BG_START_SLOT) *2;\
2293 if ((*src & 0x3F) | test_layer) {\
2294 *(dst++) = context->colors[*(src++)];\
2295 } else {\
2296 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];\
2297 }\
2298 if (slot != (BG_START_SLOT + LINEBUF_SIZE/2)) {\
2299 if ((*src & 0x3F) | test_layer) {\
2300 *(dst++) = context->colors[*(src++)];\
2301 } else {\
2302 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];\
2303 }\
2304 }\
2305 }
2306
2307 #define OUTPUT_PIXEL_H32(slot) if (slot <= (BG_START_SLOT + (256+HORIZ_BORDER)/2)) {\
2308 uint8_t *src = context->compositebuf + (slot - BG_START_SLOT) *2;\
2309 uint32_t *dst = context->output + (slot - BG_START_SLOT) *2;\
2310 if ((*src & 0x3F) | test_layer) {\
2311 *(dst++) = context->colors[*(src++)];\
2312 } else {\
2313 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];\
2314 }\
2315 if (slot != (BG_START_SLOT + (256+HORIZ_BORDER)/2)) {\
2316 if ((*src & 0x3F) | test_layer) {\
2317 *(dst++) = context->colors[*(src++)];\
2318 } else {\
2319 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];\
2320 }\
2321 }\
2322 }
2323
2324 //BG_START_SLOT => dst = 0, src = border
2325 //BG_START_SLOT + 13/2=6, dst = 6, src = border + comp + 13
2326 #define OUTPUT_PIXEL_MODE4(slot) if ((slot) >= BG_START_SLOT) {\
2327 uint8_t *src = context->compositebuf + ((slot) - BG_START_SLOT) *2;\
2328 uint32_t *dst = context->output + ((slot) - BG_START_SLOT) *2;\
2329 if ((slot) - BG_START_SLOT < BORDER_LEFT/2) {\
2330 *(dst++) = context->colors[bgindex];\
2331 *(dst++) = context->colors[bgindex];\
2332 } else if ((slot) - BG_START_SLOT < (BORDER_LEFT+256)/2){\
2333 if ((slot) - BG_START_SLOT == BORDER_LEFT/2) {\
2334 *(dst++) = context->colors[bgindex];\
2335 src++;\
2336 } else {\
2337 *(dst++) = context->colors[*(src++)];\
2338 }\
2339 *(dst++) = context->colors[*(src++)];\
2340 } else if ((slot) - BG_START_SLOT <= (HORIZ_BORDER+256)/2) {\
2341 *(dst++) = context->colors[bgindex];\
2342 if ((slot) - BG_START_SLOT < (HORIZ_BORDER+256)/2) {\
2343 *(dst++) = context->colors[bgindex];\
2344 }\
2345 }\
2346 }
2207 2347
2208 #define COLUMN_RENDER_BLOCK(column, startcyc) \ 2348 #define COLUMN_RENDER_BLOCK(column, startcyc) \
2209 case startcyc:\ 2349 case startcyc:\
2350 OUTPUT_PIXEL(startcyc)\
2210 read_map_scroll_a(column, context->vcounter, context);\ 2351 read_map_scroll_a(column, context->vcounter, context);\
2211 CHECK_LIMIT\ 2352 CHECK_LIMIT\
2212 case ((startcyc+1)&0xFF):\ 2353 case ((startcyc+1)&0xFF):\
2354 OUTPUT_PIXEL((startcyc+1)&0xFF)\
2213 external_slot(context);\ 2355 external_slot(context);\
2214 CHECK_LIMIT\ 2356 CHECK_LIMIT\
2215 case ((startcyc+2)&0xFF):\ 2357 case ((startcyc+2)&0xFF):\
2358 OUTPUT_PIXEL((startcyc+2)&0xFF)\
2216 render_map_1(context);\ 2359 render_map_1(context);\
2217 CHECK_LIMIT\ 2360 CHECK_LIMIT\
2218 case ((startcyc+3)&0xFF):\ 2361 case ((startcyc+3)&0xFF):\
2362 OUTPUT_PIXEL((startcyc+3)&0xFF)\
2219 render_map_2(context);\ 2363 render_map_2(context);\
2220 CHECK_LIMIT\ 2364 CHECK_LIMIT\
2221 case ((startcyc+4)&0xFF):\ 2365 case ((startcyc+4)&0xFF):\
2366 OUTPUT_PIXEL((startcyc+4)&0xFF)\
2222 read_map_scroll_b(column, context->vcounter, context);\ 2367 read_map_scroll_b(column, context->vcounter, context);\
2223 CHECK_LIMIT\ 2368 CHECK_LIMIT\
2224 case ((startcyc+5)&0xFF):\ 2369 case ((startcyc+5)&0xFF):\
2370 OUTPUT_PIXEL((startcyc+5)&0xFF)\
2225 read_sprite_x(context->vcounter, context);\ 2371 read_sprite_x(context->vcounter, context);\
2226 CHECK_LIMIT\ 2372 CHECK_LIMIT\
2227 case ((startcyc+6)&0xFF):\ 2373 case ((startcyc+6)&0xFF):\
2374 OUTPUT_PIXEL((startcyc+6)&0xFF)\
2228 render_map_3(context);\ 2375 render_map_3(context);\
2229 CHECK_LIMIT\ 2376 CHECK_LIMIT\
2230 case ((startcyc+7)&0xFF):\ 2377 case ((startcyc+7)&0xFF):\
2378 OUTPUT_PIXEL((startcyc+7)&0xFF)\
2231 render_map_output(context->vcounter, column, context);\ 2379 render_map_output(context->vcounter, column, context);\
2232 CHECK_LIMIT 2380 CHECK_LIMIT
2233 2381
2234 #define COLUMN_RENDER_BLOCK_REFRESH(column, startcyc) \ 2382 #define COLUMN_RENDER_BLOCK_REFRESH(column, startcyc) \
2235 case startcyc:\ 2383 case startcyc:\
2384 OUTPUT_PIXEL(startcyc)\
2236 read_map_scroll_a(column, context->vcounter, context);\ 2385 read_map_scroll_a(column, context->vcounter, context);\
2237 CHECK_LIMIT\ 2386 CHECK_LIMIT\
2238 case (startcyc+1):\ 2387 case (startcyc+1):\
2239 /* refresh, no don't run dma src */\ 2388 /* refresh, so don't run dma src */\
2389 OUTPUT_PIXEL((startcyc+1)&0xFF)\
2240 context->hslot++;\ 2390 context->hslot++;\
2241 context->cycles += slot_cycles;\ 2391 context->cycles += slot_cycles;\
2242 CHECK_ONLY\ 2392 CHECK_ONLY\
2243 case (startcyc+2):\ 2393 case (startcyc+2):\
2394 OUTPUT_PIXEL((startcyc+2)&0xFF)\
2244 render_map_1(context);\ 2395 render_map_1(context);\
2245 CHECK_LIMIT\ 2396 CHECK_LIMIT\
2246 case (startcyc+3):\ 2397 case (startcyc+3):\
2398 OUTPUT_PIXEL((startcyc+3)&0xFF)\
2247 render_map_2(context);\ 2399 render_map_2(context);\
2248 CHECK_LIMIT\ 2400 CHECK_LIMIT\
2249 case (startcyc+4):\ 2401 case (startcyc+4):\
2402 OUTPUT_PIXEL((startcyc+4)&0xFF)\
2250 read_map_scroll_b(column, context->vcounter, context);\ 2403 read_map_scroll_b(column, context->vcounter, context);\
2251 CHECK_LIMIT\ 2404 CHECK_LIMIT\
2252 case (startcyc+5):\ 2405 case (startcyc+5):\
2406 OUTPUT_PIXEL((startcyc+5)&0xFF)\
2253 read_sprite_x(context->vcounter, context);\ 2407 read_sprite_x(context->vcounter, context);\
2254 CHECK_LIMIT\ 2408 CHECK_LIMIT\
2255 case (startcyc+6):\ 2409 case (startcyc+6):\
2410 OUTPUT_PIXEL((startcyc+6)&0xFF)\
2256 render_map_3(context);\ 2411 render_map_3(context);\
2257 CHECK_LIMIT\ 2412 CHECK_LIMIT\
2258 case (startcyc+7):\ 2413 case (startcyc+7):\
2414 OUTPUT_PIXEL((startcyc+7)&0xFF)\
2259 render_map_output(context->vcounter, column, context);\ 2415 render_map_output(context->vcounter, column, context);\
2260 CHECK_LIMIT 2416 CHECK_LIMIT
2261 2417
2262 #define COLUMN_RENDER_BLOCK_MODE4(column, startcyc) \ 2418 #define COLUMN_RENDER_BLOCK_MODE4(column, startcyc) \
2263 case startcyc:\ 2419 case startcyc:\
2420 OUTPUT_PIXEL_MODE4(startcyc)\
2264 read_map_mode4(column, context->vcounter, context);\ 2421 read_map_mode4(column, context->vcounter, context);\
2265 CHECK_LIMIT\ 2422 CHECK_LIMIT\
2266 case ((startcyc+1)&0xFF):\ 2423 case ((startcyc+1)&0xFF):\
2424 OUTPUT_PIXEL_MODE4((startcyc+1)&0xFF)\
2267 if (column & 3) {\ 2425 if (column & 3) {\
2268 scan_sprite_table_mode4(context);\ 2426 scan_sprite_table_mode4(context);\
2269 } else {\ 2427 } else {\
2270 external_slot(context);\ 2428 external_slot(context);\
2271 }\ 2429 }\
2272 CHECK_LIMIT\ 2430 CHECK_LIMIT\
2273 case ((startcyc+2)&0xFF):\ 2431 case ((startcyc+2)&0xFF):\
2432 OUTPUT_PIXEL_MODE4((startcyc+2)&0xFF)\
2274 fetch_map_mode4(column, context->vcounter, context);\ 2433 fetch_map_mode4(column, context->vcounter, context);\
2275 CHECK_LIMIT\ 2434 CHECK_LIMIT\
2276 case ((startcyc+3)&0xFF):\ 2435 case ((startcyc+3)&0xFF):\
2436 OUTPUT_PIXEL_MODE4((startcyc+3)&0xFF)\
2277 render_map_mode4(context->vcounter, column, context);\ 2437 render_map_mode4(context->vcounter, column, context);\
2278 CHECK_LIMIT 2438 CHECK_LIMIT
2279 2439
2280 #define CHECK_LIMIT_HSYNC(slot) \ 2440 #define CHECK_LIMIT_HSYNC(slot) \
2281 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \ 2441 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \
2291 }\ 2451 }\
2292 CHECK_ONLY 2452 CHECK_ONLY
2293 2453
2294 #define SPRITE_RENDER_H40(slot) \ 2454 #define SPRITE_RENDER_H40(slot) \
2295 case slot:\ 2455 case slot:\
2456 OUTPUT_PIXEL_H40(slot)\
2296 if ((slot) == BG_START_SLOT + LINEBUF_SIZE/2) {\ 2457 if ((slot) == BG_START_SLOT + LINEBUF_SIZE/2) {\
2297 advance_output_line(context);\ 2458 advance_output_line(context);\
2459 if (!context->output) {\
2460 context->output = dummy_buffer;\
2461 }\
2298 }\ 2462 }\
2299 if (slot == 168 || slot == 247 || slot == 248) {\ 2463 if (slot == 168 || slot == 247 || slot == 248) {\
2300 render_border_garbage(\ 2464 render_border_garbage(\
2301 context,\ 2465 context,\
2302 context->sprite_draw_list[context->cur_slot].address,\ 2466 context->sprite_draw_list[context->cur_slot].address,\
2325 2489
2326 //Note that the line advancement check will fail if BG_START_SLOT is > 6 2490 //Note that the line advancement check will fail if BG_START_SLOT is > 6
2327 //as we're bumping up against the hcounter jump 2491 //as we're bumping up against the hcounter jump
2328 #define SPRITE_RENDER_H32(slot) \ 2492 #define SPRITE_RENDER_H32(slot) \
2329 case slot:\ 2493 case slot:\
2494 OUTPUT_PIXEL_H32(slot)\
2330 if ((slot) == BG_START_SLOT + (256+HORIZ_BORDER)/2) {\ 2495 if ((slot) == BG_START_SLOT + (256+HORIZ_BORDER)/2) {\
2331 advance_output_line(context);\ 2496 advance_output_line(context);\
2497 if (!context->output) {\
2498 context->output = dummy_buffer;\
2499 }\
2332 }\ 2500 }\
2333 if (slot == 136 || slot == 247 || slot == 248) {\ 2501 if (slot == 136 || slot == 247 || slot == 248) {\
2334 render_border_garbage(\ 2502 render_border_garbage(\
2335 context,\ 2503 context,\
2336 context->sprite_draw_list[context->cur_slot].address,\ 2504 context->sprite_draw_list[context->cur_slot].address,\
2358 2526
2359 #define MODE4_CHECK_SLOT_LINE(slot) \ 2527 #define MODE4_CHECK_SLOT_LINE(slot) \
2360 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \ 2528 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \
2361 if ((slot) == BG_START_SLOT + (256+HORIZ_BORDER)/2) {\ 2529 if ((slot) == BG_START_SLOT + (256+HORIZ_BORDER)/2) {\
2362 advance_output_line(context);\ 2530 advance_output_line(context);\
2531 if (!context->output) {\
2532 context->output = dummy_buffer;\
2533 }\
2363 }\ 2534 }\
2364 if ((slot) == 147) {\ 2535 if ((slot) == 147) {\
2365 context->hslot = 233;\ 2536 context->hslot = 233;\
2366 } else {\ 2537 } else {\
2367 context->hslot++;\ 2538 context->hslot++;\
2377 2548
2378 #define CALC_SLOT(slot, increment) ((slot+increment) > 147 && (slot+increment) < 233 ? (slot+increment-148+233): (slot+increment)) 2549 #define CALC_SLOT(slot, increment) ((slot+increment) > 147 && (slot+increment) < 233 ? (slot+increment-148+233): (slot+increment))
2379 2550
2380 #define SPRITE_RENDER_H32_MODE4(slot) \ 2551 #define SPRITE_RENDER_H32_MODE4(slot) \
2381 case slot:\ 2552 case slot:\
2553 OUTPUT_PIXEL_MODE4(slot)\
2382 read_sprite_x_mode4(context);\ 2554 read_sprite_x_mode4(context);\
2383 MODE4_CHECK_SLOT_LINE(slot)\ 2555 MODE4_CHECK_SLOT_LINE(slot)\
2384 case CALC_SLOT(slot, 1):\ 2556 case CALC_SLOT(slot, 1):\
2557 OUTPUT_PIXEL_MODE4(CALC_SLOT(slot, 1))\
2385 read_sprite_x_mode4(context);\ 2558 read_sprite_x_mode4(context);\
2386 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot,1))\ 2559 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot,1))\
2387 case CALC_SLOT(slot, 2):\ 2560 case CALC_SLOT(slot, 2):\
2561 OUTPUT_PIXEL_MODE4(CALC_SLOT(slot, 2))\
2388 fetch_sprite_cells_mode4(context);\ 2562 fetch_sprite_cells_mode4(context);\
2389 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 2))\ 2563 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 2))\
2390 case CALC_SLOT(slot, 3):\ 2564 case CALC_SLOT(slot, 3):\
2391 if ((slot + 3) == 140) {\ 2565 OUTPUT_PIXEL_MODE4(CALC_SLOT(slot, 3))\
2392 uint32_t *dst = context->output + BORDER_LEFT + 256 + 8;\
2393 uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET];\
2394 for (int i = 0; i < BORDER_RIGHT-8; i++, dst++)\
2395 {\
2396 *dst = bgcolor;\
2397 }\
2398 context->done_output = dst;\
2399 }\
2400 render_sprite_cells_mode4(context);\ 2566 render_sprite_cells_mode4(context);\
2401 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 3))\ 2567 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 3))\
2402 case CALC_SLOT(slot, 4):\ 2568 case CALC_SLOT(slot, 4):\
2569 OUTPUT_PIXEL_MODE4(CALC_SLOT(slot, 4))\
2403 fetch_sprite_cells_mode4(context);\ 2570 fetch_sprite_cells_mode4(context);\
2404 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 4))\ 2571 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 4))\
2405 case CALC_SLOT(slot, 5):\ 2572 case CALC_SLOT(slot, 5):\
2573 OUTPUT_PIXEL_MODE4(CALC_SLOT(slot, 5))\
2406 render_sprite_cells_mode4(context);\ 2574 render_sprite_cells_mode4(context);\
2407 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 5)) 2575 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 5))
2408 2576
2409 static void vdp_h40(vdp_context * context, uint32_t target_cycles) 2577 static uint32_t dummy_buffer[LINEBUF_SIZE];
2578 static void vdp_h40_line(vdp_context * context)
2410 { 2579 {
2411 uint16_t address; 2580 uint16_t address;
2412 uint32_t mask; 2581 uint32_t mask;
2413 uint32_t const slot_cycles = MCLKS_SLOT_H40; 2582 uint32_t const slot_cycles = MCLKS_SLOT_H40;
2583 uint8_t bgindex = context->regs[REG_BG_COLOR] & 0x3F;
2584 uint8_t test_layer = context->test_port >> 7 & 3;
2585
2586 //165
2587 if (!(context->regs[REG_MODE_3] & BIT_VSCROLL)) {
2588 //TODO: Develop some tests on hardware to see when vscroll latch actually happens for full plane mode
2589 //See note in vdp_h32 for why this was originally moved out of read_map_scroll
2590 //Skitchin' has a similar problem, but uses H40 mode. It seems to be able to hit the extern slot at 232
2591 //pretty consistently
2592 context->vscroll_latch[0] = context->vsram[0];
2593 context->vscroll_latch[1] = context->vsram[1];
2594 }
2595 render_sprite_cells(context);
2596 //166
2597 render_sprite_cells(context);
2598 //167
2599 context->sprite_index = 0x80;
2600 context->slot_counter = 0;
2601 render_border_garbage(
2602 context,
2603 context->sprite_draw_list[context->cur_slot].address,
2604 context->tmp_buf_b, context->buf_b_off,
2605 context->col_1
2606 );
2607 render_sprite_cells(context);
2608 scan_sprite_table(context->vcounter, context);
2609 //168
2610 render_border_garbage(
2611 context,
2612 context->sprite_draw_list[context->cur_slot].address,
2613 context->tmp_buf_b,
2614 context->buf_b_off + 8,
2615 context->col_2
2616 );
2617 //Do palette lookup for end of previous line
2618 uint8_t *src = context->compositebuf + (LINE_CHANGE_H40 - BG_START_SLOT) *2;
2619 uint32_t *dst = context->output + (LINE_CHANGE_H40 - BG_START_SLOT) *2;
2620 if (test_layer) {
2621 for (int i = 0; i < LINEBUF_SIZE - (LINE_CHANGE_H40 - BG_START_SLOT) * 2; i++)
2622 {
2623 *(dst++) = context->colors[*(src++)];
2624 }
2625 } else {
2626 for (int i = 0; i < LINEBUF_SIZE - (LINE_CHANGE_H40 - BG_START_SLOT) * 2; i++)
2627 {
2628 if (*src & 0x3F) {
2629 *(dst++) = context->colors[*(src++)];
2630 } else {
2631 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];
2632 }
2633 }
2634 }
2635 advance_output_line(context);
2636 //168-242 (inclusive)
2637 for (int i = 0; i < 28; i++)
2638 {
2639 render_sprite_cells(context);
2640 scan_sprite_table(context->vcounter, context);
2641 }
2642 //243
2643 render_border_garbage(
2644 context,
2645 context->sprite_draw_list[context->cur_slot].address,
2646 context->tmp_buf_a,
2647 context->buf_a_off,
2648 context->col_1
2649 );
2650 //244
2651 address = (context->regs[REG_HSCROLL] & 0x3F) << 10;
2652 mask = 0;
2653 if (context->regs[REG_MODE_3] & 0x2) {
2654 mask |= 0xF8;
2655 }
2656 if (context->regs[REG_MODE_3] & 0x1) {
2657 mask |= 0x7;
2658 }
2659 render_border_garbage(context, address, context->tmp_buf_a, context->buf_a_off+8, context->col_2);
2660 address += (context->vcounter & mask) * 4;
2661 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1];
2662 context->hscroll_a_fine = context->hscroll_a & 0xF;
2663 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3];
2664 context->hscroll_b_fine = context->hscroll_b & 0xF;
2665 //printf("%d: HScroll A: %d, HScroll B: %d\n", context->vcounter, context->hscroll_a, context->hscroll_b);
2666 //243-246 inclusive
2667 for (int i = 0; i < 3; i++)
2668 {
2669 render_sprite_cells(context);
2670 scan_sprite_table(context->vcounter, context);
2671 }
2672 //247
2673 render_border_garbage(
2674 context,
2675 context->sprite_draw_list[context->cur_slot].address,
2676 context->tmp_buf_b,
2677 context->buf_b_off,
2678 context->col_1
2679 );
2680 render_sprite_cells(context);
2681 scan_sprite_table(context->vcounter, context);
2682 //248
2683 render_border_garbage(
2684 context,
2685 context->sprite_draw_list[context->cur_slot].address,
2686 context->tmp_buf_b,
2687 context->buf_b_off + 8,
2688 context->col_2
2689 );
2690 render_sprite_cells(context);
2691 scan_sprite_table(context->vcounter, context);
2692 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
2693 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
2694 //250
2695 render_sprite_cells(context);
2696 scan_sprite_table(context->vcounter, context);
2697 //251
2698 scan_sprite_table(context->vcounter, context);//Just a guess
2699 //252
2700 scan_sprite_table(context->vcounter, context);//Just a guess
2701 //254
2702 render_sprite_cells(context);
2703 scan_sprite_table(context->vcounter, context);
2704 //255
2705 if (context->cur_slot >= 0 && context->sprite_draw_list[context->cur_slot].x_pos) {
2706 context->flags |= FLAG_DOT_OFLOW;
2707 }
2708 scan_sprite_table(context->vcounter, context);
2709 //0
2710 scan_sprite_table(context->vcounter, context);//Just a guess
2711 //seems like the sprite table scan fills a shift register
2712 //values are FIFO, but unused slots precede used slots
2713 //so we set cur_slot to slot_counter and let it wrap around to
2714 //the beginning of the list
2715 context->cur_slot = context->slot_counter;
2716 context->sprite_x_offset = 0;
2717 context->sprite_draws = MAX_SPRITES_LINE;
2718 //background planes and layer compositing
2719 for (int col = 0; col < 42; col+=2)
2720 {
2721 read_map_scroll_a(col, context->vcounter, context);
2722 render_map_1(context);
2723 render_map_2(context);
2724 read_map_scroll_b(col, context->vcounter, context);
2725 render_map_3(context);
2726 render_map_output(context->vcounter, col, context);
2727 }
2728 //sprite rendering phase 2
2729 for (int i = 0; i < MAX_SPRITES_LINE; i++)
2730 {
2731 read_sprite_x(context->vcounter, context);
2732 }
2733 //163
2734 context->cur_slot = MAX_SPRITES_LINE-1;
2735 memset(context->linebuf, 0, LINEBUF_SIZE);
2736 render_border_garbage(
2737 context,
2738 context->sprite_draw_list[context->cur_slot].address,
2739 context->tmp_buf_a, context->buf_a_off,
2740 context->col_1
2741 );
2742 context->flags &= ~FLAG_MASKED;
2743 render_sprite_cells(context);
2744 //164
2745 render_border_garbage(
2746 context,
2747 context->sprite_draw_list[context->cur_slot].address,
2748 context->tmp_buf_a, context->buf_a_off + 8,
2749 context->col_2
2750 );
2751 render_sprite_cells(context);
2752 context->cycles += MCLKS_LINE;
2753 vdp_advance_line(context);
2754 src = context->compositebuf;
2755 dst = context->output;
2756 if (test_layer) {
2757 for (int i = 0; i < (LINE_CHANGE_H40 - BG_START_SLOT) * 2; i++)
2758 {
2759 *(dst++) = context->colors[*(src++)];
2760 }
2761 } else {
2762 for (int i = 0; i < (LINE_CHANGE_H40 - BG_START_SLOT) * 2; i++)
2763 {
2764 if (*src & 0x3F) {
2765 *(dst++) = context->colors[*(src++)];
2766 } else {
2767 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];
2768 }
2769 }
2770 }
2771 }
2772 static void vdp_h40(vdp_context * context, uint32_t target_cycles)
2773 {
2774 uint16_t address;
2775 uint32_t mask;
2776 uint32_t const slot_cycles = MCLKS_SLOT_H40;
2777 uint8_t bgindex = context->regs[REG_BG_COLOR] & 0x3F;
2778 uint8_t test_layer = context->test_port >> 7 & 3;
2779 if (!context->output) {
2780 //This shouldn't happen normally, but it can theoretically
2781 //happen when doing border busting
2782 context->output = dummy_buffer;
2783 }
2414 switch(context->hslot) 2784 switch(context->hslot)
2415 { 2785 {
2416 for (;;) 2786 for (;;)
2417 { 2787 {
2418 case 165: 2788 case 165:
2789 //only consider doing a line at a time if the FIFO is empty, there are no pending reads and there is no DMA running
2790 if (context->fifo_read == -1 && !(context->flags & FLAG_DMA_RUN) && ((context->cd & 1) || (context->flags & FLAG_READ_FETCHED))) {
2791 while (target_cycles - context->cycles >= MCLKS_LINE && context->state != PREPARING && context->vcounter != context->inactive_start) {
2792 vdp_h40_line(context);
2793 }
2794 CHECK_ONLY
2795 }
2796 OUTPUT_PIXEL(165)
2419 if (!(context->regs[REG_MODE_3] & BIT_VSCROLL)) { 2797 if (!(context->regs[REG_MODE_3] & BIT_VSCROLL)) {
2420 //TODO: Develop some tests on hardware to see when vscroll latch actually happens for full plane mode 2798 //TODO: Develop some tests on hardware to see when vscroll latch actually happens for full plane mode
2421 //See note in vdp_h32 for why this was originally moved out of read_map_scroll 2799 //See note in vdp_h32 for why this was originally moved out of read_map_scroll
2422 //Skitchin' has a similar problem, but uses H40 mode. It seems to be able to hit the extern slot at 232 2800 //Skitchin' has a similar problem, but uses H40 mode. It seems to be able to hit the extern slot at 232
2423 //pretty consistently 2801 //pretty consistently
2424 context->vscroll_latch[0] = context->vsram[0]; 2802 context->vscroll_latch[0] = context->vsram[0];
2425 context->vscroll_latch[1] = context->vsram[1]; 2803 context->vscroll_latch[1] = context->vsram[1];
2426 } 2804 }
2427 if (context->state == PREPARING) { 2805 if (context->state == PREPARING) {
2428 uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
2429 uint32_t *dst = context->output + (context->hslot - BG_START_SLOT) * 2;
2430 if (dst >= context->done_output) {
2431 *dst = bg_color;
2432 }
2433 dst++;
2434 if (dst >= context->done_output) {
2435 *dst = bg_color;
2436 }
2437 external_slot(context); 2806 external_slot(context);
2438 } else { 2807 } else {
2439 render_sprite_cells(context); 2808 render_sprite_cells(context);
2440 } 2809 }
2441 CHECK_LIMIT 2810 CHECK_LIMIT
2442 case 166: 2811 case 166:
2812 OUTPUT_PIXEL(166)
2443 if (context->state == PREPARING) { 2813 if (context->state == PREPARING) {
2444 uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
2445 uint32_t *dst = context->output + (context->hslot - BG_START_SLOT) * 2;
2446 if (dst >= context->done_output) {
2447 *dst = bg_color;
2448 }
2449 dst++;
2450 if (dst >= context->done_output) {
2451 *dst = bg_color;
2452 }
2453 external_slot(context); 2814 external_slot(context);
2454 } else { 2815 } else {
2455 render_sprite_cells(context); 2816 render_sprite_cells(context);
2456 } 2817 }
2457 if (context->vcounter == context->inactive_start) { 2818 if (context->vcounter == context->inactive_start) {
2460 return; 2821 return;
2461 } 2822 }
2462 CHECK_LIMIT 2823 CHECK_LIMIT
2463 //sprite attribute table scan starts 2824 //sprite attribute table scan starts
2464 case 167: 2825 case 167:
2465 if (context->state == PREPARING) { 2826 OUTPUT_PIXEL(167)
2466 uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
2467 uint32_t *dst = context->output + (context->hslot - BG_START_SLOT) * 2;
2468 for (int i = 0; i < LINEBUF_SIZE - 2 * (context->hslot - BG_START_SLOT); i++, dst++)
2469 {
2470 if (dst >= context->done_output) {
2471 *dst = bg_color;
2472 }
2473 }
2474 }
2475 context->sprite_index = 0x80; 2827 context->sprite_index = 0x80;
2476 context->slot_counter = 0; 2828 context->slot_counter = 0;
2477 render_border_garbage( 2829 render_border_garbage(
2478 context, 2830 context,
2479 context->sprite_draw_list[context->cur_slot].address, 2831 context->sprite_draw_list[context->cur_slot].address,
2526 mask |= 0x7; 2878 mask |= 0x7;
2527 } 2879 }
2528 render_border_garbage(context, address, context->tmp_buf_a, context->buf_a_off+8, context->col_2); 2880 render_border_garbage(context, address, context->tmp_buf_a, context->buf_a_off+8, context->col_2);
2529 address += (context->vcounter & mask) * 4; 2881 address += (context->vcounter & mask) * 4;
2530 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1]; 2882 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1];
2883 context->hscroll_a_fine = context->hscroll_a & 0xF;
2531 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; 2884 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3];
2885 context->hscroll_b_fine = context->hscroll_b & 0xF;
2532 //printf("%d: HScroll A: %d, HScroll B: %d\n", context->vcounter, context->hscroll_a, context->hscroll_b); 2886 //printf("%d: HScroll A: %d, HScroll B: %d\n", context->vcounter, context->hscroll_a, context->hscroll_b);
2533 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } 2887 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); }
2534 context->hslot++; 2888 context->hslot++;
2535 context->cycles += h40_hsync_cycles[14]; 2889 context->cycles += h40_hsync_cycles[14];
2536 CHECK_ONLY //provides "garbage" for border when plane A selected 2890 CHECK_ONLY //provides "garbage" for border when plane A selected
2554 case 253: 2908 case 253:
2555 read_map_scroll_b(0, context->vcounter, context); 2909 read_map_scroll_b(0, context->vcounter, context);
2556 CHECK_LIMIT 2910 CHECK_LIMIT
2557 SPRITE_RENDER_H40(254) 2911 SPRITE_RENDER_H40(254)
2558 case 255: 2912 case 255:
2913 if (context->cur_slot >= 0 && context->sprite_draw_list[context->cur_slot].x_pos) {
2914 context->flags |= FLAG_DOT_OFLOW;
2915 }
2559 render_map_3(context); 2916 render_map_3(context);
2560 scan_sprite_table(context->vcounter, context);//Just a guess 2917 scan_sprite_table(context->vcounter, context);//Just a guess
2561 CHECK_LIMIT 2918 CHECK_LIMIT
2562 case 0: 2919 case 0:
2563 render_map_output(context->vcounter, 0, context); 2920 render_map_output(context->vcounter, 0, context);
2565 //seems like the sprite table scan fills a shift register 2922 //seems like the sprite table scan fills a shift register
2566 //values are FIFO, but unused slots precede used slots 2923 //values are FIFO, but unused slots precede used slots
2567 //so we set cur_slot to slot_counter and let it wrap around to 2924 //so we set cur_slot to slot_counter and let it wrap around to
2568 //the beginning of the list 2925 //the beginning of the list
2569 context->cur_slot = context->slot_counter; 2926 context->cur_slot = context->slot_counter;
2570 context->sprite_draws = MAX_DRAWS; 2927 context->sprite_x_offset = 0;
2571 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED); 2928 context->sprite_draws = MAX_SPRITES_LINE;
2572 CHECK_LIMIT 2929 CHECK_LIMIT
2573 COLUMN_RENDER_BLOCK(2, 1) 2930 COLUMN_RENDER_BLOCK(2, 1)
2574 COLUMN_RENDER_BLOCK(4, 9) 2931 COLUMN_RENDER_BLOCK(4, 9)
2575 COLUMN_RENDER_BLOCK(6, 17) 2932 COLUMN_RENDER_BLOCK(6, 17)
2576 COLUMN_RENDER_BLOCK_REFRESH(8, 25) 2933 COLUMN_RENDER_BLOCK_REFRESH(8, 25)
2589 COLUMN_RENDER_BLOCK(34, 129) 2946 COLUMN_RENDER_BLOCK(34, 129)
2590 COLUMN_RENDER_BLOCK(36, 137) 2947 COLUMN_RENDER_BLOCK(36, 137)
2591 COLUMN_RENDER_BLOCK(38, 145) 2948 COLUMN_RENDER_BLOCK(38, 145)
2592 COLUMN_RENDER_BLOCK_REFRESH(40, 153) 2949 COLUMN_RENDER_BLOCK_REFRESH(40, 153)
2593 case 161: 2950 case 161:
2951 OUTPUT_PIXEL(161)
2594 external_slot(context); 2952 external_slot(context);
2595 CHECK_LIMIT 2953 CHECK_LIMIT
2596 case 162: 2954 case 162:
2955 OUTPUT_PIXEL(162)
2597 external_slot(context); 2956 external_slot(context);
2598 CHECK_LIMIT 2957 CHECK_LIMIT
2599 //sprite render to line buffer starts 2958 //sprite render to line buffer starts
2600 case 163: 2959 case 163:
2601 context->cur_slot = MAX_DRAWS-1; 2960 OUTPUT_PIXEL(163)
2961 context->cur_slot = MAX_SPRITES_LINE-1;
2602 memset(context->linebuf, 0, LINEBUF_SIZE); 2962 memset(context->linebuf, 0, LINEBUF_SIZE);
2603 render_border_garbage( 2963 render_border_garbage(
2604 context, 2964 context,
2605 context->sprite_draw_list[context->cur_slot].address, 2965 context->sprite_draw_list[context->cur_slot].address,
2606 context->tmp_buf_a, context->buf_a_off, 2966 context->tmp_buf_a, context->buf_a_off,
2607 context->col_1 2967 context->col_1
2608 ); 2968 );
2969 context->flags &= ~FLAG_MASKED;
2609 render_sprite_cells(context); 2970 render_sprite_cells(context);
2610 CHECK_LIMIT 2971 CHECK_LIMIT
2611 case 164: 2972 case 164:
2973 OUTPUT_PIXEL(164)
2612 render_border_garbage( 2974 render_border_garbage(
2613 context, 2975 context,
2614 context->sprite_draw_list[context->cur_slot].address, 2976 context->sprite_draw_list[context->cur_slot].address,
2615 context->tmp_buf_a, context->buf_a_off + 8, 2977 context->tmp_buf_a, context->buf_a_off + 8,
2616 context->col_2 2978 context->col_2
2634 static void vdp_h32(vdp_context * context, uint32_t target_cycles) 2996 static void vdp_h32(vdp_context * context, uint32_t target_cycles)
2635 { 2997 {
2636 uint16_t address; 2998 uint16_t address;
2637 uint32_t mask; 2999 uint32_t mask;
2638 uint32_t const slot_cycles = MCLKS_SLOT_H32; 3000 uint32_t const slot_cycles = MCLKS_SLOT_H32;
3001 uint8_t bgindex = context->regs[REG_BG_COLOR] & 0x3F;
3002 uint8_t test_layer = context->test_port >> 7 & 3;
3003 if (!context->output) {
3004 //This shouldn't happen normally, but it can theoretically
3005 //happen when doing border busting
3006 context->output = dummy_buffer;
3007 }
2639 switch(context->hslot) 3008 switch(context->hslot)
2640 { 3009 {
2641 for (;;) 3010 for (;;)
2642 { 3011 {
2643 case 133: 3012 case 133:
3013 OUTPUT_PIXEL(133)
2644 if (context->state == PREPARING) { 3014 if (context->state == PREPARING) {
2645 uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
2646 uint32_t *dst = context->output + (context->hslot - BG_START_SLOT) * 2;
2647 if (dst >= context->done_output) {
2648 *dst = bg_color;
2649 }
2650 dst++;
2651 if (dst >= context->done_output) {
2652 *dst = bg_color;
2653 }
2654 external_slot(context); 3015 external_slot(context);
2655 } else { 3016 } else {
2656 render_sprite_cells(context); 3017 render_sprite_cells(context);
2657 } 3018 }
2658 CHECK_LIMIT 3019 CHECK_LIMIT
2659 case 134: 3020 case 134:
3021 OUTPUT_PIXEL(134)
2660 if (context->state == PREPARING) { 3022 if (context->state == PREPARING) {
2661 uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
2662 uint32_t *dst = context->output + (context->hslot - BG_START_SLOT) * 2;
2663 if (dst >= context->done_output) {
2664 *dst = bg_color;
2665 }
2666 dst++;
2667 if (dst >= context->done_output) {
2668 *dst = bg_color;
2669 }
2670 external_slot(context); 3023 external_slot(context);
2671 } else { 3024 } else {
2672 render_sprite_cells(context); 3025 render_sprite_cells(context);
2673 } 3026 }
2674 if (context->vcounter == context->inactive_start) { 3027 if (context->vcounter == context->inactive_start) {
2677 return; 3030 return;
2678 } 3031 }
2679 CHECK_LIMIT 3032 CHECK_LIMIT
2680 //sprite attribute table scan starts 3033 //sprite attribute table scan starts
2681 case 135: 3034 case 135:
2682 if (context->state == PREPARING) { 3035 OUTPUT_PIXEL(135)
2683 uint32_t bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F];
2684 uint32_t *dst = context->output + (context->hslot - BG_START_SLOT) * 2;
2685 for (int i = 0; i < (256+HORIZ_BORDER) - 2 * (context->hslot - BG_START_SLOT); i++)
2686 {
2687 if (dst >= context->done_output) {
2688 *(dst++) = bg_color;
2689 }
2690 }
2691 }
2692 context->sprite_index = 0x80; 3036 context->sprite_index = 0x80;
2693 context->slot_counter = 0; 3037 context->slot_counter = 0;
2694 render_border_garbage( 3038 render_border_garbage(
2695 context, 3039 context,
2696 context->sprite_draw_list[context->cur_slot].address, 3040 context->sprite_draw_list[context->cur_slot].address,
2708 SPRITE_RENDER_H32(141) 3052 SPRITE_RENDER_H32(141)
2709 SPRITE_RENDER_H32(142) 3053 SPRITE_RENDER_H32(142)
2710 SPRITE_RENDER_H32(143) 3054 SPRITE_RENDER_H32(143)
2711 SPRITE_RENDER_H32(144) 3055 SPRITE_RENDER_H32(144)
2712 case 145: 3056 case 145:
3057 OUTPUT_PIXEL(145)
2713 external_slot(context); 3058 external_slot(context);
2714 CHECK_LIMIT 3059 CHECK_LIMIT
2715 SPRITE_RENDER_H32(146) 3060 SPRITE_RENDER_H32(146)
2716 SPRITE_RENDER_H32(147) 3061 SPRITE_RENDER_H32(147)
2717 SPRITE_RENDER_H32(233) 3062 SPRITE_RENDER_H32(233)
2755 mask |= 0x7; 3100 mask |= 0x7;
2756 } 3101 }
2757 render_border_garbage(context, address, context->tmp_buf_a, context->buf_a_off+8, context->col_2); 3102 render_border_garbage(context, address, context->tmp_buf_a, context->buf_a_off+8, context->col_2);
2758 address += (context->vcounter & mask) * 4; 3103 address += (context->vcounter & mask) * 4;
2759 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1]; 3104 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1];
3105 context->hscroll_a_fine = context->hscroll_a & 0xF;
2760 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; 3106 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3];
3107 context->hscroll_b_fine = context->hscroll_b & 0xF;
2761 //printf("%d: HScroll A: %d, HScroll B: %d\n", context->vcounter, context->hscroll_a, context->hscroll_b); 3108 //printf("%d: HScroll A: %d, HScroll B: %d\n", context->vcounter, context->hscroll_a, context->hscroll_b);
2762 CHECK_LIMIT //provides "garbage" for border when plane A selected 3109 CHECK_LIMIT //provides "garbage" for border when plane A selected
2763 SPRITE_RENDER_H32(245) 3110 SPRITE_RENDER_H32(245)
2764 SPRITE_RENDER_H32(246) 3111 SPRITE_RENDER_H32(246)
2765 SPRITE_RENDER_H32(247) //provides "garbage" for border when plane B selected 3112 SPRITE_RENDER_H32(247) //provides "garbage" for border when plane B selected
2768 case 249: 3115 case 249:
2769 read_map_scroll_a(0, context->vcounter, context); 3116 read_map_scroll_a(0, context->vcounter, context);
2770 CHECK_LIMIT 3117 CHECK_LIMIT
2771 SPRITE_RENDER_H32(250) 3118 SPRITE_RENDER_H32(250)
2772 case 251: 3119 case 251:
3120 if (context->cur_slot >= 0 && context->sprite_draw_list[context->cur_slot].x_pos) {
3121 context->flags |= FLAG_DOT_OFLOW;
3122 }
2773 render_map_1(context); 3123 render_map_1(context);
2774 scan_sprite_table(context->vcounter, context);//Just a guess 3124 scan_sprite_table(context->vcounter, context);//Just a guess
2775 CHECK_LIMIT 3125 CHECK_LIMIT
2776 case 252: 3126 case 252:
2777 render_map_2(context); 3127 render_map_2(context);
2793 scan_sprite_table(context->vcounter, context);//Just a guess 3143 scan_sprite_table(context->vcounter, context);//Just a guess
2794 //reverse context slot counter so it counts the number of sprite slots 3144 //reverse context slot counter so it counts the number of sprite slots
2795 //filled rather than the number of available slots 3145 //filled rather than the number of available slots
2796 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter; 3146 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter;
2797 context->cur_slot = context->slot_counter; 3147 context->cur_slot = context->slot_counter;
2798 context->sprite_draws = MAX_DRAWS_H32; 3148 context->sprite_x_offset = 0;
2799 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED); 3149 context->sprite_draws = MAX_SPRITES_LINE_H32;
2800 CHECK_LIMIT 3150 CHECK_LIMIT
2801 COLUMN_RENDER_BLOCK(2, 1) 3151 COLUMN_RENDER_BLOCK(2, 1)
2802 COLUMN_RENDER_BLOCK(4, 9) 3152 COLUMN_RENDER_BLOCK(4, 9)
2803 COLUMN_RENDER_BLOCK(6, 17) 3153 COLUMN_RENDER_BLOCK(6, 17)
2804 COLUMN_RENDER_BLOCK_REFRESH(8, 25) 3154 COLUMN_RENDER_BLOCK_REFRESH(8, 25)
2813 COLUMN_RENDER_BLOCK(26, 97) 3163 COLUMN_RENDER_BLOCK(26, 97)
2814 COLUMN_RENDER_BLOCK(28, 105) 3164 COLUMN_RENDER_BLOCK(28, 105)
2815 COLUMN_RENDER_BLOCK(30, 113) 3165 COLUMN_RENDER_BLOCK(30, 113)
2816 COLUMN_RENDER_BLOCK_REFRESH(32, 121) 3166 COLUMN_RENDER_BLOCK_REFRESH(32, 121)
2817 case 129: 3167 case 129:
3168 OUTPUT_PIXEL(129)
2818 external_slot(context); 3169 external_slot(context);
2819 CHECK_LIMIT 3170 CHECK_LIMIT
2820 case 130: { 3171 case 130: {
3172 OUTPUT_PIXEL(130)
2821 external_slot(context); 3173 external_slot(context);
2822 CHECK_LIMIT 3174 CHECK_LIMIT
2823 } 3175 }
2824 //sprite render to line buffer starts 3176 //sprite render to line buffer starts
2825 case 131: 3177 case 131:
2826 context->cur_slot = MAX_DRAWS_H32-1; 3178 OUTPUT_PIXEL(131)
3179 context->cur_slot = MAX_SPRITES_LINE_H32-1;
2827 memset(context->linebuf, 0, LINEBUF_SIZE); 3180 memset(context->linebuf, 0, LINEBUF_SIZE);
2828 render_border_garbage( 3181 render_border_garbage(
2829 context, 3182 context,
2830 context->sprite_draw_list[context->cur_slot].address, 3183 context->sprite_draw_list[context->cur_slot].address,
2831 context->tmp_buf_a, context->buf_a_off, 3184 context->tmp_buf_a, context->buf_a_off,
2832 context->col_1 3185 context->col_1
2833 ); 3186 );
3187 context->flags &= ~FLAG_MASKED;
2834 render_sprite_cells(context); 3188 render_sprite_cells(context);
2835 CHECK_LIMIT 3189 CHECK_LIMIT
2836 case 132: 3190 case 132:
3191 OUTPUT_PIXEL(132)
2837 render_border_garbage( 3192 render_border_garbage(
2838 context, 3193 context,
2839 context->sprite_draw_list[context->cur_slot].address, 3194 context->sprite_draw_list[context->cur_slot].address,
2840 context->tmp_buf_a, context->buf_a_off + 8, 3195 context->tmp_buf_a, context->buf_a_off + 8,
2841 context->col_2 3196 context->col_2
2858 static void vdp_h32_mode4(vdp_context * context, uint32_t target_cycles) 3213 static void vdp_h32_mode4(vdp_context * context, uint32_t target_cycles)
2859 { 3214 {
2860 uint16_t address; 3215 uint16_t address;
2861 uint32_t mask; 3216 uint32_t mask;
2862 uint32_t const slot_cycles = MCLKS_SLOT_H32; 3217 uint32_t const slot_cycles = MCLKS_SLOT_H32;
3218 uint8_t bgindex = 0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET;
3219 uint8_t test_layer = context->test_port >> 7 & 3;
3220 if (!context->output) {
3221 //This shouldn't happen normally, but it can theoretically
3222 //happen when doing border busting
3223 context->output = dummy_buffer;
3224 }
2863 switch(context->hslot) 3225 switch(context->hslot)
2864 { 3226 {
2865 for (;;) 3227 for (;;)
2866 { 3228 {
2867 //sprite rendering starts 3229 //sprite rendering starts
2907 case 255: 3269 case 255:
2908 scan_sprite_table_mode4(context); 3270 scan_sprite_table_mode4(context);
2909 CHECK_LIMIT 3271 CHECK_LIMIT
2910 case 0: { 3272 case 0: {
2911 scan_sprite_table_mode4(context); 3273 scan_sprite_table_mode4(context);
2912 uint32_t *dst = context->output;;
2913 uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET];
2914 for (int i = 0; i < BORDER_LEFT-8; i++, dst++)
2915 {
2916 *dst = bgcolor;
2917 }
2918 context->done_output = dst;
2919 CHECK_LIMIT 3274 CHECK_LIMIT
2920 } 3275 }
2921 case 1: 3276 case 1:
2922 scan_sprite_table_mode4(context); 3277 scan_sprite_table_mode4(context);
2923 CHECK_LIMIT 3278 CHECK_LIMIT
2929 CHECK_LIMIT 3284 CHECK_LIMIT
2930 case 4: { 3285 case 4: {
2931 scan_sprite_table_mode4(context); 3286 scan_sprite_table_mode4(context);
2932 context->buf_a_off = 8; 3287 context->buf_a_off = 8;
2933 memset(context->tmp_buf_a, 0, 8); 3288 memset(context->tmp_buf_a, 0, 8);
2934 uint32_t *dst = context->output + BORDER_LEFT - 8;
2935 uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET];
2936 for (int i = 0; i < 8; i++, dst++)
2937 {
2938 *dst = bgcolor;
2939 }
2940 context->done_output = dst;
2941 CHECK_LIMIT 3289 CHECK_LIMIT
2942 } 3290 }
2943 COLUMN_RENDER_BLOCK_MODE4(0, 5) 3291 COLUMN_RENDER_BLOCK_MODE4(0, 5)
2944 COLUMN_RENDER_BLOCK_MODE4(1, 9) 3292 COLUMN_RENDER_BLOCK_MODE4(1, 9)
2945 COLUMN_RENDER_BLOCK_MODE4(2, 13) 3293 COLUMN_RENDER_BLOCK_MODE4(2, 13)
2971 COLUMN_RENDER_BLOCK_MODE4(28, 117) 3319 COLUMN_RENDER_BLOCK_MODE4(28, 117)
2972 COLUMN_RENDER_BLOCK_MODE4(29, 121) 3320 COLUMN_RENDER_BLOCK_MODE4(29, 121)
2973 COLUMN_RENDER_BLOCK_MODE4(30, 125) 3321 COLUMN_RENDER_BLOCK_MODE4(30, 125)
2974 COLUMN_RENDER_BLOCK_MODE4(31, 129) 3322 COLUMN_RENDER_BLOCK_MODE4(31, 129)
2975 case 133: 3323 case 133:
3324 OUTPUT_PIXEL_MODE4(133)
2976 external_slot(context); 3325 external_slot(context);
2977 CHECK_LIMIT 3326 CHECK_LIMIT
2978 case 134: 3327 case 134:
3328 OUTPUT_PIXEL_MODE4(134)
2979 external_slot(context); 3329 external_slot(context);
2980 CHECK_LIMIT 3330 CHECK_LIMIT
2981 case 135: 3331 case 135:
3332 OUTPUT_PIXEL_MODE4(135)
2982 external_slot(context); 3333 external_slot(context);
2983 CHECK_LIMIT 3334 CHECK_LIMIT
2984 case 136: { 3335 case 136: {
3336 OUTPUT_PIXEL_MODE4(136)
2985 external_slot(context); 3337 external_slot(context);
2986 //set things up for sprite rendering in the next slot 3338 //set things up for sprite rendering in the next slot
2987 memset(context->linebuf, 0, LINEBUF_SIZE); 3339 memset(context->linebuf, 0, LINEBUF_SIZE);
2988 context->cur_slot = context->sprite_index = MAX_DRAWS_H32_MODE4-1; 3340 context->cur_slot = context->sprite_index = MAX_DRAWS_H32_MODE4-1;
2989 context->sprite_draws = MAX_DRAWS_H32_MODE4; 3341 context->sprite_draws = MAX_DRAWS_H32_MODE4;
2990 uint32_t *dst = context->output + BORDER_LEFT + 256;
2991 uint32_t bgcolor = context->colors[0x10 | (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET];
2992 for (int i = 0; i < 8; i++, dst++)
2993 {
2994 *dst = bgcolor;
2995 }
2996 context->done_output = dst;
2997 CHECK_LIMIT 3342 CHECK_LIMIT
2998 }} 3343 }}
2999 default: 3344 default:
3000 context->hslot++; 3345 context->hslot++;
3001 context->cycles += MCLKS_SLOT_H32; 3346 context->cycles += MCLKS_SLOT_H32;
3006 { 3351 {
3007 uint8_t max_slot = is_h40 ? 169 : 136; 3352 uint8_t max_slot = is_h40 ? 169 : 136;
3008 if (context->hslot > max_slot) { 3353 if (context->hslot > max_slot) {
3009 return; 3354 return;
3010 } 3355 }
3011 uint32_t *dst = context->output + (context->hslot >> 3) * SCROLL_BUFFER_DRAW; 3356 uint8_t *dst = context->compositebuf + (context->hslot >> 3) * SCROLL_BUFFER_DRAW;
3012 int32_t len; 3357 int32_t len;
3013 uint32_t src_off; 3358 uint32_t src_off;
3014 if (context->hslot) { 3359 if (context->hslot) {
3015 dst -= SCROLL_BUFFER_DRAW - BORDER_LEFT; 3360 dst -= SCROLL_BUFFER_DRAW - BORDER_LEFT;
3016 src_off = 0; 3361 src_off = 0;
3017 len = context->hslot == max_slot ? BORDER_RIGHT : SCROLL_BUFFER_DRAW; 3362 len = context->hslot == max_slot ? BORDER_RIGHT : SCROLL_BUFFER_DRAW;
3018 } else { 3363 } else {
3019 src_off = SCROLL_BUFFER_DRAW - BORDER_LEFT; 3364 src_off = SCROLL_BUFFER_DRAW - BORDER_LEFT;
3020 len = BORDER_LEFT; 3365 len = BORDER_LEFT;
3021 } 3366 }
3022 uint8_t *src; 3367 uint8_t *src = NULL;
3023 if (test_layer == 2) { 3368 if (test_layer == 2) {
3024 //plane A 3369 //plane A
3025 src_off += context->buf_a_off + context->hscroll_a; 3370 src_off += context->buf_a_off - (context->hscroll_a & 0xF);
3026 src = context->tmp_buf_a; 3371 src = context->tmp_buf_a;
3027 } else if (test_layer == 3){ 3372 } else if (test_layer == 3){
3028 //plane B 3373 //plane B
3029 src_off += context->buf_b_off + context->hscroll_b; 3374 src_off += context->buf_b_off - (context->hscroll_b & 0xF);
3030 src = context->tmp_buf_b; 3375 src = context->tmp_buf_b;
3031 } else { 3376 } else {
3032 //sprite layer 3377 //sprite layer
3378 memset(dst, 0, len);
3379 dst += len;
3380 len = 0;
3381 }
3382 if (src) {
3033 for (; len >=0; len--, dst++, src_off++) 3383 for (; len >=0; len--, dst++, src_off++)
3034 { 3384 {
3035 *dst = context->colors[0]; 3385 *dst = src[src_off & SCROLL_BUFFER_MASK] & 0x3F;
3036 } 3386 }
3037 } 3387 }
3038 for (; len >=0; len--, dst++, src_off++) 3388 context->done_composite = dst;
3039 {
3040 *dst = context->colors[src[src_off & SCROLL_BUFFER_MASK] & 0x3F];
3041 }
3042 context->done_output = dst;
3043 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_DRAW; 3389 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_DRAW;
3044 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_DRAW; 3390 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_DRAW;
3045 } 3391 }
3046 3392
3047 static void check_switch_inactive(vdp_context *context, uint8_t is_h40) 3393 static void check_switch_inactive(vdp_context *context, uint8_t is_h40)
3048 { 3394 {
3049 //technically the second hcounter check should be different for H40, but this is probably close enough for now 3395 //technically the second hcounter check should be different for H40, but this is probably close enough for now
3050 if (context->state == ACTIVE && context->vcounter == context->inactive_start && (context->hslot >= (is_h40 ? 167 : 135) || context->hslot < 133)) { 3396 if (context->state == ACTIVE && context->vcounter == context->inactive_start && (context->hslot >= (is_h40 ? 167 : 135) || context->hslot < 133)) {
3051 context->state = INACTIVE; 3397 context->state = INACTIVE;
3398 context->cur_slot = MAX_SPRITES_LINE-1;
3399 context->sprite_x_offset = 0;
3052 } 3400 }
3053 } 3401 }
3054 3402
3055 static void vdp_inactive(vdp_context *context, uint32_t target_cycles, uint8_t is_h40, uint8_t mode_5) 3403 static void vdp_inactive(vdp_context *context, uint32_t target_cycles, uint8_t is_h40, uint8_t mode_5)
3056 { 3404 {
3057 uint8_t buf_clear_slot, index_reset_slot, bg_end_slot, vint_slot, line_change, jump_start, jump_dest, latch_slot; 3405 uint8_t buf_clear_slot, index_reset_slot, bg_end_slot, vint_slot, line_change, jump_start, jump_dest, latch_slot;
3058 uint8_t index_reset_value, max_draws, max_sprites; 3406 uint8_t index_reset_value, max_draws, max_sprites;
3059 uint16_t vint_line, active_line; 3407 uint16_t vint_line, active_line;
3060 uint32_t bg_color;
3061 3408
3062 if (mode_5) { 3409 if (mode_5) {
3063 if (is_h40) { 3410 if (is_h40) {
3064 latch_slot = 165; 3411 latch_slot = 165;
3065 buf_clear_slot = 163; 3412 buf_clear_slot = 163;
3066 index_reset_slot = 167; 3413 index_reset_slot = 167;
3067 bg_end_slot = BG_START_SLOT + LINEBUF_SIZE/2; 3414 bg_end_slot = BG_START_SLOT + LINEBUF_SIZE/2;
3068 max_draws = MAX_DRAWS-1; 3415 max_draws = MAX_SPRITES_LINE-1;
3069 max_sprites = MAX_SPRITES_LINE; 3416 max_sprites = MAX_SPRITES_LINE;
3070 index_reset_value = 0x80; 3417 index_reset_value = 0x80;
3071 vint_slot = VINT_SLOT_H40; 3418 vint_slot = VINT_SLOT_H40;
3072 line_change = LINE_CHANGE_H40; 3419 line_change = LINE_CHANGE_H40;
3073 jump_start = 182; 3420 jump_start = 182;
3074 jump_dest = 229; 3421 jump_dest = 229;
3075 } else { 3422 } else {
3076 bg_end_slot = BG_START_SLOT + (256+HORIZ_BORDER)/2; 3423 bg_end_slot = BG_START_SLOT + (256+HORIZ_BORDER)/2;
3077 max_draws = MAX_DRAWS_H32-1; 3424 max_draws = MAX_SPRITES_LINE_H32-1;
3078 max_sprites = MAX_SPRITES_LINE_H32; 3425 max_sprites = MAX_SPRITES_LINE_H32;
3079 buf_clear_slot = 128; 3426 buf_clear_slot = 128;
3080 index_reset_slot = 132; 3427 index_reset_slot = 132;
3081 index_reset_value = 0x80; 3428 index_reset_value = 0x80;
3082 vint_slot = VINT_SLOT_H32; 3429 vint_slot = VINT_SLOT_H32;
3099 index_reset_slot = 253; 3446 index_reset_slot = 253;
3100 index_reset_value = 0; 3447 index_reset_value = 0;
3101 vint_line = context->inactive_start + 1; 3448 vint_line = context->inactive_start + 1;
3102 vint_slot = VINT_SLOT_MODE4; 3449 vint_slot = VINT_SLOT_MODE4;
3103 line_change = LINE_CHANGE_MODE4; 3450 line_change = LINE_CHANGE_MODE4;
3104 bg_color = render_map_color(0, 0, 0);
3105 jump_start = 147; 3451 jump_start = 147;
3106 jump_dest = 233; 3452 jump_dest = 233;
3107 if (context->regs[REG_MODE_1] & BIT_MODE_4) { 3453 if (context->regs[REG_MODE_1] & BIT_MODE_4) {
3108 active_line = 0x1FF; 3454 active_line = 0x1FF;
3109 } else { 3455 } else {
3111 active_line = 0x200; 3457 active_line = 0x200;
3112 } 3458 }
3113 } 3459 }
3114 uint32_t *dst; 3460 uint32_t *dst;
3115 uint8_t *debug_dst; 3461 uint8_t *debug_dst;
3116 if ( 3462 if (context->output && context->hslot >= BG_START_SLOT && context->hslot < bg_end_slot) {
3117 (
3118 context->vcounter < context->inactive_start + context->border_bot
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); 3463 dst = context->output + 2 * (context->hslot - BG_START_SLOT);
3123 debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT); 3464 debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT);
3124 } else { 3465 } else {
3125 dst = NULL; 3466 dst = NULL;
3126 } 3467 }
3127 3468
3128 if (
3129 !dst && context->vcounter == context->inactive_start + context->border_bot
3130 && context->hslot >= line_change && context->hslot < bg_end_slot
3131 ) {
3132 dst = context->output + 2 * (context->hslot - BG_START_SLOT);
3133 debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT);
3134 }
3135
3136 uint8_t test_layer = context->test_port >> 7 & 3; 3469 uint8_t test_layer = context->test_port >> 7 & 3;
3137 if (test_layer) {
3138 dst = NULL;
3139 }
3140 3470
3141 while(context->cycles < target_cycles) 3471 while(context->cycles < target_cycles)
3142 { 3472 {
3143 check_switch_inactive(context, is_h40); 3473 check_switch_inactive(context, is_h40);
3144 if (context->hslot == BG_START_SLOT && !test_layer && ( 3474 if (context->hslot == BG_START_SLOT && context->output) {
3145 context->vcounter < context->inactive_start + context->border_bot
3146 || context->vcounter >= 0x200 - context->border_top
3147 )) {
3148 dst = context->output + (context->hslot - BG_START_SLOT) * 2; 3475 dst = context->output + (context->hslot - BG_START_SLOT) * 2;
3149 debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT); 3476 debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT);
3150 } else if (context->hslot == bg_end_slot) { 3477 } else if (context->hslot == bg_end_slot) {
3151 advance_output_line(context); 3478 advance_output_line(context);
3152 dst = NULL; 3479 dst = NULL;
3166 case 7: 3493 case 7:
3167 render_border_garbage(context, context->serial_address, context->tmp_buf_b, context->buf_b_off, context->col_1); 3494 render_border_garbage(context, context->serial_address, context->tmp_buf_b, context->buf_b_off, context->col_1);
3168 break; 3495 break;
3169 case 0: 3496 case 0:
3170 render_border_garbage(context, context->serial_address, context->tmp_buf_b, context->buf_b_off+8, context->col_2); 3497 render_border_garbage(context, context->serial_address, context->tmp_buf_b, context->buf_b_off+8, context->col_2);
3498 break;
3499 case 1:
3171 inactive_test_output(context, is_h40, test_layer); 3500 inactive_test_output(context, is_h40, test_layer);
3172 break; 3501 break;
3173 } 3502 }
3174 } 3503 }
3175 3504
3198 } else if (context->vcounter == context->inactive_start && context->hslot == 1 && (context->regs[REG_MODE_4] & BIT_INTERLACE)) { 3527 } else if (context->vcounter == context->inactive_start && context->hslot == 1 && (context->regs[REG_MODE_4] & BIT_INTERLACE)) {
3199 context->flags2 ^= FLAG2_EVEN_FIELD; 3528 context->flags2 ^= FLAG2_EVEN_FIELD;
3200 } 3529 }
3201 3530
3202 if (dst) { 3531 if (dst) {
3532 uint8_t bg_index;
3533 uint32_t bg_color;
3203 if (mode_5) { 3534 if (mode_5) {
3204 bg_color = context->colors[context->regs[REG_BG_COLOR] & 0x3F]; 3535 bg_index = context->regs[REG_BG_COLOR] & 0x3F;
3536 bg_color = context->colors[bg_index];
3205 } else if (context->regs[REG_MODE_1] & BIT_MODE_4) { 3537 } else if (context->regs[REG_MODE_1] & BIT_MODE_4) {
3206 bg_color = context->colors[MODE4_OFFSET + 0x10 + (context->regs[REG_BG_COLOR] & 0xF)]; 3538 bg_index = 0x10 + (context->regs[REG_BG_COLOR] & 0xF);
3207 } 3539 bg_color = context->colors[MODE4_OFFSET + bg_index];
3208 if (dst >= context->done_output) { 3540 } else {
3541 bg_color = render_map_color(0, 0, 0);
3542 }
3543 if (context->done_composite) {
3544 uint8_t pixel = context->compositebuf[dst-context->output];
3545 if (!(pixel & 0x3F | test_layer)) {
3546 pixel = pixel & 0xC0 | bg_index;
3547 }
3548 *(dst++) = context->colors[pixel];
3549 if ((dst - context->output) == (context->done_composite - context->compositebuf)) {
3550 context->done_composite = NULL;
3551 memset(context->compositebuf, 0, sizeof(context->compositebuf));
3552 }
3553 } else {
3209 *(dst++) = bg_color; 3554 *(dst++) = bg_color;
3210 *(debug_dst++) = DBG_SRC_BG; 3555 *(debug_dst++) = DBG_SRC_BG;
3556 }
3557 if (context->done_composite) {
3558 uint8_t pixel = context->compositebuf[dst-context->output];
3559 if (!(pixel & 0x3F | test_layer)) {
3560 pixel = pixel & 0xC0 | bg_index;
3561 }
3562 *(dst++) = context->colors[pixel];
3563 if ((dst - context->output) == (context->done_composite - context->compositebuf)) {
3564 context->done_composite = NULL;
3565 memset(context->compositebuf, 0, sizeof(context->compositebuf));
3566 }
3211 } else { 3567 } else {
3212 dst++;
3213 debug_dst++;
3214 }
3215 if (dst >= context->done_output) {
3216 *(dst++) = bg_color; 3568 *(dst++) = bg_color;
3217 *(debug_dst++) = DBG_SRC_BG; 3569 *(debug_dst++) = DBG_SRC_BG;
3218 context->done_output = dst; 3570 }
3219 } else { 3571
3220 dst++;
3221 debug_dst++;
3222 }
3223 if (context->hslot == (bg_end_slot-1)) { 3572 if (context->hslot == (bg_end_slot-1)) {
3224 *(dst++) = bg_color; 3573 if (context->done_composite) {
3225 *(debug_dst++) = DBG_SRC_BG; 3574 uint8_t pixel = context->compositebuf[dst-context->output];
3226 context->done_output = dst; 3575 if (!(pixel & 0x3F | test_layer)) {
3576 pixel = pixel & 0xC0 | bg_index;
3577 }
3578 *(dst++) = context->colors[pixel];
3579 if ((dst - context->output) == (context->done_composite - context->compositebuf)) {
3580 context->done_composite = NULL;
3581 memset(context->compositebuf, 0, sizeof(context->compositebuf));
3582 }
3583 } else {
3584 *(dst++) = bg_color;
3585 *(debug_dst++) = DBG_SRC_BG;
3586 }
3227 } 3587 }
3228 } 3588 }
3229 3589
3230 if (!is_refresh(context, context->hslot)) { 3590 if (!is_refresh(context, context->hslot)) {
3231 external_slot(context); 3591 external_slot(context);
3366 hv |= get_ext_vcounter(context); 3726 hv |= get_ext_vcounter(context);
3367 3727
3368 return hv; 3728 return hv;
3369 } 3729 }
3370 3730
3731 static void clear_pending(vdp_context *context)
3732 {
3733 context->flags &= ~FLAG_PENDING;
3734 context->address = context->address_latch;
3735 //It seems like the DMA enable bit doesn't so much enable DMA so much
3736 //as it enables changing CD5 from control port writes
3737 if (context->regs[REG_MODE_2] & BIT_DMA_ENABLE) {
3738 context->cd = context->cd_latch;
3739 } else {
3740 context->cd = (context->cd & 0x20) | (context->cd_latch & 0x1F);
3741 }
3742 }
3743
3371 int vdp_control_port_write(vdp_context * context, uint16_t value) 3744 int vdp_control_port_write(vdp_context * context, uint16_t value)
3372 { 3745 {
3373 //printf("control port write: %X at %d\n", value, context->cycles); 3746 //printf("control port write: %X at %d\n", value, context->cycles);
3374 if (context->flags & FLAG_DMA_RUN) { 3747 if (context->flags & FLAG_DMA_RUN) {
3375 return -1; 3748 return -1;
3376 } 3749 }
3377 if (context->flags & FLAG_PENDING) { 3750 if (context->flags & FLAG_PENDING) {
3378 context->address = (context->address & 0x3FFF) | (value << 14 & 0x1C000); 3751 context->address_latch = (context->address_latch & 0x3FFF) | (value << 14 & 0x1C000);
3379 //It seems like the DMA enable bit doesn't so much enable DMA so much 3752 context->cd_latch = (context->cd_latch & 0x3) | ((value >> 2) & ~0x3 & 0xFF);
3380 //as it enables changing CD5 from control port writes 3753 clear_pending(context);
3381 uint8_t preserve = (context->regs[REG_MODE_2] & BIT_DMA_ENABLE) ? 0x3 : 0x23;
3382 context->cd = (context->cd & preserve) | ((value >> 2) & ~preserve & 0xFF);
3383 context->flags &= ~FLAG_PENDING;
3384 //Should these be taken care of here or after the first write? 3754 //Should these be taken care of here or after the first write?
3385 context->flags &= ~FLAG_READ_FETCHED; 3755 context->flags &= ~FLAG_READ_FETCHED;
3386 context->flags2 &= ~FLAG2_READ_PENDING; 3756 context->flags2 &= ~FLAG2_READ_PENDING;
3387 //printf("New Address: %X, New CD: %X\n", context->address, context->cd); 3757 //printf("New Address: %X, New CD: %X\n", context->address, context->cd);
3388 if (context->cd & 0x20) { 3758 if (context->cd & 0x20) {
3407 //printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd); 3777 //printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd);
3408 } 3778 }
3409 } 3779 }
3410 } else { 3780 } else {
3411 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; 3781 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
3412 context->address = (context->address &0xC000) | (value & 0x3FFF); 3782 context->address_latch = (context->address_latch & 0x1C000) | (value & 0x3FFF);
3413 context->cd = (context->cd & 0x3C) | (value >> 14); 3783 context->cd_latch = (context->cd_latch & 0x3C) | (value >> 14);
3414 if ((value & 0xC000) == 0x8000) { 3784 if ((value & 0xC000) == 0x8000) {
3415 //Register write 3785 //Register write
3416 uint8_t reg = (value >> 8) & 0x1F; 3786 uint8_t reg = (value >> 8) & 0x1F;
3787 // The fact that this is needed seems to pour some cold water on my theory
3788 // about how the address latch actually works. Needs more search to definitively confirm
3789 context->address = (context->address & 0x1C000) | (value & 0x3FFF);
3790 context->cd = (context->cd & 0x3C) | (value >> 14);
3417 if (reg < (mode_5 ? VDP_REGS : 0xB)) { 3791 if (reg < (mode_5 ? VDP_REGS : 0xB)) {
3418 //printf("register %d set to %X\n", reg, value & 0xFF); 3792 //printf("register %d set to %X\n", reg, value & 0xFF);
3419 if (reg == REG_MODE_1 && (value & BIT_HVC_LATCH) && !(context->regs[reg] & BIT_HVC_LATCH)) { 3793 if (reg == REG_MODE_1 && (value & BIT_HVC_LATCH) && !(context->regs[reg] & BIT_HVC_LATCH)) {
3420 vdp_latch_hv(context); 3794 vdp_latch_hv(context);
3421 } 3795 }
3423 value &= 0x3F; 3797 value &= 0x3F;
3424 } 3798 }
3425 /*if (reg == REG_MODE_4 && ((value ^ context->regs[reg]) & BIT_H40)) { 3799 /*if (reg == REG_MODE_4 && ((value ^ context->regs[reg]) & BIT_H40)) {
3426 printf("Mode changed from H%d to H%d @ %d, frame: %d\n", context->regs[reg] & BIT_H40 ? 40 : 32, value & BIT_H40 ? 40 : 32, context->cycles, context->frame); 3800 printf("Mode changed from H%d to H%d @ %d, frame: %d\n", context->regs[reg] & BIT_H40 ? 40 : 32, value & BIT_H40 ? 40 : 32, context->cycles, context->frame);
3427 }*/ 3801 }*/
3802 uint8_t buffer[2] = {reg, value};
3803 event_log(EVENT_VDP_REG, context->cycles, sizeof(buffer), buffer);
3428 context->regs[reg] = value; 3804 context->regs[reg] = value;
3429 if (reg == REG_MODE_4) { 3805 if (reg == REG_MODE_4) {
3430 context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES); 3806 context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES);
3431 if (!context->double_res) { 3807 if (!context->double_res) {
3432 context->flags2 &= ~FLAG2_EVEN_FIELD; 3808 context->flags2 &= ~FLAG2_EVEN_FIELD;
3433 } 3809 }
3434 } 3810 }
3435 if (reg == REG_MODE_1 || reg == REG_MODE_2 || reg == REG_MODE_4) { 3811 if (reg == REG_MODE_1 || reg == REG_MODE_2 || reg == REG_MODE_4) {
3436 update_video_params(context); 3812 update_video_params(context);
3437 } 3813 }
3814 } else if (reg == REG_KMOD_CTRL) {
3815 if (!(value & 0xFF)) {
3816 context->system->enter_debugger = 1;
3817 }
3818 } else if (reg == REG_KMOD_MSG) {
3819 char c = value;
3820 if (c) {
3821 context->kmod_buffer_length++;
3822 if ((context->kmod_buffer_length + 1) > context->kmod_buffer_storage) {
3823 context->kmod_buffer_storage = context->kmod_buffer_length ? 128 : context->kmod_buffer_length * 2;
3824 context->kmod_msg_buffer = realloc(context->kmod_msg_buffer, context->kmod_buffer_storage);
3825 }
3826 context->kmod_msg_buffer[context->kmod_buffer_length - 1] = c;
3827 } else if (context->kmod_buffer_length) {
3828 context->kmod_msg_buffer[context->kmod_buffer_length] = 0;
3829 if (is_stdout_enabled()) {
3830 init_terminal();
3831 printf("KDEBUG MESSAGE: %s\n", context->kmod_msg_buffer);
3832 } else {
3833 // GDB remote debugging is enabled, use stderr instead
3834 fprintf(stderr, "KDEBUG MESSAGE: %s\n", context->kmod_msg_buffer);
3835 }
3836 context->kmod_buffer_length = 0;
3837 }
3838 } else if (reg == REG_KMOD_TIMER) {
3839 if (!(value & 0x80)) {
3840 if (is_stdout_enabled()) {
3841 init_terminal();
3842 printf("KDEBUG TIMER: %d\n", (context->cycles - context->timer_start_cycle) / 7);
3843 } else {
3844 // GDB remote debugging is enabled, use stderr instead
3845 fprintf(stderr, "KDEBUG TIMER: %d\n", (context->cycles - context->timer_start_cycle) / 7);
3846 }
3847 }
3848 if (value & 0xC0) {
3849 context->timer_start_cycle = context->cycles;
3850 }
3438 } 3851 }
3439 } else if (mode_5) { 3852 } else if (mode_5) {
3440 context->flags |= FLAG_PENDING; 3853 context->flags |= FLAG_PENDING;
3441 //Should these be taken care of here or after the second write? 3854 //Should these be taken care of here or after the second write?
3442 //context->flags &= ~FLAG_READ_FETCHED; 3855 //context->flags &= ~FLAG_READ_FETCHED;
3443 //context->flags2 &= ~FLAG2_READ_PENDING; 3856 //context->flags2 &= ~FLAG2_READ_PENDING;
3444 } else { 3857 } else {
3858 clear_pending(context);
3445 context->flags &= ~FLAG_READ_FETCHED; 3859 context->flags &= ~FLAG_READ_FETCHED;
3446 context->flags2 &= ~FLAG2_READ_PENDING; 3860 context->flags2 &= ~FLAG2_READ_PENDING;
3447 } 3861 }
3448 } 3862 }
3449 return 0; 3863 return 0;
3470 //printf("data port write: %X at %d\n", value, context->cycles); 3884 //printf("data port write: %X at %d\n", value, context->cycles);
3471 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) != DMA_FILL) { 3885 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) != DMA_FILL) {
3472 return -1; 3886 return -1;
3473 } 3887 }
3474 if (context->flags & FLAG_PENDING) { 3888 if (context->flags & FLAG_PENDING) {
3475 context->flags &= ~FLAG_PENDING; 3889 clear_pending(context);
3476 //Should these be cleared here? 3890 //Should these be cleared here?
3477 context->flags &= ~FLAG_READ_FETCHED; 3891 context->flags &= ~FLAG_READ_FETCHED;
3478 context->flags2 &= ~FLAG2_READ_PENDING; 3892 context->flags2 &= ~FLAG2_READ_PENDING;
3479 } 3893 }
3480 /*if (context->fifo_cur == context->fifo_end) { 3894 /*if (context->fifo_cur == context->fifo_end) {
3505 } 3919 }
3506 3920
3507 void vdp_data_port_write_pbc(vdp_context * context, uint8_t value) 3921 void vdp_data_port_write_pbc(vdp_context * context, uint8_t value)
3508 { 3922 {
3509 if (context->flags & FLAG_PENDING) { 3923 if (context->flags & FLAG_PENDING) {
3510 context->flags &= ~FLAG_PENDING; 3924 clear_pending(context);
3511 //Should these be cleared here? 3925 //Should these be cleared here?
3512 context->flags &= ~FLAG_READ_FETCHED; 3926 context->flags &= ~FLAG_READ_FETCHED;
3513 context->flags2 &= ~FLAG2_READ_PENDING; 3927 context->flags2 &= ~FLAG2_READ_PENDING;
3514 } 3928 }
3515 context->flags2 &= ~FLAG2_BYTE_PENDING; 3929 context->flags2 &= ~FLAG2_BYTE_PENDING;
3544 context->test_port = value; 3958 context->test_port = value;
3545 } 3959 }
3546 3960
3547 uint16_t vdp_control_port_read(vdp_context * context) 3961 uint16_t vdp_control_port_read(vdp_context * context)
3548 { 3962 {
3549 context->flags &= ~FLAG_PENDING; 3963 if (context->flags & FLAG_PENDING) {
3964 clear_pending(context);
3965 }
3550 context->flags2 &= ~FLAG2_BYTE_PENDING; 3966 context->flags2 &= ~FLAG2_BYTE_PENDING;
3551 //Bits 15-10 are not fixed like Charles MacDonald's doc suggests, but instead open bus values that reflect 68K prefetch 3967 //Bits 15-10 are not fixed like Charles MacDonald's doc suggests, but instead open bus values that reflect 68K prefetch
3552 uint16_t value = context->system->get_open_bus_value(context->system) & 0xFC00; 3968 uint16_t value = context->system->get_open_bus_value(context->system) & 0xFC00;
3553 if (context->fifo_read < 0) { 3969 if (context->fifo_read < 0) {
3554 value |= 0x200; 3970 value |= 0x200;
3594 } 4010 }
3595 4011
3596 uint16_t vdp_data_port_read(vdp_context * context) 4012 uint16_t vdp_data_port_read(vdp_context * context)
3597 { 4013 {
3598 if (context->flags & FLAG_PENDING) { 4014 if (context->flags & FLAG_PENDING) {
3599 context->flags &= ~FLAG_PENDING; 4015 clear_pending(context);
3600 //Should these be cleared here? 4016 //Should these be cleared here?
3601 context->flags &= ~FLAG_READ_FETCHED; 4017 context->flags &= ~FLAG_READ_FETCHED;
3602 context->flags2 &= ~FLAG2_READ_PENDING; 4018 context->flags2 &= ~FLAG2_READ_PENDING;
3603 } 4019 }
3604 if (context->cd & 1) { 4020 if (context->cd & 1) {
3605 warning("Read from VDP data port while writes are configured, CPU is now frozen. VDP Address: %X, CD: %X\n", context->address, context->cd); 4021 warning("Read from VDP data port while writes are configured, CPU is now frozen. VDP Address: %X, CD: %X\n", context->address, context->cd);
4022 context->system->enter_debugger = 1;
4023 return context->prefetch;
4024 }
4025 switch (context->cd)
4026 {
4027 case VRAM_READ:
4028 case VSRAM_READ:
4029 case CRAM_READ:
4030 case VRAM_READ8:
4031 break;
4032 default:
4033 warning("Read from VDP data port with invalid source, CPU is now frozen. VDP Address: %X, CD: %X\n", context->address, context->cd);
4034 context->system->enter_debugger = 1;
4035 return context->prefetch;
3606 } 4036 }
3607 while (!(context->flags & FLAG_READ_FETCHED)) { 4037 while (!(context->flags & FLAG_READ_FETCHED)) {
3608 vdp_run_context_full(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); 4038 vdp_run_context_full(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20));
3609 } 4039 }
3610 context->flags &= ~FLAG_READ_FETCHED; 4040 context->flags &= ~FLAG_READ_FETCHED;
3611 return context->prefetch; 4041 return context->prefetch;
3612 } 4042 }
3613 4043
3614 uint8_t vdp_data_port_read_pbc(vdp_context * context) 4044 uint8_t vdp_data_port_read_pbc(vdp_context * context)
3615 { 4045 {
3616 context->flags &= ~(FLAG_PENDING | FLAG_READ_FETCHED); 4046 if (context->flags & FLAG_PENDING) {
4047 clear_pending(context);
4048 }
4049 context->flags &= ~FLAG_READ_FETCHED;
3617 context->flags2 &= ~FLAG2_BYTE_PENDING; 4050 context->flags2 &= ~FLAG2_BYTE_PENDING;
3618 4051
3619 context->cd = VRAM_READ8; 4052 context->cd = VRAM_READ8;
3620 return context->prefetch; 4053 return context->prefetch;
3621 }
3622
3623 uint16_t vdp_test_port_read(vdp_context * context)
3624 {
3625 //TODO: Find out what actually gets returned here
3626 return context->test_port;
3627 } 4054 }
3628 4055
3629 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) 4056 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction)
3630 { 4057 {
3631 context->cycles -= deduction; 4058 context->cycles -= deduction;
3916 context->flags2 &= ~FLAG2_HINT_PENDING; 4343 context->flags2 &= ~FLAG2_HINT_PENDING;
3917 } 4344 }
3918 } 4345 }
3919 } 4346 }
3920 4347
4348 #define VDP_STATE_VERSION 3
3921 void vdp_serialize(vdp_context *context, serialize_buffer *buf) 4349 void vdp_serialize(vdp_context *context, serialize_buffer *buf)
3922 { 4350 {
4351 save_int8(buf, VDP_STATE_VERSION);
3923 save_int8(buf, VRAM_SIZE / 1024);//VRAM size in KB, needed for future proofing 4352 save_int8(buf, VRAM_SIZE / 1024);//VRAM size in KB, needed for future proofing
3924 save_buffer8(buf, context->vdpmem, VRAM_SIZE); 4353 save_buffer8(buf, context->vdpmem, VRAM_SIZE);
3925 save_buffer16(buf, context->cram, CRAM_SIZE); 4354 save_buffer16(buf, context->cram, CRAM_SIZE);
3926 save_buffer16(buf, context->vsram, VSRAM_SIZE); 4355 save_buffer16(buf, context->vsram, MAX_VSRAM_SIZE);
3927 save_buffer8(buf, context->sat_cache, SAT_CACHE_SIZE); 4356 save_buffer8(buf, context->sat_cache, SAT_CACHE_SIZE);
3928 for (int i = 0; i <= REG_DMASRC_H; i++) 4357 for (int i = 0; i <= REG_DMASRC_H; i++)
3929 { 4358 {
3930 save_int8(buf, context->regs[i]); 4359 save_int8(buf, context->regs[i]);
3931 } 4360 }
3972 //FIXME: Sprite rendering state is currently a mess 4401 //FIXME: Sprite rendering state is currently a mess
3973 save_int8(buf, context->sprite_index); 4402 save_int8(buf, context->sprite_index);
3974 save_int8(buf, context->sprite_draws); 4403 save_int8(buf, context->sprite_draws);
3975 save_int8(buf, context->slot_counter); 4404 save_int8(buf, context->slot_counter);
3976 save_int8(buf, context->cur_slot); 4405 save_int8(buf, context->cur_slot);
3977 for (int i = 0; i < MAX_DRAWS; i++) 4406 for (int i = 0; i < MAX_SPRITES_LINE; i++)
3978 { 4407 {
3979 sprite_draw *draw = context->sprite_draw_list + i; 4408 sprite_draw *draw = context->sprite_draw_list + i;
3980 save_int16(buf, draw->address); 4409 save_int16(buf, draw->address);
3981 save_int16(buf, draw->x_pos); 4410 save_int16(buf, draw->x_pos);
3982 save_int8(buf, draw->pal_priority); 4411 save_int8(buf, draw->pal_priority);
3983 save_int8(buf, draw->h_flip); 4412 save_int8(buf, draw->h_flip);
4413 save_int8(buf, draw->width);
4414 save_int8(buf, draw->height);
3984 } 4415 }
3985 for (int i = 0; i < MAX_SPRITES_LINE; i++) 4416 for (int i = 0; i < MAX_SPRITES_LINE; i++)
3986 { 4417 {
3987 sprite_info *info = context->sprite_info_list + i; 4418 sprite_info *info = context->sprite_info_list + i;
3988 save_int8(buf, info->size); 4419 save_int8(buf, info->size);
3992 save_buffer8(buf, context->linebuf, LINEBUF_SIZE); 4423 save_buffer8(buf, context->linebuf, LINEBUF_SIZE);
3993 4424
3994 save_int32(buf, context->cycles); 4425 save_int32(buf, context->cycles);
3995 save_int32(buf, context->pending_vint_start); 4426 save_int32(buf, context->pending_vint_start);
3996 save_int32(buf, context->pending_hint_start); 4427 save_int32(buf, context->pending_hint_start);
4428 save_int32(buf, context->address_latch);
4429 save_int8(buf, context->cd_latch);
3997 } 4430 }
3998 4431
3999 void vdp_deserialize(deserialize_buffer *buf, void *vcontext) 4432 void vdp_deserialize(deserialize_buffer *buf, void *vcontext)
4000 { 4433 {
4001 vdp_context *context = vcontext; 4434 vdp_context *context = vcontext;
4002 uint8_t vramk = load_int8(buf); 4435 uint8_t version = load_int8(buf);
4436 uint8_t vramk;
4437 if (version == 64) {
4438 vramk = version;
4439 version = 0;
4440 } else {
4441 vramk = load_int8(buf);
4442 }
4443 if (version > VDP_STATE_VERSION) {
4444 warning("Save state has VDP version %d, but this build only understands versions %d and lower", version, VDP_STATE_VERSION);
4445 }
4003 load_buffer8(buf, context->vdpmem, (vramk * 1024) <= VRAM_SIZE ? vramk * 1024 : VRAM_SIZE); 4446 load_buffer8(buf, context->vdpmem, (vramk * 1024) <= VRAM_SIZE ? vramk * 1024 : VRAM_SIZE);
4004 if ((vramk * 1024) > VRAM_SIZE) { 4447 if ((vramk * 1024) > VRAM_SIZE) {
4005 buf->cur_pos += (vramk * 1024) - VRAM_SIZE; 4448 buf->cur_pos += (vramk * 1024) - VRAM_SIZE;
4006 } 4449 }
4007 load_buffer16(buf, context->cram, CRAM_SIZE); 4450 load_buffer16(buf, context->cram, CRAM_SIZE);
4008 for (int i = 0; i < CRAM_SIZE; i++) 4451 for (int i = 0; i < CRAM_SIZE; i++)
4009 { 4452 {
4010 update_color_map(context, i, context->cram[i]); 4453 update_color_map(context, i, context->cram[i]);
4011 } 4454 }
4012 load_buffer16(buf, context->vsram, VSRAM_SIZE); 4455 load_buffer16(buf, context->vsram, version > 1 ? MAX_VSRAM_SIZE : MIN_VSRAM_SIZE);
4013 load_buffer8(buf, context->sat_cache, SAT_CACHE_SIZE); 4456 load_buffer8(buf, context->sat_cache, SAT_CACHE_SIZE);
4014 for (int i = 0; i <= REG_DMASRC_H; i++) 4457 for (int i = 0; i <= REG_DMASRC_H; i++)
4015 { 4458 {
4016 context->regs[i] = load_int8(buf); 4459 context->regs[i] = load_int8(buf);
4017 } 4460 }
4059 context->buf_b_off = load_int8(buf) & SCROLL_BUFFER_MASK; 4502 context->buf_b_off = load_int8(buf) & SCROLL_BUFFER_MASK;
4060 context->sprite_index = load_int8(buf); 4503 context->sprite_index = load_int8(buf);
4061 context->sprite_draws = load_int8(buf); 4504 context->sprite_draws = load_int8(buf);
4062 context->slot_counter = load_int8(buf); 4505 context->slot_counter = load_int8(buf);
4063 context->cur_slot = load_int8(buf); 4506 context->cur_slot = load_int8(buf);
4064 for (int i = 0; i < MAX_DRAWS; i++) 4507 if (version == 0) {
4065 { 4508 int cur_draw = 0;
4066 sprite_draw *draw = context->sprite_draw_list + i; 4509 for (int i = 0; i < MAX_SPRITES_LINE * 2; i++)
4067 draw->address = load_int16(buf); 4510 {
4068 draw->x_pos = load_int16(buf); 4511 if (cur_draw < MAX_SPRITES_LINE) {
4069 draw->pal_priority = load_int8(buf); 4512 sprite_draw *last = cur_draw ? context->sprite_draw_list + cur_draw - 1 : NULL;
4070 draw->h_flip = load_int8(buf); 4513 sprite_draw *draw = context->sprite_draw_list + cur_draw++;
4514 draw->address = load_int16(buf);
4515 draw->x_pos = load_int16(buf);
4516 draw->pal_priority = load_int8(buf);
4517 draw->h_flip = load_int8(buf);
4518 draw->width = 1;
4519 draw->height = 8;
4520
4521 if (last && last->width < 4 && last->h_flip == draw->h_flip && last->pal_priority == draw->pal_priority) {
4522 int adjust_x = draw->x_pos + draw->h_flip ? -8 : 8;
4523 int height = draw->address - last->address /4;
4524 if (last->x_pos == adjust_x && (
4525 (last->width > 1 && height == last->height) ||
4526 (last->width == 1 && (height == 8 || height == 16 || height == 24 || height == 32))
4527 )) {
4528 //current draw appears to be part of the same sprite as the last one, combine it
4529 cur_draw--;
4530 last->width++;
4531 }
4532 }
4533 } else {
4534 load_int16(buf);
4535 load_int16(buf);
4536 load_int8(buf);
4537 load_int8(buf);
4538 }
4539 }
4540 } else {
4541 for (int i = 0; i < MAX_SPRITES_LINE; i++)
4542 {
4543 sprite_draw *draw = context->sprite_draw_list + i;
4544 draw->address = load_int16(buf);
4545 draw->x_pos = load_int16(buf);
4546 draw->pal_priority = load_int8(buf);
4547 draw->h_flip = load_int8(buf);
4548 draw->width = load_int8(buf);
4549 draw->height = load_int8(buf);
4550 }
4071 } 4551 }
4072 for (int i = 0; i < MAX_SPRITES_LINE; i++) 4552 for (int i = 0; i < MAX_SPRITES_LINE; i++)
4073 { 4553 {
4074 sprite_info *info = context->sprite_info_list + i; 4554 sprite_info *info = context->sprite_info_list + i;
4075 info->size = load_int8(buf); 4555 info->size = load_int8(buf);
4079 load_buffer8(buf, context->linebuf, LINEBUF_SIZE); 4559 load_buffer8(buf, context->linebuf, LINEBUF_SIZE);
4080 4560
4081 context->cycles = load_int32(buf); 4561 context->cycles = load_int32(buf);
4082 context->pending_vint_start = load_int32(buf); 4562 context->pending_vint_start = load_int32(buf);
4083 context->pending_hint_start = load_int32(buf); 4563 context->pending_hint_start = load_int32(buf);
4564 if (version > 2) {
4565 context->address_latch = load_int32(buf);
4566 context->cd_latch = load_int8(buf);
4567 } else {
4568 context->address_latch = context->address;
4569 context->cd_latch = context->cd;
4570 }
4084 update_video_params(context); 4571 update_video_params(context);
4085 } 4572 }
4086 4573
4087 static vdp_context *current_vdp; 4574 static vdp_context *current_vdp;
4088 static void vdp_debug_window_close(uint8_t which) 4575 static void vdp_debug_window_close(uint8_t which)
4155 context->debug_modes[i]++; 4642 context->debug_modes[i]++;
4156 return; 4643 return;
4157 } 4644 }
4158 } 4645 }
4159 } 4646 }
4647
4648 void vdp_replay_event(vdp_context *context, uint8_t event, event_reader *reader)
4649 {
4650 uint32_t address;
4651 deserialize_buffer *buffer = &reader->buffer;
4652 switch (event)
4653 {
4654 case EVENT_VRAM_BYTE:
4655 reader_ensure_data(reader, 3);
4656 address = load_int16(buffer);
4657 break;
4658 case EVENT_VRAM_BYTE_DELTA:
4659 reader_ensure_data(reader, 2);
4660 address = reader->last_byte_address + load_int8(buffer);
4661 break;
4662 case EVENT_VRAM_BYTE_ONE:
4663 reader_ensure_data(reader, 1);
4664 address = reader->last_byte_address + 1;
4665 break;
4666 case EVENT_VRAM_BYTE_AUTO:
4667 reader_ensure_data(reader, 1);
4668 address = reader->last_byte_address + context->regs[REG_AUTOINC];
4669 break;
4670 case EVENT_VRAM_WORD:
4671 reader_ensure_data(reader, 4);
4672 address = load_int8(buffer) << 16;
4673 address |= load_int16(buffer);
4674 break;
4675 case EVENT_VRAM_WORD_DELTA:
4676 reader_ensure_data(reader, 3);
4677 address = reader->last_word_address + load_int8(buffer);
4678 break;
4679 case EVENT_VDP_REG:
4680 case EVENT_VDP_INTRAM:
4681 reader_ensure_data(reader, event == EVENT_VDP_REG ? 2 : 3);
4682 address = load_int8(buffer);
4683 break;
4684 }
4685
4686 switch (event)
4687 {
4688 case EVENT_VDP_REG: {
4689 uint8_t value = load_int8(buffer);
4690 context->regs[address] = value;
4691 if (address == REG_MODE_4) {
4692 context->double_res = (value & (BIT_INTERLACE | BIT_DOUBLE_RES)) == (BIT_INTERLACE | BIT_DOUBLE_RES);
4693 if (!context->double_res) {
4694 context->flags2 &= ~FLAG2_EVEN_FIELD;
4695 }
4696 }
4697 if (address == REG_MODE_1 || address == REG_MODE_2 || address == REG_MODE_4) {
4698 update_video_params(context);
4699 }
4700 break;
4701 }
4702 case EVENT_VRAM_BYTE:
4703 case EVENT_VRAM_BYTE_DELTA:
4704 case EVENT_VRAM_BYTE_ONE:
4705 case EVENT_VRAM_BYTE_AUTO: {
4706 uint8_t byte = load_int8(buffer);
4707 reader->last_byte_address = address;
4708 vdp_check_update_sat_byte(context, address ^ 1, byte);
4709 write_vram_byte(context, address ^ 1, byte);
4710 break;
4711 }
4712 case EVENT_VRAM_WORD:
4713 case EVENT_VRAM_WORD_DELTA: {
4714 uint16_t value = load_int16(buffer);
4715 reader->last_word_address = address;
4716 vdp_check_update_sat(context, address, value);
4717 write_vram_word(context, address, value);
4718 break;
4719 }
4720 case EVENT_VDP_INTRAM:
4721 if (address < 128) {
4722 write_cram(context, address, load_int16(buffer));
4723 } else {
4724 context->vsram[address&63] = load_int16(buffer);
4725 }
4726 break;
4727 }
4728 }