Mercurial > repos > blastem
comparison vdp.c @ 980:928442068afe
Implemented VDP read prefetch and made DMA copy not use the FIFO any more. Now up to 114 out of 122 passing on VDP FIFO Test ROM
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 24 Apr 2016 01:24:38 -0700 |
parents | 08346262990b |
children | 902c53d9c16f |
comparison
equal
deleted
inserted
replaced
979:771875b5f519 | 980:928442068afe |
---|---|
227 //2 would trigger register write 0010 | 227 //2 would trigger register write 0010 |
228 #define CRAM_WRITE 3 //0011 | 228 #define CRAM_WRITE 3 //0011 |
229 #define VSRAM_READ 4 //0100 | 229 #define VSRAM_READ 4 //0100 |
230 #define VSRAM_WRITE 5//0101 | 230 #define VSRAM_WRITE 5//0101 |
231 //6 would trigger regsiter write 0110 | 231 //6 would trigger regsiter write 0110 |
232 //7 is a mystery | 232 //7 is a mystery //0111 |
233 #define CRAM_READ 8 //1000 | 233 #define CRAM_READ 8 //1000 |
234 //9 is also a mystery //1001 | 234 //9 is also a mystery //1001 |
235 //A would trigger register write 1010 | 235 //A would trigger register write 1010 |
236 //B is a mystery 1011 | 236 //B is a mystery 1011 |
237 #define VRAM_READ8 0xC //1100 | 237 #define VRAM_READ8 0xC //1100 |
238 //D is a mystery 1101 | 238 //D is a mystery 1101 |
239 //E would trigger register write 1110 | 239 //E would trigger register write 1110 |
240 //F is a mystery 1111 | 240 //F is a mystery 1111 |
241 | |
242 //Possible theory on how bits work | |
243 //CD0 = Read/Write flag | |
244 //CD2,(CD1|CD3) = RAM type | |
245 // 00 = VRAM | |
246 // 01 = CRAM | |
247 // 10 = VSRAM | |
248 // 11 = VRAM8 | |
249 //Would result in | |
250 // 7 = VRAM8 write | |
251 // 9 = CRAM write alias | |
252 // B = CRAM write alias | |
253 // D = VRAM8 write alias | |
254 // F = VRAM8 write alais | |
255 | |
241 #define DMA_START 0x20 | 256 #define DMA_START 0x20 |
242 | 257 |
243 const char * cd_name(uint8_t cd) | 258 const char * cd_name(uint8_t cd) |
244 { | 259 { |
245 switch (cd & 0xF) | 260 switch (cd & 0xF) |
466 context->colors[addr] = color_map[value & 0xEEE]; | 481 context->colors[addr] = color_map[value & 0xEEE]; |
467 context->colors[addr + CRAM_SIZE] = color_map[(value & 0xEEE) | FBUF_SHADOW]; | 482 context->colors[addr + CRAM_SIZE] = color_map[(value & 0xEEE) | FBUF_SHADOW]; |
468 context->colors[addr + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT]; | 483 context->colors[addr + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT]; |
469 } | 484 } |
470 | 485 |
486 #define CRAM_BITS 0xEEE | |
487 #define VSRAM_BITS 0x7FF | |
488 #define VSRAM_DIRTY_BITS 0xF800 | |
489 | |
471 void external_slot(vdp_context * context) | 490 void external_slot(vdp_context * context) |
472 { | 491 { |
473 fifo_entry * start = context->fifo + context->fifo_read; | 492 fifo_entry * start = context->fifo + context->fifo_read; |
474 /*if (context->flags2 & FLAG2_READ_PENDING) { | |
475 context->flags2 &= ~FLAG2_READ_PENDING; | |
476 context->flags |= FLAG_UNUSED_SLOT; | |
477 return; | |
478 }*/ | |
479 if (context->fifo_read >= 0 && start->cycle <= context->cycles) { | 493 if (context->fifo_read >= 0 && start->cycle <= context->cycles) { |
480 switch (start->cd & 0xF) | 494 switch (start->cd & 0xF) |
481 { | 495 { |
482 case VRAM_WRITE: | 496 case VRAM_WRITE: |
483 if (start->partial) { | 497 if (start->partial) { |
506 } | 520 } |
507 context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1); | 521 context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1); |
508 if (context->fifo_read == context->fifo_write) { | 522 if (context->fifo_read == context->fifo_write) { |
509 context->fifo_read = -1; | 523 context->fifo_read = -1; |
510 } | 524 } |
511 context->flags &= ~FLAG_UNUSED_SLOT; | 525 } else if ((context->flags & FLAG_DMA_RUN) && (context->regs[REG_DMASRC_H] & 0xC0) == 0xC0) { |
512 } else { | 526 if (context->flags & FLAG_READ_FETCHED) { |
513 context->flags |= FLAG_UNUSED_SLOT; | 527 context->vdpmem[context->address ^ 1] = context->prefetch; |
528 | |
529 //Update DMA state | |
530 context->regs[REG_DMASRC_L] += 1; | |
531 if (!context->regs[REG_DMASRC_L]) { | |
532 context->regs[REG_DMASRC_M] += 1; | |
533 } | |
534 context->address += context->regs[REG_AUTOINC]; | |
535 uint16_t dma_len = ((context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]) - 1; | |
536 context->regs[REG_DMALEN_H] = dma_len >> 8; | |
537 context->regs[REG_DMALEN_L] = dma_len; | |
538 if (!dma_len) { | |
539 context->flags &= ~FLAG_DMA_RUN; | |
540 context->cd &= 0xF; | |
541 } | |
542 | |
543 context->flags &= ~FLAG_READ_FETCHED; | |
544 } else { | |
545 context->prefetch = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1]; | |
546 | |
547 context->flags |= FLAG_READ_FETCHED; | |
548 } | |
549 } else if (!(context->cd & 1) && !(context->flags & FLAG_READ_FETCHED)){ | |
550 switch(context->cd & 0xF) | |
551 { | |
552 case VRAM_READ: | |
553 if (context->flags2 & FLAG2_READ_PENDING) { | |
554 context->prefetch |= context->vdpmem[context->address | 1]; | |
555 context->flags |= FLAG_READ_FETCHED; | |
556 context->flags2 &= ~FLAG2_READ_PENDING; | |
557 //Should this happen after the prefetch or after the read? | |
558 //context->address += context->regs[REG_AUTOINC]; | |
559 } else { | |
560 context->prefetch = context->vdpmem[context->address & 0xFFFE] << 8; | |
561 context->flags2 |= FLAG2_READ_PENDING; | |
562 } | |
563 break; | |
564 case VRAM_READ8: | |
565 context->prefetch = context->vdpmem[context->address ^ 1]; | |
566 context->prefetch |= context->fifo[context->fifo_write].value & 0xFF00; | |
567 context->flags |= FLAG_READ_FETCHED; | |
568 //Should this happen after the prefetch or after the read? | |
569 //context->address += context->regs[REG_AUTOINC]; | |
570 break; | |
571 case CRAM_READ: | |
572 context->prefetch = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS; | |
573 context->prefetch |= context->fifo[context->fifo_write].value & ~CRAM_BITS; | |
574 context->flags |= FLAG_READ_FETCHED; | |
575 //Should this happen after the prefetch or after the read? | |
576 //context->address += context->regs[REG_AUTOINC]; | |
577 break; | |
578 case VSRAM_READ: { | |
579 uint16_t address = (context->address /2) & 63; | |
580 if (address >= VSRAM_SIZE) { | |
581 address = 0; | |
582 } | |
583 context->prefetch = context->vsram[address] & VSRAM_BITS; | |
584 context->prefetch |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS; | |
585 context->flags |= FLAG_READ_FETCHED; | |
586 //Should this happen after the prefetch or after the read? | |
587 //context->address += context->regs[REG_AUTOINC]; | |
588 break; | |
589 } | |
590 } | |
514 } | 591 } |
515 } | 592 } |
516 | 593 |
517 void run_dma_src(vdp_context * context, int32_t slot) | 594 void run_dma_src(vdp_context * context, int32_t slot) |
518 { | 595 { |
539 context->fifo_read = context->fifo_write; | 616 context->fifo_read = context->fifo_write; |
540 } | 617 } |
541 context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1); | 618 context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1); |
542 } | 619 } |
543 break; | 620 break; |
544 //Copy | 621 //Fill |
545 case 0xC0: | |
546 if (context->flags & FLAG_UNUSED_SLOT && context->fifo_read < 0) { | |
547 //TODO: Fix this to not use the FIFO at all once read-caching is properly implemented | |
548 context->fifo_read = (context->fifo_write-1) & (FIFO_SIZE-1); | |
549 cur = context->fifo + context->fifo_read; | |
550 cur->cycle = context->cycles; | |
551 cur->address = context->address; | |
552 cur->partial = 1; | |
553 cur->value = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1] | (cur->value & 0xFF00); | |
554 cur->cd = VRAM_WRITE; | |
555 context->flags &= ~FLAG_UNUSED_SLOT; | |
556 } | |
557 break; | |
558 case 0x80: | 622 case 0x80: |
559 if (context->fifo_read < 0) { | 623 if (context->fifo_read < 0) { |
560 context->fifo_read = (context->fifo_write-1) & (FIFO_SIZE-1); | 624 context->fifo_read = (context->fifo_write-1) & (FIFO_SIZE-1); |
561 cur = context->fifo + context->fifo_read; | 625 cur = context->fifo + context->fifo_read; |
562 cur->cycle = context->cycles; | 626 cur->cycle = context->cycles; |
1525 } | 1589 } |
1526 if (context->flags & FLAG_PENDING) { | 1590 if (context->flags & FLAG_PENDING) { |
1527 context->address = (context->address & 0x3FFF) | (value << 14); | 1591 context->address = (context->address & 0x3FFF) | (value << 14); |
1528 context->cd = (context->cd & 0x3) | ((value >> 2) & 0x3C); | 1592 context->cd = (context->cd & 0x3) | ((value >> 2) & 0x3C); |
1529 context->flags &= ~FLAG_PENDING; | 1593 context->flags &= ~FLAG_PENDING; |
1594 //Should these be taken care of here or after the first write? | |
1595 context->flags &= ~FLAG_READ_FETCHED; | |
1596 context->flags2 &= ~FLAG2_READ_PENDING; | |
1530 //printf("New Address: %X, New CD: %X\n", context->address, context->cd); | 1597 //printf("New Address: %X, New CD: %X\n", context->address, context->cd); |
1531 if (context->cd & 0x20 && (context->regs[REG_MODE_2] & BIT_DMA_ENABLE)) { | 1598 if (context->cd & 0x20 && (context->regs[REG_MODE_2] & BIT_DMA_ENABLE)) { |
1532 // | 1599 // |
1533 if((context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { | 1600 if((context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { |
1534 //DMA copy or 68K -> VDP, transfer starts immediately | 1601 //DMA copy or 68K -> VDP, transfer starts immediately |
1571 } | 1638 } |
1572 } else { | 1639 } else { |
1573 context->flags |= FLAG_PENDING; | 1640 context->flags |= FLAG_PENDING; |
1574 context->address = (context->address &0xC000) | (value & 0x3FFF); | 1641 context->address = (context->address &0xC000) | (value & 0x3FFF); |
1575 context->cd = (context->cd &0x3C) | (value >> 14); | 1642 context->cd = (context->cd &0x3C) | (value >> 14); |
1643 //Should these be taken care of here or after the second write? | |
1644 //context->flags &= ~FLAG_READ_FETCHED; | |
1645 //context->flags2 &= ~FLAG2_READ_PENDING; | |
1576 } | 1646 } |
1577 } | 1647 } |
1578 return 0; | 1648 return 0; |
1579 } | 1649 } |
1580 | 1650 |
1582 { | 1652 { |
1583 //printf("data port write: %X at %d\n", value, context->cycles); | 1653 //printf("data port write: %X at %d\n", value, context->cycles); |
1584 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { | 1654 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { |
1585 return -1; | 1655 return -1; |
1586 } | 1656 } |
1587 context->flags &= ~FLAG_PENDING; | 1657 if (context->flags & FLAG_PENDING) { |
1658 context->flags &= ~FLAG_PENDING; | |
1659 //Should these be cleared here? | |
1660 context->flags &= ~FLAG_READ_FETCHED; | |
1661 context->flags2 &= ~FLAG2_READ_PENDING; | |
1662 } | |
1588 /*if (context->fifo_cur == context->fifo_end) { | 1663 /*if (context->fifo_cur == context->fifo_end) { |
1589 printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles); | 1664 printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles); |
1590 }*/ | 1665 }*/ |
1591 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { | 1666 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { |
1592 context->flags &= ~FLAG_DMA_RUN; | 1667 context->flags &= ~FLAG_DMA_RUN; |
1617 } | 1692 } |
1618 | 1693 |
1619 uint16_t vdp_control_port_read(vdp_context * context) | 1694 uint16_t vdp_control_port_read(vdp_context * context) |
1620 { | 1695 { |
1621 context->flags &= ~FLAG_PENDING; | 1696 context->flags &= ~FLAG_PENDING; |
1622 uint16_t value = 0x3400; | 1697 //TODO: Open bus emulation |
1698 //Bits 15-10 are not fixed like Charles MacDonald's doc suggests, but instead open bus values that reflect 68K prefetch | |
1699 uint16_t value = 0; | |
1623 if (context->fifo_read < 0) { | 1700 if (context->fifo_read < 0) { |
1624 value |= 0x200; | 1701 value |= 0x200; |
1625 } | 1702 } |
1626 if (context->fifo_read == context->fifo_write) { | 1703 if (context->fifo_read == context->fifo_write) { |
1627 value |= 0x100; | 1704 value |= 0x100; |
1663 } | 1740 } |
1664 //printf("status read at cycle %d returned %X\n", context->cycles, value); | 1741 //printf("status read at cycle %d returned %X\n", context->cycles, value); |
1665 return value; | 1742 return value; |
1666 } | 1743 } |
1667 | 1744 |
1668 #define CRAM_BITS 0xEEE | |
1669 #define VSRAM_BITS 0x7FF | |
1670 #define VSRAM_DIRTY_BITS 0xF800 | |
1671 | |
1672 uint16_t vdp_data_port_read(vdp_context * context) | 1745 uint16_t vdp_data_port_read(vdp_context * context) |
1673 { | 1746 { |
1674 context->flags &= ~FLAG_PENDING; | 1747 if (context->flags & FLAG_PENDING) { |
1748 context->flags &= ~FLAG_PENDING; | |
1749 //Should these be cleared here? | |
1750 context->flags &= ~FLAG_READ_FETCHED; | |
1751 context->flags2 &= ~FLAG2_READ_PENDING; | |
1752 } | |
1675 if (context->cd & 1) { | 1753 if (context->cd & 1) { |
1676 return 0; | 1754 return 0; |
1677 } | 1755 } |
1678 //Not sure if the FIFO should be drained before processing a read or not, but it would make sense | 1756 while (!(context->flags & FLAG_READ_FETCHED)) { |
1679 context->flags &= ~FLAG_UNUSED_SLOT; | |
1680 //context->flags2 |= FLAG2_READ_PENDING; | |
1681 while (!(context->flags & FLAG_UNUSED_SLOT)) { | |
1682 vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); | 1757 vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); |
1683 } | 1758 } |
1684 uint16_t value = 0; | 1759 context->flags &= ~FLAG_READ_FETCHED; |
1685 switch (context->cd & 0xF) | 1760 //Should this happen after the prefetch or after the read? |
1686 { | |
1687 case VRAM_READ: | |
1688 value = context->vdpmem[context->address & 0xFFFE] << 8; | |
1689 context->flags &= ~FLAG_UNUSED_SLOT; | |
1690 context->flags2 |= FLAG2_READ_PENDING; | |
1691 while (!(context->flags & FLAG_UNUSED_SLOT)) { | |
1692 vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); | |
1693 } | |
1694 value |= context->vdpmem[context->address | 1]; | |
1695 break; | |
1696 case VRAM_READ8: | |
1697 value = context->vdpmem[context->address ^ 1]; | |
1698 value |= context->fifo[context->fifo_write].value & 0xFF00; | |
1699 break; | |
1700 case CRAM_READ: | |
1701 value = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS; | |
1702 value |= context->fifo[context->fifo_write].value & ~CRAM_BITS; | |
1703 break; | |
1704 case VSRAM_READ: { | |
1705 uint16_t address = (context->address /2) & 63; | |
1706 if (address >= VSRAM_SIZE) { | |
1707 address = 0; | |
1708 } | |
1709 value = context->vsram[address] & VSRAM_BITS; | |
1710 value |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS; | |
1711 break; | |
1712 } | |
1713 } | |
1714 context->address += context->regs[REG_AUTOINC]; | 1761 context->address += context->regs[REG_AUTOINC]; |
1715 return value; | 1762 return context->prefetch; |
1716 } | 1763 } |
1717 | 1764 |
1718 uint16_t vdp_hv_counter_read(vdp_context * context) | 1765 uint16_t vdp_hv_counter_read(vdp_context * context) |
1719 { | 1766 { |
1720 if (context->regs[REG_MODE_1] & BIT_HVC_LATCH) { | 1767 if (context->regs[REG_MODE_1] & BIT_HVC_LATCH) { |