diff --git a/higan/GNUmakefile b/higan/GNUmakefile index 5307f340..7c082d6d 100644 --- a/higan/GNUmakefile +++ b/higan/GNUmakefile @@ -1,24 +1,12 @@ +build := release include ../nall/GNUmakefile target := tomoko objects := libco emulator audio video resource -build := release # console := true flags += -I. -I.. -ifeq ($(build),release) - flags += -O3 - link += -s -else ifeq ($(build),debug) - flags += -g -else ifeq ($(build),instrument) - flags += -O3 -fprofile-generate - link += -lgcov -else ifeq ($(build),optimize) - flags += -O3 -fprofile-use -endif - ifeq ($(platform),windows) ifeq ($(console),true) link += -mconsole diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index ce95e184..34bee867 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -12,7 +12,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "102.05"; + static const string Version = "102.06"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "http://byuu.org/"; @@ -26,6 +26,15 @@ namespace Emulator { static constexpr double PAL = 283.75 * 15'625.0 + 25.0; } } + + //nall/vfs shorthand constants for open(), load() + namespace File { + static const auto Read = vfs::file::mode::read; + static const auto Write = vfs::file::mode::write; + static const auto Optional = false; + static const auto Required = true; + }; } +#include "platform.hpp" #include "interface.hpp" diff --git a/higan/emulator/interface.hpp b/higan/emulator/interface.hpp index 7f3b95ea..3228e2ef 100644 --- a/higan/emulator/interface.hpp +++ b/higan/emulator/interface.hpp @@ -2,18 +2,6 @@ namespace Emulator { -struct Platform { - virtual auto path(uint id) -> string { return ""; } - virtual auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> vfs::shared::file { return {}; } - virtual auto load(uint id, string name, string type) -> maybe { return nothing; } - virtual auto videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void {} - virtual auto audioSample(const double* samples, uint channels) -> void {} - virtual auto inputPoll(uint port, uint device, uint input) -> int16 { return 0; } - virtual auto inputRumble(uint port, uint device, uint input, bool enable) -> void {} - virtual auto dipSettings(Markup::Node node) -> uint { return 0; } - virtual auto notify(string text) -> void { print(text, "\n"); } -}; - struct Interface { struct Information { string manufacturer; @@ -25,6 +13,11 @@ struct Interface { } capability; } information; + struct Region { + string name; + }; + vector regions; + struct Medium { uint id; string name; @@ -96,14 +89,4 @@ struct Interface { auto videoColor(uint16 r, uint16 g, uint16 b) -> uint32; }; -//nall/vfs shorthand constants for open(), load() -struct File { - static const auto Read = vfs::file::mode::read; - static const auto Write = vfs::file::mode::write; - static const auto Optional = false; - static const auto Required = true; -}; - -extern Platform* platform; - } diff --git a/higan/emulator/platform.hpp b/higan/emulator/platform.hpp new file mode 100644 index 00000000..9e0a7c96 --- /dev/null +++ b/higan/emulator/platform.hpp @@ -0,0 +1,19 @@ +#pragma once + +namespace Emulator { + +struct Platform { + virtual auto path(uint id) -> string { return ""; } + virtual auto open(uint id, string name, vfs::file::mode mode, bool required = false) -> vfs::shared::file { return {}; } + virtual auto load(uint id, string name, string type) -> maybe { return nothing; } + virtual auto videoRefresh(const uint32* data, uint pitch, uint width, uint height) -> void {} + virtual auto audioSample(const double* samples, uint channels) -> void {} + virtual auto inputPoll(uint port, uint device, uint input) -> int16 { return 0; } + virtual auto inputRumble(uint port, uint device, uint input, bool enable) -> void {} + virtual auto dipSettings(Markup::Node node) -> uint { return 0; } + virtual auto notify(string text) -> void { print(text, "\n"); } +}; + +extern Platform* platform; + +} diff --git a/higan/fc/fc.hpp b/higan/fc/fc.hpp index b4b877b1..115ccd41 100644 --- a/higan/fc/fc.hpp +++ b/higan/fc/fc.hpp @@ -12,7 +12,7 @@ namespace Famicom { #define platform Emulator::platform - using File = Emulator::File; + namespace File = Emulator::File; using Scheduler = Emulator::Scheduler; using Cheat = Emulator::Cheat; extern Scheduler scheduler; diff --git a/higan/gb/gb.hpp b/higan/gb/gb.hpp index a817210e..c0ba694b 100644 --- a/higan/gb/gb.hpp +++ b/higan/gb/gb.hpp @@ -12,7 +12,7 @@ namespace GameBoy { #define platform Emulator::platform - using File = Emulator::File; + namespace File = Emulator::File; using Scheduler = Emulator::Scheduler; using Cheat = Emulator::Cheat; extern Scheduler scheduler; diff --git a/higan/gba/gba.hpp b/higan/gba/gba.hpp index f6fa5701..dab846e6 100644 --- a/higan/gba/gba.hpp +++ b/higan/gba/gba.hpp @@ -11,7 +11,7 @@ namespace GameBoyAdvance { #define platform Emulator::platform - using File = Emulator::File; + namespace File = Emulator::File; using Scheduler = Emulator::Scheduler; extern Scheduler scheduler; diff --git a/higan/md/bus/bus.cpp b/higan/md/bus/bus.cpp index c69c180a..2708a36f 100644 --- a/higan/md/bus/bus.cpp +++ b/higan/md/bus/bus.cpp @@ -51,6 +51,13 @@ auto BusCPU::writeWord(uint24 addr, uint16 data) -> void { auto BusCPU::readIO(uint24 addr) -> uint16 { switch(addr & ~1) { + case 0xa10000: return ( + !Region::NTSCJ() << 7 //0 = domestic (Japan); 1 = export + | Region::PAL() << 6 //0 = NTSC; 1 = PAL + | 1 << 5 //0 = Mega CD connected; 1 = no expansion connected + | 0 << 0 //0 = Model 1; 1 = Model 2+ + ); + case 0xa10002: return peripherals.controllerPort1->readData(); case 0xa10004: return peripherals.controllerPort2->readData(); case 0xa10006: return peripherals.extensionPort->readData(); diff --git a/higan/md/interface/interface.cpp b/higan/md/interface/interface.cpp index 4bada49c..b4de245a 100644 --- a/higan/md/interface/interface.cpp +++ b/higan/md/interface/interface.cpp @@ -12,6 +12,11 @@ Interface::Interface() { information.capability.states = false; information.capability.cheats = false; + regions.append({"Autodetect"}); + regions.append({"NTSC-J"}); + regions.append({"NTSC-U"}); + regions.append({"PAL"}); + media.append({ID::MegaDrive, "Mega Drive", "md"}); Port controllerPort1{ID::Port::Controller1, "Controller Port 1"}; diff --git a/higan/md/md.hpp b/higan/md/md.hpp index ae52a7c8..5f582737 100644 --- a/higan/md/md.hpp +++ b/higan/md/md.hpp @@ -12,7 +12,7 @@ namespace MegaDrive { #define platform Emulator::platform - using File = Emulator::File; + namespace File = Emulator::File; using Scheduler = Emulator::Scheduler; extern Scheduler scheduler; @@ -36,6 +36,12 @@ namespace MegaDrive { uint wait = 0; }; + struct Region { + inline static auto NTSCJ() -> bool; + inline static auto NTSCU() -> bool; + inline static auto PAL() -> bool; + }; + #include #include diff --git a/higan/md/system/system.cpp b/higan/md/system/system.cpp index 2148a703..478b537e 100644 --- a/higan/md/system/system.cpp +++ b/higan/md/system/system.cpp @@ -10,7 +10,7 @@ auto System::run() -> void { if(scheduler.enter() == Scheduler::Event::Frame) vdp.refresh(); } -auto System::load(Emulator::Interface* interface) -> bool { +auto System::load(Emulator::Interface* interface, maybe region) -> bool { information = {}; if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) { @@ -20,6 +20,7 @@ auto System::load(Emulator::Interface* interface) -> bool { auto document = BML::unserialize(information.manifest); if(!cartridge.load()) return false; + information.region = Region::NTSCU; information.colorburst = Emulator::Constants::Colorburst::NTSC; this->interface = interface; return information.loaded = true; diff --git a/higan/md/system/system.hpp b/higan/md/system/system.hpp index 1acee012..87733f1e 100644 --- a/higan/md/system/system.hpp +++ b/higan/md/system/system.hpp @@ -1,10 +1,17 @@ struct System { + enum class Region : uint { + NTSCJ, + NTSCU, + PAL, + }; + auto loaded() const -> bool { return information.loaded; } + auto region() const -> Region { return information.region; } auto colorburst() const -> double { return information.colorburst; } auto run() -> void; - auto load(Emulator::Interface*) -> bool; + auto load(Emulator::Interface*, maybe = nothing) -> bool; auto save() -> void; auto unload() -> void; auto power() -> void; @@ -14,6 +21,7 @@ private: struct Information { bool loaded = false; + Region region = Region::NTSCJ; string manifest; double colorburst = 0.0; } information; @@ -31,3 +39,7 @@ struct Peripherals { extern System system; extern Peripherals peripherals; + +auto Region::NTSCJ() -> bool { return system.region() == System::Region::NTSCJ; } +auto Region::NTSCU() -> bool { return system.region() == System::Region::NTSCU; } +auto Region::PAL() -> bool { return system.region() == System::Region::PAL; } diff --git a/higan/ms/ms.hpp b/higan/ms/ms.hpp index 64e8a6de..c3ba221b 100644 --- a/higan/ms/ms.hpp +++ b/higan/ms/ms.hpp @@ -11,7 +11,7 @@ namespace MasterSystem { #define platform Emulator::platform - using File = Emulator::File; + namespace File = Emulator::File; using Scheduler = Emulator::Scheduler; extern Scheduler scheduler; struct Interface; diff --git a/higan/pce/cpu/io.cpp b/higan/pce/cpu/io.cpp index c821dbda..7970873a 100644 --- a/higan/pce/cpu/io.cpp +++ b/higan/pce/cpu/io.cpp @@ -19,12 +19,14 @@ auto CPU::read(uint8 bank, uint13 addr) -> uint8 { if(bank == 0xff) { //$0000-03ff VDC or VPC if((addr & 0x1c00) == 0x0000) { + HuC6280::io(); //penalty cycle if(Model::PCEngine()) return vdc0.read(addr); if(Model::SuperGrafx()) return vpc.read(addr); } //$0400-07ff VCE if((addr & 0x1c00) == 0x0400) { + HuC6280::io(); //penalty cycle return vce.read(addr); } @@ -123,12 +125,14 @@ auto CPU::write(uint8 bank, uint13 addr, uint8 data) -> void { if(bank == 0xff) { //$0000-03ff VDC or VPC if((addr & 0x1c00) == 0x0000) { + HuC6280::io(); //penalty cycle if(Model::PCEngine()) return vdc0.write(addr, data); if(Model::SuperGrafx()) return vpc.write(addr, data); } //$0400-07ff VCE if((addr & 0x1c00) == 0x0400) { + HuC6280::io(); //penalty cycle return vce.write(addr, data); } @@ -186,6 +190,7 @@ auto CPU::write(uint8 bank, uint13 addr, uint8 data) -> void { //ST0, ST1, ST2 auto CPU::store(uint2 addr, uint8 data) -> void { + HuC6280::io(); //penalty cycle if(addr) addr++; //0,1,2 => 0,2,3 if(Model::PCEngine()) vdc0.write(addr, data); if(Model::SuperGrafx()) vpc.store(addr, data); diff --git a/higan/pce/pce.hpp b/higan/pce/pce.hpp index 257d4de0..3a31dae5 100644 --- a/higan/pce/pce.hpp +++ b/higan/pce/pce.hpp @@ -11,7 +11,7 @@ namespace PCEngine { #define platform Emulator::platform - using File = Emulator::File; + namespace File = Emulator::File; using Scheduler = Emulator::Scheduler; extern Scheduler scheduler; diff --git a/higan/pce/psg/channel.cpp b/higan/pce/psg/channel.cpp index 33a05e8e..936a8475 100644 --- a/higan/pce/psg/channel.cpp +++ b/higan/pce/psg/channel.cpp @@ -1,4 +1,5 @@ -auto PSG::Channel::power() -> void { +auto PSG::Channel::power(uint id) -> void { + this->id = id; memory::fill(&io, sizeof(IO)); memory::fill(&output, sizeof(Output)); } @@ -6,23 +7,31 @@ auto PSG::Channel::power() -> void { auto PSG::Channel::run() -> void { if(!io.enable) return sample(0); - if(io.noiseEnable) { - if(--io.noisePeriod == 0) { - io.noisePeriod = ~io.noiseFrequency << 7; - //todo: this should be a square wave; PRNG algorithm is also unknown - io.noiseSample = nall::random(); - } - return sample(io.noiseSample); - } - - if(io.direct) return sample(io.waveDirect); - - if(--io.period == 0) { - io.period = io.frequency; + if(!io.direct && --io.wavePeriod == 0) { + io.wavePeriod = io.waveFrequency; io.waveOffset++; + io.waveSample = io.waveBuffer[io.waveOffset]; } - return sample(io.waveData[io.waveOffset]); + if(!io.noiseEnable) { + return sample(io.waveSample); + } + + if(--io.noisePeriod == 0) { + io.noisePeriod = ~io.noiseFrequency << 7; + //todo: this should be a square wave; PRNG algorithm is also unknown + io.noiseSample = nall::random(); + } + + return sample(io.noiseSample); +} + +auto PSG::Channel::loadWavePeriod() -> void { + io.wavePeriod = io.waveFrequency; +} + +auto PSG::Channel::loadWaveSample() -> void { + io.waveSample = io.waveBuffer[io.waveOffset]; } auto PSG::Channel::sample(uint5 sample) -> void { diff --git a/higan/pce/psg/io.cpp b/higan/pce/psg/io.cpp index 9b7abb39..7ceca144 100644 --- a/higan/pce/psg/io.cpp +++ b/higan/pce/psg/io.cpp @@ -1,81 +1,81 @@ auto PSG::write(uint4 addr, uint8 data) -> void { if(addr == 0x00) { io.channel = data.bits(0,2); - return; } if(addr == 0x01) { io.volumeRight = data.bits(0,3); io.volumeLeft = data.bits(4,7); - return; } - uint3 C = io.channel; - - if(addr == 0x02) { - if(C == 6 || C == 7) return; - channel[C].io.frequency.bits(0,7) = data.bits(0,7); - return; + if(addr >= 0x02 && addr <= 0x06 && io.channel <= 5) { + channel[io.channel].write(addr, data); } - if(addr == 0x03) { - if(C == 6 || C == 7) return; - channel[C].io.frequency.bits(8,11) = data.bits(0,3); - return; - } - - if(addr == 0x04) { - if(C == 6 || C == 7) return; - if(channel[C].io.direct && !data.bit(6)) { - channel[C].io.waveOffset = 0; - } - if(!channel[C].io.enable && data.bit(7)) { - channel[C].io.waveOffset = 0; - channel[C].io.period = channel[C].io.frequency; - } - channel[C].io.volume = data.bits(0,3); - channel[C].io.direct = data.bit(6); - channel[C].io.enable = data.bit(7); - return; - } - - if(addr == 0x05) { - if(C == 6 || C == 7) return; - channel[C].io.volumeRight = data.bits(0,3); - channel[C].io.volumeLeft = data.bits(4,7); - return; - } - - if(addr == 0x06) { - if(C == 6 || C == 7) return; - if(channel[C].io.direct) { - channel[C].io.waveDirect = data.bits(0,4); - } else if(!channel[C].io.enable) { - uint5 O = channel[C].io.waveOffset++; - channel[C].io.waveData[O] = data.bits(0,4); - } - return; - } - - if(addr == 0x07) { - if(C != 4 && C != 5) return; - if(!channel[C].io.noiseEnable && data.bit(7)) { - channel[C].io.noisePeriod = ~data.bits(0,4) << 7; - channel[C].io.noiseSample = 0; - } - channel[C].io.noiseFrequency = data.bits(0,4); - channel[C].io.noiseEnable = data.bit(7); - return; + if(addr == 0x07 && io.channel >= 4 && io.channel <= 5) { + channel[io.channel].write(addr, data); } if(addr == 0x08) { io.lfoFrequency = data; - return; } if(addr == 0x09) { io.lfoControl = data.bits(0,1); io.lfoEnable = data.bit(7); - return; + if(io.lfoEnable) { + channel[1].io.waveSample = channel[1].io.waveBuffer[channel[1].io.waveOffset = 0]; + } + } +} + +auto PSG::Channel::write(uint4 addr, uint8 data) -> void { + if(addr == 0x02) { + io.waveFrequency.bits(0,7) = data.bits(0,7); + io.wavePeriod = io.waveFrequency; + } + + if(addr == 0x03) { + io.waveFrequency.bits(8,11) = data.bits(0,3); + io.wavePeriod = io.waveFrequency; + } + + if(addr == 0x04) { + if(io.direct && !data.bit(6)) { + io.waveOffset = 0; + io.waveSample = io.waveBuffer[io.waveOffset]; + } + if(!io.enable && data.bit(7) && !data.bit(6)) { + io.waveOffset++; + io.waveSample = io.waveBuffer[io.waveOffset]; + } + io.volume = data.bits(0,3); + io.direct = data.bit(6); + io.enable = data.bit(7); + } + + if(addr == 0x05) { + io.volumeRight = data.bits(0,3); + io.volumeLeft = data.bits(4,7); + } + + if(addr == 0x06) { + if(!io.direct) { + io.waveBuffer[io.waveOffset] = data.bits(0,4); + if(!io.enable) io.waveOffset++; + } + if(io.enable) { + io.waveSample = data.bits(0,4); + } + } + + //channels 4 and 5 only + if(addr == 0x07) { + if(!io.noiseEnable && data.bit(7)) { + io.noisePeriod = ~data.bits(0,4) << 7; + io.noiseSample = 0; + } + io.noiseFrequency = data.bits(0,4); + io.noiseEnable = data.bit(7); } } diff --git a/higan/pce/psg/psg.cpp b/higan/pce/psg/psg.cpp index 123d760f..2592d046 100644 --- a/higan/pce/psg/psg.cpp +++ b/higan/pce/psg/psg.cpp @@ -37,7 +37,7 @@ auto PSG::power() -> void { stream = Emulator::audio.createStream(2, system.colorburst()); memory::fill(&io, sizeof(IO)); - for(auto C : range(6)) channel[C].power(); + for(auto C : range(6)) channel[C].power(C); } } diff --git a/higan/pce/psg/psg.hpp b/higan/pce/psg/psg.hpp index 575f595b..cd2ef4e6 100644 --- a/higan/pce/psg/psg.hpp +++ b/higan/pce/psg/psg.hpp @@ -24,24 +24,29 @@ private: struct Channel { //channel.cpp - auto power() -> void; + auto power(uint id) -> void; auto run() -> void; + auto loadWavePeriod() -> void; + auto loadWaveSample() -> void; auto sample(uint5 sample) -> void; + //io.cpp + auto write(uint4 addr, uint8 data) -> void; + struct IO { - uint12 frequency; + uint12 waveFrequency; uint4 volume; uint1 direct; uint1 enable; uint4 volumeLeft; uint4 volumeRight; - uint5 waveData[32]; - uint5 waveOffset; - uint5 waveDirect; + uint5 waveBuffer[32]; uint5 noiseFrequency; //channels 4 and 5 only uint1 noiseEnable; //channels 4 and 5 only - uint12 period; + uint12 wavePeriod; + uint5 waveSample; + uint5 waveOffset; uint12 noisePeriod; uint5 noiseSample; } io; @@ -50,6 +55,8 @@ private: uint left; uint right; } output; + + uint id; } channel[6]; }; diff --git a/higan/processor/huc6280/huc6280.hpp b/higan/processor/huc6280/huc6280.hpp index 5441d1f0..e8635ad5 100644 --- a/higan/processor/huc6280/huc6280.hpp +++ b/higan/processor/huc6280/huc6280.hpp @@ -19,7 +19,7 @@ struct HuC6280 { inline auto store8(uint8, uint8) -> void; inline auto store16(uint16, uint8) -> void; - auto io() -> uint8; + auto io() -> void; auto opcode() -> uint8; auto operand() -> uint8; diff --git a/higan/processor/huc6280/instructions.cpp b/higan/processor/huc6280/instructions.cpp index c7d907ce..289dbc49 100644 --- a/higan/processor/huc6280/instructions.cpp +++ b/higan/processor/huc6280/instructions.cpp @@ -4,11 +4,11 @@ auto HuC6280::ADC(uint8 i) -> uint8 { o = A + i + C; V = ~(A ^ i) & (A ^ o) & 0x80; } else { + io(); o = (A & 0x0f) + (i & 0x0f) + (C << 0); if(o > 0x09) o += 0x06; C = o > 0x0f; o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f); - V = ~(A ^ i) & (A ^ o) & 0x80; if(o > 0x9f) o += 0x60; } C = o.bit(8); @@ -130,11 +130,11 @@ auto HuC6280::SBC(uint8 i) -> uint8 { o = A + i + C; V = ~(A ^ i) & (A ^ o) & 0x80; } else { + io(); o = (A & 0x0f) + (i & 0x0f) + (C << 0); if(o <= 0x0f) o -= 0x06; C = o > 0x0f; o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f); - V = ~(A ^ i) & (A ^ o) & 0x80; if(o <= 0xff) o -= 0x60; } C = o.bit(8); @@ -222,7 +222,6 @@ auto HuC6280::instruction_blockmove(bp alu) -> void { io(); io(); io(); - io(); bool alternate = 0; do { auto data = load16(source); @@ -497,8 +496,8 @@ L store8(zeropage, data); auto HuC6280::instruction_ST(uint2 index) -> void { auto data = operand(); io(); -L io(); - store(index, data); + io(); +L store(index, data); } auto HuC6280::instruction_TAM() -> void { diff --git a/higan/processor/huc6280/memory.cpp b/higan/processor/huc6280/memory.cpp index 9f3b21e6..9ac57335 100644 --- a/higan/processor/huc6280/memory.cpp +++ b/higan/processor/huc6280/memory.cpp @@ -20,9 +20,8 @@ auto HuC6280::store16(uint16 addr, uint8 data) -> void { // -auto HuC6280::io() -> uint8 { +auto HuC6280::io() -> void { step(r.cs); - return 0xff; } auto HuC6280::opcode() -> uint8 { diff --git a/higan/sfc/sfc.hpp b/higan/sfc/sfc.hpp index 62009d03..a3641d0b 100644 --- a/higan/sfc/sfc.hpp +++ b/higan/sfc/sfc.hpp @@ -21,7 +21,7 @@ namespace SuperFamicom { #define platform Emulator::platform - using File = Emulator::File; + namespace File = Emulator::File; using Scheduler = Emulator::Scheduler; using Cheat = Emulator::Cheat; extern Scheduler scheduler; diff --git a/higan/ws/ws.hpp b/higan/ws/ws.hpp index dcc3cce9..d8abee82 100644 --- a/higan/ws/ws.hpp +++ b/higan/ws/ws.hpp @@ -12,7 +12,7 @@ namespace WonderSwan { #define platform Emulator::platform - using File = Emulator::File; + namespace File = Emulator::File; using Scheduler = Emulator::Scheduler; using Cheat = Emulator::Cheat; extern Scheduler scheduler; diff --git a/hiro/extension/browser-dialog.cpp b/hiro/extension/browser-dialog.cpp index 7fce7784..05e31dd7 100644 --- a/hiro/extension/browser-dialog.cpp +++ b/hiro/extension/browser-dialog.cpp @@ -7,7 +7,7 @@ struct BrowserDialogWindow { auto change() -> void; auto isFolder(const string& name) -> bool; auto isMatch(const string& name) -> bool; - auto run() -> string_vector; + auto run() -> BrowserDialog::Response; auto setPath(string path) -> void; private: @@ -20,12 +20,14 @@ private: Button pathUp{&pathLayout, Size{0, 0}, 0}; ListView view{&layout, Size{~0, ~0}, 5}; HorizontalLayout controlLayout{&layout, Size{~0, 0}}; - ComboButton filterList{&controlLayout, Size{120, 0}, 5}; + ComboButton filterList{&controlLayout, Size{0, 0}, 5}; LineEdit fileName{&controlLayout, Size{~0, 0}, 5}; + ComboButton optionList{&controlLayout, Size{0, 0}, 5}; Button acceptButton{&controlLayout, Size{80, 0}, 5}; Button cancelButton{&controlLayout, Size{80, 0}, 5}; BrowserDialog::State& state; + BrowserDialog::Response response; vector filters; }; @@ -37,20 +39,20 @@ auto BrowserDialogWindow::accept() -> void { if(state.action == "openFile" && batched) { string name = batched.left()->cell(0)->text(); if(isFolder(name)) return setPath({state.path, name}); - state.response.append(string{state.path, name}); + response.selected.append(string{state.path, name}); } if(state.action == "openFiles") { for(auto item : batched) { string name = item->cell(0)->text(); - state.response.append(string{state.path, name, isFolder(name) ? "/" : ""}); + response.selected.append(string{state.path, name, isFolder(name) ? "/" : ""}); } } if(state.action == "openFolder" && batched) { string name = batched.left()->cell(0)->text(); if(!isMatch(name)) return setPath({state.path, name}); - state.response.append(string{state.path, name, "/"}); + response.selected.append(string{state.path, name, "/"}); } if(state.action == "saveFile") { @@ -60,15 +62,15 @@ auto BrowserDialogWindow::accept() -> void { if(file::exists({state.path, name})) { if(MessageDialog("File already exists; overwrite it?").question() != "Yes") return; } - state.response.append(string{state.path, name}); + response.selected.append(string{state.path, name}); } if(state.action == "selectFolder" && batched) { string name = batched.left()->cell(0)->text(); - if(isFolder(name)) state.response.append(string{state.path, name, "/"}); + if(isFolder(name)) response.selected.append(string{state.path, name, "/"}); } - if(state.response) window.setModal(false); + if(response.selected) window.setModal(false); } //table view item double-clicked, or enter pressed on selected table view item @@ -113,8 +115,8 @@ auto BrowserDialogWindow::isMatch(const string& name) -> bool { return false; } -auto BrowserDialogWindow::run() -> string_vector { - state.response.reset(); +auto BrowserDialogWindow::run() -> BrowserDialog::Response { + response = {}; layout.setMargin(5); pathName.onActivate([&] { setPath(pathName.text()); }); @@ -127,6 +129,11 @@ auto BrowserDialogWindow::run() -> string_vector { auto part = filter.split("|", 1L); filterList.append(ComboButtonItem().setText(part.left())); } + optionList.setVisible((bool)state.options).onChange([&] { response.option = optionList.selected().text(); }); + for(auto& option : state.options) { + optionList.append(ComboButtonItem().setText(option)); + } + optionList.doChange(); //updates response.option to point to the default (first) option fileName.setVisible(state.action == "saveFile").onActivate([&] { accept(); }); acceptButton.onActivate([&] { accept(); }); if(state.action == "openFile" || state.action == "openFiles" || state.action == "openFolder") acceptButton.setText("Open"); @@ -151,7 +158,7 @@ auto BrowserDialogWindow::run() -> string_vector { window.setModal(); window.setVisible(false); - return state.response; + return response; } auto BrowserDialogWindow::setPath(string path) -> void { @@ -211,6 +218,10 @@ auto BrowserDialog::openFolder() -> string { return {}; } +auto BrowserDialog::option() -> string { + return response.option; +} + auto BrowserDialog::saveFile() -> string { state.action = "saveFile"; if(!state.title) state.title = "Save File"; @@ -218,6 +229,10 @@ auto BrowserDialog::saveFile() -> string { return {}; } +auto BrowserDialog::selected() -> string_vector { + return response.selected; +} + auto BrowserDialog::selectFolder() -> string { state.action = "selectFolder"; if(!state.title) state.title = "Select Folder"; @@ -230,6 +245,11 @@ auto BrowserDialog::setFilters(const string_vector& filters) -> type& { return *this; } +auto BrowserDialog::setOptions(const string_vector& options) -> type& { + state.options = options; + return *this; +} + auto BrowserDialog::setParent(const sWindow& parent) -> type& { state.parent = parent; return *this; @@ -247,7 +267,8 @@ auto BrowserDialog::setTitle(const string& title) -> type& { auto BrowserDialog::_run() -> string_vector { if(!state.path) state.path = Path::user(); - return BrowserDialogWindow(state).run(); + response = BrowserDialogWindow(state).run(); + return response.selected; } #endif diff --git a/hiro/extension/browser-dialog.hpp b/hiro/extension/browser-dialog.hpp index 9d9b35cd..c078f1b9 100644 --- a/hiro/extension/browser-dialog.hpp +++ b/hiro/extension/browser-dialog.hpp @@ -9,9 +9,12 @@ struct BrowserDialog { auto openFile() -> string; //one existing file auto openFiles() -> string_vector; //any existing files or folders auto openFolder() -> string; //one existing folder + auto option() -> string; auto saveFile() -> string; //one file + auto selected() -> string_vector; auto selectFolder() -> string; //one existing folder auto setFilters(const string_vector& filters = {}) -> type&; + auto setOptions(const string_vector& options = {}) -> type&; auto setParent(const sWindow& parent) -> type&; auto setPath(const string& path = "") -> type&; auto setTitle(const string& title = "") -> type&; @@ -20,12 +23,17 @@ private: struct State { string action; string_vector filters = {"*"}; + string_vector options; sWindow parent; string path; - string_vector response; string title; } state; + struct Response { + string option; + string_vector selected; + } response; + auto _run() -> string_vector; friend class BrowserDialogWindow; diff --git a/icarus/GNUmakefile b/icarus/GNUmakefile index d6e84b5a..076078ec 100644 --- a/icarus/GNUmakefile +++ b/icarus/GNUmakefile @@ -1,8 +1,9 @@ +build := release include ../nall/GNUmakefile include ../hiro/GNUmakefile name := icarus -flags += -I.. -O3 +flags += -I.. link += ifeq ($(platform),windows) diff --git a/icarus/heuristics/pc-engine.cpp b/icarus/heuristics/pc-engine.cpp index aed4cb9c..b20156fd 100644 --- a/icarus/heuristics/pc-engine.cpp +++ b/icarus/heuristics/pc-engine.cpp @@ -9,6 +9,9 @@ struct PCEngineCartridge { }; PCEngineCartridge::PCEngineCartridge(string location, uint8_t* data, uint size) { + //skip header + if((size & 0x1fff) == 512) data += 512, size -= 512; + manifest.append("board\n"); manifest.append(" rom name=program.rom size=0x", hex(size), "\n"); manifest.append("\n"); diff --git a/nall/GNUmakefile b/nall/GNUmakefile index 283335a8..18b7b214 100644 --- a/nall/GNUmakefile +++ b/nall/GNUmakefile @@ -59,6 +59,23 @@ ifeq ($(compiler),) endif endif +# build settings +ifeq ($(build),release) + flags += -O3 +else ifeq ($(build),stable) + flags += -O1 +else ifeq ($(build),debug) + flags += -g +else ifeq ($(build),profile) + flags += -pg + link += -pg +else ifeq ($(build),instrument) + flags += -O3 -fprofile-generate + link += -lgcov +else ifeq ($(build),optimize) + flags += -O3 -fprofile-use +endif + # clang settings ifeq ($(findstring clang++,$(compiler)),clang++) flags += -fno-strict-aliasing -fwrapv