Update to v087r28 release.

byuu says:

Be sure to run make install, and move required images to their appropriate system profile folders.
I still have no warnings in place if those images aren't present.

Changelog:
- OBJ mosaic should hopefully be emulated correctly now (thanks to krom
  and Cydrak for testing the hardware behavior)
- emulated dummy serial registers, fixes Sonic Advance (you may still
  need to specify 512KB FlashROM with an appropriate ID, I used
  Panaonic's)
- GBA core exits scheduler (PPU thread) and calls
  interface->videoRefresh() from main thread (not required, just nice)
- SRAM, FRAM, EEPROM and FlashROM initialized to 0xFF if it does not
  exist (probably not needed, but FlashROM likes to reset to 0xFF
  anyway)
- GBA manifest.xml for file-mode will now use "gamename.xml" instead of
  "gamename.gba.xml"
- started renaming "NES" to "Famicom" and "SNES" to "Super Famicom" in
  the GUI (may or may not change source code in the long-term)
- removed target-libsnes/
- added profile/

Profiles are the major new feature. So far we have:

    Famicom.sys/{nothing (yet?)}
    Super Famicom.sys/{ipl.rom}
    Game Boy.sys/{boot.rom}
    Game Boy Color.sys/{boot.rom}
    Game Boy Advance.sys/{bios.rom[not included]}
    Super Game Boy.sfc/{boot.rom,program.rom[not included]}
    BS-X Satellaview.sfc/{program.rom,bsx.ram,bsx.pram}
    Sufami Turbo.sfc/{program.rom}

The SGB, BSX and ST cartridges ask you to load GB, BS or ST cartridges
directly now. No slot loader for them.  So the obvious downsides: you
can't quickly pick between different SGB BIOSes, but why would you want
to? Just use SGB2/JP.  It's still possible, so I'll sacrifice a little
complexity for a rare case to make it a lot easier for the more common
case.  ST cartridges currently won't let you load the secondary slot.
BS-X Town cart is the only useful game to load with nothing in the slot,
but only barely, since games are all seeded on flash and not on PSRAM
images. We can revisit a way to boot the BIOS directly if and when we
get the satellite uplink emulated and data can be downloaded onto the
PSRAM :P BS-X slotted cartridges still require the secondary slot.

My plan for BS-X slotted cartridges is to require a manifest.xml to
specify that it has the BS-X slot present.  Otherwise, we have to load
the ROM into the SNES cartridge class, and parse its header before we
can find out if it has one. Screw that.  If it's in the XML, I can tell
before loading the ROM if I need to present you with an optional slot
loading dialog.  I will probably do something similar for Sufami Turbo.
Not all games even work with a secondary slot, so why ask you to load
a second slot for them? Let the XML request a second slot. A complete
Sufami Turbo ROM set will be trivial anyway.  Not sure how I want to do
the sub dialog yet. We want basic file loading, but we don't want it to
look like the dialog 'didn't do anything' if it pops back open
immediately again. Maybe change the background color of the dialog to
a darker gray? Tacky, but it'd give you the visual cue without the need
for some subtle text changes.
This commit is contained in:
Tim Allen 2012-04-18 23:58:04 +10:00
parent d2241f1931
commit a454e9d927
57 changed files with 553 additions and 990 deletions

View File

@ -1,7 +1,7 @@
#ifndef BASE_HPP
#define BASE_HPP
static const char Version[] = "087.27";
static const char Version[] = "087.28";
#include <nall/platform.hpp>
#include <nall/algorithm.hpp>

View File

@ -103,9 +103,9 @@ uint8 Cartridge::mmio_read(uint16 addr) {
if(bootrom_enable) {
const uint8 *data = nullptr;
switch(system.revision()) { default:
case System::Revision::GameBoy: data = System::BootROM::dmg; break;
case System::Revision::SuperGameBoy: data = System::BootROM::sgb; break;
case System::Revision::GameBoyColor: data = System::BootROM::cgb; break;
case System::Revision::GameBoy: data = system.bootROM.dmg; break;
case System::Revision::SuperGameBoy: data = system.bootROM.sgb; break;
case System::Revision::GameBoyColor: data = system.bootROM.cgb; break;
}
if(addr >= 0x0000 && addr <= 0x00ff) return data[addr];
if(addr >= 0x0200 && addr <= 0x08ff && system.cgb()) return data[addr - 256];

View File

@ -1,135 +0,0 @@
#ifdef SYSTEM_CPP
//SHA256 = 4bf5021be357ce523a59ac5f4efff5d6371ae50112a6db0adf4a75916ad760a9
const uint8_t System::BootROM::cgb[2048] = {
0x31,0xfe,0xff,0x3e,0x02,0xc3,0x7c,0x00,0xd3,0x00,0x98,0xa0,0x12,0xd3,0x00,0x80,
0x00,0x40,0x1e,0x53,0xd0,0x00,0x1f,0x42,0x1c,0x00,0x14,0x2a,0x4d,0x19,0x8c,0x7e,
0x00,0x7c,0x31,0x6e,0x4a,0x45,0x52,0x4a,0x00,0x00,0xff,0x53,0x1f,0x7c,0xff,0x03,
0x1f,0x00,0xff,0x1f,0xa7,0x00,0xef,0x1b,0x1f,0x00,0xef,0x1b,0x00,0x7c,0x00,0x00,
0xff,0x03,0xce,0xed,0x66,0x66,0xcc,0x0d,0x00,0x0b,0x03,0x73,0x00,0x83,0x00,0x0c,
0x00,0x0d,0x00,0x08,0x11,0x1f,0x88,0x89,0x00,0x0e,0xdc,0xcc,0x6e,0xe6,0xdd,0xdd,
0xd9,0x99,0xbb,0xbb,0x67,0x63,0x6e,0x0e,0xec,0xcc,0xdd,0xdc,0x99,0x9f,0xbb,0xb9,
0x33,0x3e,0x3c,0x42,0xb9,0xa5,0xb9,0xa5,0x42,0x3c,0x58,0x43,0xe0,0x70,0x3e,0xfc,
0xe0,0x47,0xcd,0x75,0x02,0xcd,0x00,0x02,0x26,0xd0,0xcd,0x03,0x02,0x21,0x00,0xfe,
0x0e,0xa0,0xaf,0x22,0x0d,0x20,0xfc,0x11,0x04,0x01,0x21,0x10,0x80,0x4c,0x1a,0xe2,
0x0c,0xcd,0xc6,0x03,0xcd,0xc7,0x03,0x13,0x7b,0xfe,0x34,0x20,0xf1,0x11,0x72,0x00,
0x06,0x08,0x1a,0x13,0x22,0x23,0x05,0x20,0xf9,0xcd,0xf0,0x03,0x3e,0x01,0xe0,0x4f,
0x3e,0x91,0xe0,0x40,0x21,0xb2,0x98,0x06,0x4e,0x0e,0x44,0xcd,0x91,0x02,0xaf,0xe0,
0x4f,0x0e,0x80,0x21,0x42,0x00,0x06,0x18,0xf2,0x0c,0xbe,0x20,0xfe,0x23,0x05,0x20,
0xf7,0x21,0x34,0x01,0x06,0x19,0x78,0x86,0x2c,0x05,0x20,0xfb,0x86,0x20,0xfe,0xcd,
0x1c,0x03,0x18,0x02,0x00,0x00,0xcd,0xd0,0x05,0xaf,0xe0,0x70,0x3e,0x11,0xe0,0x50,
0x21,0x00,0x80,0xaf,0x22,0xcb,0x6c,0x28,0xfb,0xc9,0x2a,0x12,0x13,0x0d,0x20,0xfa,
0xc9,0xe5,0x21,0x0f,0xff,0xcb,0x86,0xcb,0x46,0x28,0xfc,0xe1,0xc9,0x11,0x00,0xff,
0x21,0x03,0xd0,0x0e,0x0f,0x3e,0x30,0x12,0x3e,0x20,0x12,0x1a,0x2f,0xa1,0xcb,0x37,
0x47,0x3e,0x10,0x12,0x1a,0x2f,0xa1,0xb0,0x4f,0x7e,0xa9,0xe6,0xf0,0x47,0x2a,0xa9,
0xa1,0xb0,0x32,0x47,0x79,0x77,0x3e,0x30,0x12,0xc9,0x3e,0x80,0xe0,0x68,0xe0,0x6a,
0x0e,0x6b,0x2a,0xe2,0x05,0x20,0xfb,0x4a,0x09,0x43,0x0e,0x69,0x2a,0xe2,0x05,0x20,
0xfb,0xc9,0xc5,0xd5,0xe5,0x21,0x00,0xd8,0x06,0x01,0x16,0x3f,0x1e,0x40,0xcd,0x4a,
0x02,0xe1,0xd1,0xc1,0xc9,0x3e,0x80,0xe0,0x26,0xe0,0x11,0x3e,0xf3,0xe0,0x12,0xe0,
0x25,0x3e,0x77,0xe0,0x24,0x21,0x30,0xff,0xaf,0x0e,0x10,0x22,0x2f,0x0d,0x20,0xfb,
0xc9,0xcd,0x11,0x02,0xcd,0x62,0x02,0x79,0xfe,0x38,0x20,0x14,0xe5,0xaf,0xe0,0x4f,
0x21,0xa7,0x99,0x3e,0x38,0x22,0x3c,0xfe,0x3f,0x20,0xfa,0x3e,0x01,0xe0,0x4f,0xe1,
0xc5,0xe5,0x21,0x43,0x01,0xcb,0x7e,0xcc,0x89,0x05,0xe1,0xc1,0xcd,0x11,0x02,0x79,
0xd6,0x30,0xd2,0x06,0x03,0x79,0xfe,0x01,0xca,0x06,0x03,0x7d,0xfe,0xd1,0x28,0x21,
0xc5,0x06,0x03,0x0e,0x01,0x16,0x03,0x7e,0xe6,0xf8,0xb1,0x22,0x15,0x20,0xf8,0x0c,
0x79,0xfe,0x06,0x20,0xf0,0x11,0x11,0x00,0x19,0x05,0x20,0xe7,0x11,0xa1,0xff,0x19,
0xc1,0x04,0x78,0x1e,0x83,0xfe,0x62,0x28,0x06,0x1e,0xc1,0xfe,0x64,0x20,0x07,0x7b,
0xe0,0x13,0x3e,0x87,0xe0,0x14,0xfa,0x02,0xd0,0xfe,0x00,0x28,0x0a,0x3d,0xea,0x02,
0xd0,0x79,0xfe,0x01,0xca,0x91,0x02,0x0d,0xc2,0x91,0x02,0xc9,0x0e,0x26,0xcd,0x4a,
0x03,0xcd,0x11,0x02,0xcd,0x62,0x02,0x0d,0x20,0xf4,0xcd,0x11,0x02,0x3e,0x01,0xe0,
0x4f,0xcd,0x3e,0x03,0xcd,0x41,0x03,0xaf,0xe0,0x4f,0xcd,0x3e,0x03,0xc9,0x21,0x08,
0x00,0x11,0x51,0xff,0x0e,0x05,0xcd,0x0a,0x02,0xc9,0xc5,0xd5,0xe5,0x21,0x40,0xd8,
0x0e,0x20,0x7e,0xe6,0x1f,0xfe,0x1f,0x28,0x01,0x3c,0x57,0x2a,0x07,0x07,0x07,0xe6,
0x07,0x47,0x3a,0x07,0x07,0x07,0xe6,0x18,0xb0,0xfe,0x1f,0x28,0x01,0x3c,0x0f,0x0f,
0x0f,0x47,0xe6,0xe0,0xb2,0x22,0x78,0xe6,0x03,0x5f,0x7e,0x0f,0x0f,0xe6,0x1f,0xfe,
0x1f,0x28,0x01,0x3c,0x07,0x07,0xb3,0x22,0x0d,0x20,0xc7,0xe1,0xd1,0xc1,0xc9,0x0e,
0x00,0x1a,0xe6,0xf0,0xcb,0x49,0x28,0x02,0xcb,0x37,0x47,0x23,0x7e,0xb0,0x22,0x1a,
0xe6,0x0f,0xcb,0x49,0x20,0x02,0xcb,0x37,0x47,0x23,0x7e,0xb0,0x22,0x13,0xcb,0x41,
0x28,0x0d,0xd5,0x11,0xf8,0xff,0xcb,0x49,0x28,0x03,0x11,0x08,0x00,0x19,0xd1,0x0c,
0x79,0xfe,0x18,0x20,0xcc,0xc9,0x47,0xd5,0x16,0x04,0x58,0xcb,0x10,0x17,0xcb,0x13,
0x17,0x15,0x20,0xf6,0xd1,0x22,0x23,0x22,0x23,0xc9,0x3e,0x19,0xea,0x10,0x99,0x21,
0x2f,0x99,0x0e,0x0c,0x3d,0x28,0x08,0x32,0x0d,0x20,0xf9,0x2e,0x0f,0x18,0xf3,0xc9,
0x3e,0x01,0xe0,0x4f,0xcd,0x00,0x02,0x11,0x07,0x06,0x21,0x80,0x80,0x0e,0xc0,0x1a,
0x22,0x23,0x22,0x23,0x13,0x0d,0x20,0xf7,0x11,0x04,0x01,0xcd,0x8f,0x03,0x01,0xa8,
0xff,0x09,0xcd,0x8f,0x03,0x01,0xf8,0xff,0x09,0x11,0x72,0x00,0x0e,0x08,0x23,0x1a,
0x22,0x13,0x0d,0x20,0xf9,0x21,0xc2,0x98,0x06,0x08,0x3e,0x08,0x0e,0x10,0x22,0x0d,
0x20,0xfc,0x11,0x10,0x00,0x19,0x05,0x20,0xf3,0xaf,0xe0,0x4f,0x21,0xc2,0x98,0x3e,
0x08,0x22,0x3c,0xfe,0x18,0x20,0x02,0x2e,0xe2,0xfe,0x28,0x20,0x03,0x21,0x02,0x99,
0xfe,0x38,0x20,0xed,0x21,0xd8,0x08,0x11,0x40,0xd8,0x06,0x08,0x3e,0xff,0x12,0x13,
0x12,0x13,0x0e,0x02,0xcd,0x0a,0x02,0x3e,0x00,0x12,0x13,0x12,0x13,0x13,0x13,0x05,
0x20,0xea,0xcd,0x62,0x02,0x21,0x4b,0x01,0x7e,0xfe,0x33,0x20,0x0b,0x2e,0x44,0x1e,
0x30,0x2a,0xbb,0x20,0x49,0x1c,0x18,0x04,0x2e,0x4b,0x1e,0x01,0x2a,0xbb,0x20,0x3e,
0x2e,0x34,0x01,0x10,0x00,0x2a,0x80,0x47,0x0d,0x20,0xfa,0xea,0x00,0xd0,0x21,0xc7,
0x06,0x0e,0x00,0x2a,0xb8,0x28,0x08,0x0c,0x79,0xfe,0x4f,0x20,0xf6,0x18,0x1f,0x79,
0xd6,0x41,0x38,0x1c,0x21,0x16,0x07,0x16,0x00,0x5f,0x19,0xfa,0x37,0x01,0x57,0x7e,
0xba,0x28,0x0d,0x11,0x0e,0x00,0x19,0x79,0x83,0x4f,0xd6,0x5e,0x38,0xed,0x0e,0x00,
0x21,0x33,0x07,0x06,0x00,0x09,0x7e,0xe6,0x1f,0xea,0x08,0xd0,0x7e,0xe6,0xe0,0x07,
0x07,0x07,0xea,0x0b,0xd0,0xcd,0xe9,0x04,0xc9,0x11,0x91,0x07,0x21,0x00,0xd9,0xfa,
0x0b,0xd0,0x47,0x0e,0x1e,0xcb,0x40,0x20,0x02,0x13,0x13,0x1a,0x22,0x20,0x02,0x1b,
0x1b,0xcb,0x48,0x20,0x02,0x13,0x13,0x1a,0x22,0x13,0x13,0x20,0x02,0x1b,0x1b,0xcb,
0x50,0x28,0x05,0x1b,0x2b,0x1a,0x22,0x13,0x1a,0x22,0x13,0x0d,0x20,0xd7,0x21,0x00,
0xd9,0x11,0x00,0xda,0xcd,0x64,0x05,0xc9,0x21,0x12,0x00,0xfa,0x05,0xd0,0x07,0x07,
0x06,0x00,0x4f,0x09,0x11,0x40,0xd8,0x06,0x08,0xe5,0x0e,0x02,0xcd,0x0a,0x02,0x13,
0x13,0x13,0x13,0x13,0x13,0xe1,0x05,0x20,0xf0,0x11,0x42,0xd8,0x0e,0x02,0xcd,0x0a,
0x02,0x11,0x4a,0xd8,0x0e,0x02,0xcd,0x0a,0x02,0x2b,0x2b,0x11,0x44,0xd8,0x0e,0x02,
0xcd,0x0a,0x02,0xc9,0x0e,0x60,0x2a,0xe5,0xc5,0x21,0xe8,0x07,0x06,0x00,0x4f,0x09,
0x0e,0x08,0xcd,0x0a,0x02,0xc1,0xe1,0x0d,0x20,0xec,0xc9,0xfa,0x08,0xd0,0x11,0x18,
0x00,0x3c,0x3d,0x28,0x03,0x19,0x20,0xfa,0xc9,0xcd,0x1d,0x02,0x78,0xe6,0xff,0x28,
0x0f,0x21,0xe4,0x08,0x06,0x00,0x2a,0xb9,0x28,0x08,0x04,0x78,0xfe,0x0c,0x20,0xf6,
0x18,0x2d,0x78,0xea,0x05,0xd0,0x3e,0x1e,0xea,0x02,0xd0,0x11,0x0b,0x00,0x19,0x56,
0x7a,0xe6,0x1f,0x5f,0x21,0x08,0xd0,0x3a,0x22,0x7b,0x77,0x7a,0xe6,0xe0,0x07,0x07,
0x07,0x5f,0x21,0x0b,0xd0,0x3a,0x22,0x7b,0x77,0xcd,0xe9,0x04,0xcd,0x28,0x05,0xc9,
0xcd,0x11,0x02,0xfa,0x43,0x01,0xcb,0x7f,0x28,0x04,0xe0,0x4c,0x18,0x28,0x3e,0x04,
0xe0,0x4c,0x3e,0x01,0xe0,0x6c,0x21,0x00,0xda,0xcd,0x7b,0x05,0x06,0x10,0x16,0x00,
0x1e,0x08,0xcd,0x4a,0x02,0x21,0x7a,0x00,0xfa,0x00,0xd0,0x47,0x0e,0x02,0x2a,0xb8,
0xcc,0xda,0x03,0x0d,0x20,0xf8,0xc9,0x01,0x0f,0x3f,0x7e,0xff,0xff,0xc0,0x00,0xc0,
0xf0,0xf1,0x03,0x7c,0xfc,0xfe,0xfe,0x03,0x07,0x07,0x0f,0xe0,0xe0,0xf0,0xf0,0x1e,
0x3e,0x7e,0xfe,0x0f,0x0f,0x1f,0x1f,0xff,0xff,0x00,0x00,0x01,0x01,0x01,0x03,0xff,
0xff,0xe1,0xe0,0xc0,0xf0,0xf9,0xfb,0x1f,0x7f,0xf8,0xe0,0xf3,0xfd,0x3e,0x1e,0xe0,
0xf0,0xf9,0x7f,0x3e,0x7c,0xf8,0xe0,0xf8,0xf0,0xf0,0xf8,0x00,0x00,0x7f,0x7f,0x07,
0x0f,0x9f,0xbf,0x9e,0x1f,0xff,0xff,0x0f,0x1e,0x3e,0x3c,0xf1,0xfb,0x7f,0x7f,0xfe,
0xde,0xdf,0x9f,0x1f,0x3f,0x3e,0x3c,0xf8,0xf8,0x00,0x00,0x03,0x03,0x07,0x07,0xff,
0xff,0xc1,0xc0,0xf3,0xe7,0xf7,0xf3,0xc0,0xc0,0xc0,0xc0,0x1f,0x1f,0x1e,0x3e,0x3f,
0x1f,0x3e,0x3e,0x80,0x00,0x00,0x00,0x7c,0x1f,0x07,0x00,0x0f,0xff,0xfe,0x00,0x7c,
0xf8,0xf0,0x00,0x1f,0x0f,0x0f,0x00,0x7c,0xf8,0xf8,0x00,0x3f,0x3e,0x1c,0x00,0x0f,
0x0f,0x0f,0x00,0x7c,0xff,0xff,0x00,0x00,0xf8,0xf8,0x00,0x07,0x0f,0x0f,0x00,0x81,
0xff,0xff,0x00,0xf3,0xe1,0x80,0x00,0xe0,0xff,0x7f,0x00,0xfc,0xf0,0xc0,0x00,0x3e,
0x7c,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x16,0x36,0xd1,0xdb,0xf2,0x3c,0x8c,
0x92,0x3d,0x5c,0x58,0xc9,0x3e,0x70,0x1d,0x59,0x69,0x19,0x35,0xa8,0x14,0xaa,0x75,
0x95,0x99,0x34,0x6f,0x15,0xff,0x97,0x4b,0x90,0x17,0x10,0x39,0xf7,0xf6,0xa2,0x49,
0x4e,0x43,0x68,0xe0,0x8b,0xf0,0xce,0x0c,0x29,0xe8,0xb7,0x86,0x9a,0x52,0x01,0x9d,
0x71,0x9c,0xbd,0x5d,0x6d,0x67,0x3f,0x6b,0xb3,0x46,0x28,0xa5,0xc6,0xd3,0x27,0x61,
0x18,0x66,0x6a,0xbf,0x0d,0xf4,0x42,0x45,0x46,0x41,0x41,0x52,0x42,0x45,0x4b,0x45,
0x4b,0x20,0x52,0x2d,0x55,0x52,0x41,0x52,0x20,0x49,0x4e,0x41,0x49,0x4c,0x49,0x43,
0x45,0x20,0x52,0x7c,0x08,0x12,0xa3,0xa2,0x07,0x87,0x4b,0x20,0x12,0x65,0xa8,0x16,
0xa9,0x86,0xb1,0x68,0xa0,0x87,0x66,0x12,0xa1,0x30,0x3c,0x12,0x85,0x12,0x64,0x1b,
0x07,0x06,0x6f,0x6e,0x6e,0xae,0xaf,0x6f,0xb2,0xaf,0xb2,0xa8,0xab,0x6f,0xaf,0x86,
0xae,0xa2,0xa2,0x12,0xaf,0x13,0x12,0xa1,0x6e,0xaf,0xaf,0xad,0x06,0x4c,0x6e,0xaf,
0xaf,0x12,0x7c,0xac,0xa8,0x6a,0x6e,0x13,0xa0,0x2d,0xa8,0x2b,0xac,0x64,0xac,0x6d,
0x87,0xbc,0x60,0xb4,0x13,0x72,0x7c,0xb5,0xae,0xae,0x7c,0x7c,0x65,0xa2,0x6c,0x64,
0x85,0x80,0xb0,0x40,0x88,0x20,0x68,0xde,0x00,0x70,0xde,0x20,0x78,0x20,0x20,0x38,
0x20,0xb0,0x90,0x20,0xb0,0xa0,0xe0,0xb0,0xc0,0x98,0xb6,0x48,0x80,0xe0,0x50,0x1e,
0x1e,0x58,0x20,0xb8,0xe0,0x88,0xb0,0x10,0x20,0x00,0x10,0x20,0xe0,0x18,0xe0,0x18,
0x00,0x18,0xe0,0x20,0xa8,0xe0,0x20,0x18,0xe0,0x00,0x20,0x18,0xd8,0xc8,0x18,0xe0,
0x00,0xe0,0x40,0x28,0x28,0x28,0x18,0xe0,0x60,0x20,0x18,0xe0,0x00,0x00,0x08,0xe0,
0x18,0x30,0xd0,0xd0,0xd0,0x20,0xe0,0xe8,0xff,0x7f,0xbf,0x32,0xd0,0x00,0x00,0x00,
0x9f,0x63,0x79,0x42,0xb0,0x15,0xcb,0x04,0xff,0x7f,0x31,0x6e,0x4a,0x45,0x00,0x00,
0xff,0x7f,0xef,0x1b,0x00,0x02,0x00,0x00,0xff,0x7f,0x1f,0x42,0xf2,0x1c,0x00,0x00,
0xff,0x7f,0x94,0x52,0x4a,0x29,0x00,0x00,0xff,0x7f,0xff,0x03,0x2f,0x01,0x00,0x00,
0xff,0x7f,0xef,0x03,0xd6,0x01,0x00,0x00,0xff,0x7f,0xb5,0x42,0xc8,0x3d,0x00,0x00,
0x74,0x7e,0xff,0x03,0x80,0x01,0x00,0x00,0xff,0x67,0xac,0x77,0x13,0x1a,0x6b,0x2d,
0xd6,0x7e,0xff,0x4b,0x75,0x21,0x00,0x00,0xff,0x53,0x5f,0x4a,0x52,0x7e,0x00,0x00,
0xff,0x4f,0xd2,0x7e,0x4c,0x3a,0xe0,0x1c,0xed,0x03,0xff,0x7f,0x5f,0x25,0x00,0x00,
0x6a,0x03,0x1f,0x02,0xff,0x03,0xff,0x7f,0xff,0x7f,0xdf,0x01,0x12,0x01,0x00,0x00,
0x1f,0x23,0x5f,0x03,0xf2,0x00,0x09,0x00,0xff,0x7f,0xea,0x03,0x1f,0x01,0x00,0x00,
0x9f,0x29,0x1a,0x00,0x0c,0x00,0x00,0x00,0xff,0x7f,0x7f,0x02,0x1f,0x00,0x00,0x00,
0xff,0x7f,0xe0,0x03,0x06,0x02,0x20,0x01,0xff,0x7f,0xeb,0x7e,0x1f,0x00,0x00,0x7c,
0xff,0x7f,0xff,0x3f,0x00,0x7e,0x1f,0x00,0xff,0x7f,0xff,0x03,0x1f,0x00,0x00,0x00,
0xff,0x03,0x1f,0x00,0x0c,0x00,0x00,0x00,0xff,0x7f,0x3f,0x03,0x93,0x01,0x00,0x00,
0x00,0x00,0x00,0x42,0x7f,0x03,0xff,0x7f,0xff,0x7f,0x8c,0x7e,0x00,0x7c,0x00,0x00,
0xff,0x7f,0xef,0x1b,0x80,0x61,0x00,0x00,0xff,0x7f,0x00,0x7c,0xe0,0x03,0x1f,0x7c,
0x1f,0x00,0xff,0x03,0x40,0x41,0x42,0x20,0x21,0x22,0x80,0x81,0x82,0x10,0x11,0x12,
0x12,0xb0,0x79,0xb8,0xad,0x16,0x17,0x07,0xba,0x05,0x7c,0x13,0x00,0x00,0x00,0x00,
};
#endif

View File

@ -1,23 +0,0 @@
#ifdef SYSTEM_CPP
//SHA256 = cf053eccb4ccafff9e67339d4e78e98dce7d1ed59be819d2a1ba2232c6fce1c7
const uint8_t System::BootROM::dmg[256] = {
0x31,0xfe,0xff,0xaf,0x21,0xff,0x9f,0x32,0xcb,0x7c,0x20,0xfb,0x21,0x26,0xff,0x0e,
0x11,0x3e,0x80,0x32,0xe2,0x0c,0x3e,0xf3,0xe2,0x32,0x3e,0x77,0x77,0x3e,0xfc,0xe0,
0x47,0x11,0x04,0x01,0x21,0x10,0x80,0x1a,0xcd,0x95,0x00,0xcd,0x96,0x00,0x13,0x7b,
0xfe,0x34,0x20,0xf3,0x11,0xd8,0x00,0x06,0x08,0x1a,0x13,0x22,0x23,0x05,0x20,0xf9,
0x3e,0x19,0xea,0x10,0x99,0x21,0x2f,0x99,0x0e,0x0c,0x3d,0x28,0x08,0x32,0x0d,0x20,
0xf9,0x2e,0x0f,0x18,0xf3,0x67,0x3e,0x64,0x57,0xe0,0x42,0x3e,0x91,0xe0,0x40,0x04,
0x1e,0x02,0x0e,0x0c,0xf0,0x44,0xfe,0x90,0x20,0xfa,0x0d,0x20,0xf7,0x1d,0x20,0xf2,
0x0e,0x13,0x24,0x7c,0x1e,0x83,0xfe,0x62,0x28,0x06,0x1e,0xc1,0xfe,0x64,0x20,0x06,
0x7b,0xe2,0x0c,0x3e,0x87,0xe2,0xf0,0x42,0x90,0xe0,0x42,0x15,0x20,0xd2,0x05,0x20,
0x4f,0x16,0x20,0x18,0xcb,0x4f,0x06,0x04,0xc5,0xcb,0x11,0x17,0xc1,0xcb,0x11,0x17,
0x05,0x20,0xf5,0x22,0x23,0x22,0x23,0xc9,0xce,0xed,0x66,0x66,0xcc,0x0d,0x00,0x0b,
0x03,0x73,0x00,0x83,0x00,0x0c,0x00,0x0d,0x00,0x08,0x11,0x1f,0x88,0x89,0x00,0x0e,
0xdc,0xcc,0x6e,0xe6,0xdd,0xdd,0xd9,0x99,0xbb,0xbb,0x67,0x63,0x6e,0x0e,0xec,0xcc,
0xdd,0xdc,0x99,0x9f,0xbb,0xb9,0x33,0x3e,0x3c,0x42,0xb9,0xa5,0xb9,0xa5,0x42,0x3c,
0x21,0x04,0x01,0x11,0xa8,0x00,0x1a,0x13,0xbe,0x20,0xfe,0x23,0x7d,0xfe,0x34,0x20,
0xf5,0x06,0x19,0x78,0x86,0x23,0x05,0x20,0xfb,0x86,0x20,0xfe,0x3e,0x01,0xe0,0x50,
};
#endif

View File

@ -1,23 +0,0 @@
#ifdef SYSTEM_CPP
//SHA256 = 0e4ddff32fc9d1eeaae812a157dd246459b00c9e14f2f61751f661f32361e360
const uint8_t System::BootROM::sgb[256] = {
0x31,0xfe,0xff,0x3e,0x30,0xe0,0x00,0xaf,0x21,0xff,0x9f,0x32,0xcb,0x7c,0x20,0xfb,
0x21,0x26,0xff,0x0e,0x11,0x3e,0x80,0x32,0xe2,0x0c,0x3e,0xf3,0xe2,0x32,0x3e,0x77,
0x77,0x3e,0xfc,0xe0,0x47,0x21,0x5f,0xc0,0x0e,0x08,0xaf,0x32,0x0d,0x20,0xfc,0x11,
0x4f,0x01,0x3e,0xfb,0x0e,0x06,0xf5,0x06,0x00,0x1a,0x1b,0x32,0x80,0x47,0x0d,0x20,
0xf8,0x32,0xf1,0x32,0x0e,0x0e,0xd6,0x02,0xfe,0xef,0x20,0xea,0x11,0x04,0x01,0x21,
0x10,0x80,0x1a,0xcd,0xd3,0x00,0xcd,0xd4,0x00,0x13,0x7b,0xfe,0x34,0x20,0xf3,0x11,
0xe6,0x00,0x06,0x08,0x1a,0x13,0x22,0x23,0x05,0x20,0xf9,0x3e,0x19,0xea,0x10,0x99,
0x21,0x2f,0x99,0x0e,0x0c,0x3d,0x28,0x08,0x32,0x0d,0x20,0xf9,0x2e,0x0f,0x18,0xf3,
0x3e,0x91,0xe0,0x40,0x21,0x00,0xc0,0x0e,0x00,0x3e,0x00,0xe2,0x3e,0x30,0xe2,0x06,
0x10,0x1e,0x08,0x2a,0x57,0xcb,0x42,0x3e,0x10,0x20,0x02,0x3e,0x20,0xe2,0x3e,0x30,
0xe2,0xcb,0x1a,0x1d,0x20,0xef,0x05,0x20,0xe8,0x3e,0x20,0xe2,0x3e,0x30,0xe2,0xcd,
0xc2,0x00,0x7d,0xfe,0x60,0x20,0xd2,0x0e,0x13,0x3e,0xc1,0xe2,0x0c,0x3e,0x07,0xe2,
0x18,0x3a,0x16,0x04,0xf0,0x44,0xfe,0x90,0x20,0xfa,0x1e,0x00,0x1d,0x20,0xfd,0x15,
0x20,0xf2,0xc9,0x4f,0x06,0x04,0xc5,0xcb,0x11,0x17,0xc1,0xcb,0x11,0x17,0x05,0x20,
0xf5,0x22,0x23,0x22,0x23,0xc9,0x3c,0x42,0xb9,0xa5,0xb9,0xa5,0x42,0x3c,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x01,0xe0,0x50,
};
#endif

View File

@ -3,9 +3,6 @@
#define SYSTEM_CPP
namespace GB {
#include "bootrom-dmg.cpp"
#include "bootrom-sgb.cpp"
#include "bootrom-cgb.cpp"
#include "serialization.cpp"
System system;
@ -42,6 +39,11 @@ void System::runthreadtosave() {
}
void System::init() {
file fp;
fp.open("/home/byuu/Desktop/boot.rom", file::mode::write);
fp.write(bootROM.sgb, 256);
fp.close();
assert(interface != 0);
}
@ -61,4 +63,10 @@ void System::power() {
clocks_executed = 0;
}
System::System() {
for(auto &byte : bootROM.dmg) byte = 0;
for(auto &byte : bootROM.sgb) byte = 0;
for(auto &byte : bootROM.cgb) byte = 0;
}
}

View File

@ -16,9 +16,9 @@ struct System : property<System> {
inline bool cgb() const { return revision == Revision::GameBoyColor; }
struct BootROM {
static const uint8 dmg[ 256];
static const uint8 sgb[ 256];
static const uint8 cgb[2048];
uint8 dmg[ 256];
uint8 sgb[ 256];
uint8 cgb[2048];
} bootROM;
void run();
@ -40,6 +40,8 @@ struct System : property<System> {
void serialize(serializer&);
void serialize_all(serializer&);
void serialize_init();
System();
};
#include <gb/interface/interface.hpp>

View File

@ -25,7 +25,7 @@ bool Cartridge::load(const string &markup, const uint8_t *data, unsigned size) {
has_sram = true;
ram.size = numeral(info["size"].data);
ram.mask = ram.size - 1;
for(unsigned n = 0; n < ram.size; n++) ram.data[n] = 0;
for(unsigned n = 0; n < ram.size; n++) ram.data[n] = 0xff;
}
if(info["type"].data == "EEPROM") {
@ -33,14 +33,14 @@ bool Cartridge::load(const string &markup, const uint8_t *data, unsigned size) {
eeprom.size = numeral(info["size"].data);
eeprom.mask = size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
eeprom.test = size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
for(unsigned n = 0; n < eeprom.size; n++) eeprom.data[n] = 0;
for(unsigned n = 0; n < eeprom.size; n++) eeprom.data[n] = 0xff;
}
if(info["type"].data == "FlashROM") {
has_flashrom = true;
flashrom.id = numeral(info["id"].data);
flashrom.size = numeral(info["size"].data);
for(unsigned n = 0; n < flashrom.size; n++) flashrom.data[n] = 0;
for(unsigned n = 0; n < flashrom.size; n++) flashrom.data[n] = 0xff;
}
}

View File

@ -78,9 +78,6 @@ void Cartridge::FlashROM::write(uint16 addr, uint8 byte) {
}
void Cartridge::FlashROM::power() {
id = 0x09c2;
size = 128 * 1024;
unlockhi = false;
unlocklo = false;
idmode = false;

View File

@ -132,7 +132,9 @@ void CPU::power() {
for(unsigned n = 0x0b0; n <= 0x0df; n++) bus.mmio[n] = this; //DMA
for(unsigned n = 0x100; n <= 0x10f; n++) bus.mmio[n] = this; //Timers
for(unsigned n = 0x120; n <= 0x12b; n++) bus.mmio[n] = this; //Serial
for(unsigned n = 0x130; n <= 0x133; n++) bus.mmio[n] = this; //Keypad
for(unsigned n = 0x134; n <= 0x159; n++) bus.mmio[n] = this; //Serial
for(unsigned n = 0x200; n <= 0x209; n++) bus.mmio[n] = this; //System
for(unsigned n = 0x300; n <= 0x301; n++) bus.mmio[n] = this; //System
//0x080-0x083 mirrored via gba/memory/memory.cpp //System

View File

@ -39,6 +39,27 @@ uint8 CPU::read(uint32 addr) {
return timer.control >> shift;
}
//SIOMULTI0 (SIODATA32_L)
//SIOMULTI1 (SIODATA32_H)
//SIOMULTI2
//SIOMULTI3
case 0x04000120: case 0x04000121:
case 0x04000122: case 0x04000123:
case 0x04000124: case 0x04000125:
case 0x04000126: case 0x04000127: {
auto &data = regs.serial.data[(addr >> 1) & 3];
unsigned shift = (addr & 1) * 8;
return data >> shift;
}
//SIOCNT
case 0x04000128: return regs.serial.control >> 0;
case 0x04000129: return regs.serial.control >> 8;
//SIOMLT_SEND (SIODATA8)
case 0x0400012a: return regs.serial.data8;
case 0x0400012b: return 0u;
//KEYINPUT
case 0x04000130:
for(unsigned n = 0; n < 8; n++) result |= interface->inputPoll(n) << n;
@ -54,6 +75,32 @@ uint8 CPU::read(uint32 addr) {
case 0x04000132: return regs.keypad.control >> 0;
case 0x04000133: return regs.keypad.control >> 8;
//RCNT
case 0x04000134: return regs.joybus.settings >> 0;
case 0x04000135: return regs.joybus.settings >> 8;
//JOYCNT
case 0x04000140: return regs.joybus.control >> 0;
case 0x04000141: return regs.joybus.control >> 8;
//JOY_RECV_L
//JOY_RECV_H
case 0x04000150: return regs.joybus.receive >> 0;
case 0x04000151: return regs.joybus.receive >> 8;
case 0x04000152: return regs.joybus.receive >> 16;
case 0x04000153: return regs.joybus.receive >> 24;
//JOY_TRANS_L
//JOY_TRANS_H
case 0x04000154: return regs.joybus.transmit >> 0;
case 0x04000155: return regs.joybus.transmit >> 8;
case 0x04000156: return regs.joybus.transmit >> 16;
case 0x04000157: return regs.joybus.transmit >> 24;
//JOYSTAT
case 0x04000158: return regs.joybus.status >> 0;
case 0x04000159: return regs.joybus.status >> 8;
//IE
case 0x04000200: return regs.irq.enable >> 0;
case 0x04000201: return regs.irq.enable >> 8;
@ -183,10 +230,58 @@ void CPU::write(uint32 addr, uint8 byte) {
return;
}
//SIOMULTI0 (SIODATA32_L)
//SIOMULTI1 (SIODATA32_H)
//SIOMULTI2
//SIOMULTI3
case 0x04000120: case 0x04000121:
case 0x04000122: case 0x04000123:
case 0x04000124: case 0x04000125:
case 0x04000126: case 0x04000127: {
auto &data = regs.serial.data[(addr >> 1) & 3];
unsigned shift = (addr & 1) * 8;
data = (data & ~(255 << shift)) | (byte << shift);
return;
}
//SIOCNT
case 0x04000128: regs.serial.control = (regs.serial.control & 0xff00) | (byte << 0); return;
case 0x04000129: regs.serial.control = (regs.serial.control & 0x00ff) | (byte << 8); return;
//SIOMLT_SEND (SIODATA8)
case 0x0400012a: regs.serial.data8 = byte; return;
case 0x0400012b: return;
//KEYCNT
case 0x04000132: regs.keypad.control = (regs.keypad.control & 0xff00) | (byte << 0); return;
case 0x04000133: regs.keypad.control = (regs.keypad.control & 0x00ff) | (byte << 8); return;
//RCNT
case 0x04000134: regs.joybus.settings = (regs.joybus.settings & 0xff00) | (byte << 0); return;
case 0x04000135: regs.joybus.settings = (regs.joybus.settings & 0x00ff) | (byte << 8); return;
//JOYCNT
case 0x04000140: regs.joybus.control = (regs.joybus.control & 0xff00) | (byte << 0); return;
case 0x04000141: regs.joybus.control = (regs.joybus.control & 0x00ff) | (byte << 8); return;
//JOY_RECV_L
//JOY_RECV_H
case 0x04000150: regs.joybus.receive = (regs.joybus.receive & 0xffffff00) | (byte << 0); return;
case 0x04000151: regs.joybus.receive = (regs.joybus.receive & 0xffff00ff) | (byte << 8); return;
case 0x04000152: regs.joybus.receive = (regs.joybus.receive & 0xff00ffff) | (byte << 16); return;
case 0x04000153: regs.joybus.receive = (regs.joybus.receive & 0x00ffffff) | (byte << 24); return;
//JOY_TRANS_L
//JOY_TRANS_H
case 0x04000154: regs.joybus.transmit = (regs.joybus.transmit & 0xffffff00) | (byte << 0); return;
case 0x04000155: regs.joybus.transmit = (regs.joybus.transmit & 0xffff00ff) | (byte << 8); return;
case 0x04000156: regs.joybus.transmit = (regs.joybus.transmit & 0xff00ffff) | (byte << 16); return;
case 0x04000157: regs.joybus.transmit = (regs.joybus.transmit & 0x00ffffff) | (byte << 24); return;
//JOYSTAT
case 0x04000158: regs.joybus.status = (regs.joybus.status & 0xff00) | (byte << 0); return;
case 0x04000159: regs.joybus.status = (regs.joybus.status & 0x00ff) | (byte << 8); return;
//IE
case 0x04000200: regs.irq.enable = (regs.irq.enable & 0xff00) | (byte << 0); return;
case 0x04000201: regs.irq.enable = (regs.irq.enable & 0x00ff) | (byte << 8); return;
@ -200,18 +295,17 @@ void CPU::write(uint32 addr, uint8 byte) {
case 0x04000205: regs.wait.control = (regs.wait.control & 0x00ff) | ((byte & 0x7f) << 8); return;
//IME
case 0x04000208: regs.ime = byte & 1; return;
case 0x04000208: regs.ime = byte >> 0; return;
case 0x04000209: return;
//POSTFLG + HALTCNT
case 0x04000300: regs.postboot = byte & 1; return;
//POSTFLG, HALTCNT
case 0x04000300: regs.postboot |= byte >> 0; return;
case 0x04000301: regs.mode = byte & 0x80 ? Registers::Mode::Stop : Registers::Mode::Halt; return;
//MEMCNT_L
//MEMCNT_H
case 0x04000800: regs.memory.control = (regs.memory.control & 0xffffff00) | (byte << 0); return;
case 0x04000801: regs.memory.control = (regs.memory.control & 0xffff00ff) | (byte << 8); return;
//MEMCNT_H
case 0x04000802: regs.memory.control = (regs.memory.control & 0xff00ffff) | (byte << 16); return;
case 0x04000803: regs.memory.control = (regs.memory.control & 0x00ffffff) | (byte << 24); return;

View File

@ -23,7 +23,7 @@ uint16 CPU::Registers::DMAControl::operator=(uint16 source) {
return operator uint16();
}
CPU::Registers::TimerControl::operator uint8() const {
CPU::Registers::TimerControl::operator uint16() const {
return (
(frequency << 0)
| (cascade << 2)
@ -32,12 +32,35 @@ CPU::Registers::TimerControl::operator uint8() const {
);
}
uint8 CPU::Registers::TimerControl::operator=(uint8 source) {
uint16 CPU::Registers::TimerControl::operator=(uint16 source) {
frequency = source >> 0;
cascade = source >> 2;
irq = source >> 6;
enable = source >> 7;
return operator uint8();
return operator uint16();
}
CPU::Registers::SerialControl::operator uint16() const {
return (
(shiftclockselect << 0)
| (shiftclockfrequency << 1)
| (transferenablereceive << 2)
| (transferenablesend << 3)
| (startbit << 7)
| (transferlength << 12)
| (irqenable << 14)
);
}
uint16 CPU::Registers::SerialControl::operator=(uint16 source) {
shiftclockselect = source >> 0;
shiftclockfrequency = source >> 1;
transferenablereceive = source >> 2;
transferenablesend = source >> 3;
startbit = source >> 7;
transferlength = source >> 12;
irqenable = source >> 14;
return operator uint16();
}
CPU::Registers::KeypadControl::operator uint16() const {
@ -73,6 +96,67 @@ uint16 CPU::Registers::KeypadControl::operator=(uint16 source) {
return operator uint16();
}
CPU::Registers::JoybusSettings::operator uint16() const {
return (
(sc << 0)
| (sd << 1)
| (si << 2)
| (so << 3)
| (scmode << 4)
| (sdmode << 5)
| (simode << 6)
| (somode << 7)
| (irqenable << 8)
| (mode << 14)
);
}
uint16 CPU::Registers::JoybusSettings::operator=(uint16 source) {
sc = source >> 0;
sd = source >> 1;
si = source >> 2;
so = source >> 3;
scmode = source >> 4;
sdmode = source >> 5;
simode = source >> 6;
somode = source >> 7;
irqenable = source >> 8;
mode = source >> 14;
return operator uint16();
}
CPU::Registers::JoybusControl::operator uint16() const {
return (
(resetsignal << 0)
| (receivecomplete << 1)
| (sendcomplete << 2)
| (irqenable << 6)
);
}
uint16 CPU::Registers::JoybusControl::operator=(uint16 source) {
resetsignal = source >> 0;
receivecomplete = source >> 1;
sendcomplete = source >> 2;
irqenable = source >> 6;
return operator uint16();
}
CPU::Registers::JoybusStatus::operator uint16() const {
return (
(receiveflag << 1)
| (sendflag << 3)
| (generalflag << 4)
);
}
uint16 CPU::Registers::JoybusStatus::operator=(uint16 source) {
receiveflag = source >> 1;
sendflag = source >> 3;
generalflag = source >> 4;
return operator uint16();
}
CPU::Registers::Interrupt::operator uint16() const {
return (
(vblank << 0)
@ -93,20 +177,20 @@ CPU::Registers::Interrupt::operator uint16() const {
}
uint16 CPU::Registers::Interrupt::operator=(uint16 source) {
vblank = source & (1 << 0);
hblank = source & (1 << 1);
vcoincidence = source & (1 << 2);
timer[0] = source & (1 << 3);
timer[1] = source & (1 << 4);
timer[2] = source & (1 << 5);
timer[3] = source & (1 << 6);
serial = source & (1 << 7);
dma[0] = source & (1 << 8);
dma[1] = source & (1 << 9);
dma[2] = source & (1 << 10);
dma[3] = source & (1 << 11);
keypad = source & (1 << 12);
cartridge = source & (1 << 13);
vblank = source >> 0;
hblank = source >> 1;
vcoincidence = source >> 2;
timer[0] = source >> 3;
timer[1] = source >> 4;
timer[2] = source >> 5;
timer[3] = source >> 6;
serial = source >> 7;
dma[0] = source >> 8;
dma[1] = source >> 9;
dma[2] = source >> 10;
dma[3] = source >> 11;
keypad = source >> 12;
cartridge = source >> 13;
return operator uint16();
}
@ -151,10 +235,10 @@ CPU::Registers::MemoryControl::operator uint32() const {
}
uint32 CPU::Registers::MemoryControl::operator=(uint32 source) {
disable = (source >> 0) & 1;
unknown1 = (source >> 1) & 7;
ewram = (source >> 5) & 1;
ewramwait = (source >> 24) & 15;
unknown2 = (source >> 28) & 15;
disable = source >> 0;
unknown1 = source >> 1;
ewram = source >> 5;
ewramwait = source >> 24;
unknown2 = source >> 28;
return operator uint32();
}

View File

@ -34,8 +34,8 @@ struct Registers {
uint1 irq;
uint1 enable;
operator uint8() const;
uint8 operator=(uint8 source);
operator uint16() const;
uint16 operator=(uint16 source);
TimerControl& operator=(const TimerControl&) = delete;
};
@ -45,6 +45,26 @@ struct Registers {
TimerControl control;
} timer[4];
struct SerialControl {
uint1 shiftclockselect;
uint1 shiftclockfrequency;
uint1 transferenablereceive;
uint1 transferenablesend;
uint1 startbit;
uint1 transferlength;
uint1 irqenable;
operator uint16() const;
uint16 operator=(uint16 source);
SerialControl& operator=(const SerialControl&) = delete;
};
struct Serial {
uint16 data[4];
SerialControl control;
uint8 data8;
} serial;
struct KeypadControl {
uint1 flag[10];
uint1 enable;
@ -59,17 +79,63 @@ struct Registers {
KeypadControl control;
} keypad;
bool ime;
struct JoybusSettings {
uint1 sc;
uint1 sd;
uint1 si;
uint1 so;
uint1 scmode;
uint1 sdmode;
uint1 simode;
uint1 somode;
uint1 irqenable;
uint2 mode;
operator uint16() const;
uint16 operator=(uint16 source);
JoybusSettings& operator=(const JoybusSettings&) = delete;
};
struct JoybusControl {
uint1 resetsignal;
uint1 receivecomplete;
uint1 sendcomplete;
uint1 irqenable;
operator uint16() const;
uint16 operator=(uint16 source);
JoybusControl& operator=(const JoybusControl&) = delete;
};
struct JoybusStatus {
uint1 receiveflag;
uint1 sendflag;
uint2 generalflag;
operator uint16() const;
uint16 operator=(uint16 source);
JoybusStatus& operator=(const JoybusStatus&) = delete;
};
struct Joybus {
JoybusSettings settings;
JoybusControl control;
uint32 receive;
uint32 transmit;
JoybusStatus status;
} joybus;
uint1 ime;
struct Interrupt {
bool vblank;
bool hblank;
bool vcoincidence;
bool timer[4];
bool serial;
bool dma[4];
bool keypad;
bool cartridge;
uint1 vblank;
uint1 hblank;
uint1 vcoincidence;
uint1 timer[4];
uint1 serial;
uint1 dma[4];
uint1 keypad;
uint1 cartridge;
operator uint16() const;
uint16 operator=(uint16 source);
@ -98,9 +164,9 @@ struct Registers {
} wait;
struct MemoryControl {
bool disable;
uint1 disable;
uint3 unknown1;
bool ewram;
uint1 ewram;
uint4 ewramwait;
uint4 unknown2;
@ -113,7 +179,7 @@ struct Registers {
MemoryControl control;
} memory;
bool postboot;
uint1 postboot;
enum class Mode : unsigned { Normal, Halt, Stop } mode;
unsigned clock;
} regs;

View File

@ -31,10 +31,43 @@ void CPU::serialize(serializer &s) {
s.integer(timer.control.enable);
}
for(auto &value : regs.serial.data) s.integer(value);
s.integer(regs.serial.control.shiftclockselect);
s.integer(regs.serial.control.shiftclockfrequency);
s.integer(regs.serial.control.transferenablereceive);
s.integer(regs.serial.control.transferenablesend);
s.integer(regs.serial.control.startbit);
s.integer(regs.serial.control.transferlength);
s.integer(regs.serial.control.irqenable);
s.integer(regs.serial.data8);
for(auto &flag : regs.keypad.control.flag) s.integer(flag);
s.integer(regs.keypad.control.enable);
s.integer(regs.keypad.control.condition);
s.integer(regs.joybus.settings.sc);
s.integer(regs.joybus.settings.sd);
s.integer(regs.joybus.settings.si);
s.integer(regs.joybus.settings.so);
s.integer(regs.joybus.settings.scmode);
s.integer(regs.joybus.settings.sdmode);
s.integer(regs.joybus.settings.simode);
s.integer(regs.joybus.settings.somode);
s.integer(regs.joybus.settings.irqenable);
s.integer(regs.joybus.settings.mode);
s.integer(regs.joybus.control.resetsignal);
s.integer(regs.joybus.control.receivecomplete);
s.integer(regs.joybus.control.sendcomplete);
s.integer(regs.joybus.control.irqenable);
s.integer(regs.joybus.receive);
s.integer(regs.joybus.transmit);
s.integer(regs.joybus.status.receiveflag);
s.integer(regs.joybus.status.sendflag);
s.integer(regs.joybus.status.generalflag);
s.integer(regs.ime);
s.integer(regs.irq.enable.vblank);

View File

@ -72,8 +72,8 @@ void PPU::render_background_linear(Registers::Background &bg) {
uint8 color = data[px++ ^ (tile.hflip ? 7 : 0)];
if(color) {
if(bg.control.colormode == 0) output[x] = { true, false, bg.control.priority, pram[tile.palette * 16 + color] };
if(bg.control.colormode == 1) output[x] = { true, false, bg.control.priority, pram[color] };
if(bg.control.colormode == 0) output[x].write(true, bg.control.priority, pram[tile.palette * 16 + color]);
if(bg.control.colormode == 1) output[x].write(true, bg.control.priority, pram[color]);
}
}
}
@ -102,7 +102,7 @@ void PPU::render_background_affine(Registers::Background &bg) {
if(tx < screensize && ty < screensize) {
uint8 character = vram[basemap + ty * screensize + tx];
uint8 color = vram[basechr + (character * 64) + py * 8 + px];
if(color) output[x] = { true, false, bg.control.priority, pram[color] };
if(color) output[x].write(true, bg.control.priority, pram[color]);
}
fx += bg.pa;
@ -143,7 +143,7 @@ void PPU::render_background_bitmap(Registers::Background &bg) {
if(depth || color) { //8bpp color 0 is transparent; 15bpp color is always opaque
if(depth == 0) color = pram[color];
if(depth == 1) color = color & 0x7fff;
output[x] = { true, false, bg.control.priority, color };
output[x].write(true, bg.control.priority, color);
}
}

33
bsnes/gba/ppu/mosaic.cpp Executable file
View File

@ -0,0 +1,33 @@
void PPU::render_mosaic_background(unsigned id) {
if(regs.mosaic.bghsize == 0) return;
unsigned width = 1 + regs.mosaic.bghsize;
auto &buffer = layer[id];
for(unsigned x = 0; x < 240;) {
for(unsigned m = 1; m < width; m++) {
if(x + m >= 240) break;
buffer[x + m] = buffer[x];
}
x += width;
}
}
void PPU::render_mosaic_object() {
if(regs.mosaic.objhsize == 0) return;
unsigned width = 1 + regs.mosaic.objhsize;
auto &buffer = layer[OBJ];
Pixel mosaicPixel;
mosaicPixel.mosaic = false;
unsigned counter = 0;
for(unsigned x = 0; x < 240; x++) {
if(counter == width || mosaicPixel.mosaic == false) {
mosaicPixel = buffer[x];
if(counter == width) counter = 0;
} else {
if(buffer[x].mosaic) buffer[x] = mosaicPixel;
}
counter++;
}
}

View File

@ -52,10 +52,6 @@ void PPU::render_object(Object &obj) {
y = (fy >> 8) + centery;
}
if(obj.mosaic && regs.mosaic.objhsize) {
x = (x / (1 + regs.mosaic.objhsize)) * (1 + regs.mosaic.objhsize);
}
uint9 ox = obj.x + px;
if(ox < 240 && x < obj.width && y < obj.height) {
unsigned offset = (y / 8) * rowsize + (x / 8);
@ -68,7 +64,7 @@ void PPU::render_object(Object &obj) {
windowmask[Obj][ox] = true;
} else if(output[ox].enable == false || obj.priority < output[ox].priority) {
if(obj.colors == 0) color = obj.palette * 16 + color;
output[ox] = { true, obj.mode == 1, obj.priority, pram[256 + color] };
output[ox].write(true, obj.priority, pram[256 + color], obj.mode == 1, obj.mosaic);
}
}
}

View File

@ -15,6 +15,7 @@ namespace GBA {
#include "registers.cpp"
#include "background.cpp"
#include "object.cpp"
#include "mosaic.cpp"
#include "screen.cpp"
#include "mmio.cpp"
#include "memory.cpp"
@ -119,12 +120,12 @@ void PPU::scanline() {
windowmask[0][x] = false;
windowmask[1][x] = false;
windowmask[2][x] = false;
layer[OBJ][x].enable = false;
layer[BG0][x].enable = false;
layer[BG1][x].enable = false;
layer[BG2][x].enable = false;
layer[BG3][x].enable = false;
layer[SFX][x] = { true, false, 3, pram[0] };
layer[OBJ][x].write(false);
layer[BG0][x].write(false);
layer[BG1][x].write(false);
layer[BG2][x].write(false);
layer[BG3][x].write(false);
layer[SFX][x].write(true, 3, pram[0]);
}
render_window(0);
render_window(1);
@ -148,7 +149,6 @@ void PPU::scanline() {
}
void PPU::frame() {
interface->videoRefresh(output);
scheduler.exit(Scheduler::ExitReason::FrameEvent);
}

View File

@ -34,9 +34,11 @@ struct PPU : Thread, MMIO {
void render_objects();
void render_object(Object&);
void render_mosaic_background(unsigned id);
void render_mosaic_object();
void render_forceblank();
void render_screen();
void render_mosaic(unsigned id, unsigned width);
void render_window(unsigned window);
unsigned blend(unsigned above, unsigned eva, unsigned below, unsigned evb);

View File

@ -11,10 +11,11 @@ void PPU::render_screen() {
uint16 *line = output + regs.vcounter * 240;
uint16 *last = blur + regs.vcounter * 240;
if(regs.bg[0].control.mosaic) render_mosaic(BG0, regs.mosaic.bghsize);
if(regs.bg[1].control.mosaic) render_mosaic(BG1, regs.mosaic.bghsize);
if(regs.bg[2].control.mosaic) render_mosaic(BG2, regs.mosaic.bghsize);
if(regs.bg[3].control.mosaic) render_mosaic(BG3, regs.mosaic.bghsize);
if(regs.bg[0].control.mosaic) render_mosaic_background(BG0);
if(regs.bg[1].control.mosaic) render_mosaic_background(BG1);
if(regs.bg[2].control.mosaic) render_mosaic_background(BG2);
if(regs.bg[3].control.mosaic) render_mosaic_background(BG3);
render_mosaic_object();
for(unsigned x = 0; x < 240; x++) {
Registers::WindowFlags flags;
@ -63,19 +64,6 @@ void PPU::render_screen() {
}
}
void PPU::render_mosaic(unsigned id, unsigned width) {
if(++width == 1) return;
auto &buffer = layer[id];
for(unsigned x = 0; x < 240;) {
for(unsigned m = 1; m < width; m++) {
if(x + m >= 240) break;
buffer[x + m] = buffer[x];
}
x += width;
}
}
void PPU::render_window(unsigned w) {
unsigned y = regs.vcounter;

View File

@ -75,9 +75,10 @@ void PPU::serialize(serializer &s) {
for(unsigned p = 0; p < 240; p++) {
auto &pixel = layer[l][p];
s.integer(pixel.enable);
s.integer(pixel.translucent);
s.integer(pixel.priority);
s.integer(pixel.color);
s.integer(pixel.translucent);
s.integer(pixel.mosaic);
}
}

View File

@ -1,8 +1,15 @@
struct Pixel {
bool enable;
bool translucent;
unsigned priority;
unsigned color;
//objects only
bool translucent;
bool mosaic;
alwaysinline void write(bool e) { enable = e; }
alwaysinline void write(bool e, unsigned p, unsigned c) { enable = e; priority = p; color = c; }
alwaysinline void write(bool e, unsigned p, unsigned c, bool t, bool m) { enable = e; priority = p; color = c; translucent = t; mosaic = m; }
} layer[6][240];
bool windowmask[3][240];

View File

@ -1,12 +1,3 @@
void BIOS::load(const uint8 *biosdata, unsigned biossize) {
memcpy(data, biosdata, min(size, biossize));
string sha256 = nall::sha256(data, size);
if(sha256 != "fd2547724b505f487e6dcb29ec2ecff3af35a841a77ab2e85fd87350abd36570") {
interface->message("Warning: Game Boy Advance BIOS SHA256 sum is incorrect.");
}
}
uint32 BIOS::read(uint32 addr, uint32 size) {
//GBA BIOS is read-protected; only the BIOS itself can read its own memory
//when accessed elsewhere; this returns the last value read by the BIOS program

View File

@ -27,7 +27,11 @@ void System::load() {
}
void System::run() {
while(true) {
scheduler.enter();
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) break;
}
interface->videoRefresh(ppu.output);
}
void System::runtosave() {
@ -49,7 +53,7 @@ void System::runthreadtosave() {
while(true) {
scheduler.enter();
if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break;
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent);
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) interface->videoRefresh(ppu.output);
}
}

View File

@ -7,7 +7,6 @@ struct BIOS : Memory {
unsigned size;
uint32 mdr;
void load(const uint8 *data, unsigned size);
uint32 read(uint32 addr, uint32 size);
void write(uint32 addr, uint32 size, uint32 word);

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<cartridge region="NTSC">
<bsx>
<mcu>
<map address="00-3f:8000-ffff"/>
<map address="80-bf:8000-ffff"/>
<map address="40-7f:0000-ffff"/>
<map address="c0-ff:0000-ffff"/>
<map address="20-3f:6000-7fff"/>
</mcu>
<mmio>
<map address="00-3f:5000-5fff"/>
<map address="80-bf:5000-5fff"/>
</mmio>
</bsx>
</cartridge>

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<system type="NES">
</system>

Binary file not shown.

View File

@ -0,0 +1,4 @@
<?xml version='1.0' encoding='UTF-8'?>
<system type="GBC">
<boot firmware="boot.rom" sha256="4bf5021be357ce523a59ac5f4efff5d6371ae50112a6db0adf4a75916ad760a9"/>
</system>

Binary file not shown.

View File

@ -0,0 +1,4 @@
<?xml version='1.0' encoding='UTF-8'?>
<system type="GB">
<boot firmware="boot.rom" sha256="cf053eccb4ccafff9e67339d4e78e98dce7d1ed59be819d2a1ba2232c6fce1c7"/>
</system>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<cartridge region="NTSC">
<rom>
<map mode="linear" address="00-1f:8000-ffff"/>
<map mode="linear" address="80-9f:8000-ffff"/>
</rom>
<sufamiturbo>
<slot id="A">
<rom>
<map mode="linear" address="20-3f:8000-ffff"/>
<map mode="linear" address="a0-bf:8000-ffff"/>
</rom>
<ram size="131072">
<map mode="linear" address="60-63:8000-ffff"/>
<map mode="linear" address="e0-e3:8000-ffff"/>
</ram>
</slot>
<slot id="B">
<rom>
<map mode="linear" address="40-5f:8000-ffff"/>
<map mode="linear" address="c0-df:8000-ffff"/>
</rom>
<ram size="131072">
<map mode="linear" address="70-73:8000-ffff"/>
<map mode="linear" address="f0-f3:8000-ffff"/>
</ram>
</slot>
</sufamiturbo>
</cartridge>

View File

@ -0,0 +1,4 @@
<?xml version='1.0' encoding='UTF-8'?>
<system type="SNES">
<smp firmware="spc700.rom" sha256="c95f88b299030d5afa55b1031e2b5ef2dff650c4b4e6bb6f8b1359436521278f"/>
</system>

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<cartridge region="NTSC">
<boot firmware="boot.rom" sha256="0e4ddff32fc9d1eeaae812a157dd246459b00c9e14f2f61751f661f32361e360"/>
<rom>
<map mode="linear" address="00-7f:8000-ffff"/>
<map mode="linear" address="80-ff:8000-ffff"/>
</rom>
<icd2 revision="1">
<map address="00-3f:6000-7fff"/>
<map address="80-bf:6000-7fff"/>
</icd2>
</cartridge>

View File

@ -1,44 +0,0 @@
#ifdef SMP_CPP
//this is the IPLROM for the S-SMP coprocessor.
//the S-SMP does not allow writing to the IPLROM.
//all writes are instead mapped to the extended
//RAM region, accessible when $f1.d7 is clear.
const uint8 SMP::iplrom[64] = {
/*ffc0*/ 0xcd, 0xef, //mov x,#$ef
/*ffc2*/ 0xbd, //mov sp,x
/*ffc3*/ 0xe8, 0x00, //mov a,#$00
/*ffc5*/ 0xc6, //mov (x),a
/*ffc6*/ 0x1d, //dec x
/*ffc7*/ 0xd0, 0xfc, //bne $ffc5
/*ffc9*/ 0x8f, 0xaa, 0xf4, //mov $f4,#$aa
/*ffcc*/ 0x8f, 0xbb, 0xf5, //mov $f5,#$bb
/*ffcf*/ 0x78, 0xcc, 0xf4, //cmp $f4,#$cc
/*ffd2*/ 0xd0, 0xfb, //bne $ffcf
/*ffd4*/ 0x2f, 0x19, //bra $ffef
/*ffd6*/ 0xeb, 0xf4, //mov y,$f4
/*ffd8*/ 0xd0, 0xfc, //bne $ffd6
/*ffda*/ 0x7e, 0xf4, //cmp y,$f4
/*ffdc*/ 0xd0, 0x0b, //bne $ffe9
/*ffde*/ 0xe4, 0xf5, //mov a,$f5
/*ffe0*/ 0xcb, 0xf4, //mov $f4,y
/*ffe2*/ 0xd7, 0x00, //mov ($00)+y,a
/*ffe4*/ 0xfc, //inc y
/*ffe5*/ 0xd0, 0xf3, //bne $ffda
/*ffe7*/ 0xab, 0x01, //inc $01
/*ffe9*/ 0x10, 0xef, //bpl $ffda
/*ffeb*/ 0x7e, 0xf4, //cmp y,$f4
/*ffed*/ 0x10, 0xeb, //bpl $ffda
/*ffef*/ 0xba, 0xf6, //movw ya,$f6
/*fff1*/ 0xda, 0x00, //movw $00,ya
/*fff3*/ 0xba, 0xf4, //movw ya,$f4
/*fff5*/ 0xc4, 0xf4, //mov $f4,a
/*fff7*/ 0xdd, //mov a,y
/*fff8*/ 0x5d, //mov x,a
/*fff9*/ 0xd0, 0xdb, //bne $ffd6
/*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x)
/*fffe*/ 0xc0, 0xff //reset vector location ($ffc0)
};
#endif

View File

@ -9,7 +9,6 @@ SMP smp;
#include "algorithms.cpp"
#include "core.cpp"
#include "iplrom.cpp"
#include "memory.cpp"
#include "timing.cpp"
@ -140,6 +139,7 @@ void SMP::serialize(serializer &s) {
SMP::SMP() {
apuram = new uint8[64 * 1024];
for(auto &byte : iplrom) byte = 0;
}
SMP::~SMP() {

View File

@ -1,5 +1,5 @@
struct SMP : Thread {
static const uint8 iplrom[64];
uint8 iplrom[64];
uint8 *apuram;
enum : bool { Threaded = false };

View File

@ -1,44 +0,0 @@
#ifdef SMP_CPP
//this is the IPLROM for the S-SMP coprocessor.
//the S-SMP does not allow writing to the IPLROM.
//all writes are instead mapped to the extended
//RAM region, accessible when $f1.d7 is clear.
const uint8 SMP::iplrom[64] = {
/*ffc0*/ 0xcd, 0xef, //mov x,#$ef
/*ffc2*/ 0xbd, //mov sp,x
/*ffc3*/ 0xe8, 0x00, //mov a,#$00
/*ffc5*/ 0xc6, //mov (x),a
/*ffc6*/ 0x1d, //dec x
/*ffc7*/ 0xd0, 0xfc, //bne $ffc5
/*ffc9*/ 0x8f, 0xaa, 0xf4, //mov $f4,#$aa
/*ffcc*/ 0x8f, 0xbb, 0xf5, //mov $f5,#$bb
/*ffcf*/ 0x78, 0xcc, 0xf4, //cmp $f4,#$cc
/*ffd2*/ 0xd0, 0xfb, //bne $ffcf
/*ffd4*/ 0x2f, 0x19, //bra $ffef
/*ffd6*/ 0xeb, 0xf4, //mov y,$f4
/*ffd8*/ 0xd0, 0xfc, //bne $ffd6
/*ffda*/ 0x7e, 0xf4, //cmp y,$f4
/*ffdc*/ 0xd0, 0x0b, //bne $ffe9
/*ffde*/ 0xe4, 0xf5, //mov a,$f5
/*ffe0*/ 0xcb, 0xf4, //mov $f4,y
/*ffe2*/ 0xd7, 0x00, //mov ($00)+y,a
/*ffe4*/ 0xfc, //inc y
/*ffe5*/ 0xd0, 0xf3, //bne $ffda
/*ffe7*/ 0xab, 0x01, //inc $01
/*ffe9*/ 0x10, 0xef, //bpl $ffda
/*ffeb*/ 0x7e, 0xf4, //cmp y,$f4
/*ffed*/ 0x10, 0xeb, //bpl $ffda
/*ffef*/ 0xba, 0xf6, //movw ya,$f6
/*fff1*/ 0xda, 0x00, //movw $00,ya
/*fff3*/ 0xba, 0xf4, //movw ya,$f4
/*fff5*/ 0xc4, 0xf4, //mov $f4,a
/*fff7*/ 0xdd, //mov a,y
/*fff8*/ 0x5d, //mov x,a
/*fff9*/ 0xd0, 0xdb, //bne $ffd6
/*fffb*/ 0x1f, 0x00, 0x00, //jmp ($0000+x)
/*fffe*/ 0xc0, 0xff //reset vector location ($ffc0)
};
#endif

View File

@ -6,7 +6,6 @@ namespace SNES {
SMP smp;
#include "serialization.cpp"
#include "iplrom.cpp"
#include "memory/memory.cpp"
#include "timing/timing.cpp"
@ -115,6 +114,7 @@ void SMP::reset() {
}
SMP::SMP() {
for(auto &byte : iplrom) byte = 0;
}
SMP::~SMP() {

View File

@ -1,5 +1,5 @@
struct SMP : Thread, public SMPcore {
static const uint8 iplrom[64];
uint8 iplrom[64];
uint8 apuram[64 * 1024];
enum : bool { Threaded = true };

View File

@ -1,48 +0,0 @@
processor := arm hg51b
include processor/Makefile
include $(snes)/Makefile
include $(gb)/Makefile
output := libsnes
ifeq ($(platform),x)
flags += -fPIC
else ifeq ($(platform),osx)
flags += -fPIC
else ifeq ($(platform),win)
endif
#rules
objects := $(objects) libsnes
objects := $(patsubst %,obj/%.o,$(objects))
obj/libsnes.o: $(ui)/libsnes.cpp $(ui)/*
#targets
build: $(objects)
ifeq ($(platform),x)
ar rcs out/libsnes.a $(objects)
$(cpp) -o out/libsnes.so -shared -Wl,-soname,libsnes.so.1 $(objects)
else ifeq ($(platform),osx)
ar rcs out/libsnes.a $(objects)
$(cpp) -o out/libsnes.dylib -install_name @executable_path/../Libraries/libsnes.dylib -shared -dynamiclib $(objects)
else ifeq ($(platform),win)
$(cpp) -o out/snes.dll -shared -Wl,--out-implib,libsnes.a $(objects)
endif
install:
ifeq ($(platform),x)
install -D -m 755 out/libsnes.a $(DESTDIR)$(prefix)/lib/libsnes.a
install -D -m 755 out/libsnes.so $(DESTDIR)$(prefix)/lib/libsnes.so
ldconfig -n $(DESTDIR)$(prefix)/lib
else ifeq ($(platform),osx)
cp out/libsnes.dylib /usr/local/lib/libsnes.dylib
endif
uninstall:
ifeq ($(platform),x)
rm $(DESTDIR)$(prefix)/lib/libsnes.a
rm $(DESTDIR)$(prefix)/lib/libsnes.so
else ifeq ($(platform),osx)
rm /usr/local/lib/libsnes.dylib
endif

View File

@ -1,395 +0,0 @@
#include "libsnes.hpp"
#include <snes/snes.hpp>
#include <nall/snes/cartridge.hpp>
#include <nall/gameboy/cartridge.hpp>
using namespace nall;
struct Interface : public SNES::Interface {
snes_video_refresh_t pvideo_refresh;
snes_audio_sample_t paudio_sample;
snes_input_poll_t pinput_poll;
snes_input_state_t pinput_state;
string basename;
uint16_t *buffer;
uint32_t *palette;
void videoRefresh(const uint32_t *data, bool hires, bool interlace, bool overscan) {
unsigned width = hires ? 512 : 256;
unsigned height = overscan ? 239 : 224;
unsigned pitch = 1024 >> interlace;
if(interlace) height <<= 1;
data += 9 * 1024; //skip front porch
for(unsigned y = 0; y < height; y++) {
const uint32_t *sp = data + y * pitch;
uint16_t *dp = buffer + y * pitch;
for(unsigned x = 0; x < width; x++) {
*dp++ = palette[*sp++];
}
}
if(pvideo_refresh) pvideo_refresh(buffer, width, height);
if(pinput_poll) pinput_poll();
}
void audioSample(int16_t left, int16_t right) {
if(paudio_sample) return paudio_sample(left, right);
}
int16_t inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id) {
if(pinput_state) return pinput_state(port, (unsigned)device, index, id);
return 0;
}
void message(const string &text) {
print(text, "\n");
}
string path(SNES::Cartridge::Slot slot, const string &hint) {
return { basename, hint };
}
Interface() : pvideo_refresh(0), paudio_sample(0), pinput_poll(0), pinput_state(0) {
buffer = new uint16_t[512 * 480];
palette = new uint32_t[16 * 32768];
//{llll bbbbb ggggg rrrrr} -> { rrrrr ggggg bbbbb }
for(unsigned l = 0; l < 16; l++) {
for(unsigned r = 0; r < 32; r++) {
for(unsigned g = 0; g < 32; g++) {
for(unsigned b = 0; b < 32; b++) {
double luma = (double)l / 15.0;
unsigned ar = (luma * r + 0.5);
unsigned ag = (luma * g + 0.5);
unsigned ab = (luma * b + 0.5);
palette[(l << 15) + (r << 10) + (g << 5) + (b << 0)] = (ab << 10) + (ag << 5) + (ar << 0);
}
}
}
}
}
~Interface() {
delete[] buffer;
delete[] palette;
}
};
static Interface interface;
const char* snes_library_id(void) {
static string version = {"bsnes v", Version};
return version;
}
unsigned snes_library_revision_major(void) {
return 1;
}
unsigned snes_library_revision_minor(void) {
return 3;
}
void snes_set_video_refresh(snes_video_refresh_t video_refresh) {
interface.pvideo_refresh = video_refresh;
}
void snes_set_audio_sample(snes_audio_sample_t audio_sample) {
interface.paudio_sample = audio_sample;
}
void snes_set_input_poll(snes_input_poll_t input_poll) {
interface.pinput_poll = input_poll;
}
void snes_set_input_state(snes_input_state_t input_state) {
interface.pinput_state = input_state;
}
void snes_set_controller_port_device(bool port, unsigned device) {
SNES::input.connect(port, (SNES::Input::Device)device);
}
void snes_set_cartridge_basename(const char *basename) {
interface.basename = basename;
}
void snes_init(void) {
SNES::interface = &interface;
SNES::system.init();
SNES::input.connect(SNES::Controller::Port1, SNES::Input::Device::Joypad);
SNES::input.connect(SNES::Controller::Port2, SNES::Input::Device::Joypad);
}
void snes_term(void) {
SNES::system.term();
}
void snes_power(void) {
SNES::system.power();
}
void snes_reset(void) {
SNES::system.reset();
}
void snes_run(void) {
SNES::system.run();
}
unsigned snes_serialize_size(void) {
return SNES::system.serialize_size();
}
bool snes_serialize(uint8_t *data, unsigned size) {
SNES::system.runtosave();
serializer s = SNES::system.serialize();
if(s.size() > size) return false;
memcpy(data, s.data(), s.size());
return true;
}
bool snes_unserialize(const uint8_t *data, unsigned size) {
serializer s(data, size);
return SNES::system.unserialize(s);
}
struct CheatList {
bool enable;
string code;
CheatList() : enable(false) {}
};
static linear_vector<CheatList> cheatList;
void snes_cheat_reset(void) {
cheatList.reset();
GameBoy::cheat.reset();
GameBoy::cheat.synchronize();
SNES::cheat.reset();
SNES::cheat.synchronize();
}
void snes_cheat_set(unsigned index, bool enable, const char *code) {
cheatList[index].enable = enable;
cheatList[index].code = code;
lstring list;
for(unsigned n = 0; n < cheatList.size(); n++) {
if(cheatList[n].enable) list.append(cheatList[n].code);
}
if(SNES::cartridge.mode() == SNES::Cartridge::Mode::SuperGameBoy) {
GameBoy::cheat.reset();
for(auto &code : list) {
lstring codelist;
codelist.split("+", code);
for(auto &part : codelist) {
unsigned addr, data, comp;
if(GameBoy::Cheat::decode(part, addr, data, comp)) {
GameBoy::cheat.append({ addr, data, comp });
}
}
}
GameBoy::cheat.synchronize();
return;
}
SNES::cheat.reset();
for(auto &code : list) {
lstring codelist;
codelist.split("+", code);
for(auto &part : codelist) {
unsigned addr, data;
if(SNES::Cheat::decode(part, addr, data)) {
SNES::cheat.append({ addr, data });
}
}
}
SNES::cheat.synchronize();
}
bool snes_load_cartridge_normal(
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size
) {
snes_cheat_reset();
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup;
SNES::cartridge.load(SNES::Cartridge::Mode::Normal, { xmlrom });
SNES::system.power();
return true;
}
bool snes_load_cartridge_bsx_slotted(
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size
) {
snes_cheat_reset();
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup;
if(bsx_data) SNES::bsxflash.memory.copy(bsx_data, bsx_size);
string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SnesCartridge(bsx_data, bsx_size).markup;
SNES::cartridge.load(SNES::Cartridge::Mode::BsxSlotted, xmlrom);
SNES::system.power();
return true;
}
bool snes_load_cartridge_bsx(
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size
) {
snes_cheat_reset();
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup;
if(bsx_data) SNES::bsxflash.memory.copy(bsx_data, bsx_size);
string xmlbsx = (bsx_xml && *bsx_xml) ? string(bsx_xml) : SnesCartridge(bsx_data, bsx_size).markup;
SNES::cartridge.load(SNES::Cartridge::Mode::Bsx, xmlrom);
SNES::system.power();
return true;
}
bool snes_load_cartridge_sufami_turbo(
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
const char *sta_xml, const uint8_t *sta_data, unsigned sta_size,
const char *stb_xml, const uint8_t *stb_data, unsigned stb_size
) {
snes_cheat_reset();
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup;
if(sta_data) SNES::sufamiturbo.slotA.rom.copy(sta_data, sta_size);
string xmlsta = (sta_xml && *sta_xml) ? string(sta_xml) : SnesCartridge(sta_data, sta_size).markup;
if(stb_data) SNES::sufamiturbo.slotB.rom.copy(stb_data, stb_size);
string xmlstb = (stb_xml && *stb_xml) ? string(stb_xml) : SnesCartridge(stb_data, stb_size).markup;
SNES::cartridge.load(SNES::Cartridge::Mode::SufamiTurbo, xmlrom);
SNES::system.power();
return true;
}
bool snes_load_cartridge_super_game_boy(
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
const char *dmg_xml, const uint8_t *dmg_data, unsigned dmg_size
) {
snes_cheat_reset();
if(rom_data) SNES::cartridge.rom.copy(rom_data, rom_size);
string xmlrom = (rom_xml && *rom_xml) ? string(rom_xml) : SnesCartridge(rom_data, rom_size).markup;
if(dmg_data) {
//GameBoyCartridge needs to modify dmg_data (for MMM01 emulation); so copy data
uint8_t *data = new uint8_t[dmg_size];
memcpy(data, dmg_data, dmg_size);
string xmldmg = (dmg_xml && *dmg_xml) ? string(dmg_xml) : GameBoyCartridge(data, dmg_size).markup;
GameBoy::cartridge.load(GameBoy::System::Revision::SuperGameBoy, xmldmg, data, dmg_size);
delete[] data;
}
SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, xmlrom);
SNES::system.power();
return true;
}
void snes_unload_cartridge(void) {
SNES::cartridge.unload();
}
bool snes_get_region(void) {
return SNES::system.region() == SNES::System::Region::NTSC ? 0 : 1;
}
uint8_t* snes_get_memory_data(unsigned id) {
if(SNES::cartridge.loaded() == false) return 0;
switch(id) {
case SNES_MEMORY_CARTRIDGE_RAM:
return SNES::cartridge.ram.data();
case SNES_MEMORY_CARTRIDGE_RTC:
if(SNES::cartridge.has_srtc()) return SNES::srtc.rtc;
if(SNES::cartridge.has_spc7110rtc()) return SNES::spc7110.rtc;
return 0;
case SNES_MEMORY_BSX_RAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
return SNES::bsxcartridge.sram.data();
case SNES_MEMORY_BSX_PRAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
return SNES::bsxcartridge.psram.data();
case SNES_MEMORY_SUFAMI_TURBO_A_RAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
return SNES::sufamiturbo.slotA.ram.data();
case SNES_MEMORY_SUFAMI_TURBO_B_RAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
return SNES::sufamiturbo.slotB.ram.data();
case SNES_MEMORY_GAME_BOY_RAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
return GameBoy::cartridge.ramdata;
//case SNES_MEMORY_GAME_BOY_RTC:
// if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
// return GameBoy::cartridge.rtcdata;
case SNES_MEMORY_WRAM:
return SNES::cpu.wram;
case SNES_MEMORY_APURAM:
return SNES::smp.apuram;
case SNES_MEMORY_VRAM:
return SNES::ppu.vram;
case SNES_MEMORY_OAM:
return SNES::ppu.oam;
case SNES_MEMORY_CGRAM:
return SNES::ppu.cgram;
}
return 0;
}
unsigned snes_get_memory_size(unsigned id) {
if(SNES::cartridge.loaded() == false) return 0;
unsigned size = 0;
switch(id) {
case SNES_MEMORY_CARTRIDGE_RAM:
size = SNES::cartridge.ram.size();
break;
case SNES_MEMORY_CARTRIDGE_RTC:
if(SNES::cartridge.has_srtc() || SNES::cartridge.has_spc7110rtc()) size = 20;
break;
case SNES_MEMORY_BSX_RAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
size = SNES::bsxcartridge.sram.size();
break;
case SNES_MEMORY_BSX_PRAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::Bsx) break;
size = SNES::bsxcartridge.psram.size();
break;
case SNES_MEMORY_SUFAMI_TURBO_A_RAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
size = SNES::sufamiturbo.slotA.ram.size();
break;
case SNES_MEMORY_SUFAMI_TURBO_B_RAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SufamiTurbo) break;
size = SNES::sufamiturbo.slotB.ram.size();
break;
case SNES_MEMORY_GAME_BOY_RAM:
if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
size = GameBoy::cartridge.ramsize;
break;
//case SNES_MEMORY_GAME_BOY_RTC:
// if(SNES::cartridge.mode() != SNES::Cartridge::Mode::SuperGameBoy) break;
// size = GameBoy::cartridge.rtcsize;
// break;
case SNES_MEMORY_WRAM:
size = 128 * 1024;
break;
case SNES_MEMORY_APURAM:
size = 64 * 1024;
break;
case SNES_MEMORY_VRAM:
size = 64 * 1024;
break;
case SNES_MEMORY_OAM:
size = 544;
break;
case SNES_MEMORY_CGRAM:
size = 512;
break;
}
if(size == -1U) size = 0;
return size;
}

View File

@ -1,135 +0,0 @@
#ifndef LIBSNES_HPP
#define LIBSNES_HPP
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SNES_PORT_1 0
#define SNES_PORT_2 1
#define SNES_DEVICE_NONE 0
#define SNES_DEVICE_JOYPAD 1
#define SNES_DEVICE_MULTITAP 2
#define SNES_DEVICE_MOUSE 3
#define SNES_DEVICE_SUPER_SCOPE 4
#define SNES_DEVICE_JUSTIFIER 5
#define SNES_DEVICE_JUSTIFIERS 6
#define SNES_DEVICE_SERIAL_CABLE 7
#define SNES_DEVICE_ID_JOYPAD_B 0
#define SNES_DEVICE_ID_JOYPAD_Y 1
#define SNES_DEVICE_ID_JOYPAD_SELECT 2
#define SNES_DEVICE_ID_JOYPAD_START 3
#define SNES_DEVICE_ID_JOYPAD_UP 4
#define SNES_DEVICE_ID_JOYPAD_DOWN 5
#define SNES_DEVICE_ID_JOYPAD_LEFT 6
#define SNES_DEVICE_ID_JOYPAD_RIGHT 7
#define SNES_DEVICE_ID_JOYPAD_A 8
#define SNES_DEVICE_ID_JOYPAD_X 9
#define SNES_DEVICE_ID_JOYPAD_L 10
#define SNES_DEVICE_ID_JOYPAD_R 11
#define SNES_DEVICE_ID_MOUSE_X 0
#define SNES_DEVICE_ID_MOUSE_Y 1
#define SNES_DEVICE_ID_MOUSE_LEFT 2
#define SNES_DEVICE_ID_MOUSE_RIGHT 3
#define SNES_DEVICE_ID_SUPER_SCOPE_X 0
#define SNES_DEVICE_ID_SUPER_SCOPE_Y 1
#define SNES_DEVICE_ID_SUPER_SCOPE_TRIGGER 2
#define SNES_DEVICE_ID_SUPER_SCOPE_CURSOR 3
#define SNES_DEVICE_ID_SUPER_SCOPE_TURBO 4
#define SNES_DEVICE_ID_SUPER_SCOPE_PAUSE 5
#define SNES_DEVICE_ID_JUSTIFIER_X 0
#define SNES_DEVICE_ID_JUSTIFIER_Y 1
#define SNES_DEVICE_ID_JUSTIFIER_TRIGGER 2
#define SNES_DEVICE_ID_JUSTIFIER_START 3
#define SNES_REGION_NTSC 0
#define SNES_REGION_PAL 1
#define SNES_MEMORY_CARTRIDGE_RAM 0
#define SNES_MEMORY_CARTRIDGE_RTC 1
#define SNES_MEMORY_BSX_RAM 2
#define SNES_MEMORY_BSX_PRAM 3
#define SNES_MEMORY_SUFAMI_TURBO_A_RAM 4
#define SNES_MEMORY_SUFAMI_TURBO_B_RAM 5
#define SNES_MEMORY_GAME_BOY_RAM 6
#define SNES_MEMORY_GAME_BOY_RTC 7
#define SNES_MEMORY_WRAM 100
#define SNES_MEMORY_APURAM 101
#define SNES_MEMORY_VRAM 102
#define SNES_MEMORY_OAM 103
#define SNES_MEMORY_CGRAM 104
typedef void (*snes_video_refresh_t)(const uint16_t *data, unsigned width, unsigned height);
typedef void (*snes_audio_sample_t)(uint16_t left, uint16_t right);
typedef void (*snes_input_poll_t)(void);
typedef int16_t (*snes_input_state_t)(bool port, unsigned device, unsigned index, unsigned id);
const char* snes_library_id(void);
unsigned snes_library_revision_major(void);
unsigned snes_library_revision_minor(void);
void snes_set_video_refresh(snes_video_refresh_t);
void snes_set_audio_sample(snes_audio_sample_t);
void snes_set_input_poll(snes_input_poll_t);
void snes_set_input_state(snes_input_state_t);
void snes_set_controller_port_device(bool port, unsigned device);
void snes_set_cartridge_basename(const char *basename);
void snes_init(void);
void snes_term(void);
void snes_power(void);
void snes_reset(void);
void snes_run(void);
unsigned snes_serialize_size(void);
bool snes_serialize(uint8_t *data, unsigned size);
bool snes_unserialize(const uint8_t *data, unsigned size);
void snes_cheat_reset(void);
void snes_cheat_set(unsigned index, bool enable, const char *code);
bool snes_load_cartridge_normal(
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size
);
bool snes_load_cartridge_bsx_slotted(
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size
);
bool snes_load_cartridge_bsx(
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
const char *bsx_xml, const uint8_t *bsx_data, unsigned bsx_size
);
bool snes_load_cartridge_sufami_turbo(
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
const char *sta_xml, const uint8_t *sta_data, unsigned sta_size,
const char *stb_xml, const uint8_t *stb_data, unsigned stb_size
);
bool snes_load_cartridge_super_game_boy(
const char *rom_xml, const uint8_t *rom_data, unsigned rom_size,
const char *dmg_xml, const uint8_t *dmg_data, unsigned dmg_size
);
void snes_unload_cartridge(void);
bool snes_get_region(void);
uint8_t* snes_get_memory_data(unsigned id);
unsigned snes_get_memory_size(unsigned id);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -78,8 +78,8 @@ else ifeq ($(platform),x)
sudo install -D -m 644 data/$(name).desktop $(DESTDIR)$(prefix)/share/applications/$(name).desktop
mkdir -p ~/.config/$(name)
cp -R profile/* ~/.config/$(name)
cp data/cheats.xml ~/.config/$(name)/cheats.xml
cp -R "data/Game Boy Advance.system" ~/.config/$(name)
chmod -R 777 ~/.config/$(name)
endif

View File

@ -7,13 +7,13 @@ MainWindow::MainWindow() {
windowManager->append(this, "MainWindow");
cartridgeMenu.setText("&Cartridge");
cartridgeLoadSNES.setText("Load &SNES Cartridge ...");
cartridgeLoadNES.setText("Load &NES Cartridge ...");
cartridgeLoadNES.setText("Load &Famicom Cartridge ...");
cartridgeLoadSNES.setText("Load &Super Famicom Cartridge ...");
cartridgeLoadGameBoy.setText("Load &Game Boy Cartridge ...");
cartridgeLoadGameBoyColor.setText("Load Game Boy &Color Cartridge ...");
cartridgeLoadGameBoyAdvance.setText("Load Game Boy &Advance Cartridge ...");
cartridgeLoadSatellaviewSlotted.setText("Load Satellaview-Slotted Cartridge ...");
cartridgeLoadSatellaview.setText("Load Satellaview Cartridge ...");
cartridgeLoadSatellaview.setText("Load BS-X Satellaview Cartridge ...");
cartridgeLoadSufamiTurbo.setText("Load Sufami Turbo Cartridge ...");
cartridgeLoadSuperGameBoy.setText("Load Super Game Boy Cartridge ...");
@ -203,13 +203,13 @@ MainWindow::MainWindow() {
onSize = [&] { utility->resizeMainWindow(); };
cartridgeLoadNES.onActivate = [&] {
fileBrowser->open("Load Cartridge - NES", FileBrowser::Mode::NES, [](string filename) {
fileBrowser->open("Load Cartridge - Famicom", FileBrowser::Mode::NES, [](string filename) {
interface->nes.loadCartridge(filename);
});
};
cartridgeLoadSNES.onActivate = [&] {
fileBrowser->open("Load Cartridge - SNES", FileBrowser::Mode::SNES, [](string filename) {
fileBrowser->open("Load Cartridge - Super Famicom", FileBrowser::Mode::SNES, [](string filename) {
interface->snes.loadCartridge(filename);
});
};
@ -233,9 +233,24 @@ MainWindow::MainWindow() {
};
cartridgeLoadSatellaviewSlotted.onActivate = [&] { slotLoader->loadSatellaviewSlotted(); };
cartridgeLoadSatellaview.onActivate = [&] { slotLoader->loadSatellaview(); };
cartridgeLoadSufamiTurbo.onActivate = [&] { slotLoader->loadSufamiTurbo(); };
cartridgeLoadSuperGameBoy.onActivate = [&] { slotLoader->loadSuperGameBoy(); };
cartridgeLoadSatellaview.onActivate = [&] {
fileBrowser->open("Load Cartridge - BS-X Satellaview", FileBrowser::Mode::Satellaview, [](string filename) {
interface->snes.loadSatellaviewCartridge(application->path("BS-X Satellaview.sfc/"), filename);
});
};
cartridgeLoadSufamiTurbo.onActivate = [&] {
fileBrowser->open("Load Cartridge - Sufami Turbo", FileBrowser::Mode::SufamiTurbo, [](string filename) {
interface->snes.loadSufamiTurboCartridge(application->path("Sufami Turbo.sfc/"), filename, "");
});
};
cartridgeLoadSuperGameBoy.onActivate = [&] {
fileBrowser->open("Load Cartridge - Super Game Boy", FileBrowser::Mode::GameBoy, [](string filename) {
interface->snes.loadSuperGameBoyCartridge(application->path("Super Game Boy.sfc/"), filename);
});
};
nesPower.onActivate = { &Interface::power, interface };
nesReset.onActivate = { &Interface::reset, interface };

View File

@ -55,6 +55,6 @@ NesPort2Input::NesPort2Input() {
//
NesInput::NesInput() {
name = "NES";
name = "Famicom";
append(port1, port2);
}

View File

@ -179,6 +179,6 @@ justifier2("Justifier - Port 2", false)
//
SnesInput::SnesInput() {
name = "SNES";
name = "Super Famicom";
append(port1, port2);
}

View File

@ -0,0 +1,26 @@
bool InterfaceCore::loadFirmware(string filename, string keyname, uint8_t *targetdata, unsigned targetsize) {
filename = application->path(filename);
string markup;
markup.readfile(filename);
XML::Document document(markup);
lstring keypart = keyname.split<1>(".");
if(document[keypart[0]][keypart[1]].exists()) {
auto &key = document[keypart[0]][keypart[1]];
string firmware = key["firmware"].data;
string hash = key["sha256"].data;
uint8_t *data;
unsigned size;
if(file::read({dir(filename),firmware}, data, size) == true) {
if(nall::sha256(data, size) == hash) {
memcpy(targetdata, data, min(targetsize, size));
return true;
} else {
MessageWindow::information(Window::None, {"Warning: Firmware SHA256 sum is incorrect:\n\n", dir(filename), firmware});
}
}
}
return false;
}

View File

@ -1,4 +1,8 @@
void InterfaceGB::initialize() {
loadFirmware("Game Boy.sys/manifest.xml", "system.boot", GB::system.bootROM.dmg, 256u);
loadFirmware("Super Game Boy.sfc/manifest.xml", "cartridge.boot", GB::system.bootROM.sgb, 256u);
loadFirmware("Game Boy Color.sys/manifest.xml", "system.boot", GB::system.bootROM.cgb, 2048u);
GB::interface = this;
GB::system.init();
}

View File

@ -1,24 +1,5 @@
void InterfaceGBA::initialize() {
string filename = application->path("Game Boy Advance.system/manifest.xml");
string markup;
markup.readfile(filename);
XML::Document document(markup);
if(document["system"]["bios"].exists()) {
auto &bios = document["system"]["bios"];
string firmware = bios["firmware"].data;
string hash = bios["sha256"].data;
uint8_t *data;
unsigned size;
if(file::read({dir(filename),firmware}, data, size) == true) {
if(nall::sha256(data, size) == hash) {
GBA::bios.load(data, size);
} else {
MessageWindow::information(Window::None, "Warning: GBA BIOS SHA256 sum is incorrect.");
}
}
}
loadFirmware("Game Boy Advance.sys/manifest.xml", "system.bios", GBA::bios.data, 16384u);
GBA::interface = this;
GBA::system.init();
@ -39,7 +20,7 @@ bool InterfaceGBA::loadCartridge(const string &filename) {
interface->base = {true, filename};
} else {
if(file::read(filename, data, size) == false) return false;
interface->base = {false, filename};
interface->base = {false, nall::basename(filename)};
}
interface->game = interface->base;

View File

@ -1,4 +1,5 @@
#include "../base.hpp"
#include "core.cpp"
#include "palette.cpp"
#include "nes/nes.cpp"
#include "snes/snes.cpp"

View File

@ -1,6 +1,8 @@
#include "palette.hpp"
struct InterfaceCore {
bool loadFirmware(string filename, string keyname, uint8_t *targetdata, unsigned targetsize);
virtual bool cartridgeLoaded() = 0;
virtual void unloadCartridge() = 0;

View File

@ -1,4 +1,6 @@
void InterfaceSNES::initialize() {
loadFirmware("Super Famicom.sys/manifest.xml", "system.smp", SNES::smp.iplrom, 64u);
SNES::interface = this;
SNES::system.init();
}

View File

@ -53,12 +53,12 @@ AudioSettings::AudioSettings() {
frequencyAdjustmentLabel.setFont(application->boldFont);
frequencyAdjustmentLabel.setText("Frequency: (lower to reduce audio crackling; raise to reduce video tearing)");
nes.name.setText("NES:");
nes.name.setText("FC:");
nes.slider.setLength(2001);
nes.base = 1789772;
nes.step = 56;
snes.name.setText("SNES:");
snes.name.setText("SFC:");
snes.slider.setLength(2001);
snes.base = 32000;
snes.step = 1;