# HG changeset patch # User Michael Pavone # Date 1461486278 25200 # Node ID 928442068afe9c6657b5519cd0269b4c5a94ffa2 # Parent 771875b5f519db776b9476e893d73aecaf4b7300 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 diff -r 771875b5f519 -r 928442068afe vdp.c --- a/vdp.c Sun Apr 24 00:22:38 2016 -0700 +++ b/vdp.c Sun Apr 24 01:24:38 2016 -0700 @@ -229,7 +229,7 @@ #define VSRAM_READ 4 //0100 #define VSRAM_WRITE 5//0101 //6 would trigger regsiter write 0110 -//7 is a mystery +//7 is a mystery //0111 #define CRAM_READ 8 //1000 //9 is also a mystery //1001 //A would trigger register write 1010 @@ -238,6 +238,21 @@ //D is a mystery 1101 //E would trigger register write 1110 //F is a mystery 1111 + +//Possible theory on how bits work +//CD0 = Read/Write flag +//CD2,(CD1|CD3) = RAM type +// 00 = VRAM +// 01 = CRAM +// 10 = VSRAM +// 11 = VRAM8 +//Would result in +// 7 = VRAM8 write +// 9 = CRAM write alias +// B = CRAM write alias +// D = VRAM8 write alias +// F = VRAM8 write alais + #define DMA_START 0x20 const char * cd_name(uint8_t cd) @@ -468,14 +483,13 @@ context->colors[addr + CRAM_SIZE*2] = color_map[(value & 0xEEE) | FBUF_HILIGHT]; } +#define CRAM_BITS 0xEEE +#define VSRAM_BITS 0x7FF +#define VSRAM_DIRTY_BITS 0xF800 + void external_slot(vdp_context * context) { fifo_entry * start = context->fifo + context->fifo_read; - /*if (context->flags2 & FLAG2_READ_PENDING) { - context->flags2 &= ~FLAG2_READ_PENDING; - context->flags |= FLAG_UNUSED_SLOT; - return; - }*/ if (context->fifo_read >= 0 && start->cycle <= context->cycles) { switch (start->cd & 0xF) { @@ -508,9 +522,72 @@ if (context->fifo_read == context->fifo_write) { context->fifo_read = -1; } - context->flags &= ~FLAG_UNUSED_SLOT; - } else { - context->flags |= FLAG_UNUSED_SLOT; + } else if ((context->flags & FLAG_DMA_RUN) && (context->regs[REG_DMASRC_H] & 0xC0) == 0xC0) { + if (context->flags & FLAG_READ_FETCHED) { + context->vdpmem[context->address ^ 1] = context->prefetch; + + //Update DMA state + context->regs[REG_DMASRC_L] += 1; + if (!context->regs[REG_DMASRC_L]) { + context->regs[REG_DMASRC_M] += 1; + } + context->address += context->regs[REG_AUTOINC]; + uint16_t dma_len = ((context->regs[REG_DMALEN_H] << 8) | context->regs[REG_DMALEN_L]) - 1; + context->regs[REG_DMALEN_H] = dma_len >> 8; + context->regs[REG_DMALEN_L] = dma_len; + if (!dma_len) { + context->flags &= ~FLAG_DMA_RUN; + context->cd &= 0xF; + } + + context->flags &= ~FLAG_READ_FETCHED; + } else { + context->prefetch = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1]; + + context->flags |= FLAG_READ_FETCHED; + } + } else if (!(context->cd & 1) && !(context->flags & FLAG_READ_FETCHED)){ + switch(context->cd & 0xF) + { + case VRAM_READ: + if (context->flags2 & FLAG2_READ_PENDING) { + context->prefetch |= context->vdpmem[context->address | 1]; + context->flags |= FLAG_READ_FETCHED; + context->flags2 &= ~FLAG2_READ_PENDING; + //Should this happen after the prefetch or after the read? + //context->address += context->regs[REG_AUTOINC]; + } else { + context->prefetch = context->vdpmem[context->address & 0xFFFE] << 8; + context->flags2 |= FLAG2_READ_PENDING; + } + break; + case VRAM_READ8: + context->prefetch = context->vdpmem[context->address ^ 1]; + context->prefetch |= context->fifo[context->fifo_write].value & 0xFF00; + context->flags |= FLAG_READ_FETCHED; + //Should this happen after the prefetch or after the read? + //context->address += context->regs[REG_AUTOINC]; + break; + case CRAM_READ: + context->prefetch = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS; + context->prefetch |= context->fifo[context->fifo_write].value & ~CRAM_BITS; + context->flags |= FLAG_READ_FETCHED; + //Should this happen after the prefetch or after the read? + //context->address += context->regs[REG_AUTOINC]; + break; + case VSRAM_READ: { + uint16_t address = (context->address /2) & 63; + if (address >= VSRAM_SIZE) { + address = 0; + } + context->prefetch = context->vsram[address] & VSRAM_BITS; + context->prefetch |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS; + context->flags |= FLAG_READ_FETCHED; + //Should this happen after the prefetch or after the read? + //context->address += context->regs[REG_AUTOINC]; + break; + } + } } } @@ -541,20 +618,7 @@ context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1); } break; - //Copy - case 0xC0: - if (context->flags & FLAG_UNUSED_SLOT && context->fifo_read < 0) { - //TODO: Fix this to not use the FIFO at all once read-caching is properly implemented - context->fifo_read = (context->fifo_write-1) & (FIFO_SIZE-1); - cur = context->fifo + context->fifo_read; - cur->cycle = context->cycles; - cur->address = context->address; - cur->partial = 1; - cur->value = context->vdpmem[(context->regs[REG_DMASRC_M] << 8) | context->regs[REG_DMASRC_L] ^ 1] | (cur->value & 0xFF00); - cur->cd = VRAM_WRITE; - context->flags &= ~FLAG_UNUSED_SLOT; - } - break; + //Fill case 0x80: if (context->fifo_read < 0) { context->fifo_read = (context->fifo_write-1) & (FIFO_SIZE-1); @@ -1527,6 +1591,9 @@ context->address = (context->address & 0x3FFF) | (value << 14); context->cd = (context->cd & 0x3) | ((value >> 2) & 0x3C); context->flags &= ~FLAG_PENDING; + //Should these be taken care of here or after the first write? + context->flags &= ~FLAG_READ_FETCHED; + context->flags2 &= ~FLAG2_READ_PENDING; //printf("New Address: %X, New CD: %X\n", context->address, context->cd); if (context->cd & 0x20 && (context->regs[REG_MODE_2] & BIT_DMA_ENABLE)) { // @@ -1573,6 +1640,9 @@ context->flags |= FLAG_PENDING; context->address = (context->address &0xC000) | (value & 0x3FFF); context->cd = (context->cd &0x3C) | (value >> 14); + //Should these be taken care of here or after the second write? + //context->flags &= ~FLAG_READ_FETCHED; + //context->flags2 &= ~FLAG2_READ_PENDING; } } return 0; @@ -1584,7 +1654,12 @@ if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { return -1; } - context->flags &= ~FLAG_PENDING; + if (context->flags & FLAG_PENDING) { + context->flags &= ~FLAG_PENDING; + //Should these be cleared here? + context->flags &= ~FLAG_READ_FETCHED; + context->flags2 &= ~FLAG2_READ_PENDING; + } /*if (context->fifo_cur == context->fifo_end) { printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles); }*/ @@ -1619,7 +1694,9 @@ uint16_t vdp_control_port_read(vdp_context * context) { context->flags &= ~FLAG_PENDING; - uint16_t value = 0x3400; + //TODO: Open bus emulation + //Bits 15-10 are not fixed like Charles MacDonald's doc suggests, but instead open bus values that reflect 68K prefetch + uint16_t value = 0; if (context->fifo_read < 0) { value |= 0x200; } @@ -1665,54 +1742,24 @@ return value; } -#define CRAM_BITS 0xEEE -#define VSRAM_BITS 0x7FF -#define VSRAM_DIRTY_BITS 0xF800 - uint16_t vdp_data_port_read(vdp_context * context) { - context->flags &= ~FLAG_PENDING; + if (context->flags & FLAG_PENDING) { + context->flags &= ~FLAG_PENDING; + //Should these be cleared here? + context->flags &= ~FLAG_READ_FETCHED; + context->flags2 &= ~FLAG2_READ_PENDING; + } if (context->cd & 1) { return 0; } - //Not sure if the FIFO should be drained before processing a read or not, but it would make sense - context->flags &= ~FLAG_UNUSED_SLOT; - //context->flags2 |= FLAG2_READ_PENDING; - while (!(context->flags & FLAG_UNUSED_SLOT)) { + while (!(context->flags & FLAG_READ_FETCHED)) { vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); } - uint16_t value = 0; - switch (context->cd & 0xF) - { - case VRAM_READ: - value = context->vdpmem[context->address & 0xFFFE] << 8; - context->flags &= ~FLAG_UNUSED_SLOT; - context->flags2 |= FLAG2_READ_PENDING; - while (!(context->flags & FLAG_UNUSED_SLOT)) { - vdp_run_context(context, context->cycles + ((context->regs[REG_MODE_4] & BIT_H40) ? 16 : 20)); - } - value |= context->vdpmem[context->address | 1]; - break; - case VRAM_READ8: - value = context->vdpmem[context->address ^ 1]; - value |= context->fifo[context->fifo_write].value & 0xFF00; - break; - case CRAM_READ: - value = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS; - value |= context->fifo[context->fifo_write].value & ~CRAM_BITS; - break; - case VSRAM_READ: { - uint16_t address = (context->address /2) & 63; - if (address >= VSRAM_SIZE) { - address = 0; - } - value = context->vsram[address] & VSRAM_BITS; - value |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS; - break; - } - } + context->flags &= ~FLAG_READ_FETCHED; + //Should this happen after the prefetch or after the read? context->address += context->regs[REG_AUTOINC]; - return value; + return context->prefetch; } uint16_t vdp_hv_counter_read(vdp_context * context) diff -r 771875b5f519 -r 928442068afe vdp.h --- a/vdp.h Sun Apr 24 00:22:38 2016 -0700 +++ b/vdp.h Sun Apr 24 01:24:38 2016 -0700 @@ -41,7 +41,7 @@ #define FLAG_MASKED 0x04 #define FLAG_WINDOW 0x08 #define FLAG_PENDING 0x10 -#define FLAG_UNUSED_SLOT 0x20 +#define FLAG_READ_FETCHED 0x20 #define FLAG_DMA_RUN 0x40 #define FLAG_DMA_PROG 0x80 @@ -161,6 +161,7 @@ uint16_t col_1; uint16_t col_2; uint16_t hv_latch; + uint16_t prefetch; uint8_t v_offset; uint8_t dma_cd; uint8_t hint_counter;