bsnes/higan/gba/ppu/io.cpp

386 lines
13 KiB
C++

auto PPU::readIO(uint32 addr) -> uint8 {
switch(addr) {
//DISPCNT
case 0x0400'0000: return (
Background::IO::mode << 0
| io.gameBoyColorMode << 3
| Background::IO::frame << 4
| objects.io.hblank << 5
| objects.io.mapping << 6
| io.forceBlank << 7
);
case 0x0400'0001: return (
bg0.io.enable << 0
| bg1.io.enable << 1
| bg2.io.enable << 2
| bg3.io.enable << 3
| objects.io.enable << 4
| window0.io.enable << 5
| window1.io.enable << 6
| window2.io.enable << 7
);
//GRSWP
case 0x0400'0002: return io.greenSwap;
case 0x0400'0003: return 0;
//DISPSTAT
case 0x0400'0004: return (
io.vblank << 0
| io.hblank << 1
| io.vcoincidence << 2
| io.irqvblank << 3
| io.irqhblank << 4
| io.irqvcoincidence << 5
);
case 0x0400'0005: return (
io.vcompare
);
//VCOUNT
case 0x0400'0006: return io.vcounter.byte(0);
case 0x0400'0007: return io.vcounter.byte(1);
//BG0CNT
case 0x0400'0008: return bg0.io.priority << 0 | bg0.io.characterBase << 2 | bg0.io.unused << 4 | bg0.io.mosaic << 6 | bg0.io.colorMode << 7;
case 0x0400'0009: return bg0.io.screenBase << 0 | bg0.io.affineWrap << 5 | bg0.io.screenSize << 6;
//BG1CNT
case 0x0400'000a: return bg1.io.priority << 0 | bg1.io.characterBase << 2 | bg1.io.unused << 4 | bg1.io.mosaic << 6 | bg1.io.colorMode << 7;
case 0x0400'000b: return bg1.io.screenBase << 0 | bg1.io.affineWrap << 5 | bg1.io.screenSize << 6;
//BG2CNT
case 0x0400'000c: return bg2.io.priority << 0 | bg2.io.characterBase << 2 | bg2.io.unused << 4 | bg2.io.mosaic << 6 | bg2.io.colorMode << 7;
case 0x0400'000d: return bg2.io.screenBase << 0 | bg2.io.affineWrap << 5 | bg2.io.screenSize << 6;
//BG3CNT
case 0x0400'000e: return bg3.io.priority << 0 | bg3.io.characterBase << 2 | bg3.io.unused << 4 | bg3.io.mosaic << 6 | bg3.io.colorMode << 7;
case 0x0400'000f: return bg3.io.screenBase << 0 | bg3.io.affineWrap << 5 | bg3.io.screenSize << 6;
//WININ0
case 0x0400'0048: return window0.io.active[BG0] << 0 | window0.io.active[BG1] << 1 | window0.io.active[BG2] << 2 | window0.io.active[BG3] << 3 | window0.io.active[OBJ] << 4 | window0.io.active[SFX] << 5;
//WININ1
case 0x0400'0049: return window1.io.active[BG0] << 0 | window1.io.active[BG1] << 1 | window1.io.active[BG2] << 2 | window1.io.active[BG3] << 3 | window1.io.active[OBJ] << 4 | window1.io.active[SFX] << 5;
//WINOUT
case 0x0400'004a: return window3.io.active[BG0] << 0 | window3.io.active[BG1] << 1 | window3.io.active[BG2] << 2 | window3.io.active[BG3] << 3 | window3.io.active[OBJ] << 4 | window3.io.active[SFX] << 5;
//WININ2
case 0x0400'004b: return window2.io.active[BG0] << 0 | window2.io.active[BG1] << 1 | window2.io.active[BG2] << 2 | window2.io.active[BG3] << 3 | window2.io.active[OBJ] << 4 | window2.io.active[SFX] << 5;
//MOSAIC (write-only)
//BLTCNT
case 0x0400'0050: return (
screen.io.blendAbove[BG0] << 0
| screen.io.blendAbove[BG1] << 1
| screen.io.blendAbove[BG2] << 2
| screen.io.blendAbove[BG3] << 3
| screen.io.blendAbove[OBJ] << 4
| screen.io.blendAbove[SFX] << 5
| screen.io.blendMode << 6
);
case 0x0400'0051: return (
screen.io.blendBelow[BG0] << 0
| screen.io.blendBelow[BG1] << 1
| screen.io.blendBelow[BG2] << 2
| screen.io.blendBelow[BG3] << 3
| screen.io.blendBelow[OBJ] << 4
| screen.io.blendBelow[SFX] << 5
);
//BLDALPHA
case 0x0400'0052: return screen.io.blendEVA;
case 0x0400'0053: return screen.io.blendEVB;
//BLDY (write-only)
}
return cpu.pipeline.fetch.instruction.byte(addr & 1);
}
auto PPU::writeIO(uint32 addr, uint8 data) -> void {
switch(addr) {
//DISPCNT
case 0x0400'0000:
Background::IO::mode = data.bits(0,2);
io.gameBoyColorMode = data.bit (3);
Background::IO::frame = data.bit (4);
objects.io.hblank = data.bit (5);
objects.io.mapping = data.bit (6);
io.forceBlank = data.bit (7);
return;
case 0x0400'0001:
bg0.io.enable = data.bit(0);
bg1.io.enable = data.bit(1);
bg2.io.enable = data.bit(2);
bg3.io.enable = data.bit(3);
objects.io.enable = data.bit(4);
window0.io.enable = data.bit(5);
window1.io.enable = data.bit(6);
window2.io.enable = data.bit(7);
//outside window is enabled whenever any inside window is enabled
window3.io.enable = (bool)data.bits(5,7);
return;
//GRSWP
case 0x0400'0002:
io.greenSwap = data.bit(0);
return;
case 0x0400'0003:
return;
//DISPSTAT
case 0x0400'0004:
io.irqvblank = data.bit(3);
io.irqhblank = data.bit(4);
io.irqvcoincidence = data.bit(5);
return;
case 0x0400'0005:
io.vcompare = data;
return;
//BG0CNT
case 0x0400'0008:
bg0.io.priority = data.bits(0,1);
bg0.io.characterBase = data.bits(2,3);
bg0.io.unused = data.bits(4,5);
bg0.io.mosaic = data.bit (6);
bg0.io.colorMode = data.bit (7);
return;
case 0x0400'0009:
bg0.io.screenBase = data.bits(0,4);
bg0.io.affineWrap = false;
bg0.io.screenSize = data.bits(6,7);
return;
//BG1CNT
case 0x0400'000a:
bg1.io.priority = data.bits(0,1);
bg1.io.characterBase = data.bits(2,3);
bg1.io.unused = data.bits(4,5);
bg1.io.mosaic = data.bit (6);
bg1.io.colorMode = data.bit (7);
return;
case 0x0400'000b:
bg1.io.screenBase = data.bits(0,4);
bg1.io.affineWrap = false;
bg1.io.screenSize = data.bits(6,7);
return;
//BG2CNT
case 0x0400'000c:
bg2.io.priority = data.bits(0,1);
bg2.io.characterBase = data.bits(2,3);
bg2.io.unused = data.bits(4,5);
bg2.io.mosaic = data.bit (6);
bg2.io.colorMode = data.bit (7);
return;
case 0x0400'000d:
bg2.io.screenBase = data.bits(0,4);
bg2.io.affineWrap = data.bit (5);
bg2.io.screenSize = data.bits(6,7);
return;
//BG3CNT
case 0x0400'000e:
bg3.io.priority = data.bits(0,1);
bg3.io.characterBase = data.bits(2,3);
bg3.io.unused = data.bits(4,5);
bg3.io.mosaic = data.bit (6);
bg3.io.colorMode = data.bit (7);
return;
case 0x0400'000f:
bg3.io.screenBase = data.bits(0,4);
bg3.io.affineWrap = data.bit (5);
bg3.io.screenSize = data.bits(6,7);
return;
//BG0HOFS
case 0x0400'0010: bg0.io.hoffset.bits(0,7) = data.bits(0,7); return;
case 0x0400'0011: bg0.io.hoffset.bit (8) = data.bit (0); return;
//BG0VOFS
case 0x0400'0012: bg0.io.voffset.bits(0,7) = data.bits(0,7); return;
case 0x0400'0013: bg0.io.voffset.bit (8) = data.bit (0); return;
//BG1HOFS
case 0x0400'0014: bg1.io.hoffset.bits(0,7) = data.bits(0,7); return;
case 0x0400'0015: bg1.io.hoffset.bit (8) = data.bit (0); return;
//BG1VOFS
case 0x0400'0016: bg1.io.voffset.bits(0,7) = data.bits(0,7); return;
case 0x0400'0017: bg1.io.voffset.bit (8) = data.bit (0); return;
//BG2HOFS
case 0x0400'0018: bg2.io.hoffset.bits(0,7) = data.bits(0,7); return;
case 0x0400'0019: bg2.io.hoffset.bit (8) = data.bit (0); return;
//BG2VOFS
case 0x0400'001a: bg2.io.voffset.bits(0,7) = data.bits(0,7); return;
case 0x0400'001b: bg2.io.voffset.bit (8) = data.bit (0); return;
//BG3HOFS
case 0x0400'001c: bg3.io.hoffset.bits(0,7) = data.bits(0,7); return;
case 0x0400'001d: bg3.io.hoffset.bit (8) = data.bit (0); return;
//BG3VOFS
case 0x0400'001e: bg3.io.voffset.bits(0,7) = data.bits(0,7); return;
case 0x0400'001f: bg3.io.voffset.bit (8) = data.bit (0); return;
//BG2PA
case 0x0400'0020: bg2.io.pa.byte(0) = data; return;
case 0x0400'0021: bg2.io.pa.byte(1) = data; return;
//BG2PB
case 0x0400'0022: bg2.io.pb.byte(0) = data; return;
case 0x0400'0023: bg2.io.pb.byte(1) = data; return;
//BG2PC
case 0x0400'0024: bg2.io.pc.byte(0) = data; return;
case 0x0400'0025: bg2.io.pc.byte(1) = data; return;
//BG2PD
case 0x0400'0026: bg2.io.pd.byte(0) = data; return;
case 0x0400'0027: bg2.io.pd.byte(1) = data; return;
//BG2X
case 0x0400'0028: bg2.io.x.bits( 0, 7) = data.bits(0,7); bg2.io.lx = bg2.io.x; return;
case 0x0400'0029: bg2.io.x.bits( 8,15) = data.bits(0,7); bg2.io.lx = bg2.io.x; return;
case 0x0400'002a: bg2.io.x.bits(16,23) = data.bits(0,7); bg2.io.lx = bg2.io.x; return;
case 0x0400'002b: bg2.io.x.bits(24,27) = data.bits(0,3); bg2.io.lx = bg2.io.x; return;
//BG2Y
case 0x0400'002c: bg2.io.y.bits( 0, 7) = data.bits(0,7); bg2.io.ly = bg2.io.y; return;
case 0x0400'002d: bg2.io.y.bits( 8,15) = data.bits(0,7); bg2.io.ly = bg2.io.y; return;
case 0x0400'002e: bg2.io.y.bits(16,23) = data.bits(0,7); bg2.io.ly = bg2.io.y; return;
case 0x0400'002f: bg2.io.y.bits(24,27) = data.bits(0,3); bg2.io.ly = bg2.io.y; return;
//BG3PA
case 0x0400'0030: bg3.io.pa.byte(0) = data; return;
case 0x0400'0031: bg3.io.pa.byte(1) = data; return;
//BG3PB
case 0x0400'0032: bg3.io.pb.byte(0) = data; return;
case 0x0400'0033: bg3.io.pb.byte(1) = data; return;
//BG3PC
case 0x0400'0034: bg3.io.pc.byte(0) = data; return;
case 0x0400'0035: bg3.io.pc.byte(1) = data; return;
//BG3PD
case 0x0400'0036: bg3.io.pd.byte(0) = data; return;
case 0x0400'0037: bg3.io.pd.byte(1) = data; return;
//BG3X
case 0x0400'0038: bg3.io.x.bits( 0, 7) = data.bits(0,7); bg3.io.lx = bg3.io.x; return;
case 0x0400'0039: bg3.io.x.bits( 8,15) = data.bits(0,7); bg3.io.lx = bg3.io.x; return;
case 0x0400'003a: bg3.io.x.bits(16,23) = data.bits(0,7); bg3.io.lx = bg3.io.x; return;
case 0x0400'003b: bg3.io.x.bits(24,27) = data.bits(0,3); bg3.io.lx = bg3.io.x; return;
//BG3Y
case 0x0400'003c: bg3.io.y.bits( 0, 7) = data.bits(0,7); bg3.io.ly = bg3.io.y; return;
case 0x0400'003d: bg3.io.y.bits( 8,15) = data.bits(0,7); bg3.io.ly = bg3.io.y; return;
case 0x0400'003e: bg3.io.y.bits(16,23) = data.bits(0,7); bg3.io.ly = bg3.io.y; return;
case 0x0400'003f: bg3.io.y.bits(24,27) = data.bits(0,3); bg3.io.ly = bg3.io.y; return;
//WIN0H
case 0x0400'0040: window0.io.x2 = data; return;
case 0x0400'0041: window0.io.x1 = data; return;
//WIN1H
case 0x0400'0042: window1.io.x2 = data; return;
case 0x0400'0043: window1.io.x1 = data; return;
//WIN0V
case 0x0400'0044: window0.io.y2 = data; return;
case 0x0400'0045: window0.io.y1 = data; return;
//WIN1V
case 0x0400'0046: window1.io.y2 = data; return;
case 0x0400'0047: window1.io.y1 = data; return;
//WININ0
case 0x0400'0048:
window0.io.active[BG0] = data.bit(0);
window0.io.active[BG1] = data.bit(1);
window0.io.active[BG2] = data.bit(2);
window0.io.active[BG3] = data.bit(3);
window0.io.active[OBJ] = data.bit(4);
window0.io.active[SFX] = data.bit(5);
return;
//WININ1
case 0x0400'0049:
window1.io.active[BG0] = data.bit(0);
window1.io.active[BG1] = data.bit(1);
window1.io.active[BG2] = data.bit(2);
window1.io.active[BG3] = data.bit(3);
window1.io.active[OBJ] = data.bit(4);
window1.io.active[SFX] = data.bit(5);
return;
//WINOUT
case 0x0400'004a:
window3.io.active[BG0] = data.bit(0);
window3.io.active[BG1] = data.bit(1);
window3.io.active[BG2] = data.bit(2);
window3.io.active[BG3] = data.bit(3);
window3.io.active[OBJ] = data.bit(4);
window3.io.active[SFX] = data.bit(5);
return;
//WININ2
case 0x0400'004b:
window2.io.active[BG0] = data.bit(0);
window2.io.active[BG1] = data.bit(1);
window2.io.active[BG2] = data.bit(2);
window2.io.active[BG3] = data.bit(3);
window2.io.active[OBJ] = data.bit(4);
window2.io.active[SFX] = data.bit(5);
return;
//MOSAIC
case 0x0400'004c:
Background::IO::mosaicWidth = data.bits(0,3);
Background::IO::mosaicHeight = data.bits(4,7);
return;
case 0x0400'004d:
objects.io.mosaicWidth = data.bits(0,3);
objects.io.mosaicHeight = data.bits(4,7);
return;
//BLDCNT
case 0x0400'0050:
screen.io.blendAbove[BG0] = data.bit (0);
screen.io.blendAbove[BG1] = data.bit (1);
screen.io.blendAbove[BG2] = data.bit (2);
screen.io.blendAbove[BG3] = data.bit (3);
screen.io.blendAbove[OBJ] = data.bit (4);
screen.io.blendAbove[SFX] = data.bit (5);
screen.io.blendMode = data.bits(6,7);
return;
case 0x0400'0051:
screen.io.blendBelow[BG0] = data.bit(0);
screen.io.blendBelow[BG1] = data.bit(1);
screen.io.blendBelow[BG2] = data.bit(2);
screen.io.blendBelow[BG3] = data.bit(3);
screen.io.blendBelow[OBJ] = data.bit(4);
screen.io.blendBelow[SFX] = data.bit(5);
return;
//BLDALPHA
case 0x0400'0052: screen.io.blendEVA = data.bits(0,4); return;
case 0x0400'0053: screen.io.blendEVB = data.bits(0,4); return;
//BLDY
case 0x0400'0054: screen.io.blendEVY = data.bits(0,4); return;
case 0x0400'0055: return;
}
}