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 include ../nall/GNUmakefile
target := tomoko target := tomoko
objects := libco emulator audio video resource objects := libco emulator audio video resource
build := release
# console := true # console := true
flags += -I. -I.. 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 ($(platform),windows)
ifeq ($(console),true) ifeq ($(console),true)
link += -mconsole link += -mconsole

View File

@ -12,7 +12,7 @@ using namespace nall;
namespace Emulator { namespace Emulator {
static const string Name = "higan"; 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 Author = "byuu";
static const string License = "GPLv3"; static const string License = "GPLv3";
static const string Website = "http://byuu.org/"; static const string Website = "http://byuu.org/";
@ -26,6 +26,15 @@ namespace Emulator {
static constexpr double PAL = 283.75 * 15'625.0 + 25.0; 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" #include "interface.hpp"

View File

@ -2,18 +2,6 @@
namespace Emulator { 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 Interface {
struct Information { struct Information {
string manufacturer; string manufacturer;
@ -25,6 +13,11 @@ struct Interface {
} capability; } capability;
} information; } information;
struct Region {
string name;
};
vector<Region> regions;
struct Medium { struct Medium {
uint id; uint id;
string name; string name;
@ -96,14 +89,4 @@ struct Interface {
auto videoColor(uint16 r, uint16 g, uint16 b) -> uint32; 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 { namespace Famicom {
#define platform Emulator::platform #define platform Emulator::platform
using File = Emulator::File; namespace File = Emulator::File;
using Scheduler = Emulator::Scheduler; using Scheduler = Emulator::Scheduler;
using Cheat = Emulator::Cheat; using Cheat = Emulator::Cheat;
extern Scheduler scheduler; extern Scheduler scheduler;

View File

@ -12,7 +12,7 @@
namespace GameBoy { namespace GameBoy {
#define platform Emulator::platform #define platform Emulator::platform
using File = Emulator::File; namespace File = Emulator::File;
using Scheduler = Emulator::Scheduler; using Scheduler = Emulator::Scheduler;
using Cheat = Emulator::Cheat; using Cheat = Emulator::Cheat;
extern Scheduler scheduler; extern Scheduler scheduler;

View File

@ -11,7 +11,7 @@
namespace GameBoyAdvance { namespace GameBoyAdvance {
#define platform Emulator::platform #define platform Emulator::platform
using File = Emulator::File; namespace File = Emulator::File;
using Scheduler = Emulator::Scheduler; using Scheduler = Emulator::Scheduler;
extern Scheduler scheduler; extern Scheduler scheduler;

View File

@ -51,6 +51,13 @@ auto BusCPU::writeWord(uint24 addr, uint16 data) -> void {
auto BusCPU::readIO(uint24 addr) -> uint16 { auto BusCPU::readIO(uint24 addr) -> uint16 {
switch(addr & ~1) { 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 0xa10002: return peripherals.controllerPort1->readData();
case 0xa10004: return peripherals.controllerPort2->readData(); case 0xa10004: return peripherals.controllerPort2->readData();
case 0xa10006: return peripherals.extensionPort->readData(); case 0xa10006: return peripherals.extensionPort->readData();

View File

@ -12,6 +12,11 @@ Interface::Interface() {
information.capability.states = false; information.capability.states = false;
information.capability.cheats = 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"}); media.append({ID::MegaDrive, "Mega Drive", "md"});
Port controllerPort1{ID::Port::Controller1, "Controller Port 1"}; Port controllerPort1{ID::Port::Controller1, "Controller Port 1"};

View File

@ -12,7 +12,7 @@
namespace MegaDrive { namespace MegaDrive {
#define platform Emulator::platform #define platform Emulator::platform
using File = Emulator::File; namespace File = Emulator::File;
using Scheduler = Emulator::Scheduler; using Scheduler = Emulator::Scheduler;
extern Scheduler scheduler; extern Scheduler scheduler;
@ -36,6 +36,12 @@ namespace MegaDrive {
uint wait = 0; 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/controller/controller.hpp>
#include <md/cpu/cpu.hpp> #include <md/cpu/cpu.hpp>

View File

@ -10,7 +10,7 @@ auto System::run() -> void {
if(scheduler.enter() == Scheduler::Event::Frame) vdp.refresh(); 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 = {}; information = {};
if(auto fp = platform->open(ID::System, "manifest.bml", File::Read, File::Required)) { 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); auto document = BML::unserialize(information.manifest);
if(!cartridge.load()) return false; if(!cartridge.load()) return false;
information.region = Region::NTSCU;
information.colorburst = Emulator::Constants::Colorburst::NTSC; information.colorburst = Emulator::Constants::Colorburst::NTSC;
this->interface = interface; this->interface = interface;
return information.loaded = true; return information.loaded = true;

View File

@ -1,10 +1,17 @@
struct System { struct System {
enum class Region : uint {
NTSCJ,
NTSCU,
PAL,
};
auto loaded() const -> bool { return information.loaded; } auto loaded() const -> bool { return information.loaded; }
auto region() const -> Region { return information.region; }
auto colorburst() const -> double { return information.colorburst; } auto colorburst() const -> double { return information.colorburst; }
auto run() -> void; auto run() -> void;
auto load(Emulator::Interface*) -> bool; auto load(Emulator::Interface*, maybe<Region> = nothing) -> bool;
auto save() -> void; auto save() -> void;
auto unload() -> void; auto unload() -> void;
auto power() -> void; auto power() -> void;
@ -14,6 +21,7 @@ private:
struct Information { struct Information {
bool loaded = false; bool loaded = false;
Region region = Region::NTSCJ;
string manifest; string manifest;
double colorburst = 0.0; double colorburst = 0.0;
} information; } information;
@ -31,3 +39,7 @@ struct Peripherals {
extern System system; extern System system;
extern Peripherals peripherals; 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 { namespace MasterSystem {
#define platform Emulator::platform #define platform Emulator::platform
using File = Emulator::File; namespace File = Emulator::File;
using Scheduler = Emulator::Scheduler; using Scheduler = Emulator::Scheduler;
extern Scheduler scheduler; extern Scheduler scheduler;
struct Interface; struct Interface;

View File

@ -19,12 +19,14 @@ auto CPU::read(uint8 bank, uint13 addr) -> uint8 {
if(bank == 0xff) { if(bank == 0xff) {
//$0000-03ff VDC or VPC //$0000-03ff VDC or VPC
if((addr & 0x1c00) == 0x0000) { if((addr & 0x1c00) == 0x0000) {
HuC6280::io(); //penalty cycle
if(Model::PCEngine()) return vdc0.read(addr); if(Model::PCEngine()) return vdc0.read(addr);
if(Model::SuperGrafx()) return vpc.read(addr); if(Model::SuperGrafx()) return vpc.read(addr);
} }
//$0400-07ff VCE //$0400-07ff VCE
if((addr & 0x1c00) == 0x0400) { if((addr & 0x1c00) == 0x0400) {
HuC6280::io(); //penalty cycle
return vce.read(addr); return vce.read(addr);
} }
@ -123,12 +125,14 @@ auto CPU::write(uint8 bank, uint13 addr, uint8 data) -> void {
if(bank == 0xff) { if(bank == 0xff) {
//$0000-03ff VDC or VPC //$0000-03ff VDC or VPC
if((addr & 0x1c00) == 0x0000) { if((addr & 0x1c00) == 0x0000) {
HuC6280::io(); //penalty cycle
if(Model::PCEngine()) return vdc0.write(addr, data); if(Model::PCEngine()) return vdc0.write(addr, data);
if(Model::SuperGrafx()) return vpc.write(addr, data); if(Model::SuperGrafx()) return vpc.write(addr, data);
} }
//$0400-07ff VCE //$0400-07ff VCE
if((addr & 0x1c00) == 0x0400) { if((addr & 0x1c00) == 0x0400) {
HuC6280::io(); //penalty cycle
return vce.write(addr, data); return vce.write(addr, data);
} }
@ -186,6 +190,7 @@ auto CPU::write(uint8 bank, uint13 addr, uint8 data) -> void {
//ST0, ST1, ST2 //ST0, ST1, ST2
auto CPU::store(uint2 addr, uint8 data) -> void { auto CPU::store(uint2 addr, uint8 data) -> void {
HuC6280::io(); //penalty cycle
if(addr) addr++; //0,1,2 => 0,2,3 if(addr) addr++; //0,1,2 => 0,2,3
if(Model::PCEngine()) vdc0.write(addr, data); if(Model::PCEngine()) vdc0.write(addr, data);
if(Model::SuperGrafx()) vpc.store(addr, data); if(Model::SuperGrafx()) vpc.store(addr, data);

View File

@ -11,7 +11,7 @@
namespace PCEngine { namespace PCEngine {
#define platform Emulator::platform #define platform Emulator::platform
using File = Emulator::File; namespace File = Emulator::File;
using Scheduler = Emulator::Scheduler; using Scheduler = Emulator::Scheduler;
extern Scheduler 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(&io, sizeof(IO));
memory::fill(&output, sizeof(Output)); memory::fill(&output, sizeof(Output));
} }
@ -6,23 +7,31 @@ auto PSG::Channel::power() -> void {
auto PSG::Channel::run() -> void { auto PSG::Channel::run() -> void {
if(!io.enable) return sample(0); if(!io.enable) return sample(0);
if(io.noiseEnable) { if(!io.direct && --io.wavePeriod == 0) {
if(--io.noisePeriod == 0) { io.wavePeriod = io.waveFrequency;
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;
io.waveOffset++; 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 { auto PSG::Channel::sample(uint5 sample) -> void {

View File

@ -1,81 +1,81 @@
auto PSG::write(uint4 addr, uint8 data) -> void { auto PSG::write(uint4 addr, uint8 data) -> void {
if(addr == 0x00) { if(addr == 0x00) {
io.channel = data.bits(0,2); io.channel = data.bits(0,2);
return;
} }
if(addr == 0x01) { if(addr == 0x01) {
io.volumeRight = data.bits(0,3); io.volumeRight = data.bits(0,3);
io.volumeLeft = data.bits(4,7); io.volumeLeft = data.bits(4,7);
return;
} }
uint3 C = io.channel; if(addr >= 0x02 && addr <= 0x06 && io.channel <= 5) {
channel[io.channel].write(addr, data);
if(addr == 0x02) {
if(C == 6 || C == 7) return;
channel[C].io.frequency.bits(0,7) = data.bits(0,7);
return;
} }
if(addr == 0x03) { if(addr == 0x07 && io.channel >= 4 && io.channel <= 5) {
if(C == 6 || C == 7) return; channel[io.channel].write(addr, data);
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 == 0x08) { if(addr == 0x08) {
io.lfoFrequency = data; io.lfoFrequency = data;
return;
} }
if(addr == 0x09) { if(addr == 0x09) {
io.lfoControl = data.bits(0,1); io.lfoControl = data.bits(0,1);
io.lfoEnable = data.bit(7); 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()); stream = Emulator::audio.createStream(2, system.colorburst());
memory::fill(&io, sizeof(IO)); 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 { struct Channel {
//channel.cpp //channel.cpp
auto power() -> void; auto power(uint id) -> void;
auto run() -> void; auto run() -> void;
auto loadWavePeriod() -> void;
auto loadWaveSample() -> void;
auto sample(uint5 sample) -> void; auto sample(uint5 sample) -> void;
//io.cpp
auto write(uint4 addr, uint8 data) -> void;
struct IO { struct IO {
uint12 frequency; uint12 waveFrequency;
uint4 volume; uint4 volume;
uint1 direct; uint1 direct;
uint1 enable; uint1 enable;
uint4 volumeLeft; uint4 volumeLeft;
uint4 volumeRight; uint4 volumeRight;
uint5 waveData[32]; uint5 waveBuffer[32];
uint5 waveOffset;
uint5 waveDirect;
uint5 noiseFrequency; //channels 4 and 5 only uint5 noiseFrequency; //channels 4 and 5 only
uint1 noiseEnable; //channels 4 and 5 only uint1 noiseEnable; //channels 4 and 5 only
uint12 period; uint12 wavePeriod;
uint5 waveSample;
uint5 waveOffset;
uint12 noisePeriod; uint12 noisePeriod;
uint5 noiseSample; uint5 noiseSample;
} io; } io;
@ -50,6 +55,8 @@ private:
uint left; uint left;
uint right; uint right;
} output; } output;
uint id;
} channel[6]; } channel[6];
}; };

View File

@ -19,7 +19,7 @@ struct HuC6280 {
inline auto store8(uint8, uint8) -> void; inline auto store8(uint8, uint8) -> void;
inline auto store16(uint16, uint8) -> void; inline auto store16(uint16, uint8) -> void;
auto io() -> uint8; auto io() -> void;
auto opcode() -> uint8; auto opcode() -> uint8;
auto operand() -> uint8; auto operand() -> uint8;

View File

@ -4,11 +4,11 @@ auto HuC6280::ADC(uint8 i) -> uint8 {
o = A + i + C; o = A + i + C;
V = ~(A ^ i) & (A ^ o) & 0x80; V = ~(A ^ i) & (A ^ o) & 0x80;
} else { } else {
io();
o = (A & 0x0f) + (i & 0x0f) + (C << 0); o = (A & 0x0f) + (i & 0x0f) + (C << 0);
if(o > 0x09) o += 0x06; if(o > 0x09) o += 0x06;
C = o > 0x0f; C = o > 0x0f;
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f); o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
V = ~(A ^ i) & (A ^ o) & 0x80;
if(o > 0x9f) o += 0x60; if(o > 0x9f) o += 0x60;
} }
C = o.bit(8); C = o.bit(8);
@ -130,11 +130,11 @@ auto HuC6280::SBC(uint8 i) -> uint8 {
o = A + i + C; o = A + i + C;
V = ~(A ^ i) & (A ^ o) & 0x80; V = ~(A ^ i) & (A ^ o) & 0x80;
} else { } else {
io();
o = (A & 0x0f) + (i & 0x0f) + (C << 0); o = (A & 0x0f) + (i & 0x0f) + (C << 0);
if(o <= 0x0f) o -= 0x06; if(o <= 0x0f) o -= 0x06;
C = o > 0x0f; C = o > 0x0f;
o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f); o = (A & 0xf0) + (i & 0xf0) + (C << 4) + (o & 0x0f);
V = ~(A ^ i) & (A ^ o) & 0x80;
if(o <= 0xff) o -= 0x60; if(o <= 0xff) o -= 0x60;
} }
C = o.bit(8); C = o.bit(8);
@ -222,7 +222,6 @@ auto HuC6280::instruction_blockmove(bp alu) -> void {
io(); io();
io(); io();
io(); io();
io();
bool alternate = 0; bool alternate = 0;
do { do {
auto data = load16(source); auto data = load16(source);
@ -497,8 +496,8 @@ L store8(zeropage, data);
auto HuC6280::instruction_ST(uint2 index) -> void { auto HuC6280::instruction_ST(uint2 index) -> void {
auto data = operand(); auto data = operand();
io(); io();
L io(); io();
store(index, data); L store(index, data);
} }
auto HuC6280::instruction_TAM() -> void { 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); step(r.cs);
return 0xff;
} }
auto HuC6280::opcode() -> uint8 { auto HuC6280::opcode() -> uint8 {

View File

@ -21,7 +21,7 @@
namespace SuperFamicom { namespace SuperFamicom {
#define platform Emulator::platform #define platform Emulator::platform
using File = Emulator::File; namespace File = Emulator::File;
using Scheduler = Emulator::Scheduler; using Scheduler = Emulator::Scheduler;
using Cheat = Emulator::Cheat; using Cheat = Emulator::Cheat;
extern Scheduler scheduler; extern Scheduler scheduler;

View File

@ -12,7 +12,7 @@
namespace WonderSwan { namespace WonderSwan {
#define platform Emulator::platform #define platform Emulator::platform
using File = Emulator::File; namespace File = Emulator::File;
using Scheduler = Emulator::Scheduler; using Scheduler = Emulator::Scheduler;
using Cheat = Emulator::Cheat; using Cheat = Emulator::Cheat;
extern Scheduler scheduler; extern Scheduler scheduler;

View File

@ -7,7 +7,7 @@ struct BrowserDialogWindow {
auto change() -> void; auto change() -> void;
auto isFolder(const string& name) -> bool; auto isFolder(const string& name) -> bool;
auto isMatch(const string& name) -> bool; auto isMatch(const string& name) -> bool;
auto run() -> string_vector; auto run() -> BrowserDialog::Response;
auto setPath(string path) -> void; auto setPath(string path) -> void;
private: private:
@ -20,12 +20,14 @@ private:
Button pathUp{&pathLayout, Size{0, 0}, 0}; Button pathUp{&pathLayout, Size{0, 0}, 0};
ListView view{&layout, Size{~0, ~0}, 5}; ListView view{&layout, Size{~0, ~0}, 5};
HorizontalLayout controlLayout{&layout, Size{~0, 0}}; 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}; LineEdit fileName{&controlLayout, Size{~0, 0}, 5};
ComboButton optionList{&controlLayout, Size{0, 0}, 5};
Button acceptButton{&controlLayout, Size{80, 0}, 5}; Button acceptButton{&controlLayout, Size{80, 0}, 5};
Button cancelButton{&controlLayout, Size{80, 0}, 5}; Button cancelButton{&controlLayout, Size{80, 0}, 5};
BrowserDialog::State& state; BrowserDialog::State& state;
BrowserDialog::Response response;
vector<string_vector> filters; vector<string_vector> filters;
}; };
@ -37,20 +39,20 @@ auto BrowserDialogWindow::accept() -> void {
if(state.action == "openFile" && batched) { if(state.action == "openFile" && batched) {
string name = batched.left()->cell(0)->text(); string name = batched.left()->cell(0)->text();
if(isFolder(name)) return setPath({state.path, name}); 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") { if(state.action == "openFiles") {
for(auto item : batched) { for(auto item : batched) {
string name = item->cell(0)->text(); 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) { if(state.action == "openFolder" && batched) {
string name = batched.left()->cell(0)->text(); string name = batched.left()->cell(0)->text();
if(!isMatch(name)) return setPath({state.path, name}); 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") { if(state.action == "saveFile") {
@ -60,15 +62,15 @@ auto BrowserDialogWindow::accept() -> void {
if(file::exists({state.path, name})) { if(file::exists({state.path, name})) {
if(MessageDialog("File already exists; overwrite it?").question() != "Yes") return; 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) { if(state.action == "selectFolder" && batched) {
string name = batched.left()->cell(0)->text(); 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 //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; return false;
} }
auto BrowserDialogWindow::run() -> string_vector { auto BrowserDialogWindow::run() -> BrowserDialog::Response {
state.response.reset(); response = {};
layout.setMargin(5); layout.setMargin(5);
pathName.onActivate([&] { setPath(pathName.text()); }); pathName.onActivate([&] { setPath(pathName.text()); });
@ -127,6 +129,11 @@ auto BrowserDialogWindow::run() -> string_vector {
auto part = filter.split("|", 1L); auto part = filter.split("|", 1L);
filterList.append(ComboButtonItem().setText(part.left())); 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(); }); fileName.setVisible(state.action == "saveFile").onActivate([&] { accept(); });
acceptButton.onActivate([&] { accept(); }); acceptButton.onActivate([&] { accept(); });
if(state.action == "openFile" || state.action == "openFiles" || state.action == "openFolder") acceptButton.setText("Open"); 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.setModal();
window.setVisible(false); window.setVisible(false);
return state.response; return response;
} }
auto BrowserDialogWindow::setPath(string path) -> void { auto BrowserDialogWindow::setPath(string path) -> void {
@ -211,6 +218,10 @@ auto BrowserDialog::openFolder() -> string {
return {}; return {};
} }
auto BrowserDialog::option() -> string {
return response.option;
}
auto BrowserDialog::saveFile() -> string { auto BrowserDialog::saveFile() -> string {
state.action = "saveFile"; state.action = "saveFile";
if(!state.title) state.title = "Save File"; if(!state.title) state.title = "Save File";
@ -218,6 +229,10 @@ auto BrowserDialog::saveFile() -> string {
return {}; return {};
} }
auto BrowserDialog::selected() -> string_vector {
return response.selected;
}
auto BrowserDialog::selectFolder() -> string { auto BrowserDialog::selectFolder() -> string {
state.action = "selectFolder"; state.action = "selectFolder";
if(!state.title) state.title = "Select Folder"; if(!state.title) state.title = "Select Folder";
@ -230,6 +245,11 @@ auto BrowserDialog::setFilters(const string_vector& filters) -> type& {
return *this; return *this;
} }
auto BrowserDialog::setOptions(const string_vector& options) -> type& {
state.options = options;
return *this;
}
auto BrowserDialog::setParent(const sWindow& parent) -> type& { auto BrowserDialog::setParent(const sWindow& parent) -> type& {
state.parent = parent; state.parent = parent;
return *this; return *this;
@ -247,7 +267,8 @@ auto BrowserDialog::setTitle(const string& title) -> type& {
auto BrowserDialog::_run() -> string_vector { auto BrowserDialog::_run() -> string_vector {
if(!state.path) state.path = Path::user(); if(!state.path) state.path = Path::user();
return BrowserDialogWindow(state).run(); response = BrowserDialogWindow(state).run();
return response.selected;
} }
#endif #endif

View File

@ -9,9 +9,12 @@ struct BrowserDialog {
auto openFile() -> string; //one existing file auto openFile() -> string; //one existing file
auto openFiles() -> string_vector; //any existing files or folders auto openFiles() -> string_vector; //any existing files or folders
auto openFolder() -> string; //one existing folder auto openFolder() -> string; //one existing folder
auto option() -> string;
auto saveFile() -> string; //one file auto saveFile() -> string; //one file
auto selected() -> string_vector;
auto selectFolder() -> string; //one existing folder auto selectFolder() -> string; //one existing folder
auto setFilters(const string_vector& filters = {}) -> type&; auto setFilters(const string_vector& filters = {}) -> type&;
auto setOptions(const string_vector& options = {}) -> type&;
auto setParent(const sWindow& parent) -> type&; auto setParent(const sWindow& parent) -> type&;
auto setPath(const string& path = "") -> type&; auto setPath(const string& path = "") -> type&;
auto setTitle(const string& title = "") -> type&; auto setTitle(const string& title = "") -> type&;
@ -20,12 +23,17 @@ private:
struct State { struct State {
string action; string action;
string_vector filters = {"*"}; string_vector filters = {"*"};
string_vector options;
sWindow parent; sWindow parent;
string path; string path;
string_vector response;
string title; string title;
} state; } state;
struct Response {
string option;
string_vector selected;
} response;
auto _run() -> string_vector; auto _run() -> string_vector;
friend class BrowserDialogWindow; friend class BrowserDialogWindow;

View File

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

View File

@ -9,6 +9,9 @@ struct PCEngineCartridge {
}; };
PCEngineCartridge::PCEngineCartridge(string location, uint8_t* data, uint size) { 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("board\n");
manifest.append(" rom name=program.rom size=0x", hex(size), "\n"); manifest.append(" rom name=program.rom size=0x", hex(size), "\n");
manifest.append("\n"); manifest.append("\n");

View File

@ -59,6 +59,23 @@ ifeq ($(compiler),)
endif endif
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 # clang settings
ifeq ($(findstring clang++,$(compiler)),clang++) ifeq ($(findstring clang++,$(compiler)),clang++)
flags += -fno-strict-aliasing -fwrapv flags += -fno-strict-aliasing -fwrapv