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; } }