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