diff --git a/higan/GNUmakefile b/higan/GNUmakefile index 1daac6cf..f195426e 100644 --- a/higan/GNUmakefile +++ b/higan/GNUmakefile @@ -8,6 +8,7 @@ ws := ws profile := accuracy target := tomoko +# target := loki # console := true flags += -I. -I.. -O3 diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 69d32806..56f07a27 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -6,7 +6,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "097.17"; + static const string Version = "097.18"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; diff --git a/higan/fc/GNUmakefile b/higan/fc/GNUmakefile index 265fce38..d9ad3864 100644 --- a/higan/fc/GNUmakefile +++ b/higan/fc/GNUmakefile @@ -1,3 +1,5 @@ +processors += r6502 + fc_objects := fc-interface fc-system fc-scheduler fc-input fc_objects += fc-memory fc-cartridge fc-cpu fc-apu fc-ppu fc_objects += fc-cheat diff --git a/higan/gb/GNUmakefile b/higan/gb/GNUmakefile index ff89d69c..34110715 100644 --- a/higan/gb/GNUmakefile +++ b/higan/gb/GNUmakefile @@ -1,3 +1,5 @@ +processors += lr35902 + gb_objects := gb-interface gb-system gb-scheduler gb_objects += gb-memory gb-cartridge gb_objects += gb-cpu gb-ppu gb-apu diff --git a/higan/gba/GNUmakefile b/higan/gba/GNUmakefile index 03418988..16b0e0e7 100644 --- a/higan/gba/GNUmakefile +++ b/higan/gba/GNUmakefile @@ -1,3 +1,5 @@ +processors += arm + gba_objects := gba-memory gba-interface gba-scheduler gba-system gba_objects += gba-cartridge gba-player gba_objects += gba-cpu gba-ppu gba-apu diff --git a/higan/gba/apu/mmio.cpp b/higan/gba/apu/mmio.cpp index 16dadb77..847504f7 100644 --- a/higan/gba/apu/mmio.cpp +++ b/higan/gba/apu/mmio.cpp @@ -5,19 +5,19 @@ auto APU::read(uint32 addr) -> uint8 { case 0x0400'0060: return square1.read(0); case 0x0400'0061: return 0; - //NR11 + NR12 + //NR11, NR12 case 0x0400'0062: return square1.read(1); case 0x0400'0063: return square1.read(2); - //NR13 + NR14 + //NR13, NR14 case 0x0400'0064: return square1.read(3); case 0x0400'0065: return square1.read(4); - //NR21 + NR22 + //NR21, NR22 case 0x0400'0068: return square2.read(1); case 0x0400'0069: return square2.read(2); - //NR23 + NR24 + //NR23, NR24 case 0x0400'006c: return square2.read(3); case 0x0400'006d: return square2.read(4); @@ -25,23 +25,23 @@ auto APU::read(uint32 addr) -> uint8 { case 0x0400'0070: return wave.read(0); case 0x0400'0071: return 0; - //NR31 + NR32 + //NR31, NR32 case 0x0400'0072: return wave.read(1); case 0x0400'0073: return wave.read(2); - //NR33 + NR34 + //NR33, NR34 case 0x0400'0074: return wave.read(3); case 0x0400'0075: return wave.read(4); - //NR41 + NR42 + //NR41, NR42 case 0x0400'0078: return noise.read(1); case 0x0400'0079: return noise.read(2); - //NR43 + NR44 + //NR43, NR44 case 0x0400'007c: return noise.read(3); case 0x0400'007d: return noise.read(4); - //NR50 + NR51 + //NR50, NR51 case 0x0400'0080: return sequencer.read(0); case 0x0400'0081: return sequencer.read(1); @@ -70,8 +70,8 @@ auto APU::read(uint32 addr) -> uint8 { regs.bias.level.bits(0,7) ); case 0x0400'0089: return ( - regs.bias.level.bits(8,9) - | regs.bias.amplitude << 6 + regs.bias.level.bits(8,9) << 0 + | regs.bias.amplitude << 6 ); //WAVE_RAM0_L @@ -108,7 +108,7 @@ auto APU::read(uint32 addr) -> uint8 { } - return 0u; + return 0; } auto APU::write(uint32 addr, uint8 data) -> void { @@ -118,19 +118,19 @@ auto APU::write(uint32 addr, uint8 data) -> void { case 0x0400'0060: return square1.write(0, data); case 0x0400'0061: return; - //NR11 + NR12 + //NR11, NR12 case 0x0400'0062: return square1.write(1, data); case 0x0400'0063: return square1.write(2, data); - //NR13 + NR14 + //NR13, NR14 case 0x0400'0064: return square1.write(3, data); case 0x0400'0065: return square1.write(4, data); - //NR21 + NR22 + //NR21, NR22 case 0x0400'0068: return square2.write(1, data); case 0x0400'0069: return square2.write(2, data); - //NR23 + NR24 + //NR23, NR24 case 0x0400'006c: return square2.write(3, data); case 0x0400'006d: return square2.write(4, data); @@ -138,23 +138,23 @@ auto APU::write(uint32 addr, uint8 data) -> void { case 0x0400'0070: return wave.write(0, data); case 0x0400'0071: return; - //NR31 + NR32 + //NR31, NR32 case 0x0400'0072: return wave.write(1, data); case 0x0400'0073: return wave.write(2, data); - //NR33 + NR34 + //NR33, NR34 case 0x0400'0074: return wave.write(3, data); case 0x0400'0075: return wave.write(4, data); - //NR41 + NR42 + //NR41, NR42 case 0x0400'0078: return noise.write(1, data); case 0x0400'0079: return noise.write(2, data); - //NR43 + NR44 + //NR43, NR44 case 0x0400'007c: return noise.write(3, data); case 0x0400'007d: return noise.write(4, data); - //NR50 + NR51 + //NR50, NR51 case 0x0400'0080: return sequencer.write(0, data); case 0x0400'0081: return sequencer.write(1, data); @@ -185,7 +185,7 @@ auto APU::write(uint32 addr, uint8 data) -> void { return; case 0x0400'0089: regs.bias.level.bits(8,9) = data.bits(0,1); - regs.bias.amplitude = data.bits(6,7); + regs.bias.amplitude = data.bits(6,7); return; //WAVE_RAM0_L diff --git a/higan/gba/ppu/mmio.cpp b/higan/gba/ppu/mmio.cpp index 698b0b48..5c55d5ae 100644 --- a/higan/gba/ppu/mmio.cpp +++ b/higan/gba/ppu/mmio.cpp @@ -1,41 +1,95 @@ auto PPU::read(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 >> 0; - case 0x0400'0001: return regs.control >> 8; + 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 0u; + case 0x0400'0003: return 0; //DISPSTAT - case 0x0400'0004: return regs.status >> 0; - case 0x0400'0005: return regs.status >> 8; + 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 >> 0; - case 0x0400'0007: return regs.vcounter >> 8; + 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'0009: - case 0x0400'000a: case 0x0400'000b: - case 0x0400'000c: case 0x0400'000d: - case 0x0400'000e: case 0x0400'000f: { - auto& bg = regs.bg[(addr >> 1) & 3]; - unsigned shift = (addr & 1) * 8; - return bg.control >> shift; - } + //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 - case 0x0400'0048: return regs.windowflags[In0]; - case 0x0400'0049: return regs.windowflags[In1]; - case 0x0400'004a: return regs.windowflags[Out]; - case 0x0400'004b: return regs.windowflags[Obj]; + //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 >> 0; - case 0x0400'0051: return regs.blend.control >> 8; + 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; @@ -45,162 +99,176 @@ auto PPU::read(uint32 addr) -> uint8 { } - return 0u; + return 0; } -auto PPU::write(uint32 addr, uint8 byte) -> void { +auto PPU::write(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 = (regs.control & 0xff00) | (byte << 0); return; - case 0x0400'0001: regs.control = (regs.control & 0x00ff) | (byte << 8); return; + 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 = byte >> 0; return; + case 0x0400'0002: + regs.greenswap = data.bit(0); + return; case 0x0400'0003: return; //DISPSTAT case 0x0400'0004: - regs.status.irqvblank = byte >> 3; - regs.status.irqhblank = byte >> 4; - regs.status.irqvcoincidence = byte >> 5; + 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 = byte; + regs.status.vcompare = data; return; - //BG0CNT,BG1CNT,BG2CNT,BG3CNT - case 0x0400'0008: case 0x0400'0009: - case 0x0400'000a: case 0x0400'000b: - case 0x0400'000c: case 0x0400'000d: - case 0x0400'000e: case 0x0400'000f: { - auto& bg = regs.bg[(addr >> 1) & 3]; - unsigned shift = (addr & 1) * 8; - if(addr == 0x04000009 || addr == 0x0400000b) byte &= 0xdf; //clear affine wrap for BG0,1 - bg.control = (bg.control & ~(255 << shift)) | (byte << shift); + //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'0011: - case 0x0400'0014: case 0x0400'0015: - case 0x0400'0018: case 0x0400'0019: - case 0x0400'001c: case 0x0400'001d: { - auto& bg = regs.bg[(addr >> 2) & 3]; - unsigned shift = (addr & 1) * 8; - bg.hoffset = (bg.hoffset & ~(255 << shift)) | (byte << shift); + //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'0013: - case 0x0400'0016: case 0x0400'0017: - case 0x0400'001a: case 0x0400'001b: - case 0x0400'001e: case 0x0400'001f: { - auto& bg = regs.bg[(addr >> 2) & 3]; - unsigned shift = (addr & 1) * 8; - bg.voffset = (bg.voffset & ~(255 << shift)) | (byte << shift); + //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'0021: - case 0x0400'0030: case 0x0400'0031: { - auto& bg = regs.bg[(addr >> 4) & 3]; - unsigned shift = (addr & 1) * 8; - bg.pa = (bg.pa & ~(255 << shift)) | (byte << shift); - 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'0023: - case 0x0400'0032: case 0x0400'0033: { - auto& bg = regs.bg[(addr >> 4) & 3]; - unsigned shift = (addr & 1) * 8; - bg.pb = (bg.pb & ~(255 << shift)) | (byte << shift); - 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'0025: - case 0x0400'0034: case 0x0400'0035: { - auto& bg = regs.bg[(addr >> 4) & 3]; - unsigned shift = (addr & 1) * 8; - bg.pc = (bg.pc & ~(255 << shift)) | (byte << shift); - 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'0027: - case 0x0400'0036: case 0x0400'0037: { - auto& bg = regs.bg[(addr >> 4) & 3]; - unsigned shift = (addr & 1) * 8; - bg.pd = (bg.pd & ~(255 << shift)) | (byte << shift); - 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'0029: case 0x0400'002a: case 0x0400'002b: - case 0x0400'0038: case 0x0400'0039: case 0x0400'003a: case 0x0400'003b: { - auto& bg = regs.bg[(addr >> 4) & 3]; - unsigned shift = (addr & 3) * 8; - bg.lx = bg.x = (bg.x & ~(255 << shift)) | (byte << shift); - 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'002d: case 0x0400'002e: case 0x0400'002f: - case 0x0400'003c: case 0x0400'003d: case 0x0400'003e: case 0x0400'003f: { - auto& bg = regs.bg[(addr >> 4) & 3]; - unsigned shift = (addr & 3) * 8; - bg.ly = bg.y = (bg.y & ~(255 << shift)) | (byte << shift); - 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 = byte; return; - case 0x0400'0041: regs.window[0].x1 = byte; return; + 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 = byte; return; - case 0x0400'0043: regs.window[1].x1 = byte; return; + 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 = byte; return; - case 0x0400'0045: regs.window[0].y1 = byte; return; + 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 = byte; return; - case 0x0400'0047: regs.window[1].y1 = byte; return; + case 0x0400'0046: regs.window[1].y2 = data; return; + case 0x0400'0047: regs.window[1].y1 = data; return; - //WININ - case 0x0400'0048: regs.windowflags[In0] = byte; return; - case 0x0400'0049: regs.windowflags[In1] = byte; return; - - //WINOUT - case 0x0400'004a: regs.windowflags[Out] = byte; return; - case 0x0400'004b: regs.windowflags[Obj] = byte; 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 = byte >> 0; - regs.mosaic.bgvsize = byte >> 4; + regs.mosaic.bghsize = data.bits(0,3); + regs.mosaic.bgvsize = data.bits(4,7); return; case 0x0400'004d: - regs.mosaic.objhsize = byte >> 0; - regs.mosaic.objvsize = byte >> 4; + regs.mosaic.objhsize = data.bits(0,3); + regs.mosaic.objvsize = data.bits(4,7); return; //BLDCNT - case 0x0400'0050: regs.blend.control = (regs.blend.control & 0xff00) | (byte << 0); return; - case 0x0400'0051: regs.blend.control = (regs.blend.control & 0x00ff) | (byte << 8); return; + 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 = byte & 0x1f; return; - case 0x0400'0053: regs.blend.evb = byte & 0x1f; return; + 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 = byte & 0x1f; return; + case 0x0400'0054: regs.blend.evy = data.bits(0,4); return; case 0x0400'0055: return; } diff --git a/higan/gba/ppu/ppu.cpp b/higan/gba/ppu/ppu.cpp index d6ec98b8..bff0a7b3 100644 --- a/higan/gba/ppu/ppu.cpp +++ b/higan/gba/ppu/ppu.cpp @@ -15,7 +15,6 @@ namespace GameBoyAdvance { PPU ppu; #include "video.cpp" -#include "registers.cpp" #include "background.cpp" #include "object.cpp" #include "mosaic.cpp" @@ -58,12 +57,32 @@ auto PPU::power() -> void { for(uint n = 0; n < 1024; n += 2) pram_write(n, Half, 0x0000); for(uint n = 0; n < 1024; n += 2) oam_write(n, Half, 0x0000); - regs.control = 0; + regs.control.bgmode = 0; + regs.control.cgbmode = 0; + regs.control.frame = 0; + regs.control.hblank = 0; + regs.control.objmapping = 0; + regs.control.forceblank = 0; + for(auto& enable : regs.control.enable) enable = 0; + for(auto& enablewindow : regs.control.enablewindow) enablewindow = 0; regs.greenswap = 0; - regs.status = 0; + regs.status.vblank = 0; + regs.status.hblank = 0; + regs.status.vcoincidence = 0; + regs.status.irqvblank = 0; + regs.status.irqhblank = 0; + regs.status.irqvcoincidence = 0; + regs.status.vcompare = 0; regs.vcounter = 0; for(auto& bg : regs.bg) { - bg.control = 0; + bg.control.priority = 0; + bg.control.characterbaseblock = 0; + bg.control.unused = 0; + bg.control.mosaic = 0; + bg.control.colormode = 0; + bg.control.screenbaseblock = 0; + bg.control.affinewrap = 0; + bg.control.screensize = 0; bg.hoffset = 0; bg.voffset = 0; bg.pa = 0; @@ -81,14 +100,16 @@ auto PPU::power() -> void { w.y1 = 0; w.y2 = 0; } - for(auto& f : regs.windowflags) { - f = 0; + for(auto& flags : regs.windowflags) { + for(auto& enable : flags.enable) enable = 0; } regs.mosaic.bghsize = 0; regs.mosaic.bgvsize = 0; regs.mosaic.objhsize = 0; regs.mosaic.objvsize = 0; - regs.blend.control = 0; + for(auto& above : regs.blend.control.above) above = 0; + regs.blend.control.mode = 0; + for(auto& below : regs.blend.control.below) below = 0; regs.blend.eva = 0; regs.blend.evb = 0; regs.blend.evy = 0; diff --git a/higan/gba/ppu/registers.cpp b/higan/gba/ppu/registers.cpp deleted file mode 100644 index e23b4c7c..00000000 --- a/higan/gba/ppu/registers.cpp +++ /dev/null @@ -1,140 +0,0 @@ -PPU::Registers::Control::operator uint16_t() const { - return ( - (bgmode << 0) - | (cgbmode << 3) - | (frame << 4) - | (hblank << 5) - | (objmapping << 6) - | (forceblank << 7) - | (enable[BG0] << 8) - | (enable[BG1] << 9) - | (enable[BG2] << 10) - | (enable[BG3] << 11) - | (enable[OBJ] << 12) - | (enablewindow[In0] << 13) - | (enablewindow[In1] << 14) - | (enablewindow[Obj] << 15) - ); -} - -auto PPU::Registers::Control::operator=(uint16 source) -> uint16 { - bgmode = source >> 0; - cgbmode = source >> 3; - frame = source >> 4; - hblank = source >> 5; - objmapping = source >> 6; - forceblank = source >> 7; - enable[BG0] = source >> 8; - enable[BG1] = source >> 9; - enable[BG2] = source >> 10; - enable[BG3] = source >> 11; - enable[OBJ] = source >> 12; - enablewindow[In0] = source >> 13; - enablewindow[In1] = source >> 14; - enablewindow[Obj] = source >> 15; - return operator uint16_t(); -} - -PPU::Registers::Status::operator uint16_t() const { - return ( - (vblank << 0) - | (hblank << 1) - | (vcoincidence << 2) - | (irqvblank << 3) - | (irqhblank << 4) - | (irqvcoincidence << 5) - | (vcompare << 8) - ); -} - -auto PPU::Registers::Status::operator=(uint16 source) -> uint16 { - vblank = source >> 0; - hblank = source >> 1; - vcoincidence = source >> 2; - irqvblank = source >> 3; - irqhblank = source >> 4; - irqvcoincidence = source >> 5; - vcompare = source >> 8; - return operator uint16_t(); -} - -PPU::Registers::BackgroundControl::operator uint16_t() const { - return ( - (priority << 0) - | (characterbaseblock << 2) - | (unused << 4) - | (mosaic << 6) - | (colormode << 7) - | (screenbaseblock << 8) - | (affinewrap << 13) - | (screensize << 14) - ); -} - -auto PPU::Registers::BackgroundControl::operator=(uint16 source) -> uint16 { - priority = source >> 0; - characterbaseblock = source >> 2; - unused = source >> 4; - mosaic = source >> 6; - colormode = source >> 7; - screenbaseblock = source >> 8; - affinewrap = source >> 13; - screensize = source >> 14; - return operator uint16_t(); -} - -PPU::Registers::WindowFlags::operator uint8_t() const { - return ( - (enable[BG0] << 0) - | (enable[BG1] << 1) - | (enable[BG2] << 2) - | (enable[BG3] << 3) - | (enable[OBJ] << 4) - | (enable[SFX] << 5) - ); -} - -auto PPU::Registers::WindowFlags::operator=(uint8 source) -> uint8 { - enable[BG0] = source >> 0; - enable[BG1] = source >> 1; - enable[BG2] = source >> 2; - enable[BG3] = source >> 3; - enable[OBJ] = source >> 4; - enable[SFX] = source >> 5; - return operator uint8_t(); -} - -PPU::Registers::BlendControl::operator uint16_t() const { - return ( - (above[BG0] << 0) - | (above[BG1] << 1) - | (above[BG2] << 2) - | (above[BG3] << 3) - | (above[OBJ] << 4) - | (above[SFX] << 5) - | (mode << 6) - | (below[BG0] << 8) - | (below[BG1] << 9) - | (below[BG2] << 10) - | (below[BG3] << 11) - | (below[OBJ] << 12) - | (below[SFX] << 13) - ); -} - -auto PPU::Registers::BlendControl::operator=(uint16 source) -> uint16 { - above[BG0] = source >> 0; - above[BG1] = source >> 1; - above[BG2] = source >> 2; - above[BG3] = source >> 3; - above[OBJ] = source >> 4; - above[SFX] = source >> 5; - mode = source >> 6; - below[BG0] = source >> 8; - below[BG1] = source >> 9; - below[BG2] = source >> 10; - below[BG3] = source >> 11; - below[OBJ] = source >> 12; - below[SFX] = source >> 13; - return operator uint16_t(); -} diff --git a/higan/gba/ppu/registers.hpp b/higan/gba/ppu/registers.hpp index 19b43b58..3aabf5c2 100644 --- a/higan/gba/ppu/registers.hpp +++ b/higan/gba/ppu/registers.hpp @@ -11,10 +11,6 @@ struct Registers { uint1 forceblank; uint1 enable[5]; uint1 enablewindow[3]; - - operator uint16_t() const; - auto operator=(uint16 source) -> uint16; - auto operator=(const Control&) -> Control& = delete; } control; uint1 greenswap; @@ -27,31 +23,21 @@ struct Registers { uint1 irqhblank; uint1 irqvcoincidence; uint8 vcompare; - - operator uint16_t() const; - auto operator=(uint16 source) -> uint16; - auto operator=(const Status&) -> Status& = delete; } status; uint16 vcounter; - struct BackgroundControl { - uint2 priority; - uint2 characterbaseblock; - uint2 unused; - uint1 mosaic; - uint1 colormode; - uint5 screenbaseblock; - uint1 affinewrap; //BG2,3 only - uint2 screensize; - - operator uint16_t() const; - auto operator=(uint16 source) -> uint16; - auto operator=(const BackgroundControl&) -> BackgroundControl& = delete; - }; - struct Background { - BackgroundControl control; + struct Control { + uint2 priority; + uint2 characterbaseblock; + uint2 unused; + uint1 mosaic; + uint1 colormode; + uint5 screenbaseblock; + uint1 affinewrap; //BG2,3 only + uint2 screensize; + } control; uint9 hoffset; uint9 voffset; @@ -66,20 +52,14 @@ struct Registers { uint id; } bg[4]; - struct WindowFlags { - uint1 enable[6]; - - operator uint8_t() const; - auto operator=(uint8 source) -> uint8; - auto operator=(const WindowFlags&) -> WindowFlags& = delete; - }; - struct Window { uint8 x1, x2; uint8 y1, y2; } window[2]; - WindowFlags windowflags[4]; + struct WindowFlags { + uint1 enable[6]; + } windowflags[4]; struct Mosaic { uint4 bghsize; @@ -88,18 +68,12 @@ struct Registers { uint4 objvsize; } mosaic; - struct BlendControl { - uint1 above[6]; - uint1 below[6]; - uint2 mode; - - operator uint16_t() const; - auto operator=(uint16 source) -> uint16; - auto operator=(const BlendControl&) -> BlendControl& = delete; - }; - struct Blend { - BlendControl control; + struct Control { + uint1 above[6]; + uint2 mode; + uint1 below[6]; + } control; uint5 eva; uint5 evb; uint5 evy; diff --git a/higan/gba/ppu/screen.cpp b/higan/gba/ppu/screen.cpp index ca08079c..d5438896 100644 --- a/higan/gba/ppu/screen.cpp +++ b/higan/gba/ppu/screen.cpp @@ -14,14 +14,19 @@ auto PPU::render_screen() -> void { for(auto x : range(240)) { Registers::WindowFlags flags; - flags = ~0; //enable all layers if no windows are enabled + flags.enable[BG0] = true; //enable all layers if no windows are enabled + flags.enable[BG1] = true; + flags.enable[BG2] = true; + flags.enable[BG3] = true; + flags.enable[OBJ] = true; + flags.enable[SFX] = true; //determine active window if(regs.control.enablewindow[In0] || regs.control.enablewindow[In1] || regs.control.enablewindow[Obj]) { - flags = (uint8)regs.windowflags[Out]; - if(regs.control.enablewindow[Obj] && windowmask[Obj][x]) flags = (uint8)regs.windowflags[Obj]; - if(regs.control.enablewindow[In1] && windowmask[In1][x]) flags = (uint8)regs.windowflags[In1]; - if(regs.control.enablewindow[In0] && windowmask[In0][x]) flags = (uint8)regs.windowflags[In0]; + flags = regs.windowflags[Out]; + if(regs.control.enablewindow[Obj] && windowmask[Obj][x]) flags = regs.windowflags[Obj]; + if(regs.control.enablewindow[In1] && windowmask[In1][x]) flags = regs.windowflags[In1]; + if(regs.control.enablewindow[In0] && windowmask[In0][x]) flags = regs.windowflags[In0]; } //priority sorting: find topmost two pixels @@ -40,9 +45,9 @@ auto PPU::render_screen() -> void { bool blendabove = regs.blend.control.above[a]; bool blendbelow = regs.blend.control.below[b]; uint color = above[x].color; - auto eva = min(16u, (unsigned)regs.blend.eva); - auto evb = min(16u, (unsigned)regs.blend.evb); - auto evy = min(16u, (unsigned)regs.blend.evy); + auto eva = min(16u, (uint)regs.blend.eva); + auto evb = min(16u, (uint)regs.blend.evb); + auto evy = min(16u, (uint)regs.blend.evy); //perform blending, if needed if(flags.enable[SFX] == false) { diff --git a/higan/sfc/GNUmakefile b/higan/sfc/GNUmakefile index 82421e64..b5c4488d 100644 --- a/higan/sfc/GNUmakefile +++ b/higan/sfc/GNUmakefile @@ -1,3 +1,5 @@ +processors += r65816 spc700 arm gsu hg51b upd96050 + sfc_objects := sfc-interface sfc-system sfc-scheduler sfc-controller sfc_objects += sfc-cartridge sfc-cheat sfc_objects += sfc-memory sfc-cpu sfc-smp sfc-dsp sfc-ppu diff --git a/higan/sfc/cartridge/cartridge.cpp b/higan/sfc/cartridge/cartridge.cpp index b557c25f..d424aa4e 100644 --- a/higan/sfc/cartridge/cartridge.cpp +++ b/higan/sfc/cartridge/cartridge.cpp @@ -139,10 +139,12 @@ auto Cartridge::load() -> void { } auto Cartridge::loadGameBoy() -> void { + #if defined(SFC_SUPERGAMEBOY) //invoked from ICD2::load() _sha256 = GameBoy::interface->sha256(); information.markup.gameBoy = GameBoy::interface->manifest(); information.title.gameBoy = GameBoy::interface->title(); + #endif } auto Cartridge::loadBSMemory() -> void { diff --git a/higan/sfc/coprocessor/icd2/icd2.cpp b/higan/sfc/coprocessor/icd2/icd2.cpp index 6456221f..7eb3fe93 100644 --- a/higan/sfc/coprocessor/icd2/icd2.cpp +++ b/higan/sfc/coprocessor/icd2/icd2.cpp @@ -2,10 +2,13 @@ namespace SuperFamicom { +ICD2 icd2; + +#if defined(SFC_SUPERGAMEBOY) + #include "interface/interface.cpp" #include "mmio/mmio.cpp" #include "serialization.cpp" -ICD2 icd2; auto ICD2::Enter() -> void { while(true) { @@ -78,4 +81,6 @@ auto ICD2::reset() -> void { GameBoy::system.power(); } +#endif + } diff --git a/higan/sfc/coprocessor/icd2/icd2.hpp b/higan/sfc/coprocessor/icd2/icd2.hpp index d8e2e6b0..14831815 100644 --- a/higan/sfc/coprocessor/icd2/icd2.hpp +++ b/higan/sfc/coprocessor/icd2/icd2.hpp @@ -1,3 +1,5 @@ +#if defined(SFC_SUPERGAMEBOY) + struct ICD2 : Emulator::Interface::Bind, GameBoy::Interface::Hook, Coprocessor { static auto Enter() -> void; auto main() -> void; @@ -23,4 +25,23 @@ private: GameBoy::Interface::Hook* hook = nullptr; }; +#else + +struct ICD2 : Coprocessor { + auto init() -> void {} + auto load() -> void {} + auto unload() -> void {} + auto power() -> void {} + auto reset() -> void {} + + auto read(uint24, uint8) -> uint8 { return 0; } + auto write(uint24, uint8) -> void { return; } + + auto serialize(serializer&) -> void {} + + uint revision; +}; + +#endif + extern ICD2 icd2; diff --git a/higan/sfc/interface/interface.cpp b/higan/sfc/interface/interface.cpp index 7b55a06e..4c1a6014 100644 --- a/higan/sfc/interface/interface.cpp +++ b/higan/sfc/interface/interface.cpp @@ -330,6 +330,7 @@ auto Interface::load(uint id, const stream& stream) -> void { if(id == ID::MCCROM) mcc.rom.read(stream); if(id == ID::MCCRAM) mcc.ram.read(stream); + #if defined(SFC_SUPERGAMEBOY) if(id == ID::SuperGameBoyManifest) { GameBoy::interface->load(GameBoy::ID::SystemManifest, stream); } @@ -349,6 +350,7 @@ auto Interface::load(uint id, const stream& stream) -> void { if(id == ID::GameBoyRAM) { GameBoy::interface->load(GameBoy::ID::RAM, stream); } + #endif if(id == ID::BSMemoryManifest) cartridge.information.markup.bsMemory = stream.text(); if(id == ID::BSMemoryROM) bsmemory.memory.read(stream); @@ -401,9 +403,11 @@ auto Interface::save(uint id, const stream& stream) -> void { if(id == ID::SDD1RAM) stream.write((uint8_t*)sdd1.ram.data(), sdd1.ram.size()); if(id == ID::OBC1RAM) stream.write((uint8_t*)obc1.ram.data(), obc1.ram.size()); + #if defined(SFC_SUPERGAMEBOY) if(id == ID::GameBoyRAM) { GameBoy::interface->save(GameBoy::ID::RAM, stream); } + #endif if(id == ID::MCCRAM) stream.write((uint8_t*)mcc.ram.data(), mcc.ram.size()); @@ -455,7 +459,7 @@ auto Interface::unserialize(serializer& s) -> bool { auto Interface::cheatSet(const lstring& list) -> void { cheat.reset(); - //Super Game Boy + #if defined(SFC_SUPERGAMEBOY) if(cartridge.hasICD2()) { GameBoy::cheat.reset(); for(auto& codeset : list) { @@ -468,8 +472,8 @@ auto Interface::cheatSet(const lstring& list) -> void { } return; } + #endif - //Super Famicom, Broadcast Satellaview, Sufami Turbo for(auto& codeset : list) { lstring codes = codeset.split("+"); for(auto& code : codes) { diff --git a/higan/sfc/ppu/sprite/list.cpp b/higan/sfc/ppu/sprite/list.cpp index aff53120..f4451e5e 100644 --- a/higan/sfc/ppu/sprite/list.cpp +++ b/higan/sfc/ppu/sprite/list.cpp @@ -1,5 +1,5 @@ -auto PPU::Sprite::update(uint addr, uint8 data) -> void { - if(addr < 0x0200) { +auto PPU::Sprite::update(uint10 addr, uint8 data) -> void { + if(!addr.bit(9)) { uint n = addr >> 2; //sprite# addr &= 3; if(addr == 0) { diff --git a/higan/sfc/ppu/sprite/sprite.hpp b/higan/sfc/ppu/sprite/sprite.hpp index 29d55cd1..f60c6327 100644 --- a/higan/sfc/ppu/sprite/sprite.hpp +++ b/higan/sfc/ppu/sprite/sprite.hpp @@ -3,27 +3,27 @@ struct Sprite { uint9 x; uint8 y; uint8 character; - bool nameselect; - bool vflip; - bool hflip; + uint1 nameselect; + uint1 vflip; + uint1 hflip; uint2 priority; uint3 palette; - bool size; + uint1 size; alwaysinline auto width() const -> uint; alwaysinline auto height() const -> uint; } list[128]; struct Item { - bool valid; + bool valid; uint7 index; }; struct Tile { - bool valid; + bool valid; uint9 x; uint2 priority; uint8 palette; - bool hflip; + uint1 hflip; uint8 d0, d1, d2, d3; }; @@ -44,10 +44,10 @@ struct Sprite { bool sub_enable; bool interlace; - uint3 base_size; - uint2 nameselect; + uint3 base_size; + uint2 nameselect; uint16 tiledata_addr; - uint7 first_sprite; + uint7 first_sprite; uint priority0; uint priority1; @@ -60,7 +60,7 @@ struct Sprite { struct Output { struct Pixel { - uint2 priority; //0 = none (transparent) + uint priority; //0 = none (transparent) uint8 palette; } main, sub; } output; @@ -68,7 +68,7 @@ struct Sprite { Sprite(PPU& self); //list.cpp - auto update(uint addr, uint8 data) -> void; + auto update(uint10 addr, uint8 data) -> void; auto synchronize() -> void; //sprite.cpp diff --git a/higan/sfc/sfc.hpp b/higan/sfc/sfc.hpp index d26b8cbc..b100df3d 100644 --- a/higan/sfc/sfc.hpp +++ b/higan/sfc/sfc.hpp @@ -23,7 +23,10 @@ namespace SuperFamicom { */ #include -#include + +#if defined(SFC_SUPERGAMEBOY) + #include +#endif #if defined(PROFILE_PERFORMANCE) #include diff --git a/higan/target-loki/GNUmakefile b/higan/target-loki/GNUmakefile new file mode 100644 index 00000000..72c94d56 --- /dev/null +++ b/higan/target-loki/GNUmakefile @@ -0,0 +1,73 @@ +name := loki + +include sfc/GNUmakefile +include processor/GNUmakefile +include emulator/GNUmakefile + +ui_objects := ui-loki ui-program +ui_objects += ui-terminal ui-presentation +ui_objects += ruby hiro +ui_objects += $(if $(call streq,$(platform),windows),ui-resource) + +# platform +ifeq ($(platform),windows) + ruby += video.gdi audio.directsound input.windows +else ifeq ($(platform),macosx) + ruby += video.cgl audio.openal input.quartz +else ifeq ($(platform),linux) + ruby += video.xshm audio.openal input.sdl +else ifeq ($(platform),bsd) + ruby += video.xshm audio.oss input.sdl +endif + +# ruby +include ../ruby/GNUmakefile +link += $(rubylink) + +# hiro +include ../hiro/GNUmakefile +link += $(hirolink) + +# rules +objects := $(ui_objects) $(objects) +objects := $(patsubst %,obj/%.o,$(objects)) + +obj/libco.o: ../libco/libco.c $(call rwildcard,../libco/) + +obj/ruby.o: ../ruby/ruby.cpp $(call rwildcard,../ruby/) + $(compiler) $(rubyflags) -c $< -o $@ + +obj/hiro.o: ../hiro/hiro.cpp $(call rwildcard,../hiro/) + $(compiler) $(hiroflags) -c $< -o $@ + +obj/ui-loki.o: $(ui)/loki.cpp $(call rwildcard,$(ui)/) +obj/ui-program.o: $(ui)/program/program.cpp $(call rwildcard,$(ui)/) +obj/ui-terminal.o: $(ui)/terminal/terminal.cpp $(call rwildcard,$(ui)/) +obj/ui-presentation.o: $(ui)/presentation/presentation.cpp $(call rwildcard,$(ui)/) + +obj/ui-resource.o: + windres data/resource.rc obj/ui-resource.o + +# targets +build: $(objects) + $(call unique,$(compiler) -o out/$(name) $(objects) $(link)) + +install: +ifeq ($(shell id -un),root) + $(error "make install should not be run as root") +else ifneq ($(filter $(platform),linux bsd),) + mkdir -p $(prefix)/bin/ + mkdir -p $(prefix)/share/icons/ + mkdir -p $(prefix)/share/$(name)/ + cp out/$(name) $(prefix)/bin/$(name) + cp data/higan.png $(prefix)/share/icons/$(name).png + cp -R profile/* $(prefix)/share/$(name)/ +endif + +uninstall: +ifeq ($(shell id -un),root) + $(error "make uninstall should not be run as root") +else ifneq ($(filter $(platform),linux bsd),) + if [ -f $(prefix)/bin/$(name) ]; then rm $(prefix)/bin/$(name); fi + if [ -f $(prefix)/share/icons/$(name).png ]; then rm $(prefix)/share/icons/$(name).png; fi +endif diff --git a/higan/target-loki/loki.cpp b/higan/target-loki/loki.cpp new file mode 100644 index 00000000..06c2502f --- /dev/null +++ b/higan/target-loki/loki.cpp @@ -0,0 +1,23 @@ +#include "loki.hpp" +unique_pointer