comparison vdp.c @ 470:541c1ae8abf3

Properly delay 68K on VDP reads. Dummy VDP test port implementation. Initial stab at handling undefined bits of VSRAM and CRAM.
author Mike Pavone <pavone@retrodev.com>
date Fri, 13 Sep 2013 19:22:46 -0700
parents 140af5509ce7
children f065769836e8
comparison
equal deleted inserted replaced
469:5f3344d0d42f 470:541c1ae8abf3
1 /* 1 /*
2 Copyright 2013 Michael Pavone 2 Copyright 2013 Michael Pavone
3 This file is part of BlastEm. 3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. 4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5 */ 5 */
6 #include "vdp.h" 6 #include "vdp.h"
7 #include "blastem.h" 7 #include "blastem.h"
8 #include <stdlib.h> 8 #include <stdlib.h>
389 #define DMA_START 0x20 389 #define DMA_START 0x20
390 390
391 void external_slot(vdp_context * context) 391 void external_slot(vdp_context * context)
392 { 392 {
393 fifo_entry * start = (context->fifo_end - FIFO_SIZE); 393 fifo_entry * start = (context->fifo_end - FIFO_SIZE);
394 if (context->flags2 & FLAG2_READ_PENDING) {
395 context->flags2 &= ~FLAG2_READ_PENDING;
396 context->flags |= FLAG_UNUSED_SLOT;
397 return;
398 }
394 if (context->fifo_cur != start && start->cycle <= context->cycles) { 399 if (context->fifo_cur != start && start->cycle <= context->cycles) {
395 switch (start->cd & 0xF) 400 switch (start->cd & 0xF)
396 { 401 {
397 case VRAM_WRITE: 402 case VRAM_WRITE:
398 if (start->partial) { 403 if (start->partial) {
399 //printf("VRAM Write: %X to %X\n", start->value, context->address ^ 1); 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);
405 context->last_fifo_val = start->value;
400 context->vdpmem[start->address ^ 1] = start->value; 406 context->vdpmem[start->address ^ 1] = start->value;
401 } else { 407 } else {
402 //printf("VRAM Write High: %X to %X\n", start->value >> 8, context->address); 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);
403 context->vdpmem[start->address] = start->value >> 8; 409 context->vdpmem[start->address] = start->value >> 8;
404 start->partial = 1; 410 start->partial = 1;
405 //skip auto-increment and removal of entry from fifo 411 //skip auto-increment and removal of entry from fifo
406 return; 412 return;
407 } 413 }
408 break; 414 break;
409 case CRAM_WRITE: { 415 case CRAM_WRITE: {
410 //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1)); 416 //printf("CRAM Write | %X to %X\n", start->value, (start->address/2) & (CRAM_SIZE-1));
411 write_cram(context, start->address, start->value); 417 write_cram(context, start->address, start->value);
418 context->last_fifo_val = start->value;
412 break; 419 break;
413 } 420 }
414 case VSRAM_WRITE: 421 case VSRAM_WRITE:
415 if (((start->address/2) & 63) < VSRAM_SIZE) { 422 if (((start->address/2) & 63) < VSRAM_SIZE) {
416 //printf("VSRAM Write: %X to %X\n", start->value, context->address); 423 //printf("VSRAM Write: %X to %X\n", start->value, context->address);
417 context->vsram[(start->address/2) & 63] = start->value; 424 context->vsram[(start->address/2) & 63] = start->value;
425 context->last_fifo_val = start->value;
418 } 426 }
419 427
420 break; 428 break;
421 } 429 }
422 fifo_entry * cur = start+1; 430 fifo_entry * cur = start+1;
1426 } 1434 }
1427 } 1435 }
1428 1436
1429 int vdp_control_port_write(vdp_context * context, uint16_t value) 1437 int vdp_control_port_write(vdp_context * context, uint16_t value)
1430 { 1438 {
1431 //printf("control port write: %X at %d\n", value, context->cycles); 1439 printf("control port write: %X at %d\n", value, context->cycles);
1432 if (context->flags & FLAG_DMA_RUN) { 1440 if (context->flags & FLAG_DMA_RUN) {
1433 return -1; 1441 return -1;
1434 } 1442 }
1435 if (context->flags & FLAG_PENDING) { 1443 if (context->flags & FLAG_PENDING) {
1436 context->address = (context->address & 0x3FFF) | (value << 14); 1444 context->address = (context->address & 0x3FFF) | (value << 14);
1480 return 0; 1488 return 0;
1481 } 1489 }
1482 1490
1483 int vdp_data_port_write(vdp_context * context, uint16_t value) 1491 int vdp_data_port_write(vdp_context * context, uint16_t value)
1484 { 1492 {
1485 //printf("data port write: %X at %d\n", value, context->cycles); 1493 printf("data port write: %X at %d\n", value, context->cycles);
1486 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & 0xC0) != 0x80) { 1494 if (context->flags & FLAG_DMA_RUN && (context->regs[REG_DMASRC_H] & 0xC0) != 0x80) {
1487 return -1; 1495 return -1;
1488 } 1496 }
1489 if (!(context->cd & 1)) { 1497 if (!(context->cd & 1)) {
1490 //ignore writes when cd is configured for read 1498 //ignore writes when cd is configured for read
1512 context->fifo_cur++; 1520 context->fifo_cur++;
1513 context->address += context->regs[REG_AUTOINC]; 1521 context->address += context->regs[REG_AUTOINC];
1514 return 0; 1522 return 0;
1515 } 1523 }
1516 1524
1525 void vdp_test_port_write(vdp_context * context, uint16_t value)
1526 {
1527 //TODO: implement test register
1528 }
1529
1517 uint16_t vdp_control_port_read(vdp_context * context) 1530 uint16_t vdp_control_port_read(vdp_context * context)
1518 { 1531 {
1519 context->flags &= ~FLAG_PENDING; 1532 context->flags &= ~FLAG_PENDING;
1520 uint16_t value = 0x3400; 1533 uint16_t value = 0x3400;
1521 if (context->fifo_cur == (context->fifo_end - FIFO_SIZE)) { 1534 if (context->fifo_cur == (context->fifo_end - FIFO_SIZE)) {
1547 //printf("status read at cycle %d returned %X\n", context->cycles, value); 1560 //printf("status read at cycle %d returned %X\n", context->cycles, value);
1548 //TODO: Sprite overflow, sprite collision, odd frame flag 1561 //TODO: Sprite overflow, sprite collision, odd frame flag
1549 return value; 1562 return value;
1550 } 1563 }
1551 1564
1565 #define CRAM_BITS 0xEEE
1566 #define VSRAM_BITS 0x3FF
1567
1552 uint16_t vdp_data_port_read(vdp_context * context) 1568 uint16_t vdp_data_port_read(vdp_context * context)
1553 { 1569 {
1554 context->flags &= ~FLAG_PENDING; 1570 context->flags &= ~FLAG_PENDING;
1555 if (context->cd & 1) { 1571 if (context->cd & 1) {
1556 return 0; 1572 return 0;
1557 } 1573 }
1558 //Not sure if the FIFO should be drained before processing a read or not, but it would make sense 1574 //Not sure if the FIFO should be drained before processing a read or not, but it would make sense
1559 context->flags &= ~FLAG_UNUSED_SLOT; 1575 context->flags &= ~FLAG_UNUSED_SLOT;
1576 context->flags2 |= FLAG2_READ_PENDING;
1560 while (!(context->flags & FLAG_UNUSED_SLOT)) { 1577 while (!(context->flags & FLAG_UNUSED_SLOT)) {
1561 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); 1578 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20));
1562 } 1579 }
1563 uint16_t value = 0; 1580 uint16_t value = 0;
1564 switch (context->cd & 0xF) 1581 switch (context->cd & 0xF)
1565 { 1582 {
1566 case VRAM_READ: 1583 case VRAM_READ:
1567 value = context->vdpmem[context->address] << 8; 1584 value = context->vdpmem[context->address] << 8;
1568 context->flags &= ~FLAG_UNUSED_SLOT; 1585 context->flags &= ~FLAG_UNUSED_SLOT;
1586 context->flags2 |= FLAG2_READ_PENDING;
1569 while (!(context->flags & FLAG_UNUSED_SLOT)) { 1587 while (!(context->flags & FLAG_UNUSED_SLOT)) {
1570 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20)); 1588 vdp_run_context(context, context->cycles + ((context->latched_mode & BIT_H40) ? 16 : 20));
1571 } 1589 }
1572 value |= context->vdpmem[context->address ^ 1]; 1590 value |= context->vdpmem[context->address ^ 1];
1573 break; 1591 break;
1574 case CRAM_READ: 1592 case CRAM_READ:
1575 value = context->cram[(context->address/2) & (CRAM_SIZE-1)]; 1593 value = context->cram[(context->address/2) & (CRAM_SIZE-1)] & CRAM_BITS;
1594 value |= context->last_fifo_val & ~CRAM_BITS;
1576 break; 1595 break;
1577 case VSRAM_READ: 1596 case VSRAM_READ:
1578 if (((context->address / 2) & 63) < VSRAM_SIZE) { 1597 if (((context->address / 2) & 63) < VSRAM_SIZE) {
1579 value = context->vsram[context->address & 63]; 1598 value = context->vsram[context->address & 63] & VSRAM_BITS;
1599 value |= context->last_fifo_val & ~VSRAM_BITS;
1580 } 1600 }
1581 break; 1601 break;
1582 } 1602 }
1583 context->address += context->regs[REG_AUTOINC]; 1603 context->address += context->regs[REG_AUTOINC];
1584 return value; 1604 return value;
1691 } 1711 }
1692 } 1712 }
1693 return (line << 8) | linecyc; 1713 return (line << 8) | linecyc;
1694 } 1714 }
1695 1715
1716 uint16_t vdp_test_port_read(vdp_context * context)
1717 {
1718 //TODO: Find out what actually gets returned here
1719 return 0xFFFF;
1720 }
1721
1696 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction) 1722 void vdp_adjust_cycles(vdp_context * context, uint32_t deduction)
1697 { 1723 {
1698 context->cycles -= deduction; 1724 context->cycles -= deduction;
1699 for(fifo_entry * start = (context->fifo_end - FIFO_SIZE); start < context->fifo_cur; start++) { 1725 for(fifo_entry * start = (context->fifo_end - FIFO_SIZE); start < context->fifo_cur; start++) {
1700 if (start->cycle >= deduction) { 1726 if (start->cycle >= deduction) {