summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pavone <pavone@retrodev.com>2016-04-24 01:24:38 -0700
committerMichael Pavone <pavone@retrodev.com>2016-04-24 01:24:38 -0700
commit6c2b3708efcbd900c29422510cfdc62787d3c32d (patch)
tree06bcce9141cb4df0f74803597bd77e49fd33d3f9
parentfd345a8336933105ea98c9d2d1cc5602ad611d70 (diff)
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
-rw-r--r--vdp.c177
-rw-r--r--vdp.h3
2 files changed, 114 insertions, 66 deletions
diff --git a/vdp.c b/vdp.c
index f92721a..8b1ed22 100644
--- a/vdp.c
+++ b/vdp.c
@@ -229,7 +229,7 @@ void vdp_print_sprite_table(vdp_context * context)
#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 @@ void vdp_print_sprite_table(vdp_context * context)
//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 @@ void write_cram(vdp_context * context, uint16_t address, uint16_t value)
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 @@ void external_slot(vdp_context * context)
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 @@ void run_dma_src(vdp_context * context, int32_t slot)
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 @@ int vdp_control_port_write(vdp_context * context, uint16_t value)
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 @@ int vdp_control_port_write(vdp_context * context, uint16_t value)
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 @@ int vdp_data_port_write(vdp_context * context, uint16_t value)
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 @@ void vdp_test_port_write(vdp_context * context, uint16_t value)
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 @@ uint16_t vdp_control_port_read(vdp_context * context)
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 --git a/vdp.h b/vdp.h
index ea01b3d..a69cc90 100644
--- a/vdp.h
+++ b/vdp.h
@@ -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 @@ typedef struct {
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;