mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
bf70044edc
commit
fa6cbac251
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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"};
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
build := release
|
||||
include ../nall/GNUmakefile
|
||||
include ../hiro/GNUmakefile
|
||||
|
||||
name := icarus
|
||||
flags += -I.. -O3
|
||||
flags += -I..
|
||||
link +=
|
||||
|
||||
ifeq ($(platform),windows)
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue