Update to v102r06 release.

byuu says:

Changelog:

  - added higan/emulator/platform.hpp (moved out Emulator::Platform from
    emulator/interface.hpp)
  - moved gmake build paramter to nall/GNUmakefile; both higan and
    icarus use it now
  - added build=profile mode
  - MD: added the region select I/O register
  - MD: started to add region selection support internally (still no
    external select or PAL support)
  - PCE: added cycle stealing when reading/writing to the VDC or VCE;
    and when using ST# instructions
  - PCE: cleaned up PSG to match the behavior of Mednafen (doesn't
    improve sound at all ;_;)
      - note: need to remove loadWaveSample, loadWavePeriod
  - HuC6280: ADC/SBC decimal mode consumes an extra cycle; does not set
    V flag
  - HuC6280: block transfer instructions were taking one cycle too many
  - icarus: added code to strip out PC Engine ROM headers
  - hiro: added options support to BrowserDialog

The last one sure ended in failure. The plan was to put a region
dropdown directly onto hiro::BrowserDialog, and I had all the code for
it working. But I forgot one important detail: the system loads
cartridges AFTER powering on, so even though I could technically change
the system region post-boot, I'd rather not do so.

So that means we have to know what region we want before we even select
a game. Shit.
This commit is contained in:
Tim Allen 2017-02-11 10:56:42 +11:00
parent bf70044edc
commit fa6cbac251
29 changed files with 247 additions and 148 deletions

View File

@ -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

View File

@ -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"

View File

@ -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<uint> { 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<Region> 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;
}

View File

@ -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<uint> { 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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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"};

View File

@ -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 <md/controller/controller.hpp>
#include <md/cpu/cpu.hpp>

View File

@ -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> 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;

View File

@ -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<Region> = 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; }

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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 {

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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];
};

View File

@ -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;

View File

@ -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 {

View File

@ -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 {

View File

@ -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;

View File

@ -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;

View File

@ -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<string_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

View File

@ -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;

View File

@ -1,8 +1,9 @@
build := release
include ../nall/GNUmakefile
include ../hiro/GNUmakefile
name := icarus
flags += -I.. -O3
flags += -I..
link +=
ifeq ($(platform),windows)

View File

@ -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");

View File

@ -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