comparison vdp.c @ 471:f065769836e8

Implement FIFO as a ring buffer so the behavior of reads from invalid CRAM and VSRAM bits can be implemented properly
author Mike Pavone <pavone@retrodev.com>
date Sun, 15 Sep 2013 22:20:43 -0700
parents 541c1ae8abf3
children 93dc0382fd70
comparison
equal deleted inserted replaced
470:541c1ae8abf3 471:f065769836e8
17 #define MAP_BIT_V_FLIP 0x1000 17 #define MAP_BIT_V_FLIP 0x1000
18 18
19 #define SCROLL_BUFFER_SIZE 32 19 #define SCROLL_BUFFER_SIZE 32
20 #define SCROLL_BUFFER_MASK (SCROLL_BUFFER_SIZE-1) 20 #define SCROLL_BUFFER_MASK (SCROLL_BUFFER_SIZE-1)
21 #define SCROLL_BUFFER_DRAW (SCROLL_BUFFER_SIZE/2) 21 #define SCROLL_BUFFER_DRAW (SCROLL_BUFFER_SIZE/2)
22
23 #define FIFO_SIZE 4
24 22
25 #define MCLKS_SLOT_H40 16 23 #define MCLKS_SLOT_H40 16
26 #define MCLKS_SLOT_H32 20 24 #define MCLKS_SLOT_H32 20
27 #define VINT_CYCLE_H40 (21*MCLKS_SLOT_H40+332+9*MCLKS_SLOT_H40) //21 slots before HSYNC, 16 during, 10 after 25 #define VINT_CYCLE_H40 (21*MCLKS_SLOT_H40+332+9*MCLKS_SLOT_H40) //21 slots before HSYNC, 16 during, 10 after
28 #define VINT_CYCLE_H32 ((33+20+7)*MCLKS_SLOT_H32) //33 slots before HSYNC, 20 during, 7 after TODO: confirm final number 26 #define VINT_CYCLE_H32 ((33+20+7)*MCLKS_SLOT_H32) //33 slots before HSYNC, 20 during, 7 after TODO: confirm final number
59 context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); 57 context->linebuf = malloc(LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2);
60 memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2); 58 memset(context->linebuf, 0, LINEBUF_SIZE + SCROLL_BUFFER_SIZE*2);
61 context->tmp_buf_a = context->linebuf + LINEBUF_SIZE; 59 context->tmp_buf_a = context->linebuf + LINEBUF_SIZE;
62 context->tmp_buf_b = context->tmp_buf_a + SCROLL_BUFFER_SIZE; 60 context->tmp_buf_b = context->tmp_buf_a + SCROLL_BUFFER_SIZE;
63 context->sprite_draws = MAX_DRAWS; 61 context->sprite_draws = MAX_DRAWS;
64 context->fifo_cur = malloc(sizeof(fifo_entry) * FIFO_SIZE); 62 context->fifo_write = 0;
65 context->fifo_end = context->fifo_cur + FIFO_SIZE; 63 context->fifo_read = -1;
66 context->b32 = render_depth() == 32; 64 context->b32 = render_depth() == 32;
67 if (!color_map_init_done) { 65 if (!color_map_init_done) {
68 uint8_t b,g,r; 66 uint8_t b,g,r;
69 for (uint16_t color = 0; color < (1 << 12); color++) { 67 for (uint16_t color = 0; color < (1 << 12); color++) {
70 if (color & FBUF_SHADOW) { 68 if (color & FBUF_SHADOW) {
388 #define VSRAM_WRITE 5 386 #define VSRAM_WRITE 5
389 #define DMA_START 0x20 387 #define DMA_START 0x20
390 388
391 void external_slot(vdp_context * context) 389 void external_slot(vdp_context * context)
392 { 390 {
393 fifo_entry * start = (context->fifo_end - FIFO_SIZE); 391 fifo_entry * start = context->fifo + context->fifo_read;
394 if (context->flags2 & FLAG2_READ_PENDING) { 392 if (context->flags2 & FLAG2_READ_PENDING) {
395 context->flags2 &= ~FLAG2_READ_PENDING; 393 context->flags2 &= ~FLAG2_READ_PENDING;
396 context->flags |= FLAG_UNUSED_SLOT; 394 context->flags |= FLAG_UNUSED_SLOT;
397 return; 395 return;
398 } 396 }
399 if (context->fifo_cur != start && start->cycle <= context->cycles) { 397 if (context->fifo_read >= 0 && start->cycle <= context->cycles) {
400 switch (start->cd & 0xF) 398 switch (start->cd & 0xF)
401 { 399 {
402 case VRAM_WRITE: 400 case VRAM_WRITE:
403 if (start->partial) { 401 if (start->partial) {
404 printf("VRAM Write: %X to %X at %d (line %d, slot %d)\n", start->value, start->address ^ 1, context->cycles, context->cycles/MCLKS_LINE, (context->cycles%MCLKS_LINE)/16); 402 //printf("VRAM Write: %X to %X at %d (line %d, slot %d)\n", start->value, start->address ^ 1, context->cycles, context->cycles/MCLKS_LINE, (context->cycles%MCLKS_LINE)/16);
405 context->last_fifo_val = start->value; 403 context->last_fifo_val = start->value;
406 context->vdpmem[start->address ^ 1] = start->value; 404 context->vdpmem[start->address ^ 1] = start->value;
407 } else { 405 } else {
408 printf("VRAM Write High: %X to %X at %d (line %d, slot %d)\n", start->value >> 8, start->address, context->cycles, context->cycles/MCLKS_LINE, (context->cycles%MCLKS_LINE)/16); 406 //printf("VRAM Write High: %X to %X at %d (line %d, slot %d)\n", start->value >> 8, start->address, context->cycles, context->cycles/MCLKS_LINE, (context->cycles%MCLKS_LINE)/16);
409 context->vdpmem[start->address] = start->value >> 8; 407 context->vdpmem[start->address] = start->value >> 8;
410 start->partial = 1; 408 start->partial = 1;
411 //skip auto-increment and removal of entry from fifo 409 //skip auto-increment and removal of entry from fifo
412 return; 410 return;
413 } 411 }
425 context->last_fifo_val = start->value; 423 context->last_fifo_val = start->value;
426 } 424 }
427 425
428 break; 426 break;
429 } 427 }
430 fifo_entry * cur = start+1; 428 context->fifo_read = (context->fifo_read+1) & (FIFO_SIZE-1);
431 if (cur < context->fifo_cur) { 429 if (context->fifo_read == context->fifo_write) {
432 memmove(start, cur, sizeof(fifo_entry) * (context->fifo_cur - cur)); 430 context->fifo_read = -1;
433 } 431 }
434 context->fifo_cur -= 1;
435 } else { 432 } else {
436 context->flags |= FLAG_UNUSED_SLOT; 433 context->flags |= FLAG_UNUSED_SLOT;
437 } 434 }
438 } 435 }
439 436
440 void run_dma_src(vdp_context * context, uint32_t slot) 437 void run_dma_src(vdp_context * context, uint32_t slot)
441 { 438 {
442 //TODO: Figure out what happens if CD bit 4 is not set in DMA copy mode 439 //TODO: Figure out what happens if CD bit 4 is not set in DMA copy mode
443 //TODO: Figure out what happens when CD:0-3 is not set to a write mode in DMA operations 440 //TODO: Figure out what happens when CD:0-3 is not set to a write mode in DMA operations
444 //TODO: Figure out what happens if DMA gets disabled part way through a DMA fill or DMA copy 441 //TODO: Figure out what happens if DMA gets disabled part way through a DMA fill or DMA copy
445 if (context->fifo_cur == context->fifo_end) { 442 if (context->fifo_write == context->fifo_read) {
446 return; 443 return;
447 } 444 }
448 uint16_t read_val; 445 uint16_t read_val;
449 uint8_t ran_source = 0, partial = 0; 446 uint8_t ran_source = 0, partial = 0;
450 uint16_t dma_len; 447 uint16_t dma_len;
487 ran_source = 1; 484 ran_source = 1;
488 break; 485 break;
489 } 486 }
490 487
491 if (ran_source) { 488 if (ran_source) {
492 context->fifo_cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; 489 fifo_entry * cur = context->fifo + context->fifo_write;
493 context->fifo_cur->address = context->address; 490 cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY;
494 context->fifo_cur->value = read_val; 491 cur->address = context->address;
495 context->fifo_cur->cd = context->cd; 492 cur->value = read_val;
496 context->fifo_cur->partial = partial; 493 cur->cd = context->cd;
497 context->fifo_cur++; 494 cur->partial = partial;
495 if (context->fifo_read < 0) {
496 context->fifo_read = context->fifo_write;
497 }
498 context->fifo_write = (context->fifo_write+1) & (FIFO_SIZE-1);
498 context->regs[REG_DMASRC_L] += 1; 499 context->regs[REG_DMASRC_L] += 1;
499 if (!context->regs[REG_DMASRC_L]) { 500 if (!context->regs[REG_DMASRC_L]) {
500 context->regs[REG_DMASRC_M] += 1; 501 context->regs[REG_DMASRC_M] += 1;
501 } 502 }
502 context->address += context->regs[REG_AUTOINC]; 503 context->address += context->regs[REG_AUTOINC];
1434 } 1435 }
1435 } 1436 }
1436 1437
1437 int vdp_control_port_write(vdp_context * context, uint16_t value) 1438 int vdp_control_port_write(vdp_context * context, uint16_t value)
1438 { 1439 {
1439 printf("control port write: %X at %d\n", value, context->cycles); 1440 //printf("control port write: %X at %d\n", value, context->cycles);
1440 if (context->flags & FLAG_DMA_RUN) { 1441 if (context->flags & FLAG_DMA_RUN) {
1441 return -1; 1442 return -1;
1442 } 1443 }
1443 if (context->flags & FLAG_PENDING) { 1444 if (context->flags & FLAG_PENDING) {
1444 context->address = (context->address & 0x3FFF) | (value << 14); 1445 context->address = (context->address & 0x3FFF) | (value << 14);
1488 return 0; 1489 return 0;
1489 } 1490 }
1490 1491
1491 int vdp_data_port_write(vdp_context * context, uint16_t value) 1492 int vdp_data_port_write(vdp_context * context, uint16_t value)
1492 { 1493 {
1493 printf("data port write: %X at %d\n", value, context->cycles); 1494 //printf("data port write: %X at %d\n", value, context->cycles);
1494 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { 1495 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & 0xC0) != 0x80) {
1495 return -1; 1496 return -1;
1496 }
1497 if (!(context->cd & 1)) {
1498 //ignore writes when cd is configured for read
1499 return 0;
1500 } 1497 }
1501 context->flags &= ~FLAG_PENDING; 1498 context->flags &= ~FLAG_PENDING;
1502 /*if (context->fifo_cur == context->fifo_end) { 1499 /*if (context->fifo_cur == context->fifo_end) {
1503 printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles); 1500 printf("FIFO full, waiting for space before next write at cycle %X\n", context->cycles);
1504 }*/ 1501 }*/
1505 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { 1502 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) {
1506 context->flags &= ~FLAG_DMA_RUN; 1503 context->flags &= ~FLAG_DMA_RUN;
1507 } 1504 }
1508 while (context->fifo_cur == context->fifo_end) { 1505 while (context->fifo_write == context->fifo_read) {
1509 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); 1506 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20));
1510 } 1507 }
1511 context->fifo_cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY; 1508 fifo_entry * cur = context->fifo + context->fifo_write;
1512 context->fifo_cur->address = context->address; 1509 cur->cycle = context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)*FIFO_LATENCY;
1513 context->fifo_cur->value = value; 1510 cur->address = context->address;
1511 cur->value = value;
1514 context->last_write_val = value; 1512 context->last_write_val = value;
1515 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) { 1513 if (context->cd & 0x20 && (context->regs[REG_DMASRC_H] & 0xC0) == 0x80) {
1516 context->flags |= FLAG_DMA_RUN; 1514 context->flags |= FLAG_DMA_RUN;
1517 } 1515 }
1518 context->fifo_cur->cd = context->cd; 1516 cur->cd = context->cd;
1519 context->fifo_cur->partial = 0; 1517 cur->partial = 0;
1520 context->fifo_cur++; 1518 if (context->fifo_read < 0) {
1519 context->fifo_read = context->fifo_write;
1520 }
1521 context->fifo_write = (context->fifo_write + 1) & (FIFO_SIZE-1);
1521 context->address += context->regs[REG_AUTOINC]; 1522 context->address += context->regs[REG_AUTOINC];
1522 return 0; 1523 return 0;
1523 } 1524 }
1524 1525
1525 void vdp_test_port_write(vdp_context * context, uint16_t value) 1526 void vdp_test_port_write(vdp_context * context, uint16_t value)
1529 1530
1530 uint16_t vdp_control_port_read(vdp_context * context) 1531 uint16_t vdp_control_port_read(vdp_context * context)
1531 { 1532 {
1532 context->flags &= ~FLAG_PENDING; 1533 context->flags &= ~FLAG_PENDING;
1533 uint16_t value = 0x3400; 1534 uint16_t value = 0x3400;
1534 if (context->fifo_cur == (context->fifo_end - FIFO_SIZE)) { 1535 if (context->fifo_read < 0) {
1535 value |= 0x200; 1536 value |= 0x200;
1536 } 1537 }
1537 if (context->fifo_cur == context->fifo_end) { 1538 if (context->fifo_read == context->fifo_write) {
1538 value |= 0x100; 1539 value |= 0x100;
1539 } 1540 }
1540 if (context->flags2 & FLAG2_VINT_PENDING) { 1541 if (context->flags2 & FLAG2_VINT_PENDING) {
1541 value |= 0x80; 1542 value |= 0x80;
1542 } 1543 }
1562 return value; 1563 return value;
1563 } 1564 }
1564 1565
1565 #define CRAM_BITS 0xEEE 1566 #define CRAM_BITS 0xEEE
1566 #define VSRAM_BITS 0x3FF 1567 #define VSRAM_BITS 0x3FF
1568 #define VSRAM_DIRTY_BITS 0xF800
1567 1569
1568 uint16_t vdp_data_port_read(vdp_context * context) 1570 uint16_t vdp_data_port_read(vdp_context * context)
1569 { 1571 {
1570 context->flags &= ~FLAG_PENDING; 1572 context->flags &= ~FLAG_PENDING;
1571 if (context->cd & 1) { 1573 if (context->cd & 1) {
1589 } 1591 }
1590 value |= context->vdpmem[context->address ^ 1]; 1592 value |= context->vdpmem[context->address ^ 1];
1591 break; 1593 break;
1592 case CRAM_READ: 1594 case CRAM_READ:
1593 value = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS; 1595 value = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS;
1594 value |= context->last_fifo_val & ~CRAM_BITS; 1596 value |= context->fifo[context->fifo_write].value & ~CRAM_BITS;
1595 break; 1597 break;
1596 case VSRAM_READ: 1598 case VSRAM_READ:
1597 if (((context->address / 2) & 63) < VSRAM_SIZE) { 1599 if (((context->address / 2) & 63) < VSRAM_SIZE) {
1598 value = context->vsram[context->address & 63] & VSRAM_BITS; 1600 value = context->vsram[context->address & 63] & VSRAM_BITS;
1599 value |= context->last_fifo_val & ~VSRAM_BITS; 1601 value |= context->fifo[context->fifo_write].value & VSRAM_DIRTY_BITS;
1600 } 1602 }
1601 break; 1603 break;
1602 } 1604 }
1603 context->address += context->regs[REG_AUTOINC]; 1605 context->address += context->regs[REG_AUTOINC];
1604 return value; 1606 return value;
1720 } 1722 }
1721 1723
1722 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) 1724 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction)
1723 { 1725 {
1724 context->cycles -= deduction; 1726 context->cycles -= deduction;
1725 for(fifo_entry * start = (context->fifo_end - FIFO_SIZE); start < context->fifo_cur; start++) { 1727 if (context->fifo_read >= 0) {
1726 if (start->cycle >= deduction) { 1728 int32_t idx = context->fifo_read;
1727 start->cycle -= deduction; 1729 do {
1728 } else { 1730 if (context->fifo[idx].cycle >= deduction) {
1729 start->cycle = 0; 1731 context->fifo[idx].cycle -= deduction;
1730 } 1732 } else {
1733 context->fifo[idx].cycle = 0;
1734 }
1735 idx = (idx+1) & (FIFO_SIZE-1);
1736 } while(idx != context->fifo_write);
1731 } 1737 }
1732 } 1738 }
1733 1739
1734 uint32_t vdp_next_hint(vdp_context * context) 1740 uint32_t vdp_next_hint(vdp_context * context)
1735 { 1741 {