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