bsnes/higan/gba/ppu/io.cpp

276 lines
9.0 KiB
C++

auto PPU::readIO(uint32 addr) -> uint8 {
auto bgcnt = [&]() -> Registers::Background::Control& { return regs.bg[addr.bits(1,2)].control; };
auto wf = [&]() -> Registers::WindowFlags& {
static uint id[] = {In0, In1, Out, Obj};
return regs.windowflags[id[addr.bits(0,1)]];
};
switch(addr) {
//DISPCNT
case 0x0400'0000: return (
regs.control.bgmode << 0
| regs.control.cgbmode << 3
| regs.control.frame << 4
| regs.control.hblank << 5
| regs.control.objmapping << 6
| regs.control.forceblank << 7
);
case 0x0400'0001: return (
regs.control.enable[BG0] << 0
| regs.control.enable[BG1] << 1
| regs.control.enable[BG2] << 2
| regs.control.enable[BG3] << 3
| regs.control.enable[OBJ] << 4
| regs.control.enablewindow[In0] << 5
| regs.control.enablewindow[In1] << 6
| regs.control.enablewindow[Obj] << 7
);
//GRSWP
case 0x0400'0002: return regs.greenswap;
case 0x0400'0003: return 0;
//DISPSTAT
case 0x0400'0004: return (
regs.status.vblank << 0
| regs.status.hblank << 1
| regs.status.vcoincidence << 2
| regs.status.irqvblank << 3
| regs.status.irqhblank << 4
| regs.status.irqvcoincidence << 5
);
case 0x0400'0005: return (
regs.status.vcompare
);
//VCOUNT
case 0x0400'0006: return regs.vcounter.byte(0);
case 0x0400'0007: return regs.vcounter.byte(1);
//BG0CNT, BG1CNT, BG2CNT, BG3CNT
case 0x0400'0008: case 0x0400'000a: case 0x0400'000c: case 0x0400'000e: return (
bgcnt().priority << 0
| bgcnt().characterbaseblock << 2
| bgcnt().unused << 4
| bgcnt().mosaic << 6
| bgcnt().colormode << 7
);
case 0x0400'0009: case 0x0400'000b: case 0x0400'000d: case 0x0400'000f: return (
bgcnt().screenbaseblock << 0
| bgcnt().affinewrap << 5
| bgcnt().screensize << 6
);
//WININ, WINOUT
case 0x0400'0048: case 0x0400'0049: case 0x0400'004a: case 0x0400'004b: return (
wf().enable[BG0] << 0
| wf().enable[BG1] << 1
| wf().enable[BG2] << 2
| wf().enable[BG3] << 3
| wf().enable[OBJ] << 4
| wf().enable[SFX] << 4
);
//BLTCNT
case 0x0400'0050: return (
regs.blend.control.above[BG0] << 0
| regs.blend.control.above[BG1] << 1
| regs.blend.control.above[BG2] << 2
| regs.blend.control.above[BG3] << 3
| regs.blend.control.above[OBJ] << 4
| regs.blend.control.above[SFX] << 5
| regs.blend.control.mode << 6
);
case 0x0400'0051: return (
regs.blend.control.below[BG0] << 0
| regs.blend.control.below[BG1] << 1
| regs.blend.control.below[BG2] << 2
| regs.blend.control.below[BG3] << 3
| regs.blend.control.below[OBJ] << 4
| regs.blend.control.below[SFX] << 5
);
//BLDALPHA
case 0x0400'0052: return regs.blend.eva;
case 0x0400'0053: return regs.blend.evb;
//BLDY is write-only
}
return 0;
}
auto PPU::writeIO(uint32 addr, uint8 data) -> void {
auto bgcnt = [&]() -> Registers::Background::Control& { return regs.bg[addr.bits(1,2)].control; };
auto bgofs = [&]() -> Registers::Background& { return regs.bg[addr.bits(2,3)]; };
auto bg = [&]() -> Registers::Background& { return regs.bg[addr.bits(4,5)]; };
auto wf = [&]() -> Registers::WindowFlags& {
static uint id[] = {In0, In1, Out, Obj};
return regs.windowflags[id[addr.bits(0,1)]];
};
switch(addr) {
//DISPCNT
case 0x0400'0000:
regs.control.bgmode = data.bits(0,2);
regs.control.cgbmode = data.bit (3);
regs.control.frame = data.bit (4);
regs.control.hblank = data.bit (5);
regs.control.objmapping = data.bit (6);
regs.control.forceblank = data.bit (7);
return;
case 0x0400'0001:
regs.control.enable[BG0] = data.bit(0);
regs.control.enable[BG1] = data.bit(1);
regs.control.enable[BG2] = data.bit(2);
regs.control.enable[BG3] = data.bit(3);
regs.control.enable[OBJ] = data.bit(4);
regs.control.enablewindow[In0] = data.bit(5);
regs.control.enablewindow[In1] = data.bit(6);
regs.control.enablewindow[Obj] = data.bit(7);
return;
//GRSWP
case 0x0400'0002:
regs.greenswap = data.bit(0);
return;
case 0x0400'0003: return;
//DISPSTAT
case 0x0400'0004:
regs.status.irqvblank = data.bit(3);
regs.status.irqhblank = data.bit(4);
regs.status.irqvcoincidence = data.bit(5);
return;
case 0x0400'0005:
regs.status.vcompare = data;
return;
//BG0CNT, BG1CNT, BG2CNT, BG3CNT
case 0x0400'0008: case 0x0400'000a: case 0x0400'000c: case 0x0400'000e:
bgcnt().priority = data.bits(0,1);
bgcnt().characterbaseblock = data.bits(2,3);
bgcnt().unused = data.bits(4,5);
bgcnt().mosaic = data.bit (6);
bgcnt().colormode = data.bit (7);
return;
case 0x0400'0009: case 0x0400'000b: case 0x0400'000d: case 0x0400'000f:
if(addr.bits(1,2) <= 1) data.bit(5) = 0; //clear affine wrap for BG0, BG1
bgcnt().screenbaseblock = data.bits(0,4);
bgcnt().affinewrap = data.bit (5);
bgcnt().screensize = data.bits(6,7);
return;
//BG0HOFS, BG1HOFS, BG2BOFS, BG3HOFS
case 0x0400'0010: case 0x0400'0014: case 0x0400'0018: case 0x0400'001c:
bgofs().hoffset.bits(0,7) = data;
return;
case 0x0400'0011: case 0x0400'0015: case 0x0400'0019: case 0x0400'001d:
bgofs().hoffset.bit(8) = data.bit(0);
return;
//BG0VOFS, BG1VOFS, BG2VOFS, BG3VOFS
case 0x0400'0012: case 0x0400'0016: case 0x0400'001a: case 0x0400'001e:
bgofs().voffset.bits(0,7) = data;
return;
case 0x0400'0013: case 0x0400'0017: case 0x0400'001b: case 0x0400'001f:
bgofs().voffset.bit(8) = data.bit(0);
return;
//BG2PA, BG3PA
case 0x0400'0020: case 0x0400'0030: bg().pa.byte(0) = data; return;
case 0x0400'0021: case 0x0400'0031: bg().pa.byte(1) = data; return;
//BG2PB, BG3PB
case 0x0400'0022: case 0x0400'0032: bg().pb.byte(0) = data; return;
case 0x0400'0023: case 0x0400'0033: bg().pb.byte(1) = data; return;
//BG2PC, BG3PC
case 0x0400'0024: case 0x0400'0034: bg().pc.byte(0) = data; return;
case 0x0400'0025: case 0x0400'0035: bg().pc.byte(1) = data; return;
//BG2PD, BG3PD
case 0x0400'0026: case 0x0400'0036: bg().pd.byte(0) = data; return;
case 0x0400'0027: case 0x0400'0037: bg().pd.byte(1) = data; return;
//BG2X_L, BG2X_H, BG3X_L, BG3X_H
case 0x0400'0028: case 0x0400'0038: bg().x.bits( 0, 7) = data.bits(0,7); bg().lx = bg().x; return;
case 0x0400'0029: case 0x0400'0039: bg().x.bits( 8,15) = data.bits(0,7); bg().lx = bg().x; return;
case 0x0400'002a: case 0x0400'003a: bg().x.bits(16,23) = data.bits(0,7); bg().lx = bg().x; return;
case 0x0400'002b: case 0x0400'003b: bg().x.bits(24,27) = data.bits(0,3); bg().lx = bg().x; return;
//BG2Y_L, BG2Y_H, BG3Y_L, BG3Y_H
case 0x0400'002c: case 0x0400'003c: bg().y.bits( 0, 7) = data.bits(0,7); bg().ly = bg().y; return;
case 0x0400'002d: case 0x0400'003d: bg().y.bits( 8,15) = data.bits(0,7); bg().ly = bg().y; return;
case 0x0400'002e: case 0x0400'003e: bg().y.bits(16,23) = data.bits(0,7); bg().ly = bg().y; return;
case 0x0400'002f: case 0x0400'003f: bg().y.bits(24,27) = data.bits(0,3); bg().ly = bg().y; return;
//WIN0H
case 0x0400'0040: regs.window[0].x2 = data; return;
case 0x0400'0041: regs.window[0].x1 = data; return;
//WIN1H
case 0x0400'0042: regs.window[1].x2 = data; return;
case 0x0400'0043: regs.window[1].x1 = data; return;
//WIN0V
case 0x0400'0044: regs.window[0].y2 = data; return;
case 0x0400'0045: regs.window[0].y1 = data; return;
//WIN1V
case 0x0400'0046: regs.window[1].y2 = data; return;
case 0x0400'0047: regs.window[1].y1 = data; return;
//WININ, WINOUT
case 0x0400'0048: case 0x0400'0049: case 0x0400'004a: case 0x0400'004b:
wf().enable[BG0] = data.bit(0);
wf().enable[BG1] = data.bit(1);
wf().enable[BG2] = data.bit(2);
wf().enable[BG3] = data.bit(3);
wf().enable[OBJ] = data.bit(4);
wf().enable[SFX] = data.bit(5);
return;
//MOSAIC
case 0x0400'004c:
regs.mosaic.bghsize = data.bits(0,3);
regs.mosaic.bgvsize = data.bits(4,7);
return;
case 0x0400'004d:
regs.mosaic.objhsize = data.bits(0,3);
regs.mosaic.objvsize = data.bits(4,7);
return;
//BLDCNT
case 0x0400'0050:
regs.blend.control.above[BG0] = data.bit (0);
regs.blend.control.above[BG1] = data.bit (1);
regs.blend.control.above[BG2] = data.bit (2);
regs.blend.control.above[BG3] = data.bit (3);
regs.blend.control.above[OBJ] = data.bit (4);
regs.blend.control.above[SFX] = data.bit (5);
regs.blend.control.mode = data.bits(6,7);
return;
case 0x0400'0051:
regs.blend.control.below[BG0] = data.bit(0);
regs.blend.control.below[BG1] = data.bit(1);
regs.blend.control.below[BG2] = data.bit(2);
regs.blend.control.below[BG3] = data.bit(3);
regs.blend.control.below[OBJ] = data.bit(4);
regs.blend.control.below[SFX] = data.bit(5);
return;
//BLDALPHA
case 0x0400'0052: regs.blend.eva = data.bits(0,4); return;
case 0x0400'0053: regs.blend.evb = data.bits(0,4); return;
//BLDY
case 0x0400'0054: regs.blend.evy = data.bits(0,4); return;
case 0x0400'0055: return;
}
}