bsnes/higan/md/vdp/io.cpp

342 lines
6.8 KiB
C++

//todo: does data mirroring occur for all VDP addresses; or just data/control ports?
auto VDP::readByte(uint24 addr) -> uint8 {
auto data = readWord(addr & ~1);
return data << 8 | data << 0;
}
auto VDP::writeByte(uint24 addr, uint8 data) -> void {
return writeWord(addr & ~1, data << 8 | data << 0);
}
//
auto VDP::readWord(uint24 addr) -> uint16 {
switch(addr & 0xc0001f) {
//data port
case 0xc00000: case 0xc00002: {
return readDataPort();
}
//control port
case 0xc00004: case 0xc00006: {
return readControlPort();
}
}
return 0x0000;
}
auto VDP::writeWord(uint24 addr, uint16 data) -> void {
//print("[VDP] ", hex(addr, 6L), "=", hex(data, 4L), "\n");
switch(addr & 0xc0001f) {
//data port
case 0xc00000: case 0xc00002: {
return writeDataPort(data);
}
//control port
case 0xc00004: case 0xc00006: {
return writeControlPort(data);
}
}
}
//
auto VDP::readDataPort() -> uint16 {
io.commandPending = false;
//VRAM read
if(io.command.bits(0,3) == 0) {
return 0x0000;
}
//VSRAM read
if(io.command.bits(0,3) == 4) {
return 0x0000;
}
//CRAM read
if(io.command.bits(0,3) == 8) {
return 0x0000;
}
}
auto VDP::writeDataPort(uint16 data) -> void {
io.commandPending = false;
//DMA VRAM fill
if(io.command.bits(4,5) == 2) {
io.dmaActive = true;
io.dmaFillWord = data;
return;
}
//VRAM write
if(io.command.bits(0,3) == 1) {
auto address = io.address.bits(1,15);
if(io.address.bit(0)) data = data >> 8 | data << 8;
vram[address] = data;
io.address += io.dataIncrement;
return;
}
//VSRAM write
if(io.command.bits(0,3) == 5) {
auto address = io.address.bits(1,6);
if(address >= 40) return;
//data format: ---- --yy yyyy yyyy
vsram[address] = data.bits(0,9);
io.address += io.dataIncrement;
return;
}
//CRAM write
if(io.command.bits(0,3) == 3) {
auto address = io.address.bits(1,6);
//data format: ---- bbb- ggg- rrr-
cram[address] = data.bits(1,3) << 0 | data.bits(5,7) << 3 | data.bits(9,11) << 6;
io.address += io.dataIncrement;
return;
}
}
//
auto VDP::readControlPort() -> uint16 {
io.commandPending = false;
uint16 result = 0b0011'0100'0000'0000;
result |= io.dmaActive << 1;
return result;
}
auto VDP::writeControlPort(uint16 data) -> void {
//print("[VDPC] ", hex(data, 4L), "\n");
//command write (lo)
if(io.commandPending) {
io.commandPending = false;
io.command.bits(2,5) = data.bits(4,7);
io.address.bits(14,15) = data.bits(0,1);
return;
}
//command write (hi)
if(data.bits(14,15) != 2) {
io.commandPending = true;
io.command.bits(0,1) = data.bits(14,15);
io.address.bits(0,13) = data.bits(0,13);
return;
}
//register write (d13 is ignored)
if(data.bits(14,15) == 2)
switch(data.bits(8,12)) {
//mode register 1
case 0x00: {
io.displayOverlayEnable = data.bit(0);
io.counterLatch = data.bit(1);
io.horizontalInterruptEnable = data.bit(4);
io.leftColumnBlank = data.bit(5);
return;
}
//mode register 2
case 0x01: {
io.videoMode = data.bit(2);
io.overscan = data.bit(3);
io.dmaEnable = data.bit(4);
io.verticalBlankInterruptEnable = data.bit(5);
io.displayEnable = data.bit(6);
io.externalVRAM = data.bit(7);
if(!io.dmaEnable) io.command.bit(5) = 0;
return;
}
//plane A name table location
case 0x02: {
planeA.io.nametableAddress = data.bits(3,6) << 12;
return;
}
//window name table location
case 0x03: {
window.io.nametableAddress = data.bits(1,6) << 10;
return;
}
//plane B name table location
case 0x04: {
planeB.io.nametableAddress = data.bits(0,3) << 12;
return;
}
//sprite attribute table location
case 0x05: {
io.attrtableSprite = data.bits(0,7);
return;
}
//sprite pattern base address
case 0x06: {
io.nametableBaseSprite = data.bit(5);
return;
}
//background color
case 0x07: {
io.backgroundColor = data.bits(0,5);
return;
}
//horizontal interrupt counter
case 0x0a: {
io.horizontalInterruptCounter = data.bits(0,7);
return;
}
//mode register 3
case 0x0b: {
io.horizontalScrollMode = data.bits(0,1);
io.verticalScrollMode = data.bit(2);
io.externalInterruptEnable = data.bit(3);
return;
}
//mode register 4
case 0x0c: {
io.tileWidth = data.bit(0) | data.bit(7) << 1;
io.interlaceMode = data.bits(1,2);
io.shadowHighlightEnable = data.bit(3);
io.externalColorEnable = data.bit(4);
io.horizontalSync = data.bit(5);
io.verticalSync = data.bit(6);
return;
}
//horizontal scroll data location
case 0x0d: {
io.horizontalScrollTable = data.bits(1,6);
return;
}
//nametable pattern base address
case 0x0e: {
io.nametableBasePatternA = data.bit(0);
io.nametableBasePatternB = data.bit(1);
return;
}
//data port auto-increment value
case 0x0f: {
io.dataIncrement = data.bits(0,7);
return;
}
//plane size
case 0x10: {
//0 = 32 tiles
//1 = 64 tiles
//2 = invalid (repeats first row for every scanline)
//3 = 128 tiles
static const uint shift[] = {5, 6, 0, 7};
planeA.io.nametableWidth = shift[data.bits(0,1)];
window.io.nametableWidth = shift[data.bits(0,1)];
planeB.io.nametableWidth = shift[data.bits(0,1)];
planeA.io.nametableHeight = shift[data.bits(4,5)];
window.io.nametableHeight = shift[data.bits(4,5)];
planeB.io.nametableHeight = shift[data.bits(4,5)];
return;
}
//window plane horizontal position
case 0x11: {
if(!data) {
//disable
io.windowHorizontalLo = ~0;
io.windowHorizontalHi = ~0;
} else if(data.bit(7) == 0) {
//left
io.windowHorizontalLo = 0;
io.windowHorizontalHi = (data.bits(0,4) << 4) - 1;
} else {
//right
io.windowHorizontalLo = (data.bits(0,4) << 4) - 1;
io.windowHorizontalHi = ~0;
}
return;
}
//window plane vertical position
case 0x12: {
if(!data) {
//disable
io.windowVerticalLo = ~0;
io.windowVerticalHi = ~0;
} else if(data.bit(7) == 0) {
//up
io.windowVerticalLo = 0;
io.windowVerticalHi = (data.bits(0,4) << 3) - 1;
} else {
//down
io.windowVerticalLo = (data.bits(0,4) << 3) - 1;
io.windowVerticalHi = ~0;
}
return;
}
//DMA length
case 0x13: {
io.dmaLength.bits(0,7) = data.bits(0,7);
return;
}
//DMA length
case 0x14: {
io.dmaLength.bits(8,15) = data.bits(0,7);
return;
}
//DMA source
case 0x15: {
io.dmaSource.bits(0,7) = data.bits(0,7);
return;
}
//DMA source
case 0x16: {
io.dmaSource.bits(8,15) = data.bits(0,7);
return;
}
//DMA source
case 0x17: {
io.dmaSource.bits(16,21) = data.bits(0,5);
io.dmaMode = data.bits(6,7);
return;
}
//unused
default: {
return;
}
}
}