mirror of https://github.com/bsnes-emu/bsnes.git
Update to v097r18 release.
byuu says: Changelog: - fixed SNES sprite priority regression from r17 - added nall/windows/guard.hpp to guard against global namespace pollution (similar to nall/xorg/guard.hpp) - almost fixed Windows compilation (still accuracy profile only, sorry) - finished porting all of gba/ppu's registers over to the new .bit,.bits format ... all GBA registers.cpp files gone now - the "processors :=" line in the target-$(ui)/GNUmakefile is no longer required - processors += added to each emulator core - duplicates are removed using the new nall/GNUmakefile's $(unique) function - SFC core can be compiled without the GB core now - "-DSFC_SUPERGAMEBOY" is required to build in SGB support now (it's set in target-tomoko/GNUmakefile) - started once again on loki (higan/target-loki/) [as before, loki is Linux/BSD only on account of needing hiro::Console] loki shouldn't be too horrendous ... I hope. I just have the base skeleton ready for now. But the code from v094r08 should be mostly copyable over to it. It's just that it's about 50KiB of incredibly tricky code that has to be just perfect, so it's not going to be quick. But at least with the skeleton, it'll be a lot easier to pick away at it as I want. Windows compilation fix: move hiro/windows/header.hpp line 18 (header guard) to line 16 instead.
This commit is contained in:
parent
29be18ce0c
commit
fc7d5991ce
|
@ -8,6 +8,7 @@ ws := ws
|
|||
|
||||
profile := accuracy
|
||||
target := tomoko
|
||||
# target := loki
|
||||
# console := true
|
||||
|
||||
flags += -I. -I.. -O3
|
||||
|
|
|
@ -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/";
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,7 +70,7 @@ auto APU::read(uint32 addr) -> uint8 {
|
|||
regs.bias.level.bits(0,7)
|
||||
);
|
||||
case 0x0400'0089: return (
|
||||
regs.bias.level.bits(8,9)
|
||||
regs.bias.level.bits(8,9) << 0
|
||||
| regs.bias.amplitude << 6
|
||||
);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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,15 +23,12 @@ 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 {
|
||||
struct Background {
|
||||
struct Control {
|
||||
uint2 priority;
|
||||
uint2 characterbaseblock;
|
||||
uint2 unused;
|
||||
|
@ -44,14 +37,7 @@ struct Registers {
|
|||
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;
|
||||
} 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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -3,12 +3,12 @@ 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];
|
||||
|
@ -23,7 +23,7 @@ struct Sprite {
|
|||
uint9 x;
|
||||
uint2 priority;
|
||||
uint8 palette;
|
||||
bool hflip;
|
||||
uint1 hflip;
|
||||
uint8 d0, d1, d2, d3;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
|
|
@ -23,7 +23,10 @@ namespace SuperFamicom {
|
|||
*/
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
#if defined(SFC_SUPERGAMEBOY)
|
||||
#include <gb/gb.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(PROFILE_PERFORMANCE)
|
||||
#include <nall/priority-queue.hpp>
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,23 @@
|
|||
#include "loki.hpp"
|
||||
unique_pointer<Video> video;
|
||||
unique_pointer<Audio> audio;
|
||||
unique_pointer<Input> input;
|
||||
Emulator::Interface* emulator = nullptr;
|
||||
|
||||
auto locate(string name) -> string {
|
||||
string location = {programpath(), name};
|
||||
if(inode::exists(location)) return location;
|
||||
|
||||
location = {configpath(), "loki/", name};
|
||||
if(inode::exists(location)) return location;
|
||||
|
||||
directory::create({localpath(), "loki/"});
|
||||
return {localpath(), "loki/", name};
|
||||
}
|
||||
|
||||
#include <nall/main.hpp>
|
||||
auto nall::main(lstring args) -> void {
|
||||
Application::setName("loki");
|
||||
new Program(args);
|
||||
Application::run();
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
#include <nall/nall.hpp>
|
||||
#include <ruby/ruby.hpp>
|
||||
#include <hiro/hiro.hpp>
|
||||
using namespace nall;
|
||||
using namespace ruby;
|
||||
using namespace hiro;
|
||||
extern unique_pointer<Video> video;
|
||||
extern unique_pointer<Audio> audio;
|
||||
extern unique_pointer<Input> input;
|
||||
|
||||
#include <emulator/emulator.hpp>
|
||||
extern Emulator::Interface* emulator;
|
||||
|
||||
#include <sfc/sfc.hpp>
|
||||
namespace SFC = SuperFamicom;
|
||||
|
||||
auto locate(string name) -> string;
|
||||
|
||||
#include "program/program.hpp"
|
||||
#include "terminal/terminal.hpp"
|
||||
#include "presentation/presentation.hpp"
|
|
@ -0,0 +1,28 @@
|
|||
#include "../loki.hpp"
|
||||
unique_pointer<Presentation> presentation;
|
||||
|
||||
Presentation::Presentation() {
|
||||
presentation = this;
|
||||
|
||||
onClose([&] { program->quit(); });
|
||||
|
||||
setTitle({"loki v", Emulator::Version});
|
||||
setResizable(false);
|
||||
setBackgroundColor({0, 0, 0});
|
||||
setSize({512, 480});
|
||||
setCentered();
|
||||
setVisible();
|
||||
}
|
||||
|
||||
auto Presentation::drawSplashScreen() -> void {
|
||||
uint32_t* output;
|
||||
uint length;
|
||||
if(video->lock(output, length, 512, 480)) {
|
||||
for(auto y : range(480)) {
|
||||
auto dp = output + y * (length >> 2);
|
||||
for(auto x : range(512)) *dp++ = 0xff'00'00'00;
|
||||
}
|
||||
video->unlock();
|
||||
video->refresh();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
struct Presentation : Window {
|
||||
Presentation();
|
||||
auto drawSplashScreen() -> void;
|
||||
|
||||
VerticalLayout layout{this};
|
||||
Viewport viewport{&layout, Size{~0, ~0}};
|
||||
};
|
||||
|
||||
extern unique_pointer<Presentation> presentation;
|
|
@ -0,0 +1,45 @@
|
|||
#include "../loki.hpp"
|
||||
unique_pointer<Program> program;
|
||||
|
||||
Program::Program(lstring args) {
|
||||
program = this;
|
||||
Application::onMain({&Program::main, this});
|
||||
|
||||
emulator = new SuperFamicom::Interface;
|
||||
emulator->bind = this;
|
||||
|
||||
new Terminal;
|
||||
new Presentation;
|
||||
terminal->setFocused();
|
||||
|
||||
video = Video::create();
|
||||
video->set(Video::Handle, presentation->viewport.handle());
|
||||
video->set(Video::Synchronize, false);
|
||||
if(!video->init()) video = Video::create("None");
|
||||
|
||||
audio = Audio::create();
|
||||
audio->set(Audio::Handle, presentation->viewport.handle());
|
||||
audio->set(Audio::Synchronize, true);
|
||||
audio->set(Audio::Frequency, 96000u);
|
||||
audio->set(Audio::Latency, 80u);
|
||||
if(!audio->init()) audio = Audio::create("None");
|
||||
|
||||
input = Input::create();
|
||||
input->set(Input::Handle, presentation->viewport.handle());
|
||||
if(!input->init()) input = Input::create("None");
|
||||
|
||||
presentation->drawSplashScreen();
|
||||
}
|
||||
|
||||
auto Program::load(string location) -> void {
|
||||
}
|
||||
|
||||
auto Program::main() -> void {
|
||||
}
|
||||
|
||||
auto Program::quit() -> void {
|
||||
video.reset();
|
||||
audio.reset();
|
||||
input.reset();
|
||||
Application::quit();
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
struct Program : Emulator::Interface::Bind {
|
||||
//program.cpp
|
||||
Program(lstring args);
|
||||
auto load(string) -> void;
|
||||
auto main() -> void;
|
||||
auto quit() -> void;
|
||||
|
||||
//interface.cpp
|
||||
auto loadRequest(uint id, string name, string type, bool required) -> void override {}
|
||||
auto loadRequest(uint id, string path, bool required) -> void override {}
|
||||
auto saveRequest(uint id, string path) -> void override {}
|
||||
auto videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void override {}
|
||||
auto audioSample(int16 lsample, int16 rsample) -> void override {}
|
||||
auto inputPoll(uint port, uint device, uint input) -> int16 override { return 0; }
|
||||
auto inputRumble(uint port, uint device, uint input, bool enable) -> void override {}
|
||||
auto dipSettings(const Markup::Node& node) -> uint override { return 0; }
|
||||
auto path(uint group) -> string override { return ""; }
|
||||
auto notify(string text) -> void override {}
|
||||
};
|
||||
|
||||
extern unique_pointer<Program> program;
|
|
@ -0,0 +1,18 @@
|
|||
unique_pointer<AboutWindow> aboutWindow;
|
||||
|
||||
AboutWindow::AboutWindow() {
|
||||
aboutWindow = this;
|
||||
|
||||
layout.setMargin(5);
|
||||
canvas.setIcon({locate("loki.png")});
|
||||
information.setFont(Font().setFamily(Font::Sans).setBold()).setAlignment(0.5).setText({
|
||||
"loki v", Emulator::Version, "\n\n"
|
||||
"Author: ", Emulator::Author, "\n",
|
||||
"License: ", Emulator::License, "\n",
|
||||
"Website: ", Emulator::Website
|
||||
});
|
||||
|
||||
setTitle("About loki ...");
|
||||
setSize(layout.minimumSize());
|
||||
setCentered();
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#include "../loki.hpp"
|
||||
#include "about-window.cpp"
|
||||
unique_pointer<Terminal> terminal;
|
||||
|
||||
Terminal::Terminal() {
|
||||
terminal = this;
|
||||
new AboutWindow;
|
||||
|
||||
onClose([&] { program->quit(); });
|
||||
|
||||
helpMenu.setText("Help");
|
||||
aboutAction.setText("About ...").onActivate([&] { aboutWindow->setFocused(); });
|
||||
|
||||
console.setBackgroundColor({ 56, 56, 56});
|
||||
console.setForegroundColor({255, 255, 255});
|
||||
console.setFont(Font().setFamily(Font::Mono).setSize(8));
|
||||
console.setPrompt("$ ");
|
||||
|
||||
setTitle({"loki v", Emulator::Version});
|
||||
setSize({800, 480});
|
||||
setAlignment({0.0, 1.0});
|
||||
setVisible();
|
||||
}
|
||||
|
||||
auto Terminal::showAboutWindow() -> void {
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
struct Terminal : Window {
|
||||
Terminal();
|
||||
auto showAboutWindow() -> void;
|
||||
|
||||
MenuBar menuBar{this};
|
||||
Menu helpMenu{&menuBar};
|
||||
MenuItem aboutAction{&helpMenu};
|
||||
|
||||
VerticalLayout layout{this};
|
||||
Console console{&layout, Size{~0, ~0}};
|
||||
};
|
||||
|
||||
struct AboutWindow : Window {
|
||||
AboutWindow();
|
||||
|
||||
VerticalLayout layout{this};
|
||||
Canvas canvas{&layout, Size{288, 360}, 15};
|
||||
Label information{&layout, Size{~0, 0}};
|
||||
};
|
||||
|
||||
extern unique_pointer<Terminal> terminal;
|
||||
extern unique_pointer<AboutWindow> aboutWindow;
|
|
@ -1,15 +1,16 @@
|
|||
name := higan
|
||||
flags += -DSFC_SUPERGAMEBOY
|
||||
|
||||
processors := arm gsu hg51b lr35902 r6502 r65816 spc700 upd96050 v30mz
|
||||
include processor/GNUmakefile
|
||||
|
||||
include emulator/GNUmakefile
|
||||
include fc/GNUmakefile
|
||||
include sfc/GNUmakefile
|
||||
include gb/GNUmakefile
|
||||
include gba/GNUmakefile
|
||||
include ws/GNUmakefile
|
||||
|
||||
processors := $(call unique,$(processors))
|
||||
include processor/GNUmakefile
|
||||
include emulator/GNUmakefile
|
||||
|
||||
ui_objects := ui-tomoko ui-program ui-configuration ui-input
|
||||
ui_objects += ui-settings ui-tools ui-presentation
|
||||
ui_objects += ruby hiro
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
processors += v30mz
|
||||
|
||||
ws_objects := ws-interface ws-system ws-scheduler
|
||||
ws_objects += ws-memory ws-eeprom ws-cartridge
|
||||
ws_objects += ws-cpu ws-ppu ws-apu
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#define __MSVCRT_VERSION__ WINVER
|
||||
#define NOMINMAX
|
||||
|
||||
#include <nall/windows/guard.hpp>
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
|
@ -14,6 +15,7 @@
|
|||
#include <shlobj.h>
|
||||
#include <nall/windows/registry.hpp>
|
||||
#include <nall/windows/utf8.hpp>
|
||||
#include <nall/windows/guard.hpp>
|
||||
|
||||
//MinGW/32-bit has painfully outdated platform headers ...
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ auto rootpath() -> string {
|
|||
SHGetFolderPathW(nullptr, CSIDL_WINDOWS | CSIDL_FLAG_CREATE, nullptr, 0, path);
|
||||
string result = (const char*)utf8_t(path);
|
||||
result.transform("\\", "/");
|
||||
return result.slice(0, 3);
|
||||
return slice(result, 0, 3);
|
||||
#else
|
||||
return "/";
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef NALL_WINDOWS_GUARD_HPP
|
||||
#define NALL_WINDOWS_GUARD_HPP
|
||||
|
||||
#define boolean WindowsBoolean
|
||||
#define interface WindowsBoolean
|
||||
|
||||
#else
|
||||
#undef NALL_WINDOWS_GUARD_HPP
|
||||
|
||||
#undef boolean
|
||||
#undef interface
|
||||
|
||||
#endif
|
|
@ -10,11 +10,10 @@
|
|||
#undef NOMINMAX
|
||||
#define NOMINMAX
|
||||
|
||||
#define boolean WindowsBoolean
|
||||
#include <nall/windows/guard.hpp>
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#undef boolean
|
||||
#undef interface
|
||||
#include <nall/windows/guard.hpp>
|
||||
|
||||
#if !defined(PATH_MAX)
|
||||
#define PATH_MAX 260
|
||||
|
|
|
@ -69,7 +69,7 @@ struct VideoWGL : Video, OpenGL {
|
|||
return false;
|
||||
}
|
||||
|
||||
auto lock(uint32*& data, uint& pitch, uint width, uint height) -> bool {
|
||||
auto lock(uint32_t*& data, uint& pitch, uint width, uint height) -> bool {
|
||||
OpenGL::size(width, height);
|
||||
return OpenGL::lock(data, pitch);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue