Update to higan and icarus v095r17 release.

byuu says:

higan supports Event mapping again.

Further, icarus can now detect Event ROMs and MSU1 games.

Event ROMs must be named "program.rom", "slot-(1,2,3).rom" MSU1 games
must contain "msu1.rom"; and tracks must be named "track-#.pcm"

When importing the CC'92, PF'94 ROMs, the program.rom and
slot-(1,2,3).rom files must be concatenated. The DSP firmware can
optionally be separate, but I'd recommend you go ahead and merge it all
to one file. Especially since that common "higan DSP pack" floating
around on the web left out the DSP1 ROMs (only has DSP1B) for god knows
what reason.

There is no support for loading "game.sfc+game.msu+game-*.pcm", because
I'm not going to support trying to pull in all of those files through
importing. Games will have to be distributed as game folders to use
MSU1. The MSU1 icarus support is simply so your game folders won't
require an unstable manifest.bml file to be played. So once they're in
there, they are good for life.

Note: the Event sizes in icarus' SFC heuristics are wrong for appended
firmware. Change from 0xXX8000 to 0xXX2000 and it works fine. Will be
fixed in r18.

Added Sintendo's flickering fixes. The window one's a big help for
regular controls, but the ListView double buffering does nothing for me
on Windows 7 :( Fairly sure I know why, but too lazy to try and fix that
now.

Also fixes the mMenu thing.
This commit is contained in:
Tim Allen 2015-12-20 13:53:40 +11:00
parent 2a4eb1cfc8
commit 0253db8685
20 changed files with 137 additions and 94 deletions

View File

@ -7,7 +7,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "095.16";
static const string Version = "095.17";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -44,6 +44,7 @@ auto mMenu::remove(sAction action) -> type& {
state.actions[n]->adjustOffset(-1);
}
action->setParent();
return *this;
}
auto mMenu::reset() -> type& {

View File

@ -23,7 +23,7 @@ static auto CALLBACK ListView_windowProc(HWND hwnd, UINT msg, WPARAM wparam, LPA
auto pListView::construct() -> void {
hwnd = CreateWindowEx(
WS_EX_CLIENTEDGE, WC_LISTVIEW, L"",
WS_EX_CLIENTEDGE | LVS_EX_DOUBLEBUFFER, WC_LISTVIEW, L"",
WS_CHILD | WS_TABSTOP | LVS_REPORT | LVS_SHOWSELALWAYS,
0, 0, 0, 0, _parentHandle(), nullptr, GetModuleHandle(0), 0
);

View File

@ -2,8 +2,8 @@
namespace hiro {
static const unsigned FixedStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_BORDER;
static const unsigned ResizableStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME;
static const unsigned FixedStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_BORDER | WS_CLIPCHILDREN;
static const unsigned ResizableStyle = WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CLIPCHILDREN;
auto pWindow::construct() -> void {
hwnd = CreateWindow(L"hiroWindow", L"", ResizableStyle, 128, 128, 256, 256, 0, 0, GetModuleHandle(0), 0);

View File

@ -3,6 +3,7 @@ auto Icarus::superFamicomManifest(string location) -> string {
auto files = directory::files(location, "*.rom");
concatenate(buffer, {location, "program.rom"});
concatenate(buffer, {location, "data.rom" });
for(auto& file : files.match("slot-*.rom" )) concatenate(buffer, {location, file});
for(auto& file : files.match("*.boot.rom" )) concatenate(buffer, {location, file});
for(auto& file : files.match("*.program.rom")) concatenate(buffer, {location, file});
for(auto& file : files.match("*.data.rom" )) concatenate(buffer, {location, file});
@ -23,7 +24,8 @@ auto Icarus::superFamicomManifest(vector<uint8>& buffer, string location, bool*
}
if(settings["icarus/UseHeuristics"].boolean() && !markup) {
SuperFamicomCartridge cartridge{buffer.data(), buffer.size()};
bool hasMSU1 = file::exists({location, "msu1.rom"});
SuperFamicomCartridge cartridge{buffer.data(), buffer.size(), hasMSU1};
if(markup = cartridge.markup) {
if(firmwareAppended) *firmwareAppended = cartridge.firmware_appended;
markup.append("\n");

View File

@ -1,5 +1,5 @@
struct SuperFamicomCartridge {
SuperFamicomCartridge(const uint8* data, uint size);
SuperFamicomCartridge(const uint8* data, uint size, bool has_msu1 = false);
string markup;
@ -35,6 +35,8 @@ struct SuperFamicomCartridge {
SA1,
LoROMSatellaview,
HiROMSatellaview,
CampusChallenge92,
Powerfest94,
//invalid types
Unknown,
@ -84,7 +86,7 @@ struct SuperFamicomCartridge {
bool has_st018 = false;
};
SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size, bool has_msu1) {
//skip copier header
if((size & 0x7fff) == 512) data += 512, size -= 512;
@ -376,6 +378,47 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
);
}
else if(type == Type::CampusChallenge92) {
markup.append(
" event=CC92 timer=360\n"
" map address=c0,e0:0000\n"
" map=mcu address=00-1f,80-9f:8000-ffff\n"
" rom name=program.rom size=0x40000\n"
" rom name=slot-1.rom size=0x80000\n"
" rom name=slot-2.rom size=0x80000\n"
" rom name=slot-3.rom size=0x80000\n"
" ram name=save.ram size=0x2000 volatile\n"
" map address=70-7d,f0-ff:0000-7fff mask=0x8000\n"
" necdsp model=uPD7725 frequency=8000000\n"
" map address=20-3f,a0-bf:8000-ffff mask=0x7fff\n"
" prom name=dsp1.program.rom size=0x1800\n"
" drom name=dsp1.data.rom size=0x800\n"
" dram name=dsp1.data.ram size=0x200 volatile\n"
);
return;
}
else if(type == Type::Powerfest94) {
markup.append(
" event=PF94 timer=360\n"
" map address=10,20:6000\n"
" map=mcu address=00-3f,80-bf:8000-ffff\n"
" map=mcu address=c0-ff:0000-ffff\n"
" rom name=program.rom size=0x40000\n"
" rom name=slot-1.rom size=0x80000\n"
" rom name=slot-2.rom size=0x80000\n"
" rom name=slot-3.rom size=0x100000\n"
" ram name=save.ram size=0x2000 volatile\n"
" map address=30-3f,b0-bf:6000-7fff mask=0xe000\n"
" necdsp model=uPD7725 frequency=8000000\n"
" map address=00-0f,80-8f:6000-7fff mask=0xfff\n"
" prom name=dsp1.program.rom size=0x1800\n"
" drom name=dsp1.data.rom size=0x800\n"
" dram name=dsp1.data.ram size=0x200 volatile\n"
);
return;
}
if(has_sharprtc) {
markup.append(
" sharprtc\n"
@ -481,6 +524,14 @@ SuperFamicomCartridge::SuperFamicomCartridge(const uint8* data, uint size) {
" dram name=save.ram size=0x4000\n"
);
}
if(has_msu1) {
markup.append(
" msu1\n"
" map address=00-3f,80-bf:2000-2007\n"
" rom name=msu1.rom\n"
);
}
}
auto SuperFamicomCartridge::readHeader(const uint8* data, uint size) -> void {
@ -500,6 +551,9 @@ auto SuperFamicomCartridge::readHeader(const uint8* data, uint size) -> void {
const uint8 company = data[index + Company];
const uint8 regionid = data[index + CartRegion] & 0x7f;
const uint16 complement = data[index + Complement] | data[index + Complement + 1] << 8;
const uint16 checksum = data[index + Checksum] | data[index + Checksum + 1] << 8;
this->rom_size = size;
ram_size = 1024 << (data[index + RamSize] & 7);
if(ram_size == 1024) ram_size = 0; //no RAM present
@ -544,7 +598,24 @@ auto SuperFamicomCartridge::readHeader(const uint8* data, uint size) -> void {
return;
}
//detect standard carts
//detect competition carts
if(!memcmp(data + index, "\x00\x08\x22\x02\x1c\x00\x10\x00\x08\x65\x80\x84\x20\x00\x22\x25\x00\x83\x0c\x80\x10", 21)
&& complement == 0x0100 && checksum == 0x2d02 && (size == 0x1c0000 || size == 0x1c8000)) {
type = Type::CampusChallenge92; //dark title screen version
return;
}
if(!memcmp(data + index, "\xc9\x80\x80\x44\x15\x00\x62\x09\x29\xa0\x52\x70\x50\x12\x05\x35\x31\x63\xc0\x22\x01", 21)
&& complement == 0x2011 && checksum == 0xf8c0 && (size == 0x240000 || size == 0x248000)) {
type = Type::Powerfest94; //10,000 points version
return;
}
if(!memcmp(data + index, "PREHISTORIK MAN ", 21)
&& complement == 0xffff && checksum == 0x0000 && (size == 0x240000 || size == 0x248000)) {
type = Type::Powerfest94; //1,000,000 points version
return;
}
//detect presence of BS-X flash cartridge connector (reads extended header information)
if(data[index - 14] == 'Z') {
@ -578,8 +649,11 @@ auto SuperFamicomCartridge::readHeader(const uint8* data, uint size) -> void {
type = Type::LoROM;
} else if(index == 0xffc0) {
type = Type::HiROM;
} else { //index == 0x40ffc0
} else if(index == 0x40ffc0) {
type = Type::ExHiROM;
} else {
type = Type::Unknown;
return;
}
}

View File

@ -80,8 +80,8 @@ auto CPU::enter() -> void {
}
auto CPU::enable() -> void {
function<uint8 (uint)> reader = {&CPU::mmio_read, (CPU*)&cpu};
function<void (uint, uint8)> writer = {&CPU::mmio_write, (CPU*)&cpu};
function<auto (uint, uint8) -> uint8> reader{&CPU::mmio_read, (CPU*)&cpu};
function<auto (uint, uint8) -> void> writer{&CPU::mmio_write, (CPU*)&cpu};
bus.map(reader, writer, 0x00, 0x3f, 0x2140, 0x2183);
bus.map(reader, writer, 0x80, 0xbf, 0x2140, 0x2183);
@ -95,7 +95,7 @@ auto CPU::enable() -> void {
bus.map(reader, writer, 0x00, 0x3f, 0x4300, 0x437f);
bus.map(reader, writer, 0x80, 0xbf, 0x4300, 0x437f);
reader = [](uint addr) { return cpu.wram[addr]; };
reader = [](uint addr, uint8 data) { return cpu.wram[addr]; };
writer = [](uint addr, uint8 data) { cpu.wram[addr] = data; };
bus.map(reader, writer, 0x00, 0x3f, 0x0000, 0x1fff, 0x002000);
@ -128,8 +128,8 @@ auto CPU::reset() -> void {
regs.mdr = 0x00;
regs.wai = false;
regs.pc.l = bus.read(0xfffc);
regs.pc.h = bus.read(0xfffd);
regs.pc.l = bus.read(0xfffc, regs.mdr);
regs.pc.h = bus.read(0xfffd, regs.mdr);
regs.pc.b = 0x00;
status.nmi_valid = false;

View File

@ -14,7 +14,7 @@ struct CPU : Processor::R65816, Thread, public PPUcounter {
auto interrupt_pending() -> bool;
auto port_read(uint8 port) -> uint8;
auto port_write(uint8 port, uint8 data) -> void;
auto mmio_read(uint addr) -> uint8;
auto mmio_read(uint addr, uint8 data) -> uint8;
auto mmio_write(uint addr, uint8 data) -> void;
auto op_io() -> void;

View File

@ -15,7 +15,7 @@ auto CPU::dma_addr_valid(uint abus) -> bool {
auto CPU::dma_read(uint abus) -> uint8 {
if(dma_addr_valid(abus) == false) return 0x00;
return bus.read(abus);
return bus.read(abus, regs.mdr);
}
auto CPU::dma_write(bool valid, uint addr, uint8 data) -> void {
@ -28,7 +28,7 @@ auto CPU::dma_transfer(bool direction, uint8 bbus, uint abus) -> void {
add_clocks(8);
dma_write(dma_transfer_valid(bbus, abus), 0x2100 | bbus, data);
} else {
uint8 data = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus) : 0x00;
uint8 data = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus, regs.mdr) : 0x00;
add_clocks(8);
dma_write(dma_addr_valid(abus), abus, data);
}

View File

@ -23,7 +23,7 @@ auto CPU::op_io() -> void {
}
auto CPU::op_read(uint addr) -> uint8 {
regs.mdr = bus.read(addr);
regs.mdr = bus.read(addr, regs.mdr);
add_clocks(speed(addr));
return regs.mdr;
}

View File

@ -1,4 +1,4 @@
auto CPU::mmio_read(uint addr) -> uint8 {
auto CPU::mmio_read(uint addr, uint8 data) -> uint8 {
if((addr & 0xffc0) == 0x2140) {
synchronizeSMP();
return smp.port_read(addr & 3);
@ -6,7 +6,7 @@ auto CPU::mmio_read(uint addr) -> uint8 {
switch(addr & 0xffff) {
case 0x2180: {
uint8 result = bus.read(0x7e0000 | status.wram_addr);
uint8 result = bus.read(0x7e0000 | status.wram_addr, regs.mdr);
status.wram_addr = (status.wram_addr + 1) & 0x01ffff;
return result;
}
@ -92,7 +92,7 @@ auto CPU::mmio_read(uint addr) -> uint8 {
}
}
return regs.mdr;
return data;
}
auto CPU::mmio_write(uint addr, uint8 data) -> void {

View File

@ -568,7 +568,7 @@ auto PPU::mmio_r213f() -> uint8 {
return regs.ppu2_mdr;
}
auto PPU::mmio_read(uint addr) -> uint8 {
auto PPU::mmio_read(uint addr, uint8 data) -> uint8 {
cpu.synchronizePPU();
switch(addr & 0xffff) {
@ -604,7 +604,7 @@ auto PPU::mmio_read(uint addr) -> uint8 {
case 0x213f: return mmio_r213f(); //STAT78
}
return cpu.regs.mdr;
return data;
}
auto PPU::mmio_write(uint addr, uint8 data) -> void {

View File

@ -196,7 +196,7 @@ auto mmio_r213d() -> uint8; //OPVCT
auto mmio_r213e() -> uint8; //STAT77
auto mmio_r213f() -> uint8; //STAT78
auto mmio_read(uint addr) -> uint8;
auto mmio_read(uint addr, uint8 data) -> uint8;
auto mmio_write(uint addr, uint8 data) -> void;
auto latch_counters() -> void;

View File

@ -150,8 +150,8 @@ auto PPU::frame() -> void {
}
auto PPU::enable() -> void {
function<uint8 (uint)> reader = {&PPU::mmio_read, (PPU*)&ppu};
function<void (uint, uint8)> writer = {&PPU::mmio_write, (PPU*)&ppu};
function<auto (uint, uint8) -> uint8> reader{&PPU::mmio_read, (PPU*)&ppu};
function<auto (uint, uint8) -> void> writer{&PPU::mmio_write, (PPU*)&ppu};
bus.map(reader, writer, 0x00, 0x3f, 0x2100, 0x213f);
bus.map(reader, writer, 0x80, 0xbf, 0x2100, 0x213f);

View File

@ -155,7 +155,7 @@ auto PPU::mmio_update_video_mode() -> void {
}
}
auto PPU::mmio_read(uint addr) -> uint8 {
auto PPU::mmio_read(uint addr, uint8 data) -> uint8 {
cpu.synchronizePPU();
switch(addr & 0xffff) {
@ -185,7 +185,7 @@ auto PPU::mmio_read(uint addr) -> uint8 {
case 0x2137: { //SLHV
if(cpu.pio() & 0x80) latch_counters();
return cpu.regs.mdr;
return data;
}
case 0x2138: { //OAMDATAREAD
@ -273,7 +273,7 @@ auto PPU::mmio_read(uint addr) -> uint8 {
}
}
return cpu.regs.mdr;
return data;
}
auto PPU::mmio_write(uint addr, uint8 data) -> void {

View File

@ -1,5 +1,5 @@
public:
auto mmio_read(uint addr) -> uint8;
auto mmio_read(uint addr, uint8 data) -> uint8;
auto mmio_write(uint addr, uint8 data) -> void;
private:

View File

@ -101,8 +101,8 @@ auto PPU::frame() -> void {
}
auto PPU::enable() -> void {
function<uint8 (uint)> reader = {&PPU::mmio_read, (PPU*)&ppu};
function<void (uint, uint8)> writer = {&PPU::mmio_write, (PPU*)&ppu};
function<auto (uint, uint8) -> uint8> reader{&PPU::mmio_read, (PPU*)&ppu};
function<auto (uint, uint8) -> void> writer{&PPU::mmio_write, (PPU*)&ppu};
bus.map(reader, writer, 0x00, 0x3f, 0x2100, 0x213f);
bus.map(reader, writer, 0x80, 0xbf, 0x2100, 0x213f);

View File

@ -177,44 +177,21 @@ auto Cartridge::parseMarkupEvent(Markup::Node root) -> void {
parseMarkupMemory(event.ram, root["ram"], ID::EventRAM, true);
event.board = Event::Board::CampusChallenge92;
if(root["name"].text() == "Campus Challenge '92") event.board = Event::Board::CampusChallenge92;
if(root["name"].text() == "Powerfest '94") event.board = Event::Board::Powerfest94;
event.revision = root["revision"].text() == "B" ? 2 : 1;
lstring part = root["timer"].text().split(":", 1L);
if(part.size() == 1) event.timer = part[0].natural();
if(part.size() == 2) event.timer = part[0].natural() * 60 + part[1].natural();
if(root.text() == "CC92") event.board = Event::Board::CampusChallenge92;
if(root.text() == "PF94") event.board = Event::Board::Powerfest94;
event.timer = root["timer"].natural();
for(auto node : root.find("map")) {
if(node.text() == "mcu") {
parseMarkupMap(node, {&Event::mcuRead, &event}, {&Event::mcuWrite, &event});
} else {
parseMarkupMap(node, {&Event::read, &event}, {&Event::write, &event});
}
/*
//todo: define and support markup for coprocessor/event
if(node["id"].text() == "rom") {
Mapping m({&Event::rom_read, &event}, [](unsigned, uint8) {});
parseMarkupMap(m, node);
mapping.append(m);
}
if(node["id"].text() == "ram") {
Mapping m({&Event::ram_read, &event}, {&Event::ram_write, &event});
parseMarkupMap(m, node);
mapping.append(m);
for(auto node : root["ram"].find("map")) {
parseMarkupMap(node, event.ram);
}
if(node["id"].text() == "dr") {
Mapping m([](uint, uint8 data) -> uint8 { return data; }, {&Event::dr, &event});
parseMarkupMap(m, node);
mapping.append(m);
}
if(node["id"].text() == "sr") {
Mapping m({&Event::sr, &event}, [](uint, uint8) {});
parseMarkupMap(m, node);
mapping.append(m);
}
*/
}
auto Cartridge::parseMarkupSA1(Markup::Node root) -> void {

View File

@ -4,7 +4,9 @@ namespace SuperFamicom {
Event event;
auto Event::Enter() -> void { event.enter(); }
auto Event::Enter() -> void {
event.enter();
}
auto Event::enter() -> void {
while(true) {
@ -60,19 +62,7 @@ auto Event::reset() -> void {
scoreSecondsRemaining = 0;
}
auto Event::sr(uint, uint8) -> uint8 {
return status;
}
auto Event::dr(uint, uint8 data) -> void {
select = data;
if(timer && data == 0x09) {
timerActive = true;
timerSecondsRemaining = timer;
}
}
auto Event::rom_read(uint addr, uint8 data) -> uint8 {
auto Event::mcuRead(uint addr, uint8 data) -> uint8 {
if(board == Board::CampusChallenge92) {
uint id = 0;
if(select == 0x09) id = 1;
@ -108,19 +98,24 @@ auto Event::rom_read(uint addr, uint8 data) -> uint8 {
return data;
}
auto Event::ram_read(uint addr, uint8 data) -> uint8 {
return ram.read(bus.mirror(addr, ram.size()), data);
}
auto Event::ram_write(uint addr, uint8 data) -> void {
return ram.write(bus.mirror(addr, ram.size()), data);
auto Event::mcuWrite(uint addr, uint8 data) -> void {
}
auto Event::read(uint addr, uint8 data) -> uint8 {
if(addr == 0x106000 || addr == 0xc00000) {
return status;
}
return data;
}
auto Event::write(uint addr, uint8 data) -> void {
if(addr == 0x206000 || addr == 0xe00000) {
select = data;
if(timer && data == 0x09) {
timerActive = true;
timerSecondsRemaining = timer;
}
}
}
auto Event::serialize(serializer& s) -> void {

View File

@ -11,13 +11,8 @@ struct Event : Coprocessor {
auto power() -> void;
auto reset() -> void;
auto submitScore() -> void;
auto sr(uint, uint8) -> uint8;
auto dr(uint, uint8 data) -> void;
auto rom_read(uint addr, uint8) -> uint8;
auto ram_read(uint addr, uint8) -> uint8;
auto ram_write(uint addr, uint8 data) -> void;
auto mcuRead(uint addr, uint8) -> uint8;
auto mcuWrite(uint addr, uint8) -> void;
auto read(uint addr, uint8 data) -> uint8;
auto write(uint addr, uint8 data) -> void;
@ -28,7 +23,6 @@ struct Event : Coprocessor {
MappedRAM ram;
enum class Board : uint { CampusChallenge92, Powerfest94 } board;
uint revision;
uint timer;
privileged: