comparison vdp.c @ 2118:c5d0edf1d7e7

Fix some null-pointer dereference crashes on a ROM that abuses V28/V30 mode switching
author Michael Pavone <pavone@retrodev.com>
date Sun, 06 Mar 2022 22:36:21 -0800
parents a61b47d5489e
children 01ff005b08f6
comparison
equal deleted inserted replaced
2117:03304d350339 2118:c5d0edf1d7e7
525 "0B: %.2X | E-ints %s, V-Scroll: %s, H-Scroll: %s\n" 525 "0B: %.2X | E-ints %s, V-Scroll: %s, H-Scroll: %s\n"
526 "0C: %.2X | Width: %d, Shadow/Highlight: %s\n", 526 "0C: %.2X | Width: %d, Shadow/Highlight: %s\n",
527 context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", (context->regs[REG_MODE_1] & BIT_PAL_SEL) != 0, 527 context->regs[REG_MODE_1], context->regs[REG_MODE_1] & BIT_HINT_EN ? "enabled" : "disabled", (context->regs[REG_MODE_1] & BIT_PAL_SEL) != 0,
528 context->regs[REG_MODE_1] & BIT_HVC_LATCH ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_DISP_DIS ? "disabled" : "enabled", 528 context->regs[REG_MODE_1] & BIT_HVC_LATCH ? "enabled" : "disabled", context->regs[REG_MODE_1] & BIT_DISP_DIS ? "disabled" : "enabled",
529 context->regs[REG_MODE_2], context->regs[REG_MODE_2] & BIT_DISP_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_VINT_EN ? "enabled" : "disabled", 529 context->regs[REG_MODE_2], context->regs[REG_MODE_2] & BIT_DISP_EN ? "enabled" : "disabled", context->regs[REG_MODE_2] & BIT_VINT_EN ? "enabled" : "disabled",
530 context->regs[REG_MODE_2] & BIT_PAL ? 30 : 28, context->regs[REG_MODE_2] & BIT_MODE_5 ? 5 : 4, context->regs[REG_MODE_1] & BIT_128K_VRAM ? 128 : 64, 530 context->regs[REG_MODE_2] & BIT_PAL ? 30 : 28, context->regs[REG_MODE_2] & BIT_MODE_5 ? 5 : 4, context->regs[REG_MODE_1] & BIT_128K_VRAM ? 128 : 64,
531 context->regs[REG_MODE_3], context->regs[REG_MODE_3] & BIT_EINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_3] & BIT_VSCROLL ? "2 cell" : "full", 531 context->regs[REG_MODE_3], context->regs[REG_MODE_3] & BIT_EINT_EN ? "enabled" : "disabled", context->regs[REG_MODE_3] & BIT_VSCROLL ? "2 cell" : "full",
532 hscroll[context->regs[REG_MODE_3] & 0x3], 532 hscroll[context->regs[REG_MODE_3] & 0x3],
533 context->regs[REG_MODE_4], context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32, context->regs[REG_MODE_4] & BIT_HILIGHT ? "enabled" : "disabled"); 533 context->regs[REG_MODE_4], context->regs[REG_MODE_4] & BIT_H40 ? 40 : 32, context->regs[REG_MODE_4] & BIT_HILIGHT ? "enabled" : "disabled");
534 if (context->regs[REG_MODE_2] & BIT_MODE_5) { 534 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
535 printf("\n**Table Group**\n" 535 printf("\n**Table Group**\n"
553 context->regs[REG_SCROLL_A], (context->regs[REG_SCROLL_A] & 0xE) << 10, 553 context->regs[REG_SCROLL_A], (context->regs[REG_SCROLL_A] & 0xE) << 10,
554 context->regs[REG_SAT], (context->regs[REG_SAT] & 0x7E) << 7, 554 context->regs[REG_SAT], (context->regs[REG_SAT] & 0x7E) << 7,
555 context->regs[REG_STILE_BASE], (context->regs[REG_STILE_BASE] & 2) << 11, 555 context->regs[REG_STILE_BASE], (context->regs[REG_STILE_BASE] & 2) << 11,
556 context->regs[REG_X_SCROLL], context->regs[REG_X_SCROLL], 556 context->regs[REG_X_SCROLL], context->regs[REG_X_SCROLL],
557 context->regs[REG_Y_SCROLL], context->regs[REG_Y_SCROLL]); 557 context->regs[REG_Y_SCROLL], context->regs[REG_Y_SCROLL]);
558 558
559 } 559 }
560 char * sizes[] = {"32", "64", "invalid", "128"}; 560 char * sizes[] = {"32", "64", "invalid", "128"};
561 printf("\n**Misc Group**\n" 561 printf("\n**Misc Group**\n"
562 "07: %.2X | Backdrop Color: $%X\n" 562 "07: %.2X | Backdrop Color: $%X\n"
563 "0A: %.2X | H-Int Counter: %u\n" 563 "0A: %.2X | H-Int Counter: %u\n"
590 "VCounter: %d\n" 590 "VCounter: %d\n"
591 "HCounter: %d\n" 591 "HCounter: %d\n"
592 "VINT Pending: %s\n" 592 "VINT Pending: %s\n"
593 "HINT Pending: %s\n" 593 "HINT Pending: %s\n"
594 "Status: %X\n", 594 "Status: %X\n",
595 context->address, context->cd, cd_name(context->cd), 595 context->address, context->cd, cd_name(context->cd),
596 (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",
597 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",
598 (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, 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 600 (context->test_port & TEST_BIT_DISABLE) ? "true" : "false", context->test_port >> 7 & 3
601 ); 601 );
602 //restore flags as calling vdp_control_port_read can change them 602 //restore flags as calling vdp_control_port_read can change them
603 context->flags = old_flags; 603 context->flags = old_flags;
604 context->flags2 = old_flags2; 604 context->flags2 = old_flags2;
671 static void scan_sprite_table_mode4(vdp_context * context) 671 static void scan_sprite_table_mode4(vdp_context * context)
672 { 672 {
673 if (context->sprite_index < MAX_SPRITES_FRAME_H32) { 673 if (context->sprite_index < MAX_SPRITES_FRAME_H32) {
674 uint32_t line = context->vcounter; 674 uint32_t line = context->vcounter;
675 line &= 0xFF; 675 line &= 0xFF;
676 676
677 uint32_t sat_address = mode4_address_map[(context->regs[REG_SAT] << 7 & 0x3F00) + context->sprite_index]; 677 uint32_t sat_address = mode4_address_map[(context->regs[REG_SAT] << 7 & 0x3F00) + context->sprite_index];
678 uint32_t y = context->vdpmem[sat_address+1]; 678 uint32_t y = context->vdpmem[sat_address+1];
679 uint32_t size = (context->regs[REG_MODE_2] & BIT_SPRITE_SZ) ? 16 : 8; 679 uint32_t size = (context->regs[REG_MODE_2] & BIT_SPRITE_SZ) ? 16 : 8;
680 680
681 if (y == 0xd0) { 681 if (y == 0xd0) {
682 context->sprite_index = MAX_SPRITES_FRAME_H32; 682 context->sprite_index = MAX_SPRITES_FRAME_H32;
683 return; 683 return;
684 } else { 684 } else {
685 if (y <= line && line < (y + size)) { 685 if (y <= line && line < (y + size)) {
692 context->sprite_info_list[context->slot_counter].index = context->sprite_index; 692 context->sprite_info_list[context->slot_counter].index = context->sprite_index;
693 context->sprite_info_list[context->slot_counter].y = y; 693 context->sprite_info_list[context->slot_counter].y = y;
694 } 694 }
695 context->sprite_index++; 695 context->sprite_index++;
696 } 696 }
697 697
698 if (context->sprite_index < MAX_SPRITES_FRAME_H32) { 698 if (context->sprite_index < MAX_SPRITES_FRAME_H32) {
699 y = context->vdpmem[sat_address]; 699 y = context->vdpmem[sat_address];
700 if (y == 0xd0) { 700 if (y == 0xd0) {
701 context->sprite_index = MAX_SPRITES_FRAME_H32; 701 context->sprite_index = MAX_SPRITES_FRAME_H32;
702 return; 702 return;
712 context->sprite_info_list[context->slot_counter].y = y; 712 context->sprite_info_list[context->slot_counter].y = y;
713 } 713 }
714 context->sprite_index++; 714 context->sprite_index++;
715 } 715 }
716 } 716 }
717 717
718 } 718 }
719 } 719 }
720 720
721 static void read_sprite_x(uint32_t line, vdp_context * context) 721 static void read_sprite_x(uint32_t line, vdp_context * context)
722 { 722 {
822 } else { 822 } else {
823 addr = address & 0x1F; 823 addr = address & 0x1F;
824 value = (value << 1 & 0xE) | (value << 2 & 0xE0) | (value & 0xE00); 824 value = (value << 1 & 0xE) | (value << 2 & 0xE0) | (value & 0xE00);
825 } 825 }
826 write_cram_internal(context, addr, value); 826 write_cram_internal(context, addr, value);
827 827
828 if (context->output && context->hslot >= BG_START_SLOT && ( 828 if (context->output && context->hslot >= BG_START_SLOT && (
829 context->vcounter < context->inactive_start + context->border_bot 829 context->vcounter < context->inactive_start + context->border_bot
830 || context->vcounter > 0x200 - context->border_top 830 || context->vcounter > 0x200 - context->border_top
831 )) { 831 )) {
832 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;
833 if (context->hslot < bg_end_slot) { 833 if (context->hslot < bg_end_slot) {
834 uint32_t color = (context->regs[REG_MODE_2] & BIT_MODE_5) ? context->colors[addr] : context->colors[addr + MODE4_OFFSET]; 834 uint32_t color = (context->regs[REG_MODE_2] & BIT_MODE_5) ? context->colors[addr] : context->colors[addr + MODE4_OFFSET];
982 context->fifo_read = -1; 982 context->fifo_read = -1;
983 } 983 }
984 } else if ((context->flags & FLAG_DMA_RUN) && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_COPY) { 984 } else if ((context->flags & FLAG_DMA_RUN) && (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_COPY) {
985 if (context->flags & FLAG_READ_FETCHED) { 985 if (context->flags & FLAG_READ_FETCHED) {
986 write_vram_byte(context, context->address ^ 1, context->prefetch); 986 write_vram_byte(context, context->address ^ 1, context->prefetch);
987 987
988 //Update DMA state 988 //Update DMA state
989 vdp_advance_dma(context); 989 vdp_advance_dma(context);
990 990
991 context->flags &= ~FLAG_READ_FETCHED; 991 context->flags &= ~FLAG_READ_FETCHED;
992 } else { 992 } else {
993 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];
994 994
995 context->flags |= FLAG_READ_FETCHED; 995 context->flags |= FLAG_READ_FETCHED;
996 } 996 }
997 } else if (!(context->cd & 1) && !(context->flags & FLAG_READ_FETCHED)) { 997 } else if (!(context->cd & 1) && !(context->flags & FLAG_READ_FETCHED)) {
998 switch(context->cd & 0xF) 998 switch(context->cd & 0xF)
999 { 999 {
1287 } 1287 }
1288 vscroll &= 7; 1288 vscroll &= 7;
1289 if (context->col_1 & 0x400) { 1289 if (context->col_1 & 0x400) {
1290 vscroll = 7 - vscroll; 1290 vscroll = 7 - vscroll;
1291 } 1291 }
1292 1292
1293 uint32_t address = mode4_address_map[((context->col_1 & 0x1FF) * 32) + vscroll * 4]; 1293 uint32_t address = mode4_address_map[((context->col_1 & 0x1FF) * 32) + vscroll * 4];
1294 context->fetch_tmp[0] = context->vdpmem[address]; 1294 context->fetch_tmp[0] = context->vdpmem[address];
1295 context->fetch_tmp[1] = context->vdpmem[address+1]; 1295 context->fetch_tmp[1] = context->vdpmem[address+1];
1296 } 1296 }
1297 1297
1478 if (pixel) { 1478 if (pixel) {
1479 src = DBG_SRC_B; 1479 src = DBG_SRC_B;
1480 } 1480 }
1481 break; 1481 break;
1482 } 1482 }
1483 1483
1484 *(dst++) = pixel; 1484 *(dst++) = pixel;
1485 *(debug_dst++) = src; 1485 *(debug_dst++) = src;
1486 } 1486 }
1487 plane_a_off += 8; 1487 plane_a_off += 8;
1488 plane_b_off += 8; 1488 plane_b_off += 8;
1552 if (pixel) { 1552 if (pixel) {
1553 src = DBG_SRC_B | DBG_SHADOW; 1553 src = DBG_SRC_B | DBG_SHADOW;
1554 } 1554 }
1555 break; 1555 break;
1556 } 1556 }
1557 1557
1558 *(dst++) = SHADOW_OFFSET + pixel; 1558 *(dst++) = SHADOW_OFFSET + pixel;
1559 *(debug_dst++) = src; 1559 *(debug_dst++) = src;
1560 } 1560 }
1561 plane_a_off += 8; 1561 plane_a_off += 8;
1562 plane_b_off += 8; 1562 plane_b_off += 8;
1635 if (col) 1635 if (col)
1636 { 1636 {
1637 col-=2; 1637 col-=2;
1638 dst = context->compositebuf + BORDER_LEFT + col * 8; 1638 dst = context->compositebuf + BORDER_LEFT + col * 8;
1639 debug_dst = context->layer_debug_buf + BORDER_LEFT + col * 8; 1639 debug_dst = context->layer_debug_buf + BORDER_LEFT + col * 8;
1640 1640
1641 1641
1642 uint8_t a_src, src; 1642 uint8_t a_src, src;
1643 uint8_t *buf_a; 1643 uint8_t *buf_a;
1644 int plane_a_mask; 1644 int plane_a_mask;
1645 if (context->flags & FLAG_WINDOW) { 1645 if (context->flags & FLAG_WINDOW) {
1646 plane_a_off = context->buf_a_off; 1646 plane_a_off = context->buf_a_off;
1696 //plane A 1696 //plane A
1697 //TODO: Deal with Window layer 1697 //TODO: Deal with Window layer
1698 int i; 1698 int i;
1699 i = 0; 1699 i = 0;
1700 uint8_t buf_off = context->buf_a_off - context->hscroll_a_fine + (16 - BORDER_LEFT); 1700 uint8_t buf_off = context->buf_a_off - context->hscroll_a_fine + (16 - BORDER_LEFT);
1701 //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);
1702 for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++) 1702 for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++)
1703 { 1703 {
1704 *dst = context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK]; 1704 *dst = context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK];
1705 *debug_dst = DBG_SRC_A; 1705 *debug_dst = DBG_SRC_A;
1706 } 1706 }
1709 case 3: { 1709 case 3: {
1710 //plane B 1710 //plane B
1711 int i; 1711 int i;
1712 i = 0; 1712 i = 0;
1713 uint8_t buf_off = context->buf_b_off - context->hscroll_b_fine + (16 - BORDER_LEFT); 1713 uint8_t buf_off = context->buf_b_off - context->hscroll_b_fine + (16 - BORDER_LEFT);
1714 //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);
1715 for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++) 1715 for (; i < BORDER_LEFT; buf_off++, i++, dst++, debug_dst++)
1716 { 1716 {
1717 *dst = context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK]; 1717 *dst = context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK];
1718 *debug_dst = DBG_SRC_B; 1718 *debug_dst = DBG_SRC_B;
1719 } 1719 }
1743 vscroll &= 7; 1743 vscroll &= 7;
1744 if (context->col_1 & 0x400) { 1744 if (context->col_1 & 0x400) {
1745 //vflip 1745 //vflip
1746 vscroll = 7 - vscroll; 1746 vscroll = 7 - vscroll;
1747 } 1747 }
1748 1748
1749 uint32_t pixels = planar_to_chunky[context->fetch_tmp[0]] << 1; 1749 uint32_t pixels = planar_to_chunky[context->fetch_tmp[0]] << 1;
1750 pixels |= planar_to_chunky[context->fetch_tmp[1]]; 1750 pixels |= planar_to_chunky[context->fetch_tmp[1]];
1751 1751
1752 uint32_t address = mode4_address_map[((context->col_1 & 0x1FF) * 32) + vscroll * 4 + 2]; 1752 uint32_t address = mode4_address_map[((context->col_1 & 0x1FF) * 32) + vscroll * 4 + 2];
1753 pixels |= planar_to_chunky[context->vdpmem[address]] << 3; 1753 pixels |= planar_to_chunky[context->vdpmem[address]] << 3;
1754 pixels |= planar_to_chunky[context->vdpmem[address+1]] << 2; 1754 pixels |= planar_to_chunky[context->vdpmem[address+1]] << 2;
1755 1755
1756 int i, i_inc, i_limit; 1756 int i, i_inc, i_limit;
1757 if (context->col_1 & 0x200) { 1757 if (context->col_1 & 0x200) {
1758 //hflip 1758 //hflip
1759 i = 0; 1759 i = 0;
1760 i_inc = 4; 1760 i_inc = 4;
1768 for (uint8_t *dst = context->tmp_buf_a + context->buf_a_off; i != i_limit; i += i_inc, dst++) 1768 for (uint8_t *dst = context->tmp_buf_a + context->buf_a_off; i != i_limit; i += i_inc, dst++)
1769 { 1769 {
1770 *dst = (pixels >> i & 0xF) | pal_priority; 1770 *dst = (pixels >> i & 0xF) | pal_priority;
1771 } 1771 }
1772 context->buf_a_off = (context->buf_a_off + 8) & 15; 1772 context->buf_a_off = (context->buf_a_off + 8) & 15;
1773 1773
1774 uint8_t *dst = context->compositebuf + col * 8 + BORDER_LEFT; 1774 uint8_t *dst = context->compositebuf + col * 8 + BORDER_LEFT;
1775 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;
1776 if (context->state == PREPARING) { 1776 if (context->state == PREPARING) {
1777 memset(dst, 0x10 + (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET, 8); 1777 memset(dst, 0x10 + (context->regs[REG_BG_COLOR] & 0xF) + MODE4_OFFSET, 8);
1778 memset(debug_dst, DBG_SRC_BG, 8); 1778 memset(debug_dst, DBG_SRC_BG, 8);
1779 context->done_composite = dst + 8; 1779 context->done_composite = dst + 8;
1780 return; 1780 return;
1781 } 1781 }
1782 1782
1783 if (col || !(context->regs[REG_MODE_1] & BIT_COL0_MASK)) { 1783 if (col || !(context->regs[REG_MODE_1] & BIT_COL0_MASK)) {
1784 uint8_t *sprite_src = context->linebuf + col * 8; 1784 uint8_t *sprite_src = context->linebuf + col * 8;
1785 if (context->regs[REG_MODE_1] & BIT_SPRITE_8PX) { 1785 if (context->regs[REG_MODE_1] & BIT_SPRITE_8PX) {
1786 sprite_src += 8; 1786 sprite_src += 8;
1787 } 1787 }
1848 uint32_t line = context->vcounter; 1848 uint32_t line = context->vcounter;
1849 if (line >= jump_end) { 1849 if (line >= jump_end) {
1850 line -= jump_end - jump_start; 1850 line -= jump_end - jump_start;
1851 } 1851 }
1852 uint32_t total_lines = (context->flags2 & FLAG2_REGION_PAL) ? 313 : 262; 1852 uint32_t total_lines = (context->flags2 & FLAG2_REGION_PAL) ? 313 : 262;
1853 1853
1854 if (total_lines - line <= context->border_top) { 1854 if (total_lines - line <= context->border_top) {
1855 line -= total_lines - context->border_top; 1855 line -= total_lines - context->border_top;
1856 } else { 1856 } else {
1857 line += context->border_top; 1857 line += context->border_top;
1858 } 1858 }
1885 { 1885 {
1886 *(fb++) = context->debugcolors[context->layer_debug_buf[i]]; 1886 *(fb++) = context->debugcolors[context->layer_debug_buf[i]];
1887 } 1887 }
1888 } 1888 }
1889 } 1889 }
1890 1890
1891 context->vcounter++; 1891 context->vcounter++;
1892 if (context->vcounter == jump_start) { 1892 if (context->vcounter == jump_start) {
1893 context->vcounter = jump_end; 1893 context->vcounter = jump_end;
1894 } else { 1894 } else {
1895 context->vcounter &= 0x1FF; 1895 context->vcounter &= 0x1FF;
1972 uint16_t address = row_address + (col & hscroll_mask) * 2; 1972 uint16_t address = row_address + (col & hscroll_mask) * 2;
1973 //pccv hnnn nnnn nnnn 1973 //pccv hnnn nnnn nnnn
1974 // 1974 //
1975 uint16_t entry = context->vdpmem[address] << 8 | context->vdpmem[address + 1]; 1975 uint16_t entry = context->vdpmem[address] << 8 | context->vdpmem[address + 1];
1976 uint8_t pal = entry >> 9 & 0x30; 1976 uint8_t pal = entry >> 9 & 0x30;
1977 1977
1978 uint32_t *dst = fb + (row * pitch * 8 / sizeof(uint32_t)) + col * 8; 1978 uint32_t *dst = fb + (row * pitch * 8 / sizeof(uint32_t)) + col * 8;
1979 address = (entry & 0x7FF) * 32; 1979 address = (entry & 0x7FF) * 32;
1980 int y_diff = 4; 1980 int y_diff = 4;
1981 if (entry & 0x1000) { 1981 if (entry & 0x1000) {
1982 y_diff = -4; 1982 y_diff = -4;
2011 } 2011 }
2012 } 2012 }
2013 } 2013 }
2014 render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_PLANE], 1024); 2014 render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_PLANE], 1024);
2015 } 2015 }
2016 2016
2017 if (context->enabled_debuggers & (1 << VDP_DEBUG_VRAM)) { 2017 if (context->enabled_debuggers & (1 << VDP_DEBUG_VRAM)) {
2018 uint32_t pitch; 2018 uint32_t pitch;
2019 uint32_t *fb = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_VRAM], &pitch); 2019 uint32_t *fb = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_VRAM], &pitch);
2020 2020
2021 uint8_t pal = (context->debug_modes[VDP_DEBUG_VRAM] % 4) << 4; 2021 uint8_t pal = (context->debug_modes[VDP_DEBUG_VRAM] % 4) << 4;
2022 for (int y = 0; y < 512; y++) 2022 for (int y = 0; y < 512; y++)
2023 { 2023 {
2024 uint32_t *line = fb + y * pitch / sizeof(uint32_t); 2024 uint32_t *line = fb + y * pitch / sizeof(uint32_t);
2025 int row = y >> 4; 2025 int row = y >> 4;
2037 *(line++) = context->colors[right]; 2037 *(line++) = context->colors[right];
2038 *(line++) = context->colors[right]; 2038 *(line++) = context->colors[right];
2039 } 2039 }
2040 } 2040 }
2041 } 2041 }
2042 2042
2043 render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_VRAM], 1024); 2043 render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_VRAM], 1024);
2044 } 2044 }
2045 2045
2046 if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) { 2046 if (context->enabled_debuggers & (1 << VDP_DEBUG_CRAM)) {
2047 uint32_t starting_line = 512 - 32*4; 2047 uint32_t starting_line = 512 - 32*4;
2048 uint32_t *line = context->debug_fbs[VDP_DEBUG_CRAM] 2048 uint32_t *line = context->debug_fbs[VDP_DEBUG_CRAM]
2049 + 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);
2050 if (context->regs[REG_MODE_2] & BIT_MODE_5) { 2050 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
2051 for (int pal = 0; pal < 4; pal ++) 2051 for (int pal = 0; pal < 4; pal ++)
2052 { 2052 {
2053 uint32_t *cur; 2053 uint32_t *cur;
2100 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]);
2101 } 2101 }
2102 if (context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE)) { 2102 if (context->enabled_debuggers & (1 << VDP_DEBUG_COMPOSITE)) {
2103 render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_COMPOSITE], LINEBUF_SIZE); 2103 render_framebuffer_updated(context->debug_fb_indices[VDP_DEBUG_COMPOSITE], LINEBUF_SIZE);
2104 context->debug_fbs[VDP_DEBUG_COMPOSITE] = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_COMPOSITE], &context->debug_fb_pitch[VDP_DEBUG_COMPOSITE]); 2104 context->debug_fbs[VDP_DEBUG_COMPOSITE] = render_get_framebuffer(context->debug_fb_indices[VDP_DEBUG_COMPOSITE], &context->debug_fb_pitch[VDP_DEBUG_COMPOSITE]);
2105 } 2105 }
2106 } 2106 }
2107 2107
2108 void vdp_force_update_framebuffer(vdp_context *context) 2108 void vdp_force_update_framebuffer(vdp_context *context)
2109 { 2109 {
2110 if (!context->fb) { 2110 if (!context->fb) {
2111 return; 2111 return;
2112 } 2112 }
2113 uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top; 2113 uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top;
2114 2114
2115 uint16_t to_fill = lines_max - context->output_lines; 2115 uint16_t to_fill = lines_max - context->output_lines;
2116 memset( 2116 memset(
2117 ((char *)context->fb) + context->output_pitch * context->output_lines, 2117 ((char *)context->fb) + context->output_pitch * context->output_lines,
2118 0, 2118 0,
2119 to_fill * context->output_pitch 2119 to_fill * context->output_pitch
2129 uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top; 2129 uint16_t lines_max = context->inactive_start + context->border_bot + context->border_top;
2130 uint32_t output_line = context->vcounter; 2130 uint32_t output_line = context->vcounter;
2131 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) { 2131 if (!(context->regs[REG_MODE_2] & BIT_MODE_5)) {
2132 //vcounter increment occurs much later in Mode 4 2132 //vcounter increment occurs much later in Mode 4
2133 output_line++; 2133 output_line++;
2134 } 2134 }
2135 2135
2136 if (context->output_lines >= lines_max || (!context->pushed_frame && output_line == context->inactive_start + context->border_top)) { 2136 if (context->output_lines >= lines_max || (!context->pushed_frame && output_line == context->inactive_start + context->border_top)) {
2137 //we've either filled up a full frame or we're at the bottom of screen in the current defined mode + border crop 2137 //we've either filled up a full frame or we're at the bottom of screen in the current defined mode + border crop
2138 if (!headless) { 2138 if (!headless) {
2139 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));
2140 uint8_t is_even = context->flags2 & FLAG2_EVEN_FIELD; 2140 uint8_t is_even = context->flags2 & FLAG2_EVEN_FIELD;
2148 vdp_update_per_frame_debug(context); 2148 vdp_update_per_frame_debug(context);
2149 context->h40_lines = 0; 2149 context->h40_lines = 0;
2150 context->frame++; 2150 context->frame++;
2151 context->output_lines = 0; 2151 context->output_lines = 0;
2152 } 2152 }
2153 2153
2154 if (output_line < context->inactive_start + context->border_bot) { 2154 if (output_line < context->inactive_start + context->border_bot) {
2155 if (context->output_lines) { 2155 if (context->output_lines) {
2156 output_line = context->output_lines++;//context->border_top + context->vcounter; 2156 output_line = context->output_lines++;//context->border_top + context->vcounter;
2157 } else if (!output_line && !context->border_top) { 2157 } else if (!output_line && !context->border_top) {
2158 //top border is completely cropped so we won't hit the case below 2158 //top border is completely cropped so we won't hit the case below
2182 #ifdef DEBUG_FB_FILL 2182 #ifdef DEBUG_FB_FILL
2183 for (int i = 0; i < LINEBUF_SIZE; i++) 2183 for (int i = 0; i < LINEBUF_SIZE; i++)
2184 { 2184 {
2185 context->output[i] = 0xFFFF00FF; 2185 context->output[i] = 0xFFFF00FF;
2186 } 2186 }
2187 #endif 2187 #endif
2188 if (context->output && (context->regs[REG_MODE_4] & BIT_H40)) { 2188 if (context->output && (context->regs[REG_MODE_4] & BIT_H40)) {
2189 context->h40_lines++; 2189 context->h40_lines++;
2190 } 2190 }
2191 } 2191 }
2192 2192
2239 //plane A 2239 //plane A
2240 //TODO: Deal with Window layer 2240 //TODO: Deal with Window layer
2241 int i; 2241 int i;
2242 i = 0; 2242 i = 0;
2243 uint8_t buf_off = context->buf_a_off - context->hscroll_a_fine; 2243 uint8_t buf_off = context->buf_a_off - context->hscroll_a_fine;
2244 //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);
2245 for (; i < BORDER_RIGHT; buf_off++, i++, dst++) 2245 for (; i < BORDER_RIGHT; buf_off++, i++, dst++)
2246 { 2246 {
2247 *dst = context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK] & 0x3F; 2247 *dst = context->tmp_buf_a[buf_off & SCROLL_BUFFER_MASK] & 0x3F;
2248 } 2248 }
2249 break; 2249 break;
2251 case 3: { 2251 case 3: {
2252 //plane B 2252 //plane B
2253 int i; 2253 int i;
2254 i = 0; 2254 i = 0;
2255 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);
2256 //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);
2257 for (; i < BORDER_RIGHT; buf_off++, i++, dst++) 2257 for (; i < BORDER_RIGHT; buf_off++, i++, dst++)
2258 { 2258 {
2259 *dst = context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK] & 0x3F; 2259 *dst = context->tmp_buf_b[buf_off & SCROLL_BUFFER_MASK] & 0x3F;
2260 } 2260 }
2261 break; 2261 break;
2284 *(dst++) = context->colors[*(src++)];\ 2284 *(dst++) = context->colors[*(src++)];\
2285 } else {\ 2285 } else {\
2286 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];\ 2286 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];\
2287 }\ 2287 }\
2288 } 2288 }
2289 2289
2290 #define OUTPUT_PIXEL_H40(slot) if (slot <= (BG_START_SLOT + LINEBUF_SIZE/2)) {\ 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;\ 2291 uint8_t *src = context->compositebuf + (slot - BG_START_SLOT) *2;\
2292 uint32_t *dst = context->output + (slot - BG_START_SLOT) *2;\ 2292 uint32_t *dst = context->output + (slot - BG_START_SLOT) *2;\
2293 if ((*src & 0x3F) | test_layer) {\ 2293 if ((*src & 0x3F) | test_layer) {\
2294 *(dst++) = context->colors[*(src++)];\ 2294 *(dst++) = context->colors[*(src++)];\
2301 } else {\ 2301 } else {\
2302 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];\ 2302 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];\
2303 }\ 2303 }\
2304 }\ 2304 }\
2305 } 2305 }
2306 2306
2307 #define OUTPUT_PIXEL_H32(slot) if (slot <= (BG_START_SLOT + (256+HORIZ_BORDER)/2)) {\ 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;\ 2308 uint8_t *src = context->compositebuf + (slot - BG_START_SLOT) *2;\
2309 uint32_t *dst = context->output + (slot - BG_START_SLOT) *2;\ 2309 uint32_t *dst = context->output + (slot - BG_START_SLOT) *2;\
2310 if ((*src & 0x3F) | test_layer) {\ 2310 if ((*src & 0x3F) | test_layer) {\
2311 *(dst++) = context->colors[*(src++)];\ 2311 *(dst++) = context->colors[*(src++)];\
2318 } else {\ 2318 } else {\
2319 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];\ 2319 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];\
2320 }\ 2320 }\
2321 }\ 2321 }\
2322 } 2322 }
2323 2323
2324 //BG_START_SLOT => dst = 0, src = border 2324 //BG_START_SLOT => dst = 0, src = border
2325 //BG_START_SLOT + 13/2=6, dst = 6, src = border + comp + 13 2325 //BG_START_SLOT + 13/2=6, dst = 6, src = border + comp + 13
2326 #define OUTPUT_PIXEL_MODE4(slot) if ((slot) >= BG_START_SLOT) {\ 2326 #define OUTPUT_PIXEL_MODE4(slot) if ((slot) >= BG_START_SLOT) {\
2327 uint8_t *src = context->compositebuf + ((slot) - BG_START_SLOT) *2;\ 2327 uint8_t *src = context->compositebuf + ((slot) - BG_START_SLOT) *2;\
2328 uint32_t *dst = context->output + ((slot) - BG_START_SLOT) *2;\ 2328 uint32_t *dst = context->output + ((slot) - BG_START_SLOT) *2;\
2412 CHECK_LIMIT\ 2412 CHECK_LIMIT\
2413 case (startcyc+7):\ 2413 case (startcyc+7):\
2414 OUTPUT_PIXEL((startcyc+7)&0xFF)\ 2414 OUTPUT_PIXEL((startcyc+7)&0xFF)\
2415 render_map_output(context->vcounter, column, context);\ 2415 render_map_output(context->vcounter, column, context);\
2416 CHECK_LIMIT 2416 CHECK_LIMIT
2417 2417
2418 #define COLUMN_RENDER_BLOCK_MODE4(column, startcyc) \ 2418 #define COLUMN_RENDER_BLOCK_MODE4(column, startcyc) \
2419 case startcyc:\ 2419 case startcyc:\
2420 OUTPUT_PIXEL_MODE4(startcyc)\ 2420 OUTPUT_PIXEL_MODE4(startcyc)\
2421 read_map_mode4(column, context->vcounter, context);\ 2421 read_map_mode4(column, context->vcounter, context);\
2422 CHECK_LIMIT\ 2422 CHECK_LIMIT\
2434 CHECK_LIMIT\ 2434 CHECK_LIMIT\
2435 case ((startcyc+3)&0xFF):\ 2435 case ((startcyc+3)&0xFF):\
2436 OUTPUT_PIXEL_MODE4((startcyc+3)&0xFF)\ 2436 OUTPUT_PIXEL_MODE4((startcyc+3)&0xFF)\
2437 render_map_mode4(context->vcounter, column, context);\ 2437 render_map_mode4(context->vcounter, column, context);\
2438 CHECK_LIMIT 2438 CHECK_LIMIT
2439 2439
2440 #define CHECK_LIMIT_HSYNC(slot) \ 2440 #define CHECK_LIMIT_HSYNC(slot) \
2441 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \ 2441 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \
2442 if (slot >= HSYNC_SLOT_H40 && slot < HSYNC_END_H40) {\ 2442 if (slot >= HSYNC_SLOT_H40 && slot < HSYNC_END_H40) {\
2443 context->cycles += h40_hsync_cycles[slot - HSYNC_SLOT_H40];\ 2443 context->cycles += h40_hsync_cycles[slot - HSYNC_SLOT_H40];\
2444 } else {\ 2444 } else {\
2521 } else {\ 2521 } else {\
2522 context->hslot++;\ 2522 context->hslot++;\
2523 }\ 2523 }\
2524 context->cycles += slot_cycles;\ 2524 context->cycles += slot_cycles;\
2525 CHECK_ONLY 2525 CHECK_ONLY
2526 2526
2527 #define MODE4_CHECK_SLOT_LINE(slot) \ 2527 #define MODE4_CHECK_SLOT_LINE(slot) \
2528 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \ 2528 if (context->flags & FLAG_DMA_RUN) { run_dma_src(context, -1); } \
2529 if ((slot) == BG_START_SLOT + (256+HORIZ_BORDER)/2) {\ 2529 if ((slot) == BG_START_SLOT + (256+HORIZ_BORDER)/2) {\
2530 advance_output_line(context);\ 2530 advance_output_line(context);\
2531 if (!context->output) {\ 2531 if (!context->output) {\
2545 }\ 2545 }\
2546 }\ 2546 }\
2547 CHECK_ONLY 2547 CHECK_ONLY
2548 2548
2549 #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))
2550 2550
2551 #define SPRITE_RENDER_H32_MODE4(slot) \ 2551 #define SPRITE_RENDER_H32_MODE4(slot) \
2552 case slot:\ 2552 case slot:\
2553 OUTPUT_PIXEL_MODE4(slot)\ 2553 OUTPUT_PIXEL_MODE4(slot)\
2554 read_sprite_x_mode4(context);\ 2554 read_sprite_x_mode4(context);\
2555 MODE4_CHECK_SLOT_LINE(slot)\ 2555 MODE4_CHECK_SLOT_LINE(slot)\
2580 uint16_t address; 2580 uint16_t address;
2581 uint32_t mask; 2581 uint32_t mask;
2582 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; 2583 uint8_t bgindex = context->regs[REG_BG_COLOR] & 0x3F;
2584 uint8_t test_layer = context->test_port >> 7 & 3; 2584 uint8_t test_layer = context->test_port >> 7 & 3;
2585 2585
2586 //165 2586 //165
2587 if (!(context->regs[REG_MODE_3] & BIT_VSCROLL)) { 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 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 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 2590 //Skitchin' has a similar problem, but uses H40 mode. It seems to be able to hit the extern slot at 232
2612 context->sprite_draw_list[context->cur_slot].address, 2612 context->sprite_draw_list[context->cur_slot].address,
2613 context->tmp_buf_b, 2613 context->tmp_buf_b,
2614 context->buf_b_off + 8, 2614 context->buf_b_off + 8,
2615 context->col_2 2615 context->col_2
2616 ); 2616 );
2617
2617 //Do palette lookup for end of previous line 2618 //Do palette lookup for end of previous line
2618 uint8_t *src = context->compositebuf + (LINE_CHANGE_H40 - BG_START_SLOT) *2; 2619 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 uint32_t *dst = context->output + (LINE_CHANGE_H40 - BG_START_SLOT) *2;
2620 if (test_layer) { 2621 if (context->output) {
2621 for (int i = 0; i < LINEBUF_SIZE - (LINE_CHANGE_H40 - BG_START_SLOT) * 2; i++) 2622 if (test_layer) {
2622 { 2623 for (int i = 0; i < LINEBUF_SIZE - (LINE_CHANGE_H40 - BG_START_SLOT) * 2; i++)
2623 *(dst++) = context->colors[*(src++)]; 2624 {
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++)]; 2625 *(dst++) = context->colors[*(src++)];
2630 } else { 2626 }
2631 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex]; 2627 } else {
2628 for (int i = 0; i < LINEBUF_SIZE - (LINE_CHANGE_H40 - BG_START_SLOT) * 2; i++)
2629 {
2630 if (*src & 0x3F) {
2631 *(dst++) = context->colors[*(src++)];
2632 } else {
2633 *(dst++) = context->colors[(*(src++) & 0xC0) | bgindex];
2634 }
2632 } 2635 }
2633 } 2636 }
2634 } 2637 }
2635 advance_output_line(context); 2638 advance_output_line(context);
2636 //168-242 (inclusive) 2639 //168-242 (inclusive)
2750 ); 2753 );
2751 render_sprite_cells(context); 2754 render_sprite_cells(context);
2752 context->cycles += MCLKS_LINE; 2755 context->cycles += MCLKS_LINE;
2753 vdp_advance_line(context); 2756 vdp_advance_line(context);
2754 src = context->compositebuf; 2757 src = context->compositebuf;
2758 if (!context->output) {
2759 return;
2760 }
2755 dst = context->output; 2761 dst = context->output;
2756 if (test_layer) { 2762 if (test_layer) {
2757 for (int i = 0; i < (LINE_CHANGE_H40 - BG_START_SLOT) * 2; i++) 2763 for (int i = 0; i < (LINE_CHANGE_H40 - BG_START_SLOT) * 2; i++)
2758 { 2764 {
2759 *(dst++) = context->colors[*(src++)]; 2765 *(dst++) = context->colors[*(src++)];
2790 if (context->fifo_read == -1 && !(context->flags & FLAG_DMA_RUN) && ((context->cd & 1) || (context->flags & FLAG_READ_FETCHED))) { 2796 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) { 2797 while (target_cycles - context->cycles >= MCLKS_LINE && context->state != PREPARING && context->vcounter != context->inactive_start) {
2792 vdp_h40_line(context); 2798 vdp_h40_line(context);
2793 } 2799 }
2794 CHECK_ONLY 2800 CHECK_ONLY
2801 if (!context->output) {
2802 //This shouldn't happen normally, but it can theoretically
2803 //happen when doing border busting
2804 context->output = dummy_buffer;
2805 }
2795 } 2806 }
2796 OUTPUT_PIXEL(165) 2807 OUTPUT_PIXEL(165)
2797 if (!(context->regs[REG_MODE_3] & BIT_VSCROLL)) { 2808 if (!(context->regs[REG_MODE_3] & BIT_VSCROLL)) {
2798 //TODO: Develop some tests on hardware to see when vscroll latch actually happens for full plane mode 2809 //TODO: Develop some tests on hardware to see when vscroll latch actually happens for full plane mode
2799 //See note in vdp_h32 for why this was originally moved out of read_map_scroll 2810 //See note in vdp_h32 for why this was originally moved out of read_map_scroll
3403 static void vdp_inactive(vdp_context *context, uint32_t target_cycles, uint8_t is_h40, uint8_t mode_5) 3414 static void vdp_inactive(vdp_context *context, uint32_t target_cycles, uint8_t is_h40, uint8_t mode_5)
3404 { 3415 {
3405 uint8_t buf_clear_slot, index_reset_slot, bg_end_slot, vint_slot, line_change, jump_start, jump_dest, latch_slot; 3416 uint8_t buf_clear_slot, index_reset_slot, bg_end_slot, vint_slot, line_change, jump_start, jump_dest, latch_slot;
3406 uint8_t index_reset_value, max_draws, max_sprites; 3417 uint8_t index_reset_value, max_draws, max_sprites;
3407 uint16_t vint_line, active_line; 3418 uint16_t vint_line, active_line;
3408 3419
3409 if (mode_5) { 3420 if (mode_5) {
3410 if (is_h40) { 3421 if (is_h40) {
3411 latch_slot = 165; 3422 latch_slot = 165;
3412 buf_clear_slot = 163; 3423 buf_clear_slot = 163;
3413 index_reset_slot = 167; 3424 index_reset_slot = 167;
3463 dst = context->output + 2 * (context->hslot - BG_START_SLOT); 3474 dst = context->output + 2 * (context->hslot - BG_START_SLOT);
3464 debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT); 3475 debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT);
3465 } else { 3476 } else {
3466 dst = NULL; 3477 dst = NULL;
3467 } 3478 }
3468 3479
3469 uint8_t test_layer = context->test_port >> 7 & 3; 3480 uint8_t test_layer = context->test_port >> 7 & 3;
3470 3481
3471 while(context->cycles < target_cycles) 3482 while(context->cycles < target_cycles)
3472 { 3483 {
3473 check_switch_inactive(context, is_h40); 3484 check_switch_inactive(context, is_h40);
3474 if (context->hslot == BG_START_SLOT && context->output) { 3485 if (context->hslot == BG_START_SLOT && context->output) {
3475 dst = context->output + (context->hslot - BG_START_SLOT) * 2; 3486 dst = context->output + (context->hslot - BG_START_SLOT) * 2;
3476 debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT); 3487 debug_dst = context->layer_debug_buf + 2 * (context->hslot - BG_START_SLOT);
3477 } else if (context->hslot == bg_end_slot) { 3488 } else if (context->hslot == bg_end_slot) {
3478 advance_output_line(context); 3489 advance_output_line(context);
3479 dst = NULL; 3490 dst = NULL;
3480 } 3491 }
3481 //this will need some tweaking to properly interact with 128K mode, 3492 //this will need some tweaking to properly interact with 128K mode,
3482 //but this should be good enough for now 3493 //but this should be good enough for now
3483 context->serial_address += 1024; 3494 context->serial_address += 1024;
3484 if (test_layer) { 3495 if (test_layer) {
3485 switch (context->hslot & 7) 3496 switch (context->hslot & 7)
3486 { 3497 {
3499 case 1: 3510 case 1:
3500 inactive_test_output(context, is_h40, test_layer); 3511 inactive_test_output(context, is_h40, test_layer);
3501 break; 3512 break;
3502 } 3513 }
3503 } 3514 }
3504 3515
3505 if (context->hslot == buf_clear_slot) { 3516 if (context->hslot == buf_clear_slot) {
3506 if (mode_5) { 3517 if (mode_5) {
3507 context->cur_slot = max_draws; 3518 context->cur_slot = max_draws;
3508 } else { 3519 } else {
3509 context->cur_slot = context->sprite_index = MAX_DRAWS_H32_MODE4-1; 3520 context->cur_slot = context->sprite_index = MAX_DRAWS_H32_MODE4-1;
3513 } else if (context->hslot == index_reset_slot) { 3524 } else if (context->hslot == index_reset_slot) {
3514 context->sprite_index = index_reset_value; 3525 context->sprite_index = index_reset_value;
3515 context->slot_counter = mode_5 ? 0 : max_sprites; 3526 context->slot_counter = mode_5 ? 0 : max_sprites;
3516 } else if (context->hslot == latch_slot) { 3527 } else if (context->hslot == latch_slot) {
3517 //it seems unlikely to me that vscroll actually gets latched when the display is off 3528 //it seems unlikely to me that vscroll actually gets latched when the display is off
3518 //but it's the only straightforward way to reconcile what I'm seeing between Skitchin 3529 //but it's the only straightforward way to reconcile what I'm seeing between Skitchin
3519 //(which seems to expect vscroll to be latched early) and the intro of Gunstar Heroes 3530 //(which seems to expect vscroll to be latched early) and the intro of Gunstar Heroes
3520 //(which disables the display and ends up with garbage if vscroll is latched during that period) 3531 //(which disables the display and ends up with garbage if vscroll is latched during that period)
3521 //without it. Some more tests are definitely needed 3532 //without it. Some more tests are definitely needed
3522 context->vscroll_latch[0] = context->vsram[0]; 3533 context->vscroll_latch[0] = context->vsram[0];
3523 context->vscroll_latch[1] = context->vsram[1]; 3534 context->vscroll_latch[1] = context->vsram[1];
3525 context->flags2 |= FLAG2_VINT_PENDING; 3536 context->flags2 |= FLAG2_VINT_PENDING;
3526 context->pending_vint_start = context->cycles; 3537 context->pending_vint_start = context->cycles;
3527 } else if (context->vcounter == context->inactive_start && context->hslot == 1 && (context->regs[REG_MODE_4] & BIT_INTERLACE)) { 3538 } else if (context->vcounter == context->inactive_start && context->hslot == 1 && (context->regs[REG_MODE_4] & BIT_INTERLACE)) {
3528 context->flags2 ^= FLAG2_EVEN_FIELD; 3539 context->flags2 ^= FLAG2_EVEN_FIELD;
3529 } 3540 }
3530 3541
3531 if (dst) { 3542 if (dst) {
3532 uint8_t bg_index; 3543 uint8_t bg_index;
3533 uint32_t bg_color; 3544 uint32_t bg_color;
3534 if (mode_5) { 3545 if (mode_5) {
3535 bg_index = context->regs[REG_BG_COLOR] & 0x3F; 3546 bg_index = context->regs[REG_BG_COLOR] & 0x3F;
3566 } 3577 }
3567 } else { 3578 } else {
3568 *(dst++) = bg_color; 3579 *(dst++) = bg_color;
3569 *(debug_dst++) = DBG_SRC_BG; 3580 *(debug_dst++) = DBG_SRC_BG;
3570 } 3581 }
3571 3582
3572 if (context->hslot == (bg_end_slot-1)) { 3583 if (context->hslot == (bg_end_slot-1)) {
3573 if (context->done_composite) { 3584 if (context->done_composite) {
3574 uint8_t pixel = context->compositebuf[dst-context->output]; 3585 uint8_t pixel = context->compositebuf[dst-context->output];
3575 if (!(pixel & 0x3F | test_layer)) { 3586 if (!(pixel & 0x3F | test_layer)) {
3576 pixel = pixel & 0xC0 | bg_index; 3587 pixel = pixel & 0xC0 | bg_index;
3584 *(dst++) = bg_color; 3595 *(dst++) = bg_color;
3585 *(debug_dst++) = DBG_SRC_BG; 3596 *(debug_dst++) = DBG_SRC_BG;
3586 } 3597 }
3587 } 3598 }
3588 } 3599 }
3589 3600
3590 if (!is_refresh(context, context->hslot)) { 3601 if (!is_refresh(context, context->hslot)) {
3591 external_slot(context); 3602 external_slot(context);
3592 if (context->flags & FLAG_DMA_RUN && !is_refresh(context, context->hslot)) { 3603 if (context->flags & FLAG_DMA_RUN && !is_refresh(context, context->hslot)) {
3593 run_dma_src(context, context->hslot); 3604 run_dma_src(context, context->hslot);
3594 } 3605 }
3595 } 3606 }
3596 3607
3597 if (is_h40) { 3608 if (is_h40) {
3598 if (context->hslot >= HSYNC_SLOT_H40 && context->hslot < HSYNC_END_H40) { 3609 if (context->hslot >= HSYNC_SLOT_H40 && context->hslot < HSYNC_END_H40) {
3599 context->cycles += h40_hsync_cycles[context->hslot - HSYNC_SLOT_H40]; 3610 context->cycles += h40_hsync_cycles[context->hslot - HSYNC_SLOT_H40];
3600 } else { 3611 } else {
3601 context->cycles += MCLKS_SLOT_H40; 3612 context->cycles += MCLKS_SLOT_H40;
3623 uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40; 3634 uint8_t is_h40 = context->regs[REG_MODE_4] & BIT_H40;
3624 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5; 3635 uint8_t mode_5 = context->regs[REG_MODE_2] & BIT_MODE_5;
3625 while(context->cycles < target_cycles) 3636 while(context->cycles < target_cycles)
3626 { 3637 {
3627 check_switch_inactive(context, is_h40); 3638 check_switch_inactive(context, is_h40);
3628 3639
3629 if (is_active(context)) { 3640 if (is_active(context)) {
3630 if (mode_5) { 3641 if (mode_5) {
3631 if (is_h40) { 3642 if (is_h40) {
3632 vdp_h40(context, target_cycles); 3643 vdp_h40(context, target_cycles);
3633 } else { 3644 } else {
3669 if (!dmalen) { 3680 if (!dmalen) {
3670 dmalen = 0x10000; 3681 dmalen = 0x10000;
3671 } 3682 }
3672 uint32_t min_dma_complete = dmalen * (context->regs[REG_MODE_4] & BIT_H40 ? 16 : 20); 3683 uint32_t min_dma_complete = dmalen * (context->regs[REG_MODE_4] & BIT_H40 ? 16 : 20);
3673 if ( 3684 if (
3674 (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_COPY 3685 (context->regs[REG_DMASRC_H] & DMA_TYPE_MASK) == DMA_COPY
3675 || (((context->cd & 0xF) == VRAM_WRITE) && !(context->regs[REG_MODE_2] & BIT_128K_VRAM))) { 3686 || (((context->cd & 0xF) == VRAM_WRITE) && !(context->regs[REG_MODE_2] & BIT_128K_VRAM))) {
3676 //DMA copies take twice as long to complete since they require a read and a write 3687 //DMA copies take twice as long to complete since they require a read and a write
3677 //DMA Fills and transfers to VRAM also take twice as long as it requires 2 writes for a single word 3688 //DMA Fills and transfers to VRAM also take twice as long as it requires 2 writes for a single word
3678 //unless 128KB mode is enabled 3689 //unless 128KB mode is enabled
3679 min_dma_complete *= 2; 3690 min_dma_complete *= 2;
3722 hv = context->hslot; 3733 hv = context->hslot;
3723 } else { 3734 } else {
3724 hv = context->hv_latch & 0xFF; 3735 hv = context->hv_latch & 0xFF;
3725 } 3736 }
3726 hv |= get_ext_vcounter(context); 3737 hv |= get_ext_vcounter(context);
3727 3738
3728 return hv; 3739 return hv;
3729 } 3740 }
3730 3741
3731 static void clear_pending(vdp_context *context) 3742 static void clear_pending(vdp_context *context)
3732 { 3743 {
3733 context->flags &= ~FLAG_PENDING; 3744 context->flags &= ~FLAG_PENDING;
3734 context->address = context->address_latch; 3745 context->address = context->address_latch;
3735 //It seems like the DMA enable bit doesn't so much enable DMA so much 3746 //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 3747 //as it enables changing CD5 from control port writes
3737 if (context->regs[REG_MODE_2] & BIT_DMA_ENABLE) { 3748 if (context->regs[REG_MODE_2] & BIT_DMA_ENABLE) {
3738 context->cd = context->cd_latch; 3749 context->cd = context->cd_latch;
3739 } else { 3750 } else {
3740 context->cd = (context->cd & 0x20) | (context->cd_latch & 0x1F); 3751 context->cd = (context->cd & 0x20) | (context->cd_latch & 0x1F);
4046 if (context->flags & FLAG_PENDING) { 4057 if (context->flags & FLAG_PENDING) {
4047 clear_pending(context); 4058 clear_pending(context);
4048 } 4059 }
4049 context->flags &= ~FLAG_READ_FETCHED; 4060 context->flags &= ~FLAG_READ_FETCHED;
4050 context->flags2 &= ~FLAG2_BYTE_PENDING; 4061 context->flags2 &= ~FLAG2_BYTE_PENDING;
4051 4062
4052 context->cd = VRAM_READ8; 4063 context->cd = VRAM_READ8;
4053 return context->prefetch; 4064 return context->prefetch;
4054 } 4065 }
4055 4066
4056 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) 4067 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction)
4264 uint32_t cycles = context->cycles; 4275 uint32_t cycles = context->cycles;
4265 if (context->hslot >= LINE_CHANGE_H40) { 4276 if (context->hslot >= LINE_CHANGE_H40) {
4266 if (context->hslot < 183) { 4277 if (context->hslot < 183) {
4267 cycles += (183 - context->hslot) * MCLKS_SLOT_H40; 4278 cycles += (183 - context->hslot) * MCLKS_SLOT_H40;
4268 } 4279 }
4269 4280
4270 if (context->hslot < HSYNC_SLOT_H40) { 4281 if (context->hslot < HSYNC_SLOT_H40) {
4271 cycles += (HSYNC_SLOT_H40 - (context->hslot >= 229 ? context->hslot : 229)) * MCLKS_SLOT_H40; 4282 cycles += (HSYNC_SLOT_H40 - (context->hslot >= 229 ? context->hslot : 229)) * MCLKS_SLOT_H40;
4272 } 4283 }
4273 for (int slot = context->hslot <= HSYNC_SLOT_H40 ? HSYNC_SLOT_H40 : context->hslot; slot < HSYNC_END_H40; slot++ ) 4284 for (int slot = context->hslot <= HSYNC_SLOT_H40 ? HSYNC_SLOT_H40 : context->hslot; slot < HSYNC_END_H40; slot++ )
4274 { 4285 {
4275 cycles += h40_hsync_cycles[slot - HSYNC_SLOT_H40]; 4286 cycles += h40_hsync_cycles[slot - HSYNC_SLOT_H40];
4276 } 4287 }
4277 cycles += (256 - (context->hslot > HSYNC_END_H40 ? context->hslot : HSYNC_END_H40)) * MCLKS_SLOT_H40; 4288 cycles += (256 - (context->hslot > HSYNC_END_H40 ? context->hslot : HSYNC_END_H40)) * MCLKS_SLOT_H40;
4278 } 4289 }
4279 4290
4280 cycles += (VINT_SLOT_H40 - (context->hslot >= LINE_CHANGE_H40 ? 0 : context->hslot)) * MCLKS_SLOT_H40; 4291 cycles += (VINT_SLOT_H40 - (context->hslot >= LINE_CHANGE_H40 ? 0 : context->hslot)) * MCLKS_SLOT_H40;
4281 return cycles; 4292 return cycles;
4282 } 4293 }
4283 } else { 4294 } else {
4284 if (context->hslot >= LINE_CHANGE_H32 || context->hslot <= VINT_SLOT_H32) { 4295 if (context->hslot >= LINE_CHANGE_H32 || context->hslot <= VINT_SLOT_H32) {
4329 void vdp_int_ack(vdp_context * context) 4340 void vdp_int_ack(vdp_context * context)
4330 { 4341 {
4331 //CPU interrupt acknowledge is only used in Mode 5 4342 //CPU interrupt acknowledge is only used in Mode 5
4332 if (context->regs[REG_MODE_2] & BIT_MODE_5) { 4343 if (context->regs[REG_MODE_2] & BIT_MODE_5) {
4333 //Apparently the VDP interrupt controller is not very smart 4344 //Apparently the VDP interrupt controller is not very smart
4334 //Instead of paying attention to what interrupt is being acknowledged it just 4345 //Instead of paying attention to what interrupt is being acknowledged it just
4335 //clears the pending flag for whatever interrupt it is currently asserted 4346 //clears the pending flag for whatever interrupt it is currently asserted
4336 //which may be different from the interrupt it was asserting when the 68k 4347 //which may be different from the interrupt it was asserting when the 68k
4337 //started the interrupt process. The window for this is narrow and depends 4348 //started the interrupt process. The window for this is narrow and depends
4338 //on the latency between the int enable register write and the interrupt being 4349 //on the latency between the int enable register write and the interrupt being
4339 //asserted, but Fatal Rewind depends on this due to some buggy code 4350 //asserted, but Fatal Rewind depends on this due to some buggy code
4419 save_int8(buf, info->size); 4430 save_int8(buf, info->size);
4420 save_int8(buf, info->index); 4431 save_int8(buf, info->index);
4421 save_int16(buf, info->y); 4432 save_int16(buf, info->y);
4422 } 4433 }
4423 save_buffer8(buf, context->linebuf, LINEBUF_SIZE); 4434 save_buffer8(buf, context->linebuf, LINEBUF_SIZE);
4424 4435
4425 save_int32(buf, context->cycles); 4436 save_int32(buf, context->cycles);
4426 save_int32(buf, context->pending_vint_start); 4437 save_int32(buf, context->pending_vint_start);
4427 save_int32(buf, context->pending_hint_start); 4438 save_int32(buf, context->pending_hint_start);
4428 save_int32(buf, context->address_latch); 4439 save_int32(buf, context->address_latch);
4429 save_int8(buf, context->cd_latch); 4440 save_int8(buf, context->cd_latch);
4515 draw->x_pos = load_int16(buf); 4526 draw->x_pos = load_int16(buf);
4516 draw->pal_priority = load_int8(buf); 4527 draw->pal_priority = load_int8(buf);
4517 draw->h_flip = load_int8(buf); 4528 draw->h_flip = load_int8(buf);
4518 draw->width = 1; 4529 draw->width = 1;
4519 draw->height = 8; 4530 draw->height = 8;
4520 4531
4521 if (last && last->width < 4 && last->h_flip == draw->h_flip && last->pal_priority == draw->pal_priority) { 4532 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; 4533 int adjust_x = draw->x_pos + draw->h_flip ? -8 : 8;
4523 int height = draw->address - last->address /4; 4534 int height = draw->address - last->address /4;
4524 if (last->x_pos == adjust_x && ( 4535 if (last->x_pos == adjust_x && (
4525 (last->width > 1 && height == last->height) || 4536 (last->width > 1 && height == last->height) ||
4526 (last->width == 1 && (height == 8 || height == 16 || height == 24 || height == 32)) 4537 (last->width == 1 && (height == 8 || height == 16 || height == 24 || height == 32))
4527 )) { 4538 )) {
4528 //current draw appears to be part of the same sprite as the last one, combine it 4539 //current draw appears to be part of the same sprite as the last one, combine it
4529 cur_draw--; 4540 cur_draw--;
4530 last->width++; 4541 last->width++;
4555 info->size = load_int8(buf); 4566 info->size = load_int8(buf);
4556 info->index = load_int8(buf); 4567 info->index = load_int8(buf);
4557 info->y = load_int16(buf); 4568 info->y = load_int16(buf);
4558 } 4569 }
4559 load_buffer8(buf, context->linebuf, LINEBUF_SIZE); 4570 load_buffer8(buf, context->linebuf, LINEBUF_SIZE);
4560 4571
4561 context->cycles = load_int32(buf); 4572 context->cycles = load_int32(buf);
4562 context->pending_vint_start = load_int32(buf); 4573 context->pending_vint_start = load_int32(buf);
4563 context->pending_hint_start = load_int32(buf); 4574 context->pending_hint_start = load_int32(buf);
4564 if (version > 2) { 4575 if (version > 2) {
4565 context->address_latch = load_int32(buf); 4576 context->address_latch = load_int32(buf);
4680 case EVENT_VDP_INTRAM: 4691 case EVENT_VDP_INTRAM:
4681 reader_ensure_data(reader, event == EVENT_VDP_REG ? 2 : 3); 4692 reader_ensure_data(reader, event == EVENT_VDP_REG ? 2 : 3);
4682 address = load_int8(buffer); 4693 address = load_int8(buffer);
4683 break; 4694 break;
4684 } 4695 }
4685 4696
4686 switch (event) 4697 switch (event)
4687 { 4698 {
4688 case EVENT_VDP_REG: { 4699 case EVENT_VDP_REG: {
4689 uint8_t value = load_int8(buffer); 4700 uint8_t value = load_int8(buffer);
4690 context->regs[address] = value; 4701 context->regs[address] = value;