comparison vdp.c @ 1931:374a5ae694e8 mame_interp

Merge from default
author Michael Pavone <pavone@retrodev.com>
date Sat, 18 Apr 2020 11:42:53 -0700
parents c7e3e3ebb64a
children c3c62dbf1ceb
comparison
equal deleted inserted replaced
1843:13abdc98379e 1931:374a5ae694e8
68 {127, 0, 0}, //Window 68 {127, 0, 0}, //Window
69 {0, 127, 0}, //B 69 {0, 127, 0}, //B
70 {127, 0, 127} //Sprites 70 {127, 0, 127} //Sprites
71 }; 71 };
72 72
73 static uint32_t calc_crop(uint32_t crop, uint32_t border)
74 {
75 return crop >= border ? 0 : border - crop;
76 }
77
73 static void update_video_params(vdp_context *context) 78 static void update_video_params(vdp_context *context)
74 { 79 {
80 uint32_t top_crop = render_overscan_top();
81 uint32_t bot_crop = render_overscan_bot();
82 uint32_t border_top;
75 if (context->regs[REG_MODE_2] & BIT_MODE_5) { 83 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
76 if (context->regs[REG_MODE_2] & BIT_PAL) { 84 if (context->regs[REG_MODE_2] & BIT_PAL) {
77 if (context->flags2 & FLAG2_REGION_PAL) { 85 if (context->flags2 & FLAG2_REGION_PAL) {
78 context->inactive_start = PAL_INACTIVE_START; 86 context->inactive_start = PAL_INACTIVE_START;
79 context->border_top = BORDER_TOP_V30_PAL; 87 border_top = BORDER_TOP_V30_PAL;
80 context->border_bot = BORDER_BOT_V30_PAL; 88 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V30_PAL);
81 } else { 89 } else {
82 //the behavior here is rather weird and needs more investigation 90 //the behavior here is rather weird and needs more investigation
83 context->inactive_start = 0xF0; 91 context->inactive_start = 0xF0;
84 context->border_top = 1; 92 border_top = 1;
85 context->border_bot = 3; 93 context->border_bot = calc_crop(bot_crop, 3);
86 } 94 }
87 } else { 95 } else {
88 context->inactive_start = NTSC_INACTIVE_START; 96 context->inactive_start = NTSC_INACTIVE_START;
89 if (context->flags2 & FLAG2_REGION_PAL) { 97 if (context->flags2 & FLAG2_REGION_PAL) {
90 context->border_top = BORDER_TOP_V28_PAL; 98 border_top = BORDER_TOP_V28_PAL;
91 context->border_bot = BORDER_BOT_V28_PAL; 99 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V28_PAL);
92 } else { 100 } else {
93 context->border_top = BORDER_TOP_V28; 101 border_top = BORDER_TOP_V28;
94 context->border_bot = BORDER_TOP_V28; 102 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V28);
95 } 103 }
96 } 104 }
97 if (context->regs[REG_MODE_4] & BIT_H40) { 105 if (context->regs[REG_MODE_4] & BIT_H40) {
98 context->max_sprites_frame = MAX_SPRITES_FRAME; 106 context->max_sprites_frame = MAX_SPRITES_FRAME;
99 context->max_sprites_line = MAX_SPRITES_LINE; 107 context->max_sprites_line = MAX_SPRITES_LINE;
110 } 118 }
111 } 119 }
112 } else { 120 } else {
113 context->inactive_start = MODE4_INACTIVE_START; 121 context->inactive_start = MODE4_INACTIVE_START;
114 if (context->flags2 & FLAG2_REGION_PAL) { 122 if (context->flags2 & FLAG2_REGION_PAL) {
115 context->border_top = BORDER_TOP_V24_PAL; 123 border_top = BORDER_TOP_V24_PAL;
116 context->border_bot = BORDER_BOT_V24_PAL; 124 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V24_PAL);
117 } else { 125 } else {
118 context->border_top = BORDER_TOP_V24; 126 border_top = BORDER_TOP_V24;
119 context->border_bot = BORDER_BOT_V24; 127 context->border_bot = calc_crop(bot_crop, BORDER_BOT_V24);
120 } 128 }
121 if (!(context->regs[REG_MODE_1] & BIT_MODE_4)){ 129 if (!(context->regs[REG_MODE_1] & BIT_MODE_4)){
122 context->state = INACTIVE; 130 context->state = INACTIVE;
123 } else if (context->state == INACTIVE) { 131 } else if (context->state == INACTIVE) {
124 //Undo forced INACTIVE state due to neither Mode 4 nor Mode 5 being active 132 //Undo forced INACTIVE state due to neither Mode 4 nor Mode 5 being active
128 else if (context->vcounter == 0x1FF) { 136 else if (context->vcounter == 0x1FF) {
129 context->state = PREPARING; 137 context->state = PREPARING;
130 } 138 }
131 } 139 }
132 } 140 }
141 context->border_top = calc_crop(top_crop, border_top);
142 context->top_offset = border_top - context->border_top;
133 } 143 }
134 144
135 static uint8_t color_map_init_done; 145 static uint8_t color_map_init_done;
136 146
137 vdp_context *init_vdp_context(uint8_t region_pal) 147 vdp_context *init_vdp_context(uint8_t region_pal, uint8_t has_max_vsram)
138 { 148 {
139 vdp_context *context = calloc(1, sizeof(vdp_context) + VRAM_SIZE); 149 vdp_context *context = calloc(1, sizeof(vdp_context) + VRAM_SIZE);
140 if (headless) { 150 if (headless) {
141 context->output = malloc(LINEBUF_SIZE * sizeof(uint32_t)); 151 context->fb = malloc(512 * LINEBUF_SIZE * sizeof(uint32_t));
142 context->output_pitch = 0; 152 context->output_pitch = LINEBUF_SIZE * sizeof(uint32_t);
143 } else { 153 } else {
144 context->cur_buffer = FRAMEBUFFER_ODD; 154 context->cur_buffer = FRAMEBUFFER_ODD;
145 context->fb = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch); 155 context->fb = render_get_framebuffer(FRAMEBUFFER_ODD, &context->output_pitch);
146 } 156 }
147 context->sprite_draws = MAX_DRAWS; 157 context->sprite_draws = MAX_SPRITES_LINE;
148 context->fifo_write = 0; 158 context->fifo_write = 0;
149 context->fifo_read = -1; 159 context->fifo_read = -1;
150 context->regs[REG_HINT] = context->hint_counter = 0xFF; 160 context->regs[REG_HINT] = context->hint_counter = 0xFF;
161 context->vsram_size = has_max_vsram ? MAX_VSRAM_SIZE : MIN_VSRAM_SIZE;
151 162
152 if (!color_map_init_done) { 163 if (!color_map_init_done) {
153 uint8_t b,g,r; 164 uint8_t b,g,r;
154 for (uint16_t color = 0; color < (1 << 12); color++) { 165 for (uint16_t color = 0; color < (1 << 12); color++) {
155 if (color & FBUF_SHADOW) { 166 if (color & FBUF_SHADOW) {
233 } 244 }
234 if (region_pal) { 245 if (region_pal) {
235 context->flags2 |= FLAG2_REGION_PAL; 246 context->flags2 |= FLAG2_REGION_PAL;
236 } 247 }
237 update_video_params(context); 248 update_video_params(context);
238 if (!headless) { 249 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * context->border_top);
239 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * context->border_top);
240 }
241 return context; 250 return context;
242 } 251 }
243 252
244 void vdp_free(vdp_context *context) 253 void vdp_free(vdp_context *context)
245 { 254 {
267 } 276 }
268 } 277 }
269 278
270 static void render_sprite_cells(vdp_context * context) 279 static void render_sprite_cells(vdp_context * context)
271 { 280 {
281 if (context->cur_slot > MAX_SPRITES_LINE) {
282 context->cur_slot--;
283 return;
284 }
285 if (context->cur_slot < 0) {
286 return;
287 }
272 sprite_draw * d = context->sprite_draw_list + context->cur_slot; 288 sprite_draw * d = context->sprite_draw_list + context->cur_slot;
273 context->serial_address = d->address; 289 uint16_t address = d->address;
274 if (context->cur_slot >= context->sprite_draws) { 290 address += context->sprite_x_offset * d->height * 4;
275 291 context->serial_address = address;
276 uint16_t dir; 292 uint16_t dir;
277 int16_t x; 293 int16_t x;
278 if (d->h_flip) { 294 if (d->h_flip) {
279 x = d->x_pos + 7; 295 x = d->x_pos + 7 + 8 * (d->width - context->sprite_x_offset - 1);
280 dir = -1; 296 dir = -1;
281 } else { 297 } else {
282 x = d->x_pos; 298 x = d->x_pos + context->sprite_x_offset * 8;
283 dir = 1; 299 dir = 1;
284 } 300 }
285 //printf("Draw Slot %d of %d, Rendering sprite cell from %X to x: %d\n", context->cur_slot, context->sprite_draws, d->address, x); 301 if (d->x_pos) {
286 context->cur_slot--; 302 context->flags |= FLAG_CAN_MASK;
287 for (uint16_t address = d->address; address != ((d->address+4) & 0xFFFF); address++) { 303 if (!(context->flags & FLAG_MASKED)) {
288 if (x >= 0 && x < 320) { 304 x -= 128;
289 if (!(context->linebuf[x] & 0xF)) { 305 //printf("Draw Slot %d of %d, Rendering sprite cell from %X to x: %d\n", context->cur_slot, context->sprite_draws, d->address, x);
290 context->linebuf[x] = (context->vdpmem[address] >> 4) | d->pal_priority; 306 uint8_t collide = 0;
291 } else if (context->vdpmem[address] >> 4) { 307 if (x >= 8 && x < 312) {
292 context->flags2 |= FLAG2_SPRITE_COLLIDE; 308 //sprite is fully visible
293 } 309 for (; address != ((context->serial_address+4) & 0xFFFF); address++) {
294 } 310 uint8_t pixel = context->vdpmem[address] >> 4;
295 x += dir; 311 if (!(context->linebuf[x] & 0xF)) {
296 if (x >= 0 && x < 320) { 312 context->linebuf[x] = pixel | d->pal_priority;
297 if (!(context->linebuf[x] & 0xF)) { 313 } else {
298 context->linebuf[x] = (context->vdpmem[address] & 0xF) | d->pal_priority; 314 collide |= pixel;
299 } else if (context->vdpmem[address] & 0xF) { 315 }
300 context->flags2 |= FLAG2_SPRITE_COLLIDE; 316 x += dir;
301 } 317 pixel = context->vdpmem[address] & 0xF;
302 } 318 if (!(context->linebuf[x] & 0xF)) {
303 x += dir; 319 context->linebuf[x] = pixel | d->pal_priority;
304 } 320 } else {
305 } else { 321 collide |= pixel;
322 }
323 x += dir;
324 }
325 } else if (x > -8 && x < 327) {
326 //sprite is partially visible
327 for (; address != ((context->serial_address+4) & 0xFFFF); address++) {
328 if (x >= 0 && x < 320) {
329 uint8_t pixel = context->vdpmem[address] >> 4;
330 if (!(context->linebuf[x] & 0xF)) {
331 context->linebuf[x] = pixel | d->pal_priority;
332 } else {
333 collide |= pixel;
334 }
335 }
336 x += dir;
337 if (x >= 0 && x < 320) {
338 uint8_t pixel = context->vdpmem[address] & 0xF;
339 if (!(context->linebuf[x] & 0xF)) {
340 context->linebuf[x] = pixel | d->pal_priority;
341 } else {
342 collide |= pixel;
343 }
344 }
345 x += dir;
346 }
347 }
348 if (collide) {
349 context->flags2 |= FLAG2_SPRITE_COLLIDE;
350 }
351 }
352 } else if (context->flags & FLAG_CAN_MASK) {
353 context->flags |= FLAG_MASKED;
354 context->flags &= ~FLAG_CAN_MASK;
355 }
356
357 context->sprite_x_offset++;
358 if (context->sprite_x_offset == d->width) {
359 d->x_pos = 0;
360 context->sprite_x_offset = 0;
306 context->cur_slot--; 361 context->cur_slot--;
307 } 362 }
308 } 363 }
309 364
310 static void fetch_sprite_cells_mode4(vdp_context * context) 365 static void fetch_sprite_cells_mode4(vdp_context * context)
528 "Status: %X\n", 583 "Status: %X\n",
529 context->address, context->cd, cd_name(context->cd), 584 context->address, context->cd, cd_name(context->cd),
530 (context->flags & FLAG_PENDING) ? "word" : (context->flags2 & FLAG2_BYTE_PENDING) ? "byte" : "none", 585 (context->flags & FLAG_PENDING) ? "word" : (context->flags2 & FLAG2_BYTE_PENDING) ? "byte" : "none",
531 context->vcounter, context->hslot*2, (context->flags2 & FLAG2_VINT_PENDING) ? "true" : "false", 586 context->vcounter, context->hslot*2, (context->flags2 & FLAG2_VINT_PENDING) ? "true" : "false",
532 (context->flags2 & FLAG2_HINT_PENDING) ? "true" : "false", vdp_control_port_read(context)); 587 (context->flags2 & FLAG2_HINT_PENDING) ? "true" : "false", vdp_control_port_read(context));
588 printf("\nDebug Register: %X | Output disabled: %s, Force Layer: %d\n", context->test_port,
589 (context->test_port & TEST_BIT_DISABLE) ? "true" : "false", context->test_port >> 7 & 3
590 );
533 //restore flags as calling vdp_control_port_read can change them 591 //restore flags as calling vdp_control_port_read can change them
534 context->flags = old_flags; 592 context->flags = old_flags;
535 context->flags2 = old_flags2; 593 context->flags2 = old_flags2;
536 } 594 }
537 595
693 if (context->double_res) { 751 if (context->double_res) {
694 address = ((tileinfo & 0x3FF) << 6) + row * 4; 752 address = ((tileinfo & 0x3FF) << 6) + row * 4;
695 } else { 753 } else {
696 address = ((tileinfo & 0x7FF) << 5) + row * 4; 754 address = ((tileinfo & 0x7FF) << 5) + row * 4;
697 } 755 }
698 int16_t x = ((context->vdpmem[att_addr+ 2] & 0x3) << 8 | context->vdpmem[att_addr + 3]) & 0x1FF; 756 context->sprite_draws--;
699 if (x) { 757 context->sprite_draw_list[context->sprite_draws].x_pos = ((context->vdpmem[att_addr+ 2] & 0x3) << 8 | context->vdpmem[att_addr + 3]) & 0x1FF;
700 context->flags |= FLAG_CAN_MASK; 758 context->sprite_draw_list[context->sprite_draws].address = address;
701 } else if(context->flags & (FLAG_CAN_MASK | FLAG_DOT_OFLOW)) { 759 context->sprite_draw_list[context->sprite_draws].pal_priority = pal_priority;
702 context->flags |= FLAG_MASKED; 760 context->sprite_draw_list[context->sprite_draws].h_flip = (tileinfo & MAP_BIT_H_FLIP) ? 1 : 0;
703 } 761 context->sprite_draw_list[context->sprite_draws].width = width;
704 762 context->sprite_draw_list[context->sprite_draws].height = height;
705 context->flags &= ~FLAG_DOT_OFLOW;
706 int16_t i;
707 if (context->flags & FLAG_MASKED) {
708 for (i=0; i < width && context->sprite_draws; i++) {
709 --context->sprite_draws;
710 context->sprite_draw_list[context->sprite_draws].x_pos = -128;
711 context->sprite_draw_list[context->sprite_draws].address = address + i * height * 4;
712 }
713 } else {
714 x -= 128;
715 int16_t base_x = x;
716 int16_t dir;
717 if (tileinfo & MAP_BIT_H_FLIP) {
718 x += (width-1) * 8;
719 dir = -8;
720 } else {
721 dir = 8;
722 }
723 //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);
724 for (i=0; i < width && context->sprite_draws; i++, x += dir) {
725 --context->sprite_draws;
726 context->sprite_draw_list[context->sprite_draws].address = address + i * height * 4;
727 context->sprite_draw_list[context->sprite_draws].x_pos = x;
728 context->sprite_draw_list[context->sprite_draws].pal_priority = pal_priority;
729 context->sprite_draw_list[context->sprite_draws].h_flip = (tileinfo & MAP_BIT_H_FLIP) ? 1 : 0;
730 }
731 }
732 //Used to be i < width
733 //TODO: Confirm this is the right condition on hardware
734 if (!context->sprite_draws) {
735 context->flags |= FLAG_DOT_OFLOW;
736 }
737 } else {
738 context->flags |= FLAG_DOT_OFLOW;
739 } 763 }
740 } 764 }
741 context->cur_slot++; 765 context->cur_slot++;
742 } 766 }
743 767
788 addr = address & 0x1F; 812 addr = address & 0x1F;
789 value = (value << 1 & 0xE) | (value << 2 & 0xE0) | (value & 0xE00); 813 value = (value << 1 & 0xE) | (value << 2 & 0xE0) | (value & 0xE00);
790 } 814 }
791 write_cram_internal(context, addr, value); 815 write_cram_internal(context, addr, value);
792 816
793 if (context->hslot >= BG_START_SLOT && ( 817 if (context->output && context->hslot >= BG_START_SLOT && (
794 context->vcounter < context->inactive_start + context->border_bot 818 context->vcounter < context->inactive_start + context->border_bot
795 || context->vcounter > 0x200 - context->border_top 819 || context->vcounter > 0x200 - context->border_top
796 )) { 820 )) {
797 uint8_t bg_end_slot = BG_START_SLOT + (context->regs[REG_MODE_4] & BIT_H40) ? LINEBUF_SIZE/2 : (256+HORIZ_BORDER)/2; 821 uint8_t bg_end_slot = BG_START_SLOT + (context->regs[REG_MODE_4] & BIT_H40) ? LINEBUF_SIZE/2 : (256+HORIZ_BORDER)/2;
798 if (context->hslot < bg_end_slot) { 822 if (context->hslot < bg_end_slot) {
913 write_cram(context, start->address, start->partial ? context->fifo[context->fifo_write].value : start->value); 937 write_cram(context, start->address, start->partial ? context->fifo[context->fifo_write].value : start->value);
914 } 938 }
915 break; 939 break;
916 } 940 }
917 case VSRAM_WRITE: 941 case VSRAM_WRITE:
918 if (((start->address/2) & 63) < VSRAM_SIZE) { 942 if (((start->address/2) & 63) < context->vsram_size) {
919 //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); 943 //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);
920 if (start->partial == 3) { 944 if (start->partial == 3) {
921 if (start->address & 1) { 945 if (start->address & 1) {
922 context->vsram[(start->address/2) & 63] &= 0xFF; 946 context->vsram[(start->address/2) & 63] &= 0xFF;
923 context->vsram[(start->address/2) & 63] |= start->value << 8; 947 context->vsram[(start->address/2) & 63] |= start->value << 8;
950 } else { 974 } else {
951 context->prefetch = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1]; 975 context->prefetch = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1];
952 976
953 context->flags |= FLAG_READ_FETCHED; 977 context->flags |= FLAG_READ_FETCHED;
954 } 978 }
955 } else if (!(context->cd & 1) && !(context->flags & (FLAG_READ_FETCHED|FLAG_PENDING))) { 979 } else if (!(context->cd & 1) && !(context->flags & FLAG_READ_FETCHED)) {
956 switch(context->cd & 0xF) 980 switch(context->cd & 0xF)
957 { 981 {
958 case VRAM_READ: 982 case VRAM_READ:
959 if (context->flags2 & FLAG2_READ_PENDING) { 983 if (context->flags2 & FLAG2_READ_PENDING) {
960 context->prefetch |= context->vdpmem[context->address | 1]; 984 context->prefetch |= context->vdpmem[context->address | 1];
987 //Should this happen after the prefetch or after the read? 1011 //Should this happen after the prefetch or after the read?
988 increment_address(context); 1012 increment_address(context);
989 break; 1013 break;
990 case VSRAM_READ: { 1014 case VSRAM_READ: {
991 uint16_t address = (context->address /2) & 63; 1015 uint16_t address = (context->address /2) & 63;
992 if (address >= VSRAM_SIZE) { 1016 if (address >= context->vsram_size) {
993 address = 0; 1017 address = 0;
994 } 1018 }
995 context->prefetch = context->vsram[address] & VSRAM_BITS; 1019 context->prefetch = context->vsram[address] & VSRAM_BITS;
996 context->prefetch |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS; 1020 context->prefetch |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS;
997 context->flags |= FLAG_READ_FETCHED; 1021 context->flags |= FLAG_READ_FETCHED;
1123 } 1147 }
1124 vscroll &= context->vscroll_latch[vsram_off] + line; 1148 vscroll &= context->vscroll_latch[vsram_off] + line;
1125 context->v_offset = vscroll & v_offset_mask; 1149 context->v_offset = vscroll & v_offset_mask;
1126 //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); 1150 //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);
1127 vscroll >>= vscroll_shift; 1151 vscroll >>= vscroll_shift;
1128 uint16_t hscroll_mask; 1152 //TODO: Verify the behavior for a setting of 2
1129 uint16_t v_mul; 1153 static const uint16_t hscroll_masks[] = {0x1F, 0x3F, 0x1F, 0x7F};
1130 switch(context->regs[REG_SCROLL] & 0x3) 1154 static const uint16_t v_shifts[] = {6, 7, 0, 8};
1131 { 1155 uint16_t hscroll_mask = hscroll_masks[context->regs[REG_SCROLL] & 0x3];
1132 case 0: 1156 uint16_t v_shift = v_shifts[context->regs[REG_SCROLL] & 0x3];
1133 hscroll_mask = 0x1F;
1134 v_mul = 64;
1135 break;
1136 case 0x1:
1137 hscroll_mask = 0x3F;
1138 v_mul = 128;
1139 break;
1140 case 0x2:
1141 //TODO: Verify this behavior
1142 hscroll_mask = 0x1F;
1143 v_mul = 0;
1144 break;
1145 case 0x3:
1146 hscroll_mask = 0x7F;
1147 v_mul = 256;
1148 break;
1149 }
1150 uint16_t hscroll, offset; 1157 uint16_t hscroll, offset;
1151 for (int i = 0; i < 2; i++) { 1158 for (int i = 0; i < 2; i++) {
1152 hscroll = (column - 2 + i - ((hscroll_val/8) & 0xFFFE)) & hscroll_mask; 1159 hscroll = (column - 2 + i - ((hscroll_val/8) & 0xFFFE)) & hscroll_mask;
1153 offset = address + ((vscroll * v_mul + hscroll*2) & 0x1FFF); 1160 offset = address + (((vscroll << v_shift) + hscroll*2) & 0x1FFF);
1154 //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); 1161 //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);
1155 uint16_t col_val = (context->vdpmem[offset] << 8) | context->vdpmem[offset+1]; 1162 uint16_t col_val = (context->vdpmem[offset] << 8) | context->vdpmem[offset+1];
1156 if (i) { 1163 if (i) {
1157 context->col_2 = col_val; 1164 context->col_2 = col_val;
1158 } else { 1165 } else {
1206 } else { 1213 } else {
1207 address += 4 * context->v_offset; 1214 address += 4 * context->v_offset;
1208 } 1215 }
1209 uint8_t pal_priority = (col >> 9) & 0x70; 1216 uint8_t pal_priority = (col >> 9) & 0x70;
1210 uint32_t bits = *((uint32_t *)(&context->vdpmem[address])); 1217 uint32_t bits = *((uint32_t *)(&context->vdpmem[address]));
1218 tmp_buf += offset;
1211 if (col & MAP_BIT_H_FLIP) { 1219 if (col & MAP_BIT_H_FLIP) {
1212 uint32_t shift = 28; 1220 uint32_t shift = 28;
1213 for (int i = 0; i < 4; i++) 1221 for (int i = 0; i < 4; i++)
1214 { 1222 {
1215 uint8_t right = pal_priority | ((bits >> shift) & 0xF); 1223 uint8_t right = pal_priority | ((bits >> shift) & 0xF);
1216 shift -= 4; 1224 shift -= 4;
1217 tmp_buf[offset++] = pal_priority | ((bits >> shift) & 0xF); 1225 *(tmp_buf++) = pal_priority | ((bits >> shift) & 0xF);
1218 shift -= 4; 1226 shift -= 4;
1219 offset &= SCROLL_BUFFER_MASK; 1227 *(tmp_buf++) = right;
1220 tmp_buf[offset++] = right;
1221 offset &= SCROLL_BUFFER_MASK;
1222 } 1228 }
1223 } else { 1229 } else {
1224 for (int i = 0; i < 4; i++) 1230 for (int i = 0; i < 4; i++)
1225 { 1231 {
1226 uint8_t right = pal_priority | (bits & 0xF); 1232 uint8_t right = pal_priority | (bits & 0xF);
1227 bits >>= 4; 1233 bits >>= 4;
1228 tmp_buf[offset++] = pal_priority | (bits & 0xF); 1234 *(tmp_buf++) = pal_priority | (bits & 0xF);
1229 offset &= SCROLL_BUFFER_MASK;
1230 bits >>= 4; 1235 bits >>= 4;
1231 tmp_buf[offset++] = right; 1236 *(tmp_buf++) = right;
1232 offset &= SCROLL_BUFFER_MASK;
1233 } 1237 }
1234 } 1238 }
1235 } 1239 }
1236 1240
1237 static void render_map_1(vdp_context * context) 1241 static void render_map_1(vdp_context * context)
1326 return (sh_pixel){.index = pixel, .intensity = intensity}; 1330 return (sh_pixel){.index = pixel, .intensity = intensity};
1327 } 1331 }
1328 1332
1329 static void render_normal(vdp_context *context, int32_t col, uint8_t *dst, uint8_t *debug_dst, int plane_a_off, int plane_b_off) 1333 static void render_normal(vdp_context *context, int32_t col, uint8_t *dst, uint8_t *debug_dst, int plane_a_off, int plane_b_off)
1330 { 1334 {
1331 int start = 0; 1335 uint8_t *sprite_buf = context->linebuf + col * 8;
1332 if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) { 1336 if (!col && (context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1333 memset(dst, 0, 8); 1337 memset(dst, 0, 8);
1334 memset(debug_dst, DBG_SRC_BG, 8); 1338 memset(debug_dst, DBG_SRC_BG, 8);
1335 dst += 8; 1339 dst += 8;
1336 debug_dst += 8; 1340 debug_dst += 8;
1337 start = 8; 1341 sprite_buf += 8;
1338 } 1342 plane_a_off += 8;
1339 uint8_t *sprite_buf = context->linebuf + col * 8 + start; 1343 plane_b_off += 8;
1340 for (int i = start; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i) 1344 for (int i = 0; i < 8; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1341 { 1345 {
1342 uint8_t sprite, plane_a, plane_b; 1346 uint8_t sprite, plane_a, plane_b;
1343 plane_a = context->tmp_buf_a[plane_a_off & SCROLL_BUFFER_MASK]; 1347 plane_a = context->tmp_buf_a[plane_a_off & SCROLL_BUFFER_MASK];
1344 plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK]; 1348 plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1345 sprite = *sprite_buf; 1349 *(dst++) = composite_normal(context, debug_dst, *sprite_buf, plane_a, plane_b, context->regs[REG_BG_COLOR]) & 0x3F;
1346 *(dst++) = composite_normal(context, debug_dst, sprite, plane_a, plane_b, context->regs[REG_BG_COLOR]) & 0x3F; 1350 debug_dst++;
1347 debug_dst++; 1351 }
1352 } else {
1353 for (int i = 0; i < 16; ++plane_a_off, ++plane_b_off, ++sprite_buf, ++i)
1354 {
1355 uint8_t sprite, plane_a, plane_b;
1356 plane_a = context->tmp_buf_a[plane_a_off & SCROLL_BUFFER_MASK];
1357 plane_b = context->tmp_buf_b[plane_b_off & SCROLL_BUFFER_MASK];
1358 *(dst++) = composite_normal(context, debug_dst, *sprite_buf, plane_a, plane_b, context->regs[REG_BG_COLOR]) & 0x3F;
1359 debug_dst++;
1360 }
1348 } 1361 }
1349 } 1362 }
1350 1363
1351 static void render_highlight(vdp_context *context, int32_t col, uint8_t *dst, uint8_t *debug_dst, int plane_a_off, int plane_b_off) 1364 static void render_highlight(vdp_context *context, int32_t col, uint8_t *dst, uint8_t *debug_dst, int plane_a_off, int plane_b_off)
1352 { 1365 {
1607 uint8_t a_src, src; 1620 uint8_t a_src, src;
1608 if (context->flags & FLAG_WINDOW) { 1621 if (context->flags & FLAG_WINDOW) {
1609 plane_a_off = context->buf_a_off; 1622 plane_a_off = context->buf_a_off;
1610 a_src = DBG_SRC_W; 1623 a_src = DBG_SRC_W;
1611 } else { 1624 } else {
1612 plane_a_off = context->buf_a_off - (context->hscroll_a & 0xF); 1625 plane_a_off = context->buf_a_off - context->hscroll_a_fine;
1613 a_src = DBG_SRC_A; 1626 a_src = DBG_SRC_A;
1614 } 1627 }
1615 plane_b_off = context->buf_b_off - (context->hscroll_b & 0xF); 1628 plane_b_off = context->buf_b_off - context->hscroll_b_fine;
1616 //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7)); 1629 //printf("A | tmp_buf offset: %d\n", 8 - (context->hscroll_a & 0x7));
1617 1630
1618 if (context->regs[REG_MODE_4] & BIT_HILIGHT) { 1631 if (context->regs[REG_MODE_4] & BIT_HILIGHT) {
1619 if (output_disabled || test_layer) { 1632 if (output_disabled || test_layer) {
1620 render_testreg_highlight(context, col, dst, debug_dst, plane_a_off, plane_b_off, output_disabled, test_layer); 1633 render_testreg_highlight(context, col, dst, debug_dst, plane_a_off, plane_b_off, output_disabled, test_layer);
1640 switch(test_layer) 1653 switch(test_layer)
1641 { 1654 {
1642 case 1: 1655 case 1:
1643 memset(dst, 0, BORDER_LEFT); 1656 memset(dst, 0, BORDER_LEFT);
1644 memset(debug_dst, DBG_SRC_BG, BORDER_LEFT); 1657 memset(debug_dst, DBG_SRC_BG, BORDER_LEFT);
1658 dst += BORDER_LEFT;
1645 break; 1659 break;
1646 case 2: { 1660 case 2: {
1647 //plane A 1661 //plane A
1648 //TODO: Deal with Window layer 1662 //TODO: Deal with Window layer
1649 int i; 1663 int i;
1650 i = 0; 1664 i = 0;
1651 uint8_t buf_off = context->buf_a_off - (context->hscroll_a & 0xF) + (16 - BORDER_LEFT); 1665 uint8_t buf_off = context->buf_a_off - context->hscroll_a_fine + (16 - BORDER_LEFT);
1652 //uint8_t *src = context->tmp_buf_a + ((context->buf_a_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_a & 0xF))) & SCROLL_BUFFER_MASK); 1666 //uint8_t *src = context->tmp_buf_a + ((context->buf_a_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_a & 0xF))) & SCROLL_BUFFER_MASK);
1653 for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++) 1667 for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++)
1654 { 1668 {
1655 *dst = context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK]; 1669 *dst = context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK];
1656 *debug_dst = DBG_SRC_A; 1670 *debug_dst = DBG_SRC_A;
1659 } 1673 }
1660 case 3: { 1674 case 3: {
1661 //plane B 1675 //plane B
1662 int i; 1676 int i;
1663 i = 0; 1677 i = 0;
1664 uint8_t buf_off = context->buf_b_off - (context->hscroll_b & 0xF) + (16 - BORDER_LEFT); 1678 uint8_t buf_off = context->buf_b_off - context->hscroll_b_fine + (16 - BORDER_LEFT);
1665 //uint8_t *src = context->tmp_buf_b + ((context->buf_b_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_b & 0xF))) & SCROLL_BUFFER_MASK); 1679 //uint8_t *src = context->tmp_buf_b + ((context->buf_b_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_b & 0xF))) & SCROLL_BUFFER_MASK);
1666 for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++) 1680 for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++)
1667 { 1681 {
1668 *dst = context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK]; 1682 *dst = context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK];
1669 *debug_dst = DBG_SRC_B; 1683 *debug_dst = DBG_SRC_B;
1672 } 1686 }
1673 } 1687 }
1674 } else { 1688 } else {
1675 memset(dst, pixel, BORDER_LEFT); 1689 memset(dst, pixel, BORDER_LEFT);
1676 memset(debug_dst, DBG_SRC_BG, BORDER_LEFT); 1690 memset(debug_dst, DBG_SRC_BG, BORDER_LEFT);
1677 } 1691 dst += BORDER_LEFT;
1678 dst += BORDER_LEFT; 1692 }
1679 } 1693 }
1680 context->done_composite = dst; 1694 context->done_composite = dst;
1681 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; 1695 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
1682 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK; 1696 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
1683 } 1697 }
1723 context->buf_a_off = (context->buf_a_off + 8) & 15; 1737 context->buf_a_off = (context->buf_a_off + 8) & 15;
1724 1738
1725 uint8_t *dst = context->compositebuf + col * 8 + BORDER_LEFT; 1739 uint8_t *dst = context->compositebuf + col * 8 + BORDER_LEFT;
1726 uint8_t *debug_dst = context->layer_debug_buf + col * 8 + BORDER_LEFT; 1740 uint8_t *debug_dst = context->layer_debug_buf + col * 8 + BORDER_LEFT;
1727 if (context->state == PREPARING) { 1741 if (context->state == PREPARING) {
1728 memset(dst, 0, 8); 1742 memset(dst, 0x10 + (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET, 8);
1729 memset(debug_dst, DBG_SRC_BG, 8); 1743 memset(debug_dst, DBG_SRC_BG, 8);
1730 context->done_composite = dst + 8; 1744 context->done_composite = dst + 8;
1731 return; 1745 return;
1732 } 1746 }
1733 1747
1750 *(debug_dst++) = DBG_SRC_S; 1764 *(debug_dst++) = DBG_SRC_S;
1751 } 1765 }
1752 } 1766 }
1753 context->done_composite = dst; 1767 context->done_composite = dst;
1754 } else { 1768 } else {
1755 memset(dst, 0, 8); 1769 memset(dst, 0x10 + (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET, 8);
1756 memset(dst, DBG_SRC_BG, 8); 1770 memset(debug_dst, DBG_SRC_BG, 8);
1757 context->done_composite = dst + 8; 1771 context->done_composite = dst + 8;
1758 } 1772 }
1759 } 1773 }
1760 1774
1761 static uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19}; 1775 static uint32_t const h40_hsync_cycles[] = {19, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 18, 20, 20, 20, 19};
1807 } else { 1821 } else {
1808 line += context->border_top; 1822 line += context->border_top;
1809 } 1823 }
1810 if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) { 1824 if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) {
1811 uint32_t *fb = context->debug_fbs[VDP_DEBUG_CRAM] + context->debug_fb_pitch[VDP_DEBUG_CRAM] * line / sizeof(uint32_t); 1825 uint32_t *fb = context->debug_fbs[VDP_DEBUG_CRAM] + context->debug_fb_pitch[VDP_DEBUG_CRAM] * line / sizeof(uint32_t);
1812 for (int i = 0; i < 64; i++) 1826 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
1813 { 1827 for (int i = 0; i < 64; i++)
1814 for (int x = 0; x < 8; x++)
1815 { 1828 {
1816 *(fb++) = context->colors[i]; 1829 for (int x = 0; x < 8; x++)
1830 {
1831 *(fb++) = context->colors[i];
1832 }
1833 }
1834 } else {
1835 for (int i = MODE4_OFFSET; i < MODE4_OFFSET+32; i++)
1836 {
1837 for (int x = 0; x < 16; x++)
1838 {
1839 *(fb++) = context->colors[i];
1840 }
1817 } 1841 }
1818 } 1842 }
1819 } 1843 }
1820 if ( 1844 if (
1821 context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE) 1845 context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE)
1986 2010
1987 if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) { 2011 if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) {
1988 uint32_t starting_line = 512 - 32*4; 2012 uint32_t starting_line = 512 - 32*4;
1989 uint32_t *line = context->debug_fbs[VDP_DEBUG_CRAM] 2013 uint32_t *line = context->debug_fbs[VDP_DEBUG_CRAM]
1990 + context->debug_fb_pitch[VDP_DEBUG_CRAM] * starting_line / sizeof(uint32_t); 2014 + context->debug_fb_pitch[VDP_DEBUG_CRAM] * starting_line / sizeof(uint32_t);
1991 for (int pal = 0; pal < 4; pal ++) 2015 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
1992 { 2016 for (int pal = 0; pal < 4; pal ++)
1993 uint32_t *cur;
1994 for (int y = 0; y < 31; y++)
1995 { 2017 {
2018 uint32_t *cur;
2019 for (int y = 0; y < 31; y++)
2020 {
2021 cur = line;
2022 for (int offset = 0; offset < 16; offset++)
2023 {
2024 for (int x = 0; x < 31; x++)
2025 {
2026 *(cur++) = context->colors[pal * 16 + offset];
2027 }
2028 *(cur++) = 0xFF000000;
2029 }
2030 line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t);
2031 }
1996 cur = line; 2032 cur = line;
1997 for (int offset = 0; offset < 16; offset++) 2033 for (int x = 0; x < 512; x++)
1998 { 2034 {
1999 for (int x = 0; x < 31; x++) 2035 *(cur++) = 0xFF000000;
2036 }
2037 line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t);
2038 }
2039 } else {
2040 for (int pal = 0; pal < 2; pal ++)
2041 {
2042 uint32_t *cur;
2043 for (int y = 0; y < 31; y++)
2044 {
2045 cur = line;
2046 for (int offset = MODE4_OFFSET; offset < MODE4_OFFSET + 16; offset++)
2000 { 2047 {
2001 *(cur++) = context->colors[pal * 16 + offset]; 2048 for (int x = 0; x < 31; x++)
2049 {
2050 *(cur++) = context->colors[pal * 16 + offset];
2051 }
2052 *(cur++) = 0xFF000000;
2002 } 2053 }
2054 line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t);
2055 }
2056 cur = line;
2057 for (int x = 0; x < 512; x++)
2058 {
2003 *(cur++) = 0xFF000000; 2059 *(cur++) = 0xFF000000;
2004 } 2060 }
2005 line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t); 2061 line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t);
2006 } 2062 }
2007 cur = line;
2008 for (int x = 0; x < 512; x++)
2009 {
2010 *(cur++) = 0xFF000000;
2011 }
2012 line += context->debug_fb_pitch[VDP_DEBUG_CRAM] / sizeof(uint32_t);
2013 } 2063 }
2014 render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_CRAM], 512); 2064 render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_CRAM], 512);
2015 context->debug_fbs[VDP_DEBUG_CRAM] = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_CRAM], &context->debug_fb_pitch[VDP_DEBUG_CRAM]); 2065 context->debug_fbs[VDP_DEBUG_CRAM] = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_CRAM], &context->debug_fb_pitch[VDP_DEBUG_CRAM]);
2016 } 2066 }
2017 if (context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE)) { 2067 if (context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE)) {
2020 } 2070 }
2021 } 2071 }
2022 2072
2023 void vdp_force_update_framebuffer(vdp_context *context) 2073 void vdp_force_update_framebuffer(vdp_context *context)
2024 { 2074 {
2025 uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL) 2075 if (!context->fb) {
2026 ? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL 2076 return;
2027 : 224 + BORDER_TOP_V28 + BORDER_BOT_V28; 2077 }
2078 uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top;
2028 2079
2029 uint16_t to_fill = lines_max - context->output_lines; 2080 uint16_t to_fill = lines_max - context->output_lines;
2030 memset( 2081 memset(
2031 ((char *)context->fb) + context->output_pitch * context->output_lines, 2082 ((char *)context->fb) + context->output_pitch * context->output_lines,
2032 0, 2083 0,
2037 vdp_update_per_frame_debug(context); 2088 vdp_update_per_frame_debug(context);
2038 } 2089 }
2039 2090
2040 static void advance_output_line(vdp_context *context) 2091 static void advance_output_line(vdp_context *context)
2041 { 2092 {
2042 if (headless) { 2093 //This function is kind of gross because of the need to deal with vertical border busting via mode changes
2043 if (context->vcounter == context->inactive_start) { 2094 uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top;
2044 context->frame++; 2095 uint32_t output_line = context->vcounter;
2045 } 2096 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) {
2046 context->vcounter &= 0x1FF; 2097 //vcounter increment occurs much later in Mode 4
2047 } else { 2098 output_line++;
2048 uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL) 2099 }
2049 ? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL 2100
2050 : 224 + BORDER_TOP_V28 + BORDER_BOT_V28; 2101 if (context->output_lines >= lines_max || (!context->pushed_frame && output_line == context->inactive_start + context->border_top)) {
2051 2102 //we've either filled up a full frame or we're at the bottom of screen in the current defined mode + border crop
2052 if (context->output_lines == lines_max) { 2103 if (!headless) {
2053 render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER)); 2104 render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER));
2054 context->cur_buffer = context->flags2 & FLAG2_EVEN_FIELD ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD; 2105 uint8_t is_even = context->flags2 & FLAG2_EVEN_FIELD;
2055 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch); 2106 if (context->vcounter <= context->inactive_start && (context->regs[REG_MODE_4] & BIT_INTERLACE)) {
2056 vdp_update_per_frame_debug(context); 2107 is_even = !is_even;
2057 context->h40_lines = 0; 2108 }
2058 context->frame++; 2109 context->cur_buffer = is_even ? FRAMEBUFFER_EVEN : FRAMEBUFFER_ODD;
2110 context->pushed_frame = 1;
2111 context->fb = NULL;
2112 }
2113 vdp_update_per_frame_debug(context);
2114 context->h40_lines = 0;
2115 context->frame++;
2116 context->output_lines = 0;
2117 }
2118
2119 if (output_line < context->inactive_start + context->border_bot) {
2120 if (context->output_lines) {
2121 output_line = context->output_lines++;//context->border_top + context->vcounter;
2122 } else if (!output_line && !context->border_top) {
2123 //top border is completely cropped so we won't hit the case below
2124 output_line = 0;
2125 context->output_lines = 1;
2126 context->pushed_frame = 0;
2127 } else {
2128 context->output_lines = output_line + 1;
2129 }
2130 } else if (output_line >= 0x200 - context->border_top) {
2131 if (output_line == 0x200 - context->border_top) {
2132 //We're at the top of the display, force context->output_lines to be zero to avoid
2133 //potential screen rolling if the mode is changed at an inopportune time
2059 context->output_lines = 0; 2134 context->output_lines = 0;
2060 } 2135 context->pushed_frame = 0;
2061 uint32_t output_line = context->vcounter; 2136 }
2062 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) { 2137 output_line = context->output_lines++;//context->vcounter - (0x200 - context->border_top);
2063 //vcounter increment occurs much later in Mode 4 2138 } else {
2064 output_line++; 2139 context->output = NULL;
2065 } 2140 return;
2066 if (output_line < context->inactive_start + context->border_bot && context->output_lines > 0) { 2141 }
2067 output_line = context->output_lines++;//context->border_top + context->vcounter; 2142 if (!context->fb) {
2068 } else if (output_line >= 0x200 - context->border_top) { 2143 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch);
2069 if (output_line == 0x200 - context->border_top) { 2144 }
2070 //We're at the top of the display, force context->output_lines to be zero to avoid 2145 output_line += context->top_offset;
2071 //potential screen rolling if the mode is changed at an inopportune time 2146 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * output_line);
2072 context->output_lines = 0;
2073 }
2074 output_line = context->output_lines++;//context->vcounter - (0x200 - context->border_top);
2075 } else {
2076 context->output = NULL;
2077 }
2078 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * output_line);
2079 #ifdef DEBUG_FB_FILL 2147 #ifdef DEBUG_FB_FILL
2080 for (int i = 0; i < LINEBUF_SIZE; i++) 2148 for (int i = 0; i < LINEBUF_SIZE; i++)
2081 { 2149 {
2082 context->output[i] = 0xFFFF00FF; 2150 context->output[i] = 0xFFFF00FF;
2083 } 2151 }
2084 #endif 2152 #endif
2085 if (context->output && (context->regs[REG_MODE_4] & BIT_H40)) { 2153 if (context->output && (context->regs[REG_MODE_4] & BIT_H40)) {
2086 context->h40_lines++; 2154 context->h40_lines++;
2087 }
2088 } 2155 }
2089 } 2156 }
2090 2157
2091 void vdp_release_framebuffer(vdp_context *context) 2158 void vdp_release_framebuffer(vdp_context *context)
2092 { 2159 {
2093 render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER)); 2160 if (context->fb) {
2094 context->output = context->fb = NULL; 2161 render_framebuffer_updated(context->cur_buffer, context->h40_lines > (context->inactive_start + context->border_top) / 2 ? LINEBUF_SIZE : (256+HORIZ_BORDER));
2162 context->output = context->fb = NULL;
2163 }
2095 } 2164 }
2096 2165
2097 void vdp_reacquire_framebuffer(vdp_context *context) 2166 void vdp_reacquire_framebuffer(vdp_context *context)
2098 { 2167 {
2099 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch); 2168 uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top;
2100 uint16_t lines_max = (context->flags2 & FLAG2_REGION_PAL)
2101 ? 240 + BORDER_TOP_V30_PAL + BORDER_BOT_V30_PAL
2102 : 224 + BORDER_TOP_V28 + BORDER_BOT_V28;
2103 if (context->output_lines <= lines_max && context->output_lines > 0) { 2169 if (context->output_lines <= lines_max && context->output_lines > 0) {
2104 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * (context->output_lines - 1)); 2170 context->fb = render_get_framebuffer(context->cur_buffer, &context->output_pitch);
2171 context->output = (uint32_t *)(((char *)context->fb) + context->output_pitch * (context->output_lines - 1 + context->top_offset));
2105 } else { 2172 } else {
2106 context->output = NULL; 2173 context->output = NULL;
2107 } 2174 }
2108 } 2175 }
2109 2176
2136 case 2: { 2203 case 2: {
2137 //plane A 2204 //plane A
2138 //TODO: Deal with Window layer 2205 //TODO: Deal with Window layer
2139 int i; 2206 int i;
2140 i = 0; 2207 i = 0;
2141 uint8_t buf_off = context->buf_a_off - (context->hscroll_a & 0xF); 2208 uint8_t buf_off = context->buf_a_off - context->hscroll_a_fine;
2142 //uint8_t *src = context->tmp_buf_a + ((context->buf_a_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_a & 0xF))) & SCROLL_BUFFER_MASK); 2209 //uint8_t *src = context->tmp_buf_a + ((context->buf_a_off + (i ? 0 : (16 - BORDER_LEFT) - (context->hscroll_a & 0xF))) & SCROLL_BUFFER_MASK);
2143 for (; i < BORDER_RIGHT; buf_off++, i++, dst++) 2210 for (; i < BORDER_RIGHT; buf_off++, i++, dst++)
2144 { 2211 {
2145 *dst = context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK] & 0x3F; 2212 *dst = context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK] & 0x3F;
2146 } 2213 }
2213 if (slot != (BG_START_SLOT + (256+HORIZ_BORDER)/2)) {\ 2280 if (slot != (BG_START_SLOT + (256+HORIZ_BORDER)/2)) {\
2214 if ((*src & 0x3F) | test_layer) {\ 2281 if ((*src & 0x3F) | test_layer) {\
2215 *(dst++) = context->colors[*(src++)];\ 2282 *(dst++) = context->colors[*(src++)];\
2216 } else {\ 2283 } else {\
2217 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];\ 2284 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];\
2285 }\
2286 }\
2287 }
2288
2289 //BG_START_SLOT => dst = 0, src = border
2290 //BG_START_SLOT + 13/2=6, dst = 6, src = border + comp + 13
2291 #define OUTPUT_PIXEL_MODE4(slot) if ((slot) >= BG_START_SLOT) {\
2292 uint8_t *src = context->compositebuf + ((slot) - BG_START_SLOT) *2;\
2293 uint32_t *dst = context->output + ((slot) - BG_START_SLOT) *2;\
2294 if ((slot) - BG_START_SLOT < BORDER_LEFT/2) {\
2295 *(dst++) = context->colors[bgindex];\
2296 *(dst++) = context->colors[bgindex];\
2297 } else if ((slot) - BG_START_SLOT < (BORDER_LEFT+256)/2){\
2298 if ((slot) - BG_START_SLOT == BORDER_LEFT/2) {\
2299 *(dst++) = context->colors[bgindex];\
2300 src++;\
2301 } else {\
2302 *(dst++) = context->colors[*(src++)];\
2303 }\
2304 *(dst++) = context->colors[*(src++)];\
2305 } else if ((slot) - BG_START_SLOT <= (HORIZ_BORDER+256)/2) {\
2306 *(dst++) = context->colors[bgindex];\
2307 if ((slot) - BG_START_SLOT < (HORIZ_BORDER+256)/2) {\
2308 *(dst++) = context->colors[bgindex];\
2218 }\ 2309 }\
2219 }\ 2310 }\
2220 } 2311 }
2221 2312
2222 #define COLUMN_RENDER_BLOCK(column, startcyc) \ 2313 #define COLUMN_RENDER_BLOCK(column, startcyc) \
2289 render_map_output(context->vcounter, column, context);\ 2380 render_map_output(context->vcounter, column, context);\
2290 CHECK_LIMIT 2381 CHECK_LIMIT
2291 2382
2292 #define COLUMN_RENDER_BLOCK_MODE4(column, startcyc) \ 2383 #define COLUMN_RENDER_BLOCK_MODE4(column, startcyc) \
2293 case startcyc:\ 2384 case startcyc:\
2294 OUTPUT_PIXEL(startcyc)\ 2385 OUTPUT_PIXEL_MODE4(startcyc)\
2295 read_map_mode4(column, context->vcounter, context);\ 2386 read_map_mode4(column, context->vcounter, context);\
2296 CHECK_LIMIT\ 2387 CHECK_LIMIT\
2297 case ((startcyc+1)&0xFF):\ 2388 case ((startcyc+1)&0xFF):\
2298 OUTPUT_PIXEL((startcyc+1)&0xFF)\ 2389 OUTPUT_PIXEL_MODE4((startcyc+1)&0xFF)\
2299 if (column & 3) {\ 2390 if (column & 3) {\
2300 scan_sprite_table_mode4(context);\ 2391 scan_sprite_table_mode4(context);\
2301 } else {\ 2392 } else {\
2302 external_slot(context);\ 2393 external_slot(context);\
2303 }\ 2394 }\
2304 CHECK_LIMIT\ 2395 CHECK_LIMIT\
2305 case ((startcyc+2)&0xFF):\ 2396 case ((startcyc+2)&0xFF):\
2306 OUTPUT_PIXEL((startcyc+2)&0xFF)\ 2397 OUTPUT_PIXEL_MODE4((startcyc+2)&0xFF)\
2307 fetch_map_mode4(column, context->vcounter, context);\ 2398 fetch_map_mode4(column, context->vcounter, context);\
2308 CHECK_LIMIT\ 2399 CHECK_LIMIT\
2309 case ((startcyc+3)&0xFF):\ 2400 case ((startcyc+3)&0xFF):\
2310 OUTPUT_PIXEL((startcyc+3)&0xFF)\ 2401 OUTPUT_PIXEL_MODE4((startcyc+3)&0xFF)\
2311 render_map_mode4(context->vcounter, column, context);\ 2402 render_map_mode4(context->vcounter, column, context);\
2312 CHECK_LIMIT 2403 CHECK_LIMIT
2313 2404
2314 #define CHECK_LIMIT_HSYNC(slot) \ 2405 #define CHECK_LIMIT_HSYNC(slot) \
2315 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \ 2406 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \
2422 2513
2423 #define CALC_SLOT(slot, increment) ((slot+increment) > 147 && (slot+increment) < 233 ? (slot+increment-148+233): (slot+increment)) 2514 #define CALC_SLOT(slot, increment) ((slot+increment) > 147 && (slot+increment) < 233 ? (slot+increment-148+233): (slot+increment))
2424 2515
2425 #define SPRITE_RENDER_H32_MODE4(slot) \ 2516 #define SPRITE_RENDER_H32_MODE4(slot) \
2426 case slot:\ 2517 case slot:\
2427 OUTPUT_PIXEL_H32(slot)\ 2518 OUTPUT_PIXEL_MODE4(slot)\
2428 read_sprite_x_mode4(context);\ 2519 read_sprite_x_mode4(context);\
2429 MODE4_CHECK_SLOT_LINE(slot)\ 2520 MODE4_CHECK_SLOT_LINE(slot)\
2430 case CALC_SLOT(slot, 1):\ 2521 case CALC_SLOT(slot, 1):\
2431 OUTPUT_PIXEL(CALC_SLOT(slot, 1))\ 2522 OUTPUT_PIXEL_MODE4(CALC_SLOT(slot, 1))\
2432 read_sprite_x_mode4(context);\ 2523 read_sprite_x_mode4(context);\
2433 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot,1))\ 2524 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot,1))\
2434 case CALC_SLOT(slot, 2):\ 2525 case CALC_SLOT(slot, 2):\
2435 OUTPUT_PIXEL(CALC_SLOT(slot, 2))\ 2526 OUTPUT_PIXEL_MODE4(CALC_SLOT(slot, 2))\
2436 fetch_sprite_cells_mode4(context);\ 2527 fetch_sprite_cells_mode4(context);\
2437 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 2))\ 2528 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 2))\
2438 case CALC_SLOT(slot, 3):\ 2529 case CALC_SLOT(slot, 3):\
2439 OUTPUT_PIXEL(CALC_SLOT(slot, 3))\ 2530 OUTPUT_PIXEL_MODE4(CALC_SLOT(slot, 3))\
2440 render_sprite_cells_mode4(context);\ 2531 render_sprite_cells_mode4(context);\
2441 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 3))\ 2532 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 3))\
2442 case CALC_SLOT(slot, 4):\ 2533 case CALC_SLOT(slot, 4):\
2443 OUTPUT_PIXEL(CALC_SLOT(slot, 4))\ 2534 OUTPUT_PIXEL_MODE4(CALC_SLOT(slot, 4))\
2444 fetch_sprite_cells_mode4(context);\ 2535 fetch_sprite_cells_mode4(context);\
2445 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 4))\ 2536 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 4))\
2446 case CALC_SLOT(slot, 5):\ 2537 case CALC_SLOT(slot, 5):\
2447 OUTPUT_PIXEL(CALC_SLOT(slot, 5))\ 2538 OUTPUT_PIXEL_MODE4(CALC_SLOT(slot, 5))\
2448 render_sprite_cells_mode4(context);\ 2539 render_sprite_cells_mode4(context);\
2449 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 5)) 2540 MODE4_CHECK_SLOT_LINE(CALC_SLOT(slot, 5))
2450 2541
2451 static uint32_t dummy_buffer[LINEBUF_SIZE]; 2542 static uint32_t dummy_buffer[LINEBUF_SIZE];
2543 static void vdp_h40_line(vdp_context * context)
2544 {
2545 uint16_t address;
2546 uint32_t mask;
2547 uint32_t const slot_cycles = MCLKS_SLOT_H40;
2548 uint8_t bgindex = context->regs[REG_BG_COLOR] & 0x3F;
2549 uint8_t test_layer = context->test_port >> 7 & 3;
2550
2551 //165
2552 if (!(context->regs[REG_MODE_3] & BIT_VSCROLL)) {
2553 //TODO: Develop some tests on hardware to see when vscroll latch actually happens for full plane mode
2554 //See note in vdp_h32 for why this was originally moved out of read_map_scroll
2555 //Skitchin' has a similar problem, but uses H40 mode. It seems to be able to hit the extern slot at 232
2556 //pretty consistently
2557 context->vscroll_latch[0] = context->vsram[0];
2558 context->vscroll_latch[1] = context->vsram[1];
2559 }
2560 render_sprite_cells(context);
2561 //166
2562 render_sprite_cells(context);
2563 //167
2564 context->sprite_index = 0x80;
2565 context->slot_counter = 0;
2566 render_border_garbage(
2567 context,
2568 context->sprite_draw_list[context->cur_slot].address,
2569 context->tmp_buf_b, context->buf_b_off,
2570 context->col_1
2571 );
2572 render_sprite_cells(context);
2573 scan_sprite_table(context->vcounter, context);
2574 //168
2575 render_border_garbage(
2576 context,
2577 context->sprite_draw_list[context->cur_slot].address,
2578 context->tmp_buf_b,
2579 context->buf_b_off + 8,
2580 context->col_2
2581 );
2582 //Do palette lookup for end of previous line
2583 uint8_t *src = context->compositebuf + (LINE_CHANGE_H40 - BG_START_SLOT) *2;
2584 uint32_t *dst = context->output + (LINE_CHANGE_H40 - BG_START_SLOT) *2;
2585 if (test_layer) {
2586 for (int i = 0; i < LINEBUF_SIZE - (LINE_CHANGE_H40 - BG_START_SLOT) * 2; i++)
2587 {
2588 *(dst++) = context->colors[*(src++)];
2589 }
2590 } else {
2591 for (int i = 0; i < LINEBUF_SIZE - (LINE_CHANGE_H40 - BG_START_SLOT) * 2; i++)
2592 {
2593 if (*src & 0x3F) {
2594 *(dst++) = context->colors[*(src++)];
2595 } else {
2596 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];
2597 }
2598 }
2599 }
2600 advance_output_line(context);
2601 //168-242 (inclusive)
2602 for (int i = 0; i < 28; i++)
2603 {
2604 render_sprite_cells(context);
2605 scan_sprite_table(context->vcounter, context);
2606 }
2607 //243
2608 render_border_garbage(
2609 context,
2610 context->sprite_draw_list[context->cur_slot].address,
2611 context->tmp_buf_a,
2612 context->buf_a_off,
2613 context->col_1
2614 );
2615 //244
2616 address = (context->regs[REG_HSCROLL] & 0x3F) << 10;
2617 mask = 0;
2618 if (context->regs[REG_MODE_3] & 0x2) {
2619 mask |= 0xF8;
2620 }
2621 if (context->regs[REG_MODE_3] & 0x1) {
2622 mask |= 0x7;
2623 }
2624 render_border_garbage(context, address, context->tmp_buf_a, context->buf_a_off+8, context->col_2);
2625 address += (context->vcounter & mask) * 4;
2626 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1];
2627 context->hscroll_a_fine = context->hscroll_a & 0xF;
2628 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3];
2629 context->hscroll_b_fine = context->hscroll_b & 0xF;
2630 //printf("%d: HScroll A: %d, HScroll B: %d\n", context->vcounter, context->hscroll_a, context->hscroll_b);
2631 //243-246 inclusive
2632 for (int i = 0; i < 3; i++)
2633 {
2634 render_sprite_cells(context);
2635 scan_sprite_table(context->vcounter, context);
2636 }
2637 //247
2638 render_border_garbage(
2639 context,
2640 context->sprite_draw_list[context->cur_slot].address,
2641 context->tmp_buf_b,
2642 context->buf_b_off,
2643 context->col_1
2644 );
2645 render_sprite_cells(context);
2646 scan_sprite_table(context->vcounter, context);
2647 //248
2648 render_border_garbage(
2649 context,
2650 context->sprite_draw_list[context->cur_slot].address,
2651 context->tmp_buf_b,
2652 context->buf_b_off + 8,
2653 context->col_2
2654 );
2655 render_sprite_cells(context);
2656 scan_sprite_table(context->vcounter, context);
2657 context->buf_a_off = (context->buf_a_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
2658 context->buf_b_off = (context->buf_b_off + SCROLL_BUFFER_DRAW) & SCROLL_BUFFER_MASK;
2659 //250
2660 render_sprite_cells(context);
2661 scan_sprite_table(context->vcounter, context);
2662 //251
2663 scan_sprite_table(context->vcounter, context);//Just a guess
2664 //252
2665 scan_sprite_table(context->vcounter, context);//Just a guess
2666 //254
2667 render_sprite_cells(context);
2668 scan_sprite_table(context->vcounter, context);
2669 //255
2670 if (context->cur_slot >= 0 && context->sprite_draw_list[context->cur_slot].x_pos) {
2671 context->flags |= FLAG_DOT_OFLOW;
2672 }
2673 scan_sprite_table(context->vcounter, context);
2674 //0
2675 scan_sprite_table(context->vcounter, context);//Just a guess
2676 //seems like the sprite table scan fills a shift register
2677 //values are FIFO, but unused slots precede used slots
2678 //so we set cur_slot to slot_counter and let it wrap around to
2679 //the beginning of the list
2680 context->cur_slot = context->slot_counter;
2681 context->sprite_x_offset = 0;
2682 context->sprite_draws = MAX_SPRITES_LINE;
2683 //background planes and layer compositing
2684 for (int col = 0; col < 42; col+=2)
2685 {
2686 read_map_scroll_a(col, context->vcounter, context);
2687 render_map_1(context);
2688 render_map_2(context);
2689 read_map_scroll_b(col, context->vcounter, context);
2690 render_map_3(context);
2691 render_map_output(context->vcounter, col, context);
2692 }
2693 //sprite rendering phase 2
2694 for (int i = 0; i < MAX_SPRITES_LINE; i++)
2695 {
2696 read_sprite_x(context->vcounter, context);
2697 }
2698 //163
2699 context->cur_slot = MAX_SPRITES_LINE-1;
2700 memset(context->linebuf, 0, LINEBUF_SIZE);
2701 render_border_garbage(
2702 context,
2703 context->sprite_draw_list[context->cur_slot].address,
2704 context->tmp_buf_a, context->buf_a_off,
2705 context->col_1
2706 );
2707 context->flags &= ~FLAG_MASKED;
2708 render_sprite_cells(context);
2709 //164
2710 render_border_garbage(
2711 context,
2712 context->sprite_draw_list[context->cur_slot].address,
2713 context->tmp_buf_a, context->buf_a_off + 8,
2714 context->col_2
2715 );
2716 render_sprite_cells(context);
2717 context->cycles += MCLKS_LINE;
2718 vdp_advance_line(context);
2719 src = context->compositebuf;
2720 dst = context->output;
2721 if (test_layer) {
2722 for (int i = 0; i < (LINE_CHANGE_H40 - BG_START_SLOT) * 2; i++)
2723 {
2724 *(dst++) = context->colors[*(src++)];
2725 }
2726 } else {
2727 for (int i = 0; i < (LINE_CHANGE_H40 - BG_START_SLOT) * 2; i++)
2728 {
2729 if (*src & 0x3F) {
2730 *(dst++) = context->colors[*(src++)];
2731 } else {
2732 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];
2733 }
2734 }
2735 }
2736 }
2452 static void vdp_h40(vdp_context * context, uint32_t target_cycles) 2737 static void vdp_h40(vdp_context * context, uint32_t target_cycles)
2453 { 2738 {
2454 uint16_t address; 2739 uint16_t address;
2455 uint32_t mask; 2740 uint32_t mask;
2456 uint32_t const slot_cycles = MCLKS_SLOT_H40; 2741 uint32_t const slot_cycles = MCLKS_SLOT_H40;
2464 switch(context->hslot) 2749 switch(context->hslot)
2465 { 2750 {
2466 for (;;) 2751 for (;;)
2467 { 2752 {
2468 case 165: 2753 case 165:
2754 //only consider doing a line at a time if the FIFO is empty, there are no pending reads and there is no DMA running
2755 if (context->fifo_read == -1 && !(context->flags & FLAG_DMA_RUN) && ((context->cd & 1) || (context->flags & FLAG_READ_FETCHED))) {
2756 while (target_cycles - context->cycles >= MCLKS_LINE && context->state != PREPARING && context->vcounter != context->inactive_start) {
2757 vdp_h40_line(context);
2758 }
2759 CHECK_ONLY
2760 }
2469 OUTPUT_PIXEL(165) 2761 OUTPUT_PIXEL(165)
2470 if (!(context->regs[REG_MODE_3] & BIT_VSCROLL)) { 2762 if (!(context->regs[REG_MODE_3] & BIT_VSCROLL)) {
2471 //TODO: Develop some tests on hardware to see when vscroll latch actually happens for full plane mode 2763 //TODO: Develop some tests on hardware to see when vscroll latch actually happens for full plane mode
2472 //See note in vdp_h32 for why this was originally moved out of read_map_scroll 2764 //See note in vdp_h32 for why this was originally moved out of read_map_scroll
2473 //Skitchin' has a similar problem, but uses H40 mode. It seems to be able to hit the extern slot at 232 2765 //Skitchin' has a similar problem, but uses H40 mode. It seems to be able to hit the extern slot at 232
2551 mask |= 0x7; 2843 mask |= 0x7;
2552 } 2844 }
2553 render_border_garbage(context, address, context->tmp_buf_a, context->buf_a_off+8, context->col_2); 2845 render_border_garbage(context, address, context->tmp_buf_a, context->buf_a_off+8, context->col_2);
2554 address += (context->vcounter & mask) * 4; 2846 address += (context->vcounter & mask) * 4;
2555 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1]; 2847 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1];
2848 context->hscroll_a_fine = context->hscroll_a & 0xF;
2556 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; 2849 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3];
2850 context->hscroll_b_fine = context->hscroll_b & 0xF;
2557 //printf("%d: HScroll A: %d, HScroll B: %d\n", context->vcounter, context->hscroll_a, context->hscroll_b); 2851 //printf("%d: HScroll A: %d, HScroll B: %d\n", context->vcounter, context->hscroll_a, context->hscroll_b);
2558 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } 2852 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); }
2559 context->hslot++; 2853 context->hslot++;
2560 context->cycles += h40_hsync_cycles[14]; 2854 context->cycles += h40_hsync_cycles[14];
2561 CHECK_ONLY //provides "garbage" for border when plane A selected 2855 CHECK_ONLY //provides "garbage" for border when plane A selected
2579 case 253: 2873 case 253:
2580 read_map_scroll_b(0, context->vcounter, context); 2874 read_map_scroll_b(0, context->vcounter, context);
2581 CHECK_LIMIT 2875 CHECK_LIMIT
2582 SPRITE_RENDER_H40(254) 2876 SPRITE_RENDER_H40(254)
2583 case 255: 2877 case 255:
2878 if (context->cur_slot >= 0 && context->sprite_draw_list[context->cur_slot].x_pos) {
2879 context->flags |= FLAG_DOT_OFLOW;
2880 }
2584 render_map_3(context); 2881 render_map_3(context);
2585 scan_sprite_table(context->vcounter, context);//Just a guess 2882 scan_sprite_table(context->vcounter, context);//Just a guess
2586 CHECK_LIMIT 2883 CHECK_LIMIT
2587 case 0: 2884 case 0:
2588 render_map_output(context->vcounter, 0, context); 2885 render_map_output(context->vcounter, 0, context);
2590 //seems like the sprite table scan fills a shift register 2887 //seems like the sprite table scan fills a shift register
2591 //values are FIFO, but unused slots precede used slots 2888 //values are FIFO, but unused slots precede used slots
2592 //so we set cur_slot to slot_counter and let it wrap around to 2889 //so we set cur_slot to slot_counter and let it wrap around to
2593 //the beginning of the list 2890 //the beginning of the list
2594 context->cur_slot = context->slot_counter; 2891 context->cur_slot = context->slot_counter;
2595 context->sprite_draws = MAX_DRAWS; 2892 context->sprite_x_offset = 0;
2596 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED); 2893 context->sprite_draws = MAX_SPRITES_LINE;
2597 CHECK_LIMIT 2894 CHECK_LIMIT
2598 COLUMN_RENDER_BLOCK(2, 1) 2895 COLUMN_RENDER_BLOCK(2, 1)
2599 COLUMN_RENDER_BLOCK(4, 9) 2896 COLUMN_RENDER_BLOCK(4, 9)
2600 COLUMN_RENDER_BLOCK(6, 17) 2897 COLUMN_RENDER_BLOCK(6, 17)
2601 COLUMN_RENDER_BLOCK_REFRESH(8, 25) 2898 COLUMN_RENDER_BLOCK_REFRESH(8, 25)
2624 external_slot(context); 2921 external_slot(context);
2625 CHECK_LIMIT 2922 CHECK_LIMIT
2626 //sprite render to line buffer starts 2923 //sprite render to line buffer starts
2627 case 163: 2924 case 163:
2628 OUTPUT_PIXEL(163) 2925 OUTPUT_PIXEL(163)
2629 context->cur_slot = MAX_DRAWS-1; 2926 context->cur_slot = MAX_SPRITES_LINE-1;
2630 memset(context->linebuf, 0, LINEBUF_SIZE); 2927 memset(context->linebuf, 0, LINEBUF_SIZE);
2631 render_border_garbage( 2928 render_border_garbage(
2632 context, 2929 context,
2633 context->sprite_draw_list[context->cur_slot].address, 2930 context->sprite_draw_list[context->cur_slot].address,
2634 context->tmp_buf_a, context->buf_a_off, 2931 context->tmp_buf_a, context->buf_a_off,
2635 context->col_1 2932 context->col_1
2636 ); 2933 );
2934 context->flags &= ~FLAG_MASKED;
2637 render_sprite_cells(context); 2935 render_sprite_cells(context);
2638 CHECK_LIMIT 2936 CHECK_LIMIT
2639 case 164: 2937 case 164:
2640 OUTPUT_PIXEL(164) 2938 OUTPUT_PIXEL(164)
2641 render_border_garbage( 2939 render_border_garbage(
2767 mask |= 0x7; 3065 mask |= 0x7;
2768 } 3066 }
2769 render_border_garbage(context, address, context->tmp_buf_a, context->buf_a_off+8, context->col_2); 3067 render_border_garbage(context, address, context->tmp_buf_a, context->buf_a_off+8, context->col_2);
2770 address += (context->vcounter & mask) * 4; 3068 address += (context->vcounter & mask) * 4;
2771 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1]; 3069 context->hscroll_a = context->vdpmem[address] << 8 | context->vdpmem[address+1];
3070 context->hscroll_a_fine = context->hscroll_a & 0xF;
2772 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3]; 3071 context->hscroll_b = context->vdpmem[address+2] << 8 | context->vdpmem[address+3];
3072 context->hscroll_b_fine = context->hscroll_b & 0xF;
2773 //printf("%d: HScroll A: %d, HScroll B: %d\n", context->vcounter, context->hscroll_a, context->hscroll_b); 3073 //printf("%d: HScroll A: %d, HScroll B: %d\n", context->vcounter, context->hscroll_a, context->hscroll_b);
2774 CHECK_LIMIT //provides "garbage" for border when plane A selected 3074 CHECK_LIMIT //provides "garbage" for border when plane A selected
2775 SPRITE_RENDER_H32(245) 3075 SPRITE_RENDER_H32(245)
2776 SPRITE_RENDER_H32(246) 3076 SPRITE_RENDER_H32(246)
2777 SPRITE_RENDER_H32(247) //provides "garbage" for border when plane B selected 3077 SPRITE_RENDER_H32(247) //provides "garbage" for border when plane B selected
2780 case 249: 3080 case 249:
2781 read_map_scroll_a(0, context->vcounter, context); 3081 read_map_scroll_a(0, context->vcounter, context);
2782 CHECK_LIMIT 3082 CHECK_LIMIT
2783 SPRITE_RENDER_H32(250) 3083 SPRITE_RENDER_H32(250)
2784 case 251: 3084 case 251:
3085 if (context->cur_slot >= 0 && context->sprite_draw_list[context->cur_slot].x_pos) {
3086 context->flags |= FLAG_DOT_OFLOW;
3087 }
2785 render_map_1(context); 3088 render_map_1(context);
2786 scan_sprite_table(context->vcounter, context);//Just a guess 3089 scan_sprite_table(context->vcounter, context);//Just a guess
2787 CHECK_LIMIT 3090 CHECK_LIMIT
2788 case 252: 3091 case 252:
2789 render_map_2(context); 3092 render_map_2(context);
2805 scan_sprite_table(context->vcounter, context);//Just a guess 3108 scan_sprite_table(context->vcounter, context);//Just a guess
2806 //reverse context slot counter so it counts the number of sprite slots 3109 //reverse context slot counter so it counts the number of sprite slots
2807 //filled rather than the number of available slots 3110 //filled rather than the number of available slots
2808 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter; 3111 //context->slot_counter = MAX_SPRITES_LINE - context->slot_counter;
2809 context->cur_slot = context->slot_counter; 3112 context->cur_slot = context->slot_counter;
2810 context->sprite_draws = MAX_DRAWS_H32; 3113 context->sprite_x_offset = 0;
2811 context->flags &= (~FLAG_CAN_MASK & ~FLAG_MASKED); 3114 context->sprite_draws = MAX_SPRITES_LINE_H32;
2812 CHECK_LIMIT 3115 CHECK_LIMIT
2813 COLUMN_RENDER_BLOCK(2, 1) 3116 COLUMN_RENDER_BLOCK(2, 1)
2814 COLUMN_RENDER_BLOCK(4, 9) 3117 COLUMN_RENDER_BLOCK(4, 9)
2815 COLUMN_RENDER_BLOCK(6, 17) 3118 COLUMN_RENDER_BLOCK(6, 17)
2816 COLUMN_RENDER_BLOCK_REFRESH(8, 25) 3119 COLUMN_RENDER_BLOCK_REFRESH(8, 25)
2836 CHECK_LIMIT 3139 CHECK_LIMIT
2837 } 3140 }
2838 //sprite render to line buffer starts 3141 //sprite render to line buffer starts
2839 case 131: 3142 case 131:
2840 OUTPUT_PIXEL(131) 3143 OUTPUT_PIXEL(131)
2841 context->cur_slot = MAX_DRAWS_H32-1; 3144 context->cur_slot = MAX_SPRITES_LINE_H32-1;
2842 memset(context->linebuf, 0, LINEBUF_SIZE); 3145 memset(context->linebuf, 0, LINEBUF_SIZE);
2843 render_border_garbage( 3146 render_border_garbage(
2844 context, 3147 context,
2845 context->sprite_draw_list[context->cur_slot].address, 3148 context->sprite_draw_list[context->cur_slot].address,
2846 context->tmp_buf_a, context->buf_a_off, 3149 context->tmp_buf_a, context->buf_a_off,
2847 context->col_1 3150 context->col_1
2848 ); 3151 );
3152 context->flags &= ~FLAG_MASKED;
2849 render_sprite_cells(context); 3153 render_sprite_cells(context);
2850 CHECK_LIMIT 3154 CHECK_LIMIT
2851 case 132: 3155 case 132:
2852 OUTPUT_PIXEL(132) 3156 OUTPUT_PIXEL(132)
2853 render_border_garbage( 3157 render_border_garbage(
2980 COLUMN_RENDER_BLOCK_MODE4(28, 117) 3284 COLUMN_RENDER_BLOCK_MODE4(28, 117)
2981 COLUMN_RENDER_BLOCK_MODE4(29, 121) 3285 COLUMN_RENDER_BLOCK_MODE4(29, 121)
2982 COLUMN_RENDER_BLOCK_MODE4(30, 125) 3286 COLUMN_RENDER_BLOCK_MODE4(30, 125)
2983 COLUMN_RENDER_BLOCK_MODE4(31, 129) 3287 COLUMN_RENDER_BLOCK_MODE4(31, 129)
2984 case 133: 3288 case 133:
2985 OUTPUT_PIXEL(133) 3289 OUTPUT_PIXEL_MODE4(133)
2986 external_slot(context); 3290 external_slot(context);
2987 CHECK_LIMIT 3291 CHECK_LIMIT
2988 case 134: 3292 case 134:
2989 OUTPUT_PIXEL(134) 3293 OUTPUT_PIXEL_MODE4(134)
2990 external_slot(context); 3294 external_slot(context);
2991 CHECK_LIMIT 3295 CHECK_LIMIT
2992 case 135: 3296 case 135:
2993 OUTPUT_PIXEL(135) 3297 OUTPUT_PIXEL_MODE4(135)
2994 external_slot(context); 3298 external_slot(context);
2995 CHECK_LIMIT 3299 CHECK_LIMIT
2996 case 136: { 3300 case 136: {
2997 OUTPUT_PIXEL(136) 3301 OUTPUT_PIXEL_MODE4(136)
2998 external_slot(context); 3302 external_slot(context);
2999 //set things up for sprite rendering in the next slot 3303 //set things up for sprite rendering in the next slot
3000 memset(context->linebuf, 0, LINEBUF_SIZE); 3304 memset(context->linebuf, 0, LINEBUF_SIZE);
3001 context->cur_slot = context->sprite_index = MAX_DRAWS_H32_MODE4-1; 3305 context->cur_slot = context->sprite_index = MAX_DRAWS_H32_MODE4-1;
3002 context->sprite_draws = MAX_DRAWS_H32_MODE4; 3306 context->sprite_draws = MAX_DRAWS_H32_MODE4;
3026 len = BORDER_LEFT; 3330 len = BORDER_LEFT;
3027 } 3331 }
3028 uint8_t *src = NULL; 3332 uint8_t *src = NULL;
3029 if (test_layer == 2) { 3333 if (test_layer == 2) {
3030 //plane A 3334 //plane A
3031 src_off += context->buf_a_off + context->hscroll_a; 3335 src_off += context->buf_a_off - (context->hscroll_a & 0xF);
3032 src = context->tmp_buf_a; 3336 src = context->tmp_buf_a;
3033 } else if (test_layer == 3){ 3337 } else if (test_layer == 3){
3034 //plane B 3338 //plane B
3035 src_off += context->buf_b_off + context->hscroll_b; 3339 src_off += context->buf_b_off - (context->hscroll_b & 0xF);
3036 src = context->tmp_buf_b; 3340 src = context->tmp_buf_b;
3037 } else { 3341 } else {
3038 //sprite layer 3342 //sprite layer
3039 memset(dst, 0, len); 3343 memset(dst, 0, len);
3040 dst += len; 3344 dst += len;
3062 static void vdp_inactive(vdp_context *context, uint32_t target_cycles, uint8_t is_h40, uint8_t mode_5) 3366 static void vdp_inactive(vdp_context *context, uint32_t target_cycles, uint8_t is_h40, uint8_t mode_5)
3063 { 3367 {
3064 uint8_t buf_clear_slot, index_reset_slot, bg_end_slot, vint_slot, line_change, jump_start, jump_dest, latch_slot; 3368 uint8_t buf_clear_slot, index_reset_slot, bg_end_slot, vint_slot, line_change, jump_start, jump_dest, latch_slot;
3065 uint8_t index_reset_value, max_draws, max_sprites; 3369 uint8_t index_reset_value, max_draws, max_sprites;
3066 uint16_t vint_line, active_line; 3370 uint16_t vint_line, active_line;
3067 uint32_t bg_color;
3068 3371
3069 if (mode_5) { 3372 if (mode_5) {
3070 if (is_h40) { 3373 if (is_h40) {
3071 latch_slot = 165; 3374 latch_slot = 165;
3072 buf_clear_slot = 163; 3375 buf_clear_slot = 163;
3073 index_reset_slot = 167; 3376 index_reset_slot = 167;
3074 bg_end_slot = BG_START_SLOT + LINEBUF_SIZE/2; 3377 bg_end_slot = BG_START_SLOT + LINEBUF_SIZE/2;
3075 max_draws = MAX_DRAWS-1; 3378 max_draws = MAX_SPRITES_LINE-1;
3076 max_sprites = MAX_SPRITES_LINE; 3379 max_sprites = MAX_SPRITES_LINE;
3077 index_reset_value = 0x80; 3380 index_reset_value = 0x80;
3078 vint_slot = VINT_SLOT_H40; 3381 vint_slot = VINT_SLOT_H40;
3079 line_change = LINE_CHANGE_H40; 3382 line_change = LINE_CHANGE_H40;
3080 jump_start = 182; 3383 jump_start = 182;
3081 jump_dest = 229; 3384 jump_dest = 229;
3082 } else { 3385 } else {
3083 bg_end_slot = BG_START_SLOT + (256+HORIZ_BORDER)/2; 3386 bg_end_slot = BG_START_SLOT + (256+HORIZ_BORDER)/2;
3084 max_draws = MAX_DRAWS_H32-1; 3387 max_draws = MAX_SPRITES_LINE_H32-1;
3085 max_sprites = MAX_SPRITES_LINE_H32; 3388 max_sprites = MAX_SPRITES_LINE_H32;
3086 buf_clear_slot = 128; 3389 buf_clear_slot = 128;
3087 index_reset_slot = 132; 3390 index_reset_slot = 132;
3088 index_reset_value = 0x80; 3391 index_reset_value = 0x80;
3089 vint_slot = VINT_SLOT_H32; 3392 vint_slot = VINT_SLOT_H32;
3106 index_reset_slot = 253; 3409 index_reset_slot = 253;
3107 index_reset_value = 0; 3410 index_reset_value = 0;
3108 vint_line = context->inactive_start + 1; 3411 vint_line = context->inactive_start + 1;
3109 vint_slot = VINT_SLOT_MODE4; 3412 vint_slot = VINT_SLOT_MODE4;
3110 line_change = LINE_CHANGE_MODE4; 3413 line_change = LINE_CHANGE_MODE4;
3111 bg_color = render_map_color(0, 0, 0);
3112 jump_start = 147; 3414 jump_start = 147;
3113 jump_dest = 233; 3415 jump_dest = 233;
3114 if (context->regs[REG_MODE_1] & BIT_MODE_4) { 3416 if (context->regs[REG_MODE_1] & BIT_MODE_4) {
3115 active_line = 0x1FF; 3417 active_line = 0x1FF;
3116 } else { 3418 } else {
3154 case 7: 3456 case 7:
3155 render_border_garbage(context, context->serial_address, context->tmp_buf_b, context->buf_b_off, context->col_1); 3457 render_border_garbage(context, context->serial_address, context->tmp_buf_b, context->buf_b_off, context->col_1);
3156 break; 3458 break;
3157 case 0: 3459 case 0:
3158 render_border_garbage(context, context->serial_address, context->tmp_buf_b, context->buf_b_off+8, context->col_2); 3460 render_border_garbage(context, context->serial_address, context->tmp_buf_b, context->buf_b_off+8, context->col_2);
3461 break;
3462 case 1:
3159 inactive_test_output(context, is_h40, test_layer); 3463 inactive_test_output(context, is_h40, test_layer);
3160 break; 3464 break;
3161 } 3465 }
3162 } 3466 }
3163 3467
3187 context->flags2 ^= FLAG2_EVEN_FIELD; 3491 context->flags2 ^= FLAG2_EVEN_FIELD;
3188 } 3492 }
3189 3493
3190 if (dst) { 3494 if (dst) {
3191 uint8_t bg_index; 3495 uint8_t bg_index;
3496 uint32_t bg_color;
3192 if (mode_5) { 3497 if (mode_5) {
3193 bg_index = context->regs[REG_BG_COLOR] & 0x3F; 3498 bg_index = context->regs[REG_BG_COLOR] & 0x3F;
3194 bg_color = context->colors[bg_index]; 3499 bg_color = context->colors[bg_index];
3195 } else if (context->regs[REG_MODE_1] & BIT_MODE_4) { 3500 } else if (context->regs[REG_MODE_1] & BIT_MODE_4) {
3196 bg_index = 0x10 + (context->regs[REG_BG_COLOR] & 0xF); 3501 bg_index = 0x10 + (context->regs[REG_BG_COLOR] & 0xF);
3197 bg_color = context->colors[MODE4_OFFSET + bg_index]; 3502 bg_color = context->colors[MODE4_OFFSET + bg_index];
3503 } else {
3504 bg_color = render_map_color(0, 0, 0);
3198 } 3505 }
3199 if (context->done_composite) { 3506 if (context->done_composite) {
3200 uint8_t pixel = context->compositebuf[dst-context->output]; 3507 uint8_t pixel = context->compositebuf[dst-context->output];
3201 if (!(pixel & 0x3F | test_layer)) { 3508 if (!(pixel & 0x3F | test_layer)) {
3202 pixel = pixel & 0xC0 | bg_index; 3509 pixel = pixel & 0xC0 | bg_index;
3382 hv |= get_ext_vcounter(context); 3689 hv |= get_ext_vcounter(context);
3383 3690
3384 return hv; 3691 return hv;
3385 } 3692 }
3386 3693
3694 static void clear_pending(vdp_context *context)
3695 {
3696 context->flags &= ~FLAG_PENDING;
3697 context->address = context->address_latch;
3698 //It seems like the DMA enable bit doesn't so much enable DMA so much
3699 //as it enables changing CD5 from control port writes
3700 if (context->regs[REG_MODE_2] & BIT_DMA_ENABLE) {
3701 context->cd = context->cd_latch;
3702 } else {
3703 context->cd = (context->cd & 0x20) | (context->cd_latch & 0x1F);
3704 }
3705 }
3706
3387 int vdp_control_port_write(vdp_context * context, uint16_t value) 3707 int vdp_control_port_write(vdp_context * context, uint16_t value)
3388 { 3708 {
3389 //printf("control port write: %X at %d\n", value, context->cycles); 3709 //printf("control port write: %X at %d\n", value, context->cycles);
3390 if (context->flags & FLAG_DMA_RUN) { 3710 if (context->flags & FLAG_DMA_RUN) {
3391 return -1; 3711 return -1;
3392 } 3712 }
3393 if (context->flags & FLAG_PENDING) { 3713 if (context->flags & FLAG_PENDING) {
3394 context->address = (context->address & 0x3FFF) | (value << 14 & 0x1C000); 3714 context->address_latch = (context->address_latch & 0x3FFF) | (value << 14 & 0x1C000);
3395 //It seems like the DMA enable bit doesn't so much enable DMA so much 3715 context->cd_latch = (context->cd_latch & 0x3) | ((value >> 2) & ~0x3 & 0xFF);
3396 //as it enables changing CD5 from control port writes 3716 clear_pending(context);
3397 uint8_t preserve = (context->regs[REG_MODE_2] & BIT_DMA_ENABLE) ? 0x3 : 0x23;
3398 context->cd = (context->cd & preserve) | ((value >> 2) & ~preserve & 0xFF);
3399 context->flags &= ~FLAG_PENDING;
3400 //Should these be taken care of here or after the first write? 3717 //Should these be taken care of here or after the first write?
3401 context->flags &= ~FLAG_READ_FETCHED; 3718 context->flags &= ~FLAG_READ_FETCHED;
3402 context->flags2 &= ~FLAG2_READ_PENDING; 3719 context->flags2 &= ~FLAG2_READ_PENDING;
3403 //printf("New Address: %X, New CD: %X\n", context->address, context->cd); 3720 //printf("New Address: %X, New CD: %X\n", context->address, context->cd);
3404 if (context->cd & 0x20) { 3721 if (context->cd & 0x20) {
3423 //printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd); 3740 //printf("DMA Fill Address: %X, New CD: %X\n", context->address, context->cd);
3424 } 3741 }
3425 } 3742 }
3426 } else { 3743 } else {
3427 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; 3744 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
3428 context->address = (context->address &0xC000) | (value & 0x3FFF); 3745 //contrary to what's in Charles MacDonald's doc, it seems top 2 address bits are cleared
3429 context->cd = (context->cd & 0x3C) | (value >> 14); 3746 //needed for the Mona in 344 Bytes demo
3747 context->address_latch = (context->address_latch & 0x1C000) | (value & 0x3FFF);
3748 context->cd_latch = (context->cd_latch & 0x3C) | (value >> 14);
3430 if ((value & 0xC000) == 0x8000) { 3749 if ((value & 0xC000) == 0x8000) {
3431 //Register write 3750 //Register write
3432 uint8_t reg = (value >> 8) & 0x1F; 3751 uint8_t reg = (value >> 8) & 0x1F;
3433 if (reg < (mode_5 ? VDP_REGS : 0xB)) { 3752 if (reg < (mode_5 ? VDP_REGS : 0xB)) {
3434 //printf("register %d set to %X\n", reg, value & 0xFF); 3753 //printf("register %d set to %X\n", reg, value & 0xFF);
3486 //printf("data port write: %X at %d\n", value, context->cycles); 3805 //printf("data port write: %X at %d\n", value, context->cycles);
3487 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) != DMA_FILL) { 3806 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) != DMA_FILL) {
3488 return -1; 3807 return -1;
3489 } 3808 }
3490 if (context->flags & FLAG_PENDING) { 3809 if (context->flags & FLAG_PENDING) {
3491 context->flags &= ~FLAG_PENDING; 3810 clear_pending(context);
3492 //Should these be cleared here? 3811 //Should these be cleared here?
3493 context->flags &= ~FLAG_READ_FETCHED; 3812 context->flags &= ~FLAG_READ_FETCHED;
3494 context->flags2 &= ~FLAG2_READ_PENDING; 3813 context->flags2 &= ~FLAG2_READ_PENDING;
3495 } 3814 }
3496 /*if (context->fifo_cur == context->fifo_end) { 3815 /*if (context->fifo_cur == context->fifo_end) {
3521 } 3840 }
3522 3841
3523 void vdp_data_port_write_pbc(vdp_context * context, uint8_t value) 3842 void vdp_data_port_write_pbc(vdp_context * context, uint8_t value)
3524 { 3843 {
3525 if (context->flags & FLAG_PENDING) { 3844 if (context->flags & FLAG_PENDING) {
3526 context->flags &= ~FLAG_PENDING; 3845 clear_pending(context);
3527 //Should these be cleared here? 3846 //Should these be cleared here?
3528 context->flags &= ~FLAG_READ_FETCHED; 3847 context->flags &= ~FLAG_READ_FETCHED;
3529 context->flags2 &= ~FLAG2_READ_PENDING; 3848 context->flags2 &= ~FLAG2_READ_PENDING;
3530 } 3849 }
3531 context->flags2 &= ~FLAG2_BYTE_PENDING; 3850 context->flags2 &= ~FLAG2_BYTE_PENDING;
3560 context->test_port = value; 3879 context->test_port = value;
3561 } 3880 }
3562 3881
3563 uint16_t vdp_control_port_read(vdp_context * context) 3882 uint16_t vdp_control_port_read(vdp_context * context)
3564 { 3883 {
3565 context->flags &= ~FLAG_PENDING; 3884 if (context->flags & FLAG_PENDING) {
3885 clear_pending(context);
3886 }
3566 context->flags2 &= ~FLAG2_BYTE_PENDING; 3887 context->flags2 &= ~FLAG2_BYTE_PENDING;
3567 //Bits 15-10 are not fixed like Charles MacDonald's doc suggests, but instead open bus values that reflect 68K prefetch 3888 //Bits 15-10 are not fixed like Charles MacDonald's doc suggests, but instead open bus values that reflect 68K prefetch
3568 uint16_t value = context->system->get_open_bus_value(context->system) & 0xFC00; 3889 uint16_t value = context->system->get_open_bus_value(context->system) & 0xFC00;
3569 if (context->fifo_read < 0) { 3890 if (context->fifo_read < 0) {
3570 value |= 0x200; 3891 value |= 0x200;
3610 } 3931 }
3611 3932
3612 uint16_t vdp_data_port_read(vdp_context * context) 3933 uint16_t vdp_data_port_read(vdp_context * context)
3613 { 3934 {
3614 if (context->flags & FLAG_PENDING) { 3935 if (context->flags & FLAG_PENDING) {
3615 context->flags &= ~FLAG_PENDING; 3936 clear_pending(context);
3616 //Should these be cleared here? 3937 //Should these be cleared here?
3617 context->flags &= ~FLAG_READ_FETCHED; 3938 context->flags &= ~FLAG_READ_FETCHED;
3618 context->flags2 &= ~FLAG2_READ_PENDING; 3939 context->flags2 &= ~FLAG2_READ_PENDING;
3619 } 3940 }
3620 if (context->cd & 1) { 3941 if (context->cd & 1) {
3627 return context->prefetch; 3948 return context->prefetch;
3628 } 3949 }
3629 3950
3630 uint8_t vdp_data_port_read_pbc(vdp_context * context) 3951 uint8_t vdp_data_port_read_pbc(vdp_context * context)
3631 { 3952 {
3632 context->flags &= ~(FLAG_PENDING | FLAG_READ_FETCHED); 3953 if (context->flags & FLAG_PENDING) {
3954 clear_pending(context);
3955 }
3956 context->flags &= ~FLAG_READ_FETCHED;
3633 context->flags2 &= ~FLAG2_BYTE_PENDING; 3957 context->flags2 &= ~FLAG2_BYTE_PENDING;
3634 3958
3635 context->cd = VRAM_READ8; 3959 context->cd = VRAM_READ8;
3636 return context->prefetch; 3960 return context->prefetch;
3637 }
3638
3639 uint16_t vdp_test_port_read(vdp_context * context)
3640 {
3641 //TODO: Find out what actually gets returned here
3642 return context->test_port;
3643 } 3961 }
3644 3962
3645 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) 3963 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction)
3646 { 3964 {
3647 context->cycles -= deduction; 3965 context->cycles -= deduction;
3932 context->flags2 &= ~FLAG2_HINT_PENDING; 4250 context->flags2 &= ~FLAG2_HINT_PENDING;
3933 } 4251 }
3934 } 4252 }
3935 } 4253 }
3936 4254
4255 #define VDP_STATE_VERSION 3
3937 void vdp_serialize(vdp_context *context, serialize_buffer *buf) 4256 void vdp_serialize(vdp_context *context, serialize_buffer *buf)
3938 { 4257 {
4258 save_int8(buf, VDP_STATE_VERSION);
3939 save_int8(buf, VRAM_SIZE / 1024);//VRAM size in KB, needed for future proofing 4259 save_int8(buf, VRAM_SIZE / 1024);//VRAM size in KB, needed for future proofing
3940 save_buffer8(buf, context->vdpmem, VRAM_SIZE); 4260 save_buffer8(buf, context->vdpmem, VRAM_SIZE);
3941 save_buffer16(buf, context->cram, CRAM_SIZE); 4261 save_buffer16(buf, context->cram, CRAM_SIZE);
3942 save_buffer16(buf, context->vsram, VSRAM_SIZE); 4262 save_buffer16(buf, context->vsram, MAX_VSRAM_SIZE);
3943 save_buffer8(buf, context->sat_cache, SAT_CACHE_SIZE); 4263 save_buffer8(buf, context->sat_cache, SAT_CACHE_SIZE);
3944 for (int i = 0; i <= REG_DMASRC_H; i++) 4264 for (int i = 0; i <= REG_DMASRC_H; i++)
3945 { 4265 {
3946 save_int8(buf, context->regs[i]); 4266 save_int8(buf, context->regs[i]);
3947 } 4267 }
3988 //FIXME: Sprite rendering state is currently a mess 4308 //FIXME: Sprite rendering state is currently a mess
3989 save_int8(buf, context->sprite_index); 4309 save_int8(buf, context->sprite_index);
3990 save_int8(buf, context->sprite_draws); 4310 save_int8(buf, context->sprite_draws);
3991 save_int8(buf, context->slot_counter); 4311 save_int8(buf, context->slot_counter);
3992 save_int8(buf, context->cur_slot); 4312 save_int8(buf, context->cur_slot);
3993 for (int i = 0; i < MAX_DRAWS; i++) 4313 for (int i = 0; i < MAX_SPRITES_LINE; i++)
3994 { 4314 {
3995 sprite_draw *draw = context->sprite_draw_list + i; 4315 sprite_draw *draw = context->sprite_draw_list + i;
3996 save_int16(buf, draw->address); 4316 save_int16(buf, draw->address);
3997 save_int16(buf, draw->x_pos); 4317 save_int16(buf, draw->x_pos);
3998 save_int8(buf, draw->pal_priority); 4318 save_int8(buf, draw->pal_priority);
3999 save_int8(buf, draw->h_flip); 4319 save_int8(buf, draw->h_flip);
4320 save_int8(buf, draw->width);
4321 save_int8(buf, draw->height);
4000 } 4322 }
4001 for (int i = 0; i < MAX_SPRITES_LINE; i++) 4323 for (int i = 0; i < MAX_SPRITES_LINE; i++)
4002 { 4324 {
4003 sprite_info *info = context->sprite_info_list + i; 4325 sprite_info *info = context->sprite_info_list + i;
4004 save_int8(buf, info->size); 4326 save_int8(buf, info->size);
4008 save_buffer8(buf, context->linebuf, LINEBUF_SIZE); 4330 save_buffer8(buf, context->linebuf, LINEBUF_SIZE);
4009 4331
4010 save_int32(buf, context->cycles); 4332 save_int32(buf, context->cycles);
4011 save_int32(buf, context->pending_vint_start); 4333 save_int32(buf, context->pending_vint_start);
4012 save_int32(buf, context->pending_hint_start); 4334 save_int32(buf, context->pending_hint_start);
4335 save_int32(buf, context->address_latch);
4336 save_int8(buf, context->cd_latch);
4013 } 4337 }
4014 4338
4015 void vdp_deserialize(deserialize_buffer *buf, void *vcontext) 4339 void vdp_deserialize(deserialize_buffer *buf, void *vcontext)
4016 { 4340 {
4017 vdp_context *context = vcontext; 4341 vdp_context *context = vcontext;
4018 uint8_t vramk = load_int8(buf); 4342 uint8_t version = load_int8(buf);
4343 uint8_t vramk;
4344 if (version == 64) {
4345 vramk = version;
4346 version = 0;
4347 } else {
4348 vramk = load_int8(buf);
4349 }
4350 if (version > VDP_STATE_VERSION) {
4351 warning("Save state has VDP version %d, but this build only understands versions %d and lower", version, VDP_STATE_VERSION);
4352 }
4019 load_buffer8(buf, context->vdpmem, (vramk * 1024) <= VRAM_SIZE ? vramk * 1024 : VRAM_SIZE); 4353 load_buffer8(buf, context->vdpmem, (vramk * 1024) <= VRAM_SIZE ? vramk * 1024 : VRAM_SIZE);
4020 if ((vramk * 1024) > VRAM_SIZE) { 4354 if ((vramk * 1024) > VRAM_SIZE) {
4021 buf->cur_pos += (vramk * 1024) - VRAM_SIZE; 4355 buf->cur_pos += (vramk * 1024) - VRAM_SIZE;
4022 } 4356 }
4023 load_buffer16(buf, context->cram, CRAM_SIZE); 4357 load_buffer16(buf, context->cram, CRAM_SIZE);
4024 for (int i = 0; i < CRAM_SIZE; i++) 4358 for (int i = 0; i < CRAM_SIZE; i++)
4025 { 4359 {
4026 update_color_map(context, i, context->cram[i]); 4360 update_color_map(context, i, context->cram[i]);
4027 } 4361 }
4028 load_buffer16(buf, context->vsram, VSRAM_SIZE); 4362 load_buffer16(buf, context->vsram, version > 1 ? MAX_VSRAM_SIZE : MIN_VSRAM_SIZE);
4029 load_buffer8(buf, context->sat_cache, SAT_CACHE_SIZE); 4363 load_buffer8(buf, context->sat_cache, SAT_CACHE_SIZE);
4030 for (int i = 0; i <= REG_DMASRC_H; i++) 4364 for (int i = 0; i <= REG_DMASRC_H; i++)
4031 { 4365 {
4032 context->regs[i] = load_int8(buf); 4366 context->regs[i] = load_int8(buf);
4033 } 4367 }
4075 context->buf_b_off = load_int8(buf) & SCROLL_BUFFER_MASK; 4409 context->buf_b_off = load_int8(buf) & SCROLL_BUFFER_MASK;
4076 context->sprite_index = load_int8(buf); 4410 context->sprite_index = load_int8(buf);
4077 context->sprite_draws = load_int8(buf); 4411 context->sprite_draws = load_int8(buf);
4078 context->slot_counter = load_int8(buf); 4412 context->slot_counter = load_int8(buf);
4079 context->cur_slot = load_int8(buf); 4413 context->cur_slot = load_int8(buf);
4080 for (int i = 0; i < MAX_DRAWS; i++) 4414 if (version == 0) {
4081 { 4415 int cur_draw = 0;
4082 sprite_draw *draw = context->sprite_draw_list + i; 4416 for (int i = 0; i < MAX_SPRITES_LINE * 2; i++)
4083 draw->address = load_int16(buf); 4417 {
4084 draw->x_pos = load_int16(buf); 4418 if (cur_draw < MAX_SPRITES_LINE) {
4085 draw->pal_priority = load_int8(buf); 4419 sprite_draw *last = cur_draw ? context->sprite_draw_list + cur_draw - 1 : NULL;
4086 draw->h_flip = load_int8(buf); 4420 sprite_draw *draw = context->sprite_draw_list + cur_draw++;
4421 draw->address = load_int16(buf);
4422 draw->x_pos = load_int16(buf);
4423 draw->pal_priority = load_int8(buf);
4424 draw->h_flip = load_int8(buf);
4425 draw->width = 1;
4426 draw->height = 8;
4427
4428 if (last && last->width < 4 && last->h_flip == draw->h_flip && last->pal_priority == draw->pal_priority) {
4429 int adjust_x = draw->x_pos + draw->h_flip ? -8 : 8;
4430 int height = draw->address - last->address /4;
4431 if (last->x_pos == adjust_x && (
4432 (last->width > 1 && height == last->height) ||
4433 (last->width == 1 && (height == 8 || height == 16 || height == 24 || height == 32))
4434 )) {
4435 //current draw appears to be part of the same sprite as the last one, combine it
4436 cur_draw--;
4437 last->width++;
4438 }
4439 }
4440 } else {
4441 load_int16(buf);
4442 load_int16(buf);
4443 load_int8(buf);
4444 load_int8(buf);
4445 }
4446 }
4447 } else {
4448 for (int i = 0; i < MAX_SPRITES_LINE; i++)
4449 {
4450 sprite_draw *draw = context->sprite_draw_list + i;
4451 draw->address = load_int16(buf);
4452 draw->x_pos = load_int16(buf);
4453 draw->pal_priority = load_int8(buf);
4454 draw->h_flip = load_int8(buf);
4455 draw->width = load_int8(buf);
4456 draw->height = load_int8(buf);
4457 }
4087 } 4458 }
4088 for (int i = 0; i < MAX_SPRITES_LINE; i++) 4459 for (int i = 0; i < MAX_SPRITES_LINE; i++)
4089 { 4460 {
4090 sprite_info *info = context->sprite_info_list + i; 4461 sprite_info *info = context->sprite_info_list + i;
4091 info->size = load_int8(buf); 4462 info->size = load_int8(buf);
4095 load_buffer8(buf, context->linebuf, LINEBUF_SIZE); 4466 load_buffer8(buf, context->linebuf, LINEBUF_SIZE);
4096 4467
4097 context->cycles = load_int32(buf); 4468 context->cycles = load_int32(buf);
4098 context->pending_vint_start = load_int32(buf); 4469 context->pending_vint_start = load_int32(buf);
4099 context->pending_hint_start = load_int32(buf); 4470 context->pending_hint_start = load_int32(buf);
4471 if (version > 2) {
4472 context->address_latch = load_int32(buf);
4473 context->cd_latch = load_int8(buf);
4474 } else {
4475 context->address_latch = context->address;
4476 context->cd_latch = context->cd;
4477 }
4100 update_video_params(context); 4478 update_video_params(context);
4101 } 4479 }
4102 4480
4103 static vdp_context *current_vdp; 4481 static vdp_context *current_vdp;
4104 static void vdp_debug_window_close(uint8_t which) 4482 static void vdp_debug_window_close(uint8_t which)