mirror of https://github.com/bsnes-emu/bsnes.git
Update to v106r68 release.
byuu says: Changelog: - nall: converted range, iterator, vector to 64-bit - added (very poor) ColecoVision emulation (including Coleco Adam expansion) - added MSX skeleton - added Neo Geo Pocket skeleton - moved audio,video,resource folders into emulator folder - SFC heuristics: BS-X Town cart is "ZBSJ" [hex_usr] The nall change is for future work on things like BPA: I need to be able to handle files larger than 4GB. It is extremely possible that there are still some truncations to 32-bit lurking around, and even more disastrously, possibly some -1s lurking that won't sign-extend to `(uint64_t)0-1`. There's a lot more classes left to do: `string`, `array_view`, `array_span`, etc.
This commit is contained in:
parent
90da691717
commit
3159285eaa
|
@ -34,7 +34,7 @@ endif
|
||||||
$(call delete,obj/*)
|
$(call delete,obj/*)
|
||||||
$(call delete,out/*)
|
$(call delete,out/*)
|
||||||
|
|
||||||
install:
|
install: all
|
||||||
ifeq ($(platform),macos)
|
ifeq ($(platform),macos)
|
||||||
cp -R out/$(name).app /Applications/$(name).app
|
cp -R out/$(name).app /Applications/$(name).app
|
||||||
else ifneq ($(filter $(platform),linux bsd),)
|
else ifneq ($(filter $(platform),linux bsd),)
|
||||||
|
|
|
@ -34,16 +34,13 @@ else
|
||||||
$(error "unsupported platform")
|
$(error "unsupported platform")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
objects := libco emulator audio video resource
|
objects := libco emulator
|
||||||
|
|
||||||
obj/libco.o: ../libco/libco.c
|
obj/libco.o: ../libco/libco.c
|
||||||
obj/emulator.o: emulator/emulator.cpp
|
obj/emulator.o: emulator/emulator.cpp
|
||||||
obj/audio.o: audio/audio.cpp
|
|
||||||
obj/video.o: video/video.cpp
|
|
||||||
obj/resource.o: resource/resource.cpp
|
|
||||||
|
|
||||||
ifeq ($(target),higan)
|
ifeq ($(target),higan)
|
||||||
cores := fc sfc ms md pce gb gba ws
|
cores := fc sfc ms md pce msx gb gba ws ngp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(target),bsnes)
|
ifeq ($(target),bsnes)
|
||||||
|
@ -70,6 +67,10 @@ ifneq ($(filter $(cores),pce),)
|
||||||
include pce/GNUmakefile
|
include pce/GNUmakefile
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(filter $(cores),msx),)
|
||||||
|
include msx/GNUmakefile
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ($(filter $(cores),gb),)
|
ifneq ($(filter $(cores),gb),)
|
||||||
include gb/GNUmakefile
|
include gb/GNUmakefile
|
||||||
endif
|
endif
|
||||||
|
@ -82,6 +83,10 @@ ifneq ($(filter $(cores),ws),)
|
||||||
include ws/GNUmakefile
|
include ws/GNUmakefile
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(filter $(cores),ngp),)
|
||||||
|
include ngp/GNUmakefile
|
||||||
|
endif
|
||||||
|
|
||||||
include processor/GNUmakefile
|
include processor/GNUmakefile
|
||||||
|
|
||||||
flags += $(foreach c,$(call strupper,$(cores)),-DCORE_$c)
|
flags += $(foreach c,$(call strupper,$(cores)),-DCORE_$c)
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#include <emulator/emulator.hpp>
|
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
|
|
||||||
#include "stream.cpp"
|
#include "stream.cpp"
|
|
@ -1,5 +1,9 @@
|
||||||
#include <emulator/emulator.hpp>
|
#include <emulator/emulator.hpp>
|
||||||
|
|
||||||
|
#include <emulator/audio/audio.cpp>
|
||||||
|
#include <emulator/video/video.cpp>
|
||||||
|
#include <emulator/resource/resource.cpp>
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
|
|
||||||
Platform* platform = nullptr;
|
Platform* platform = nullptr;
|
||||||
|
|
|
@ -20,15 +20,15 @@
|
||||||
#include <nall/hash/sha256.hpp>
|
#include <nall/hash/sha256.hpp>
|
||||||
using namespace nall;
|
using namespace nall;
|
||||||
|
|
||||||
#include "types.hpp"
|
|
||||||
#include <libco/libco.h>
|
#include <libco/libco.h>
|
||||||
#include <audio/audio.hpp>
|
#include <emulator/types.hpp>
|
||||||
#include <video/video.hpp>
|
#include <emulator/audio/audio.hpp>
|
||||||
#include <resource/resource.hpp>
|
#include <emulator/video/video.hpp>
|
||||||
|
#include <emulator/resource/resource.hpp>
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "106.67";
|
static const string Version = "106.68";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "https://byuu.org/";
|
static const string Website = "https://byuu.org/";
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Emulator {
|
||||||
|
|
||||||
|
template<typename type>
|
||||||
|
struct WritableMemory {
|
||||||
|
inline auto reset() -> void {
|
||||||
|
delete[] self.data;
|
||||||
|
self.data = nullptr;
|
||||||
|
self.size = 0;
|
||||||
|
self.mask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto allocate(uint size, type fill = ~0ull) -> void {
|
||||||
|
delete[] self.data;
|
||||||
|
self.size = size;
|
||||||
|
self.mask = bit::round(size) - 1;
|
||||||
|
self.data = new uint8[self.mask];
|
||||||
|
memory::fill<type>(self.data, size, fill);
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit operator bool() const { return (bool)self.data; }
|
||||||
|
inline auto data() -> type* { return self.data; }
|
||||||
|
inline auto size() const -> uint { return self.size; }
|
||||||
|
inline auto mask() const -> uint { return self.mask; }
|
||||||
|
|
||||||
|
inline auto operator[](uint address) -> type& {
|
||||||
|
return self.data[address & self.mask];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto read(uint address) -> type {
|
||||||
|
return self.data[address & self.mask];
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto write(uint address, type data) -> void {
|
||||||
|
self.data[address & self.mask] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct {
|
||||||
|
type* data = nullptr;
|
||||||
|
uint size = 0;
|
||||||
|
uint mask = 0;
|
||||||
|
} self;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Before Width: | Height: | Size: 332 B After Width: | Height: | Size: 332 B |
Before Width: | Height: | Size: 329 B After Width: | Height: | Size: 329 B |
Before Width: | Height: | Size: 342 B After Width: | Height: | Size: 342 B |
|
@ -1,5 +1,3 @@
|
||||||
#include <emulator/emulator.hpp>
|
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
|
|
||||||
#include "sprite.cpp"
|
#include "sprite.cpp"
|
|
@ -41,7 +41,7 @@ auto System::load(Emulator::Interface* interface) -> bool {
|
||||||
if(auto name = document["system/cpu/rom/name"].text()) {
|
if(auto name = document["system/cpu/rom/name"].text()) {
|
||||||
if(auto fp = platform->open(ID::System, name, File::Read, File::Required)) {
|
if(auto fp = platform->open(ID::System, name, File::Read, File::Required)) {
|
||||||
fp->read(bios.data, bios.size);
|
fp->read(bios.data, bios.size);
|
||||||
}
|
} else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!cartridge.load()) return false;
|
if(!cartridge.load()) return false;
|
||||||
|
|
|
@ -9,6 +9,13 @@ Cartridge cartridge;
|
||||||
auto Cartridge::load() -> bool {
|
auto Cartridge::load() -> bool {
|
||||||
information = {};
|
information = {};
|
||||||
|
|
||||||
|
if(Model::ColecoVision()) {
|
||||||
|
if(auto loaded = platform->load(ID::ColecoVision, "ColecoVision", "cv", {"NTSC", "PAL"})) {
|
||||||
|
information.pathID = loaded.pathID;
|
||||||
|
information.region = loaded.option;
|
||||||
|
} else return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(Model::SG1000()) {
|
if(Model::SG1000()) {
|
||||||
if(auto loaded = platform->load(ID::SG1000, "SG-1000", "sg1000", {"NTSC", "PAL"})) {
|
if(auto loaded = platform->load(ID::SG1000, "SG-1000", "sg1000", {"NTSC", "PAL"})) {
|
||||||
information.pathID = loaded.pathID;
|
information.pathID = loaded.pathID;
|
||||||
|
|
|
@ -18,7 +18,7 @@ struct Cartridge {
|
||||||
//serialization.cpp
|
//serialization.cpp
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
private:
|
//private:
|
||||||
struct Information {
|
struct Information {
|
||||||
uint pathID = 0;
|
uint pathID = 0;
|
||||||
string region;
|
string region;
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace MasterSystem {
|
||||||
|
|
||||||
ControllerPort controllerPort1;
|
ControllerPort controllerPort1;
|
||||||
ControllerPort controllerPort2;
|
ControllerPort controllerPort2;
|
||||||
|
#include "numberpad/numberpad.cpp"
|
||||||
#include "gamepad/gamepad.cpp"
|
#include "gamepad/gamepad.cpp"
|
||||||
|
|
||||||
Controller::Controller(uint port) : port(port) {
|
Controller::Controller(uint port) : port(port) {
|
||||||
|
@ -36,6 +37,7 @@ auto ControllerPort::connect(uint deviceID) -> void {
|
||||||
|
|
||||||
switch(deviceID) { default:
|
switch(deviceID) { default:
|
||||||
case ID::Device::None: device = new Controller(port); break;
|
case ID::Device::None: device = new Controller(port); break;
|
||||||
|
case ID::Device::NumberPad: device = new NumberPad(port); break;
|
||||||
case ID::Device::Gamepad: device = new Gamepad(port); break;
|
case ID::Device::Gamepad: device = new Gamepad(port); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,8 @@ struct Controller : Thread {
|
||||||
static auto Enter() -> void;
|
static auto Enter() -> void;
|
||||||
auto main() -> void;
|
auto main() -> void;
|
||||||
|
|
||||||
virtual auto readData() -> uint7 { return 0x7f; }
|
virtual auto readData() -> uint8 { return 0xff; }
|
||||||
|
virtual auto writeData(uint8 data) -> void {}
|
||||||
|
|
||||||
const uint port;
|
const uint port;
|
||||||
};
|
};
|
||||||
|
@ -24,4 +25,5 @@ struct ControllerPort {
|
||||||
extern ControllerPort controllerPort1;
|
extern ControllerPort controllerPort1;
|
||||||
extern ControllerPort controllerPort2;
|
extern ControllerPort controllerPort2;
|
||||||
|
|
||||||
|
#include "numberpad/numberpad.hpp"
|
||||||
#include "gamepad/gamepad.hpp"
|
#include "gamepad/gamepad.hpp"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
Gamepad::Gamepad(uint port) : Controller(port) {
|
Gamepad::Gamepad(uint port) : Controller(port) {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Gamepad::readData() -> uint7 {
|
auto Gamepad::readData() -> uint8 {
|
||||||
uint7 data = 0x7f;
|
uint8 data = 0xff;
|
||||||
data.bit(0) = !platform->inputPoll(port, ID::Device::Gamepad, Up);
|
data.bit(0) = !platform->inputPoll(port, ID::Device::Gamepad, Up);
|
||||||
data.bit(1) = !platform->inputPoll(port, ID::Device::Gamepad, Down);
|
data.bit(1) = !platform->inputPoll(port, ID::Device::Gamepad, Down);
|
||||||
data.bit(2) = !platform->inputPoll(port, ID::Device::Gamepad, Left);
|
data.bit(2) = !platform->inputPoll(port, ID::Device::Gamepad, Left);
|
||||||
|
|
|
@ -5,5 +5,5 @@ struct Gamepad : Controller {
|
||||||
|
|
||||||
Gamepad(uint port);
|
Gamepad(uint port);
|
||||||
|
|
||||||
auto readData() -> uint7 override;
|
auto readData() -> uint8 override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
NumberPad::NumberPad(uint port) : Controller(port) {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto NumberPad::readData() -> uint8 {
|
||||||
|
const uint device = ID::Device::NumberPad;
|
||||||
|
uint8 data = 0xff;
|
||||||
|
if(select == 0) {
|
||||||
|
if(platform->inputPoll(port, device, One )) data.bits(0,3) = 0b1101;
|
||||||
|
else if(platform->inputPoll(port, device, Two )) data.bits(0,3) = 0b0111;
|
||||||
|
else if(platform->inputPoll(port, device, Three)) data.bits(0,3) = 0b1100;
|
||||||
|
else if(platform->inputPoll(port, device, Four )) data.bits(0,3) = 0b0010;
|
||||||
|
else if(platform->inputPoll(port, device, Five )) data.bits(0,3) = 0b0011;
|
||||||
|
else if(platform->inputPoll(port, device, Six )) data.bits(0,3) = 0b1110;
|
||||||
|
else if(platform->inputPoll(port, device, Seven)) data.bits(0,3) = 0b0101;
|
||||||
|
else if(platform->inputPoll(port, device, Eight)) data.bits(0,3) = 0b0001;
|
||||||
|
else if(platform->inputPoll(port, device, Nine )) data.bits(0,3) = 0b1011;
|
||||||
|
else if(platform->inputPoll(port, device, Star )) data.bits(0,3) = 0b1001;
|
||||||
|
else if(platform->inputPoll(port, device, Zero )) data.bits(0,3) = 0b1010;
|
||||||
|
else if(platform->inputPoll(port, device, Pound)) data.bits(0,3) = 0b0110;
|
||||||
|
data.bit(6) = !platform->inputPoll(port, device, R);
|
||||||
|
} else {
|
||||||
|
data.bit(0) = !platform->inputPoll(port, device, Up);
|
||||||
|
data.bit(1) = !platform->inputPoll(port, device, Right);
|
||||||
|
data.bit(2) = !platform->inputPoll(port, device, Down);
|
||||||
|
data.bit(3) = !platform->inputPoll(port, device, Left);
|
||||||
|
data.bit(6) = !platform->inputPoll(port, device, L);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto NumberPad::writeData(uint8 data) -> void {
|
||||||
|
select = data.bit(0);
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
struct NumberPad : Controller {
|
||||||
|
enum : uint {
|
||||||
|
Up, Down, Left, Right,
|
||||||
|
L, R,
|
||||||
|
One, Two, Three,
|
||||||
|
Four, Five, Six,
|
||||||
|
Seven, Eight, Nine,
|
||||||
|
Star, Zero, Pound,
|
||||||
|
};
|
||||||
|
|
||||||
|
NumberPad(uint port);
|
||||||
|
|
||||||
|
auto readData() -> uint8;
|
||||||
|
auto writeData(uint8 data) -> void;
|
||||||
|
|
||||||
|
uint1 select;
|
||||||
|
};
|
|
@ -0,0 +1,33 @@
|
||||||
|
auto CPU::readColeco(uint16 address) -> uint8 {
|
||||||
|
uint8 data = 0xff;
|
||||||
|
if(address >= 0x0000 && address <= 0x1fff && coleco.replaceBIOS) return expansion.read(address);
|
||||||
|
if(address >= 0x2000 && address <= 0x7fff && coleco.replaceRAM ) return expansion.read(address);
|
||||||
|
if(address >= 0x0000 && address <= 0x1fff) return system.bios[address & 0x1fff];
|
||||||
|
if(address >= 0x6000 && address <= 0x7fff) return ram.read(address - 0x6000);
|
||||||
|
if(address >= 0x8000 && address <= 0xffff) return cartridge.rom.read(address - 0x8000);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::writeColeco(uint16 address, uint8 data) -> void {
|
||||||
|
if(address >= 0x0000 && address <= 0x1fff && coleco.replaceBIOS) return expansion.write(address, data);
|
||||||
|
if(address >= 0x2000 && address <= 0x7fff && coleco.replaceRAM) return expansion.write(address, data);
|
||||||
|
if(address >= 0x6000 && address <= 0x7fff) return ram.write(address - 0x6000, data);
|
||||||
|
if(address >= 0x8000 && address <= 0xffff) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::inColeco(uint8 address) -> uint8 {
|
||||||
|
uint8 data = 0xff;
|
||||||
|
if(address >= 0xa0 && address <= 0xbf) return !address.bit(0) ? vdp.data() : vdp.status();
|
||||||
|
if(address >= 0xe0 && address <= 0xff && address.bit(1) == 0) return controllerPort1.device->readData();
|
||||||
|
if(address >= 0xe0 && address <= 0xff && address.bit(1) == 1) return controllerPort2.device->readData();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::outColeco(uint8 address, uint8 data) -> void {
|
||||||
|
if(address == 0x53) coleco.replaceRAM = data.bit(0);
|
||||||
|
if(address == 0x7f) coleco.replaceBIOS = data.bit(1);
|
||||||
|
if(address >= 0x80 && address <= 0x9f) controllerPort1.device->writeData(0), controllerPort2.device->writeData(0);
|
||||||
|
if(address >= 0xa0 && address <= 0xbf) return !address.bit(0) ? vdp.data(data) : vdp.control(data);
|
||||||
|
if(address >= 0xc0 && address <= 0xdf) controllerPort1.device->writeData(1), controllerPort2.device->writeData(1);
|
||||||
|
if(address >= 0xe0 && address <= 0xff) return psg.write(data);
|
||||||
|
}
|
|
@ -3,7 +3,8 @@
|
||||||
namespace MasterSystem {
|
namespace MasterSystem {
|
||||||
|
|
||||||
CPU cpu;
|
CPU cpu;
|
||||||
#include "bus.cpp"
|
#include "coleco.cpp"
|
||||||
|
#include "sega.cpp"
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
|
|
||||||
auto CPU::Enter() -> void {
|
auto CPU::Enter() -> void {
|
||||||
|
@ -60,14 +61,36 @@ auto CPU::setINT(bool value) -> void {
|
||||||
state.intLine = value;
|
state.intLine = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto CPU::read(uint16 address) -> uint8 {
|
||||||
|
return Model::ColecoVision() ? readColeco(address) : readSega(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::write(uint16 address, uint8 data) -> void {
|
||||||
|
return Model::ColecoVision() ? writeColeco(address, data) : writeSega(address, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::in(uint8 address) -> uint8 {
|
||||||
|
return Model::ColecoVision() ? inColeco(address) : inSega(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto CPU::out(uint8 address, uint8 data) -> void {
|
||||||
|
return Model::ColecoVision() ? outColeco(address, data) : outSega(address, data);
|
||||||
|
}
|
||||||
|
|
||||||
auto CPU::power() -> void {
|
auto CPU::power() -> void {
|
||||||
Z80::bus = this;
|
Z80::bus = this;
|
||||||
Z80::power();
|
Z80::power();
|
||||||
create(CPU::Enter, system.colorburst());
|
create(CPU::Enter, system.colorburst());
|
||||||
|
|
||||||
|
if(Model::ColecoVision()) ram.allocate(0x0400), expansion.allocate(0x1000);
|
||||||
|
if(Model::SG1000()) ram.allocate(0x0400);
|
||||||
|
if(Model::SC3000()) ram.allocate(0x0800);
|
||||||
|
if(Model::MasterSystem()) ram.allocate(0x2000);
|
||||||
|
if(Model::GameGear()) ram.allocate(0x2000);
|
||||||
|
|
||||||
r.pc = 0x0000; //reset vector address
|
r.pc = 0x0000; //reset vector address
|
||||||
|
|
||||||
state = {};
|
state = {};
|
||||||
|
coleco = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,27 @@ struct CPU : Processor::Z80, Processor::Z80::Bus, Thread {
|
||||||
auto setNMI(bool value) -> void;
|
auto setNMI(bool value) -> void;
|
||||||
auto setINT(bool value) -> void;
|
auto setINT(bool value) -> void;
|
||||||
|
|
||||||
|
auto read(uint16 address) -> uint8 override;
|
||||||
|
auto write(uint16 address, uint8 data) -> void override;
|
||||||
|
|
||||||
|
auto in(uint8 address) -> uint8 override;
|
||||||
|
auto out(uint8 address, uint8 data) -> void override;
|
||||||
|
|
||||||
auto power() -> void;
|
auto power() -> void;
|
||||||
|
|
||||||
//bus.cpp
|
//coleco.cpp
|
||||||
auto read(uint16 addr) -> uint8 override;
|
auto readColeco(uint16 address) -> uint8;
|
||||||
auto write(uint16 addr, uint8 data) -> void override;
|
auto writeColeco(uint16 address, uint8 data) -> void;
|
||||||
|
|
||||||
auto in(uint8 addr) -> uint8 override;
|
auto inColeco(uint8 address) -> uint8;
|
||||||
auto out(uint8 addr, uint8 data) -> void override;
|
auto outColeco(uint8 address, uint8 data) -> void;
|
||||||
|
|
||||||
|
//sega.cpp
|
||||||
|
auto readSega(uint16 address) -> uint8;
|
||||||
|
auto writeSega(uint16 address, uint8 data) -> void;
|
||||||
|
|
||||||
|
auto inSega(uint8 address) -> uint8;
|
||||||
|
auto outSega(uint8 address, uint8 data) -> void;
|
||||||
|
|
||||||
//serialization.cpp
|
//serialization.cpp
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
@ -26,12 +39,18 @@ struct CPU : Processor::Z80, Processor::Z80::Bus, Thread {
|
||||||
vector<Thread*> peripherals;
|
vector<Thread*> peripherals;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8 ram[8 * 1024];
|
Emulator::WritableMemory<uint8> ram;
|
||||||
|
Emulator::WritableMemory<uint8> expansion;
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
bool nmiLine = 0;
|
bool nmiLine = 0;
|
||||||
bool intLine = 0;
|
bool intLine = 0;
|
||||||
} state;
|
} state;
|
||||||
|
|
||||||
|
struct Coleco {
|
||||||
|
uint1 replaceBIOS;
|
||||||
|
uint1 replaceRAM;
|
||||||
|
} coleco;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern CPU cpu;
|
extern CPU cpu;
|
||||||
|
|
|
@ -1,27 +1,22 @@
|
||||||
auto CPU::read(uint16 addr) -> uint8 {
|
auto CPU::readSega(uint16 address) -> uint8 {
|
||||||
uint8 data;
|
uint8 data = 0xff;
|
||||||
|
if(auto result = cartridge.read(address)) {
|
||||||
if(auto result = cartridge.read(addr)) {
|
|
||||||
data = result();
|
data = result();
|
||||||
} else if(addr >= 0xc000) {
|
} else if(address >= 0xc000) {
|
||||||
data = ram[addr & 0x1fff];
|
data = ram.read(address);
|
||||||
}
|
}
|
||||||
|
if(auto result = cheat.find(address, data)) data = result();
|
||||||
if(auto result = cheat.find(addr, data)) {
|
|
||||||
data = result();
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::write(uint16 addr, uint8 data) -> void {
|
auto CPU::writeSega(uint16 address, uint8 data) -> void {
|
||||||
if(cartridge.write(addr, data)) {
|
if(cartridge.write(address, data)) {
|
||||||
} else if(addr >= 0xc000) {
|
} else if(address >= 0xc000) {
|
||||||
ram[addr & 0x1fff] = data;
|
ram.write(address, data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::in(uint8 addr) -> uint8 {
|
auto CPU::inSega(uint8 addr) -> uint8 {
|
||||||
switch(addr >> 6) {
|
switch(addr >> 6) {
|
||||||
|
|
||||||
case 0: {
|
case 0: {
|
||||||
|
@ -87,7 +82,7 @@ auto CPU::in(uint8 addr) -> uint8 {
|
||||||
return 0xff;
|
return 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto CPU::out(uint8 addr, uint8 data) -> void {
|
auto CPU::outSega(uint8 addr, uint8 data) -> void {
|
||||||
if(addr == 0x06) {
|
if(addr == 0x06) {
|
||||||
if(Model::GameGear()) return psg.balance(data);
|
if(Model::GameGear()) return psg.balance(data);
|
||||||
}
|
}
|
|
@ -3,7 +3,7 @@ auto CPU::serialize(serializer& s) -> void {
|
||||||
Z80::Bus::serialize(s);
|
Z80::Bus::serialize(s);
|
||||||
Thread::serialize(s);
|
Thread::serialize(s);
|
||||||
|
|
||||||
s.array(ram);
|
s.array(ram.data(), ram.size());
|
||||||
|
|
||||||
s.integer(state.nmiLine);
|
s.integer(state.nmiLine);
|
||||||
s.integer(state.intLine);
|
s.integer(state.intLine);
|
||||||
|
|
|
@ -0,0 +1,104 @@
|
||||||
|
auto ColecoVisionInterface::information() -> Information {
|
||||||
|
Information information;
|
||||||
|
information.manufacturer = "Coleco Industries";
|
||||||
|
information.name = "ColecoVision";
|
||||||
|
information.extension = "cv";
|
||||||
|
return information;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ColecoVisionInterface::displays() -> vector<Display> {
|
||||||
|
Display display;
|
||||||
|
display.type = Display::Type::CRT;
|
||||||
|
display.colors = 1 << 4;
|
||||||
|
display.width = 256;
|
||||||
|
display.height = 192;
|
||||||
|
display.internalWidth = 256;
|
||||||
|
display.internalHeight = 192;
|
||||||
|
display.aspectCorrection = 1.0;
|
||||||
|
if(Region::NTSC()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (262.0 * 684.0);
|
||||||
|
if(Region::PAL()) display.refreshRate = (system.colorburst() * 15.0 / 5.0) / (312.0 * 684.0);
|
||||||
|
return {display};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ColecoVisionInterface::color(uint32 color) -> uint64 {
|
||||||
|
switch(color.bits(0,3)) {
|
||||||
|
case 0: return 0x0000'0000'0000ull; //transparent
|
||||||
|
case 1: return 0x0000'0000'0000ull; //black
|
||||||
|
case 2: return 0x2121'c8c8'4242ull; //medium green
|
||||||
|
case 3: return 0x5e5e'dcdc'7878ull; //light green
|
||||||
|
case 4: return 0x5454'5555'ededull; //dark blue
|
||||||
|
case 5: return 0x7d7d'7676'fcfcull; //light blue
|
||||||
|
case 6: return 0xd4d4'5252'4d4dull; //dark red
|
||||||
|
case 7: return 0x4242'ebeb'f5f5ull; //cyan
|
||||||
|
case 8: return 0xfcfc'5555'5454ull; //medium red
|
||||||
|
case 9: return 0xffff'7979'7878ull; //light red
|
||||||
|
case 10: return 0xd4d4'c1c1'5454ull; //dark yellow
|
||||||
|
case 11: return 0xe6e6'cece'8080ull; //light yellow
|
||||||
|
case 12: return 0x2121'b0b0'3b3bull; //dark green
|
||||||
|
case 13: return 0xc9c9'5b5b'babaull; //magenta
|
||||||
|
case 14: return 0xcccc'cccc'ccccull; //gray
|
||||||
|
case 15: return 0xffff'ffff'ffffull; //white
|
||||||
|
}
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ColecoVisionInterface::ports() -> vector<Port> { return {
|
||||||
|
{ID::Port::Controller1, "Controller Port 1"},
|
||||||
|
{ID::Port::Controller2, "Controller Port 2"}};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ColecoVisionInterface::devices(uint port) -> vector<Device> {
|
||||||
|
if(port == ID::Port::Controller1) return {
|
||||||
|
{ID::Device::None, "None"},
|
||||||
|
{ID::Device::NumberPad, "Gamepad"}
|
||||||
|
};
|
||||||
|
|
||||||
|
if(port == ID::Port::Controller2) return {
|
||||||
|
{ID::Device::None, "None"},
|
||||||
|
{ID::Device::NumberPad, "Gamepad"}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ColecoVisionInterface::inputs(uint device) -> vector<Input> {
|
||||||
|
using Type = Input::Type;
|
||||||
|
|
||||||
|
if(device == ID::Device::NumberPad) return {
|
||||||
|
{Type::Hat, "Up"},
|
||||||
|
{Type::Hat, "Down"},
|
||||||
|
{Type::Hat, "Left"},
|
||||||
|
{Type::Hat, "Right"},
|
||||||
|
{Type::Button, "L"},
|
||||||
|
{Type::Button, "R"},
|
||||||
|
{Type::Button, "1"},
|
||||||
|
{Type::Button, "2"},
|
||||||
|
{Type::Button, "3"},
|
||||||
|
{Type::Button, "4"},
|
||||||
|
{Type::Button, "5"},
|
||||||
|
{Type::Button, "6"},
|
||||||
|
{Type::Button, "7"},
|
||||||
|
{Type::Button, "8"},
|
||||||
|
{Type::Button, "9"},
|
||||||
|
{Type::Button, "Star"},
|
||||||
|
{Type::Button, "0"},
|
||||||
|
{Type::Button, "Pound"}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ColecoVisionInterface::load() -> bool {
|
||||||
|
return system.load(this, System::Model::ColecoVision);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ColecoVisionInterface::connected(uint port) -> uint {
|
||||||
|
if(port == ID::Port::Controller1) return settings.controllerPort1;
|
||||||
|
if(port == ID::Port::Controller2) return settings.controllerPort2;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ColecoVisionInterface::connect(uint port, uint device) -> void {
|
||||||
|
if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device);
|
||||||
|
if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device);
|
||||||
|
}
|
|
@ -3,6 +3,7 @@
|
||||||
namespace MasterSystem {
|
namespace MasterSystem {
|
||||||
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
|
#include "colecovision.cpp"
|
||||||
#include "sg-1000.cpp"
|
#include "sg-1000.cpp"
|
||||||
#include "sc-3000.cpp"
|
#include "sc-3000.cpp"
|
||||||
#include "master-system.cpp"
|
#include "master-system.cpp"
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace MasterSystem {
|
||||||
struct ID {
|
struct ID {
|
||||||
enum : uint {
|
enum : uint {
|
||||||
System,
|
System,
|
||||||
|
ColecoVision,
|
||||||
SG1000,
|
SG1000,
|
||||||
SC3000,
|
SC3000,
|
||||||
MasterSystem,
|
MasterSystem,
|
||||||
|
@ -23,6 +24,7 @@ struct ID {
|
||||||
SC3000Controls,
|
SC3000Controls,
|
||||||
MasterSystemControls,
|
MasterSystemControls,
|
||||||
GameGearControls,
|
GameGearControls,
|
||||||
|
NumberPad,
|
||||||
Gamepad,
|
Gamepad,
|
||||||
};};
|
};};
|
||||||
};
|
};
|
||||||
|
@ -48,6 +50,22 @@ struct Interface : Emulator::Interface {
|
||||||
auto set(const string& name, const any& value) -> bool override;
|
auto set(const string& name, const any& value) -> bool override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ColecoVisionInterface : Interface {
|
||||||
|
auto information() -> Information override;
|
||||||
|
|
||||||
|
auto displays() -> vector<Display> override;
|
||||||
|
auto color(uint32 color) -> uint64 override;
|
||||||
|
|
||||||
|
auto ports() -> vector<Port> override;
|
||||||
|
auto devices(uint port) -> vector<Device> override;
|
||||||
|
auto inputs(uint device) -> vector<Input> override;
|
||||||
|
|
||||||
|
auto load() -> bool override;
|
||||||
|
|
||||||
|
auto connected(uint port) -> uint override;
|
||||||
|
auto connect(uint port, uint device) -> void override;
|
||||||
|
};
|
||||||
|
|
||||||
struct SG1000Interface : Interface {
|
struct SG1000Interface : Interface {
|
||||||
auto information() -> Information override;
|
auto information() -> Information override;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <emulator/emulator.hpp>
|
#include <emulator/emulator.hpp>
|
||||||
#include <emulator/thread.hpp>
|
#include <emulator/thread.hpp>
|
||||||
#include <emulator/scheduler.hpp>
|
#include <emulator/scheduler.hpp>
|
||||||
|
#include <emulator/memory.hpp>
|
||||||
#include <emulator/cheat.hpp>
|
#include <emulator/cheat.hpp>
|
||||||
|
|
||||||
#include <processor/z80/z80.hpp>
|
#include <processor/z80/z80.hpp>
|
||||||
|
@ -30,6 +31,7 @@ namespace MasterSystem {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Model {
|
struct Model {
|
||||||
|
inline static auto ColecoVision() -> bool;
|
||||||
inline static auto SG1000() -> bool;
|
inline static auto SG1000() -> bool;
|
||||||
inline static auto SC3000() -> bool;
|
inline static auto SC3000() -> bool;
|
||||||
inline static auto MasterSystem() -> bool;
|
inline static auto MasterSystem() -> bool;
|
||||||
|
|
|
@ -29,6 +29,13 @@ auto System::load(Emulator::Interface* interface, Model model) -> bool {
|
||||||
} else return false;
|
} else return false;
|
||||||
|
|
||||||
auto document = BML::unserialize(information.manifest);
|
auto document = BML::unserialize(information.manifest);
|
||||||
|
|
||||||
|
if(MasterSystem::Model::ColecoVision()) {
|
||||||
|
if(auto fp = platform->open(ID::System, "bios.rom", File::Read, File::Required)) {
|
||||||
|
fp->read(bios, 0x2000);
|
||||||
|
} else return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(!cartridge.load()) return false;
|
if(!cartridge.load()) return false;
|
||||||
|
|
||||||
if(cartridge.region() == "NTSC") {
|
if(cartridge.region() == "NTSC") {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
struct System {
|
struct System {
|
||||||
enum class Model : uint { SG1000, SC3000, MasterSystem, GameGear };
|
enum class Model : uint { ColecoVision, SG1000, SC3000, MasterSystem, GameGear };
|
||||||
enum class Region : uint { NTSC, PAL };
|
enum class Region : uint { NTSC, PAL };
|
||||||
|
|
||||||
auto loaded() const -> bool { return information.loaded; }
|
auto loaded() const -> bool { return information.loaded; }
|
||||||
|
@ -23,6 +23,8 @@ struct System {
|
||||||
auto serializeAll(serializer&) -> void;
|
auto serializeAll(serializer&) -> void;
|
||||||
auto serialize(serializer&) -> void;
|
auto serialize(serializer&) -> void;
|
||||||
|
|
||||||
|
uint8 bios[0x2000];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Emulator::Interface* interface = nullptr;
|
Emulator::Interface* interface = nullptr;
|
||||||
|
|
||||||
|
@ -38,6 +40,7 @@ private:
|
||||||
|
|
||||||
extern System system;
|
extern System system;
|
||||||
|
|
||||||
|
auto Model::ColecoVision() -> bool { return system.model() == System::Model::ColecoVision; }
|
||||||
auto Model::SG1000() -> bool { return system.model() == System::Model::SG1000; }
|
auto Model::SG1000() -> bool { return system.model() == System::Model::SG1000; }
|
||||||
auto Model::SC3000() -> bool { return system.model() == System::Model::SC3000; }
|
auto Model::SC3000() -> bool { return system.model() == System::Model::SC3000; }
|
||||||
auto Model::MasterSystem() -> bool { return system.model() == System::Model::MasterSystem; }
|
auto Model::MasterSystem() -> bool { return system.model() == System::Model::MasterSystem; }
|
||||||
|
|
|
@ -38,10 +38,10 @@ auto VDP::Background::graphics1(uint8 hoffset, uint9 voffset) -> void {
|
||||||
|
|
||||||
uint8 color = vdp.vram[colorAddress];
|
uint8 color = vdp.vram[colorAddress];
|
||||||
uint3 index = hoffset ^ 7;
|
uint3 index = hoffset ^ 7;
|
||||||
if(vdp.vram[patternAddress].bit(index)) {
|
if(!vdp.vram[patternAddress].bit(index)) {
|
||||||
output.color = color.bits(4,7);
|
|
||||||
} else {
|
|
||||||
output.color = color.bits(0,3);
|
output.color = color.bits(0,3);
|
||||||
|
} else {
|
||||||
|
output.color = color.bits(4,7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,12 +67,12 @@ auto VDP::Background::graphics2(uint8 hoffset, uint9 voffset) -> void {
|
||||||
colorAddress.bit(13) = vdp.io.colorTableAddress.bit(7);
|
colorAddress.bit(13) = vdp.io.colorTableAddress.bit(7);
|
||||||
|
|
||||||
uint8 colorMask = vdp.io.colorTableAddress.bits(0,6) << 1 | 1;
|
uint8 colorMask = vdp.io.colorTableAddress.bits(0,6) << 1 | 1;
|
||||||
uint8 color = vdp.vram[colorAddress] & colorMask;
|
uint8 color = vdp.vram[colorAddress];
|
||||||
uint3 index = hoffset ^ 7;
|
uint3 index = hoffset ^ 7;
|
||||||
if(vdp.vram[patternAddress].bit(index)) {
|
if(!vdp.vram[patternAddress].bit(index)) {
|
||||||
output.color = color.bits(4,7);
|
|
||||||
} else {
|
|
||||||
output.color = color.bits(0,3);
|
output.color = color.bits(0,3);
|
||||||
|
} else {
|
||||||
|
output.color = color.bits(4,7);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ auto VDP::registerWrite(uint4 addr, uint8 data) -> void {
|
||||||
case 0x0: {
|
case 0x0: {
|
||||||
io.externalSync = data.bit(0);
|
io.externalSync = data.bit(0);
|
||||||
io.mode.bit(1) = data.bit(1);
|
io.mode.bit(1) = data.bit(1);
|
||||||
io.mode.bit(3) = data.bit(2) & !Model::SG1000() & !Model::SC3000();
|
io.mode.bit(3) = data.bit(2) & !Model::ColecoVision() && !Model::SG1000() & !Model::SC3000();
|
||||||
io.spriteShift = data.bit(3);
|
io.spriteShift = data.bit(3);
|
||||||
io.lineInterrupts = data.bit(4);
|
io.lineInterrupts = data.bit(4);
|
||||||
io.leftClip = data.bit(5);
|
io.leftClip = data.bit(5);
|
||||||
|
|
|
@ -72,7 +72,7 @@ auto VDP::step(uint clocks) -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::refresh() -> void {
|
auto VDP::refresh() -> void {
|
||||||
if(Model::SG1000() || Model::SC3000()) {
|
if(Model::ColecoVision() || Model::SG1000() || Model::SC3000()) {
|
||||||
uint32* screen = buffer;
|
uint32* screen = buffer;
|
||||||
screen += 24 * 256;
|
screen += 24 * 256;
|
||||||
Emulator::video.refresh(screen, 256 * sizeof(uint32), 256, 192);
|
Emulator::video.refresh(screen, 256 * sizeof(uint32), 256, 192);
|
||||||
|
@ -108,6 +108,8 @@ auto VDP::power() -> void {
|
||||||
create(VDP::Enter, system.colorburst() * 15.0 / 5.0);
|
create(VDP::Enter, system.colorburst() * 15.0 / 5.0);
|
||||||
|
|
||||||
memory::fill<uint32>(buffer, 256 * 264);
|
memory::fill<uint32>(buffer, 256 * 264);
|
||||||
|
for(auto& byte : vram) byte = 0x00;
|
||||||
|
for(auto& byte : cram) byte = 0x00;
|
||||||
io = {};
|
io = {};
|
||||||
|
|
||||||
background.power();
|
background.power();
|
||||||
|
@ -115,7 +117,7 @@ auto VDP::power() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto VDP::palette(uint5 index) -> uint12 {
|
auto VDP::palette(uint5 index) -> uint12 {
|
||||||
if(Model::SG1000() || Model::SC3000()) return index.bits(0,3);
|
if(Model::ColecoVision() || Model::SG1000() || Model::SC3000()) return index.bits(0,3);
|
||||||
//Master System and Game Gear approximate TMS9918A colors by converting to RGB6 palette colors
|
//Master System and Game Gear approximate TMS9918A colors by converting to RGB6 palette colors
|
||||||
static uint6 palette[16] = {
|
static uint6 palette[16] = {
|
||||||
0x00, 0x00, 0x08, 0x0c, 0x10, 0x30, 0x01, 0x3c,
|
0x00, 0x00, 0x08, 0x0c, 0x10, 0x30, 0x01, 0x3c,
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
processors += z80
|
||||||
|
|
||||||
|
objects += msx-interface msx-system
|
||||||
|
|
||||||
|
obj/msx-interface.o: msx/interface/interface.cpp
|
||||||
|
obj/msx-system.o: msx/system/system.cpp
|
|
@ -0,0 +1,107 @@
|
||||||
|
#include <msx/msx.hpp>
|
||||||
|
|
||||||
|
namespace MSX {
|
||||||
|
|
||||||
|
auto Interface::information() -> Information {
|
||||||
|
Information information;
|
||||||
|
information.manufacturer = "";
|
||||||
|
information.name = "MSX";
|
||||||
|
information.extension = ".msx";
|
||||||
|
return information;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::displays() -> vector<Display> {
|
||||||
|
Display display;
|
||||||
|
display.type = Display::Type::CRT;
|
||||||
|
display.colors = 1 << 4;
|
||||||
|
display.width = 256;
|
||||||
|
display.height = 192;
|
||||||
|
display.internalWidth = 256;
|
||||||
|
display.internalHeight = 192;
|
||||||
|
display.aspectCorrection = 1.0;
|
||||||
|
display.refreshRate = 60.0; //todo: PAL
|
||||||
|
return {display};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::color(uint32 color) -> uint64 {
|
||||||
|
switch(color.bits(0,3)) {
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::loaded() -> bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::hashes() -> vector<string> {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::manifests() -> vector<string> {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::titles() -> vector<string> {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::load() -> bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::save() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::unload() -> void {
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::ports() -> vector<Port> { return {
|
||||||
|
{ID::Port::Controller1, "Controller Port 1"},
|
||||||
|
{ID::Port::Controller2, "Controller Port 2"}};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::devices(uint port) -> vector<Device> {
|
||||||
|
if(port == ID::Port::Controller1) return {
|
||||||
|
{ID::Device::None, "None" },
|
||||||
|
{ID::Device::Gamepad, "Gamepad"}
|
||||||
|
};
|
||||||
|
|
||||||
|
if(port == ID::Port::Controller2) return {
|
||||||
|
{ID::Device::None, "None" },
|
||||||
|
{ID::Device::Gamepad, "Gamepad"}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::inputs(uint device) -> vector<Input> {
|
||||||
|
using Type = Input::Type;
|
||||||
|
|
||||||
|
if(device == ID::Device::Gamepad) return {
|
||||||
|
{Type::Hat, "Up" },
|
||||||
|
{Type::Hat, "Down" },
|
||||||
|
{Type::Hat, "Left" },
|
||||||
|
{Type::Hat, "Right"},
|
||||||
|
{Type::Button, "1" },
|
||||||
|
{Type::Button, "2" }
|
||||||
|
};
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::power() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::run() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::serialize() -> serializer {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::unserialize(serializer& s) -> bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
#if defined(CORE_MSX)
|
||||||
|
|
||||||
|
namespace MSX {
|
||||||
|
|
||||||
|
struct ID {
|
||||||
|
enum : uint {
|
||||||
|
System,
|
||||||
|
MSX,
|
||||||
|
MSX2,
|
||||||
|
MSX2Plus,
|
||||||
|
MSXTurboR,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Port { enum : uint {
|
||||||
|
Controller1,
|
||||||
|
Controller2,
|
||||||
|
};};
|
||||||
|
|
||||||
|
struct Device { enum : uint {
|
||||||
|
None,
|
||||||
|
Gamepad,
|
||||||
|
};};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Interface : Emulator::Interface {
|
||||||
|
auto information() -> Information override;
|
||||||
|
|
||||||
|
auto displays() -> vector<Display> override;
|
||||||
|
auto color(uint32 color) -> uint64 override;
|
||||||
|
|
||||||
|
auto loaded() -> bool override;
|
||||||
|
auto hashes() -> vector<string> override;
|
||||||
|
auto manifests() -> vector<string> override;
|
||||||
|
auto titles() -> vector<string> override;
|
||||||
|
auto load() -> bool override;
|
||||||
|
auto save() -> void override;
|
||||||
|
auto unload() -> void override;
|
||||||
|
|
||||||
|
auto ports() -> vector<Port> override;
|
||||||
|
auto devices(uint port) -> vector<Device> override;
|
||||||
|
auto inputs(uint device) -> vector<Input> override;
|
||||||
|
|
||||||
|
auto power() -> void override;
|
||||||
|
auto run() -> void override;
|
||||||
|
|
||||||
|
auto serialize() -> serializer override;
|
||||||
|
auto unserialize(serializer&) -> bool override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,47 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//license: GPLv3
|
||||||
|
//started: ...
|
||||||
|
|
||||||
|
#include <emulator/emulator.hpp>
|
||||||
|
#include <emulator/thread.hpp>
|
||||||
|
#include <emulator/scheduler.hpp>
|
||||||
|
#include <emulator/cheat.hpp>
|
||||||
|
|
||||||
|
#include <processor/z80/z80.hpp>
|
||||||
|
|
||||||
|
namespace MSX {
|
||||||
|
#define platform Emulator::platform
|
||||||
|
namespace File = Emulator::File;
|
||||||
|
using Scheduler = Emulator::Scheduler;
|
||||||
|
using Cheat = Emulator::Cheat;
|
||||||
|
extern Scheduler scheduler;
|
||||||
|
extern Cheat cheat;
|
||||||
|
|
||||||
|
struct Thread : Emulator::Thread {
|
||||||
|
auto create(auto (*entrypoint)() -> void, double frequency) -> void {
|
||||||
|
Emulator::Thread::create(entrypoint, frequency);
|
||||||
|
scheduler.append(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto synchronize(Thread& thread) -> void {
|
||||||
|
if(clock() >= thread.clock()) scheduler.resume(thread);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Model {
|
||||||
|
inline static auto MSX() -> bool;
|
||||||
|
inline static auto MSX2() -> bool;
|
||||||
|
inline static auto MSX2Plus() -> bool;
|
||||||
|
inline static auto MSXTurboR() -> bool;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Region {
|
||||||
|
inline static auto NTSC() -> bool;
|
||||||
|
inline static auto PAL() -> bool;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <msx/system/system.hpp>
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <msx/interface/interface.hpp>
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include <msx/msx.hpp>
|
||||||
|
|
||||||
|
namespace MSX {
|
||||||
|
|
||||||
|
System system;
|
||||||
|
Scheduler scheduler;
|
||||||
|
Cheat cheat;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
struct System {
|
||||||
|
enum class Model : uint { MSX, MSX2, MSX2Plus, MSXTurboR };
|
||||||
|
enum class Region : uint { NTSC, PAL };
|
||||||
|
|
||||||
|
auto loaded() const -> bool { return information.loaded; }
|
||||||
|
auto model() const -> Model { return information.model; }
|
||||||
|
auto region() const -> Region { return information.region; }
|
||||||
|
|
||||||
|
struct Information {
|
||||||
|
string manifest;
|
||||||
|
bool loaded = false;
|
||||||
|
Model model = Model::MSX;
|
||||||
|
Region region = Region::NTSC;
|
||||||
|
} information;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern System system;
|
||||||
|
|
||||||
|
auto Model::MSX() -> bool { return system.model() == System::Model::MSX; }
|
||||||
|
auto Model::MSX2() -> bool { return system.model() == System::Model::MSX2; }
|
||||||
|
auto Model::MSX2Plus() -> bool { return system.model() == System::Model::MSX2Plus; }
|
||||||
|
auto Model::MSXTurboR() -> bool { return system.model() == System::Model::MSXTurboR; }
|
||||||
|
|
||||||
|
auto Region::NTSC() -> bool { return system.region() == System::Region::NTSC; }
|
||||||
|
auto Region::PAL() -> bool { return system.region() == System::Region::PAL; }
|
|
@ -0,0 +1,6 @@
|
||||||
|
processors += z80
|
||||||
|
|
||||||
|
objects += ngp-interface ngp-system
|
||||||
|
|
||||||
|
obj/ngp-interface.o: ngp/interface/interface.cpp
|
||||||
|
obj/ngp-system.o: ngp/system/system.cpp
|
|
@ -0,0 +1,92 @@
|
||||||
|
#include <ngp/ngp.hpp>
|
||||||
|
|
||||||
|
namespace NeoGeoPocket {
|
||||||
|
|
||||||
|
#include "neo-geo-pocket.cpp"
|
||||||
|
#include "neo-geo-pocket-color.cpp"
|
||||||
|
|
||||||
|
//todo: add correct values
|
||||||
|
auto Interface::displays() -> vector<Display> {
|
||||||
|
Display display;
|
||||||
|
display.type = Display::Type::LCD;
|
||||||
|
display.colors = 1;
|
||||||
|
display.width = 320;
|
||||||
|
display.height = 240;
|
||||||
|
display.internalWidth = 320;
|
||||||
|
display.internalHeight = 240;
|
||||||
|
display.aspectCorrection = 1.0;
|
||||||
|
display.refreshRate = 60.0;
|
||||||
|
return {display};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::color(uint32 color) -> uint64 {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::loaded() -> bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::hashes() -> vector<string> {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::manifests() -> vector<string> {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::titles() -> vector<string> {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::load() -> bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::save() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::unload() -> void {
|
||||||
|
save();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::ports() -> vector<Port> { return {
|
||||||
|
{ID::Port::Hardware, "Hardware"}};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::devices(uint port) -> vector<Device> {
|
||||||
|
if(port == ID::Port::Hardware) return {
|
||||||
|
{ID::Device::Controls, "Controls"}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::inputs(uint device) -> vector<Input> {
|
||||||
|
using Type = Input::Type;
|
||||||
|
|
||||||
|
if(device == ID::Device::Controls) return {
|
||||||
|
{Type::Hat, "Up" },
|
||||||
|
{Type::Hat, "Down" },
|
||||||
|
{Type::Hat, "Left" },
|
||||||
|
{Type::Hat, "Right"}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::power() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::run() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::serialize() -> serializer {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Interface::unserialize(serializer& s) -> bool {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
#if defined(CORE_NGP)
|
||||||
|
|
||||||
|
namespace NeoGeoPocket {
|
||||||
|
|
||||||
|
struct ID {
|
||||||
|
enum : uint {
|
||||||
|
System,
|
||||||
|
NeoGeoPocket,
|
||||||
|
NeoGeoPocketColor,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Port { enum : uint {
|
||||||
|
Hardware,
|
||||||
|
};};
|
||||||
|
|
||||||
|
struct Device { enum : uint {
|
||||||
|
Controls,
|
||||||
|
};};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Interface : Emulator::Interface {
|
||||||
|
auto displays() -> vector<Display> override;
|
||||||
|
auto color(uint32 color) -> uint64 override;
|
||||||
|
|
||||||
|
auto loaded() -> bool override;
|
||||||
|
auto hashes() -> vector<string> override;
|
||||||
|
auto manifests() -> vector<string> override;
|
||||||
|
auto titles() -> vector<string> override;
|
||||||
|
auto load() -> bool override;
|
||||||
|
auto save() -> void override;
|
||||||
|
auto unload() -> void override;
|
||||||
|
|
||||||
|
auto ports() -> vector<Port> override;
|
||||||
|
auto devices(uint port) -> vector<Device> override;
|
||||||
|
auto inputs(uint device) -> vector<Input> override;
|
||||||
|
|
||||||
|
auto power() -> void override;
|
||||||
|
auto run() -> void override;
|
||||||
|
|
||||||
|
auto serialize() -> serializer override;
|
||||||
|
auto unserialize(serializer&) -> bool override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NeoGeoPocketInterface : Interface {
|
||||||
|
auto information() -> Information override;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct NeoGeoPocketColorInterface : Interface {
|
||||||
|
auto information() -> Information override;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,7 @@
|
||||||
|
auto NeoGeoPocketColorInterface::information() -> Information {
|
||||||
|
Information information;
|
||||||
|
information.manufacturer = "SNK";
|
||||||
|
information.name = "Neo Geo Pocket Color";
|
||||||
|
information.extension = "ngpc";
|
||||||
|
return information;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
auto NeoGeoPocketInterface::information() -> Information {
|
||||||
|
Information information;
|
||||||
|
information.manufacturer = "SNK";
|
||||||
|
information.name = "Neo Geo Pocket";
|
||||||
|
information.extension = "ngp";
|
||||||
|
return information;
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//license: GPLv3
|
||||||
|
//started: ...
|
||||||
|
|
||||||
|
#include <emulator/emulator.hpp>
|
||||||
|
#include <emulator/thread.hpp>
|
||||||
|
#include <emulator/scheduler.hpp>
|
||||||
|
#include <emulator/cheat.hpp>
|
||||||
|
|
||||||
|
#include <processor/z80/z80.hpp>
|
||||||
|
|
||||||
|
namespace NeoGeoPocket {
|
||||||
|
#define platform Emulator::platform
|
||||||
|
namespace File = Emulator::File;
|
||||||
|
using Scheduler = Emulator::Scheduler;
|
||||||
|
using Cheat = Emulator::Cheat;
|
||||||
|
extern Scheduler scheduler;
|
||||||
|
extern Cheat cheat;
|
||||||
|
|
||||||
|
struct Thread : Emulator::Thread {
|
||||||
|
auto create(auto (*entrypoint)() -> void, double frequency) -> void {
|
||||||
|
Emulator::Thread::create(entrypoint, frequency);
|
||||||
|
scheduler.append(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline auto synchronize(Thread& thread) -> void {
|
||||||
|
if(clock() >= thread.clock()) scheduler.resume(thread);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Model {
|
||||||
|
inline static auto NeoGeoPocket() -> bool;
|
||||||
|
inline static auto NeoGeoPocketColor() -> bool;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include <ngp/system/system.hpp>
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <ngp/interface/interface.hpp>
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include <ngp/ngp.hpp>
|
||||||
|
|
||||||
|
namespace NeoGeoPocket {
|
||||||
|
|
||||||
|
System system;
|
||||||
|
Scheduler scheduler;
|
||||||
|
Cheat cheat;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
struct System {
|
||||||
|
enum class Model : uint { NeoGeoPocket, NeoGeoPocketColor };
|
||||||
|
|
||||||
|
auto loaded() const -> bool { return information.loaded; }
|
||||||
|
auto model() const -> Model { return information.model; }
|
||||||
|
|
||||||
|
struct Information {
|
||||||
|
string manifest;
|
||||||
|
bool loaded = false;
|
||||||
|
Model model = Model::NeoGeoPocket;
|
||||||
|
} information;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern System system;
|
||||||
|
|
||||||
|
auto Model::NeoGeoPocket() -> bool { return system.model() == System::Model::NeoGeoPocket; }
|
||||||
|
auto Model::NeoGeoPocketColor() -> bool { return system.model() == System::Model::NeoGeoPocketColor; }
|
|
@ -0,0 +1 @@
|
||||||
|
system name:ColecoVision
|
|
@ -0,0 +1 @@
|
||||||
|
system name:MSX
|
|
@ -0,0 +1 @@
|
||||||
|
system name:Neo Geo Pocket Color
|
|
@ -0,0 +1 @@
|
||||||
|
system name:Neo Geo Pocket
|
|
@ -63,7 +63,7 @@ auto Program::loadState(string filename) -> bool {
|
||||||
if(filename != "Quick/Undo") saveUndoState();
|
if(filename != "Quick/Undo") saveUndoState();
|
||||||
if(filename == "Quick/Undo") saveRedoState();
|
if(filename == "Quick/Undo") saveRedoState();
|
||||||
auto serializerRLE = Decode::RLE<1>({memory.data() + 3 * sizeof(uint), memory.size() - 3 * sizeof(uint)});
|
auto serializerRLE = Decode::RLE<1>({memory.data() + 3 * sizeof(uint), memory.size() - 3 * sizeof(uint)});
|
||||||
serializer s{serializerRLE.data(), serializerRLE.size()};
|
serializer s{serializerRLE.data(), (uint)serializerRLE.size()};
|
||||||
if(!emulator->unserialize(s)) return showMessage({"[", prefix, "] is in incompatible format"}), false;
|
if(!emulator->unserialize(s)) return showMessage({"[", prefix, "] is in incompatible format"}), false;
|
||||||
return showMessage({"Loaded [", prefix, "]"}), true;
|
return showMessage({"Loaded [", prefix, "]"}), true;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -4,9 +4,11 @@
|
||||||
#include <ms/interface/interface.hpp>
|
#include <ms/interface/interface.hpp>
|
||||||
#include <md/interface/interface.hpp>
|
#include <md/interface/interface.hpp>
|
||||||
#include <pce/interface/interface.hpp>
|
#include <pce/interface/interface.hpp>
|
||||||
|
#include <msx/interface/interface.hpp>
|
||||||
#include <gb/interface/interface.hpp>
|
#include <gb/interface/interface.hpp>
|
||||||
#include <gba/interface/interface.hpp>
|
#include <gba/interface/interface.hpp>
|
||||||
#include <ws/interface/interface.hpp>
|
#include <ws/interface/interface.hpp>
|
||||||
|
#include <ngp/interface/interface.hpp>
|
||||||
#include "platform.cpp"
|
#include "platform.cpp"
|
||||||
#include "game.cpp"
|
#include "game.cpp"
|
||||||
#include "state.cpp"
|
#include "state.cpp"
|
||||||
|
@ -42,6 +44,12 @@ Program::Program(Arguments arguments) {
|
||||||
#ifdef CORE_PCE
|
#ifdef CORE_PCE
|
||||||
emulators.append(new PCEngine::SuperGrafxInterface);
|
emulators.append(new PCEngine::SuperGrafxInterface);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CORE_MS
|
||||||
|
emulators.append(new MasterSystem::ColecoVisionInterface);
|
||||||
|
#endif
|
||||||
|
#ifdef CORE_MSX
|
||||||
|
emulators.append(new MSX::Interface);
|
||||||
|
#endif
|
||||||
#ifdef CORE_GB
|
#ifdef CORE_GB
|
||||||
emulators.append(new GameBoy::GameBoyInterface);
|
emulators.append(new GameBoy::GameBoyInterface);
|
||||||
#endif
|
#endif
|
||||||
|
@ -63,6 +71,12 @@ Program::Program(Arguments arguments) {
|
||||||
#ifdef CORE_WS
|
#ifdef CORE_WS
|
||||||
emulators.append(new WonderSwan::PocketChallengeV2Interface);
|
emulators.append(new WonderSwan::PocketChallengeV2Interface);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef CORE_NGP
|
||||||
|
emulators.append(new NeoGeoPocket::NeoGeoPocketInterface);
|
||||||
|
#endif
|
||||||
|
#ifdef CORE_NGP
|
||||||
|
emulators.append(new NeoGeoPocket::NeoGeoPocketColorInterface);
|
||||||
|
#endif
|
||||||
|
|
||||||
new Presentation;
|
new Presentation;
|
||||||
presentation->setVisible();
|
presentation->setVisible();
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
auto Icarus::colecoVisionManifest(string location) -> string {
|
||||||
|
vector<uint8_t> buffer;
|
||||||
|
concatenate(buffer, {location, "program.rom"});
|
||||||
|
return colecoVisionManifest(buffer, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Icarus::colecoVisionManifest(vector<uint8_t>& buffer, string location) -> string {
|
||||||
|
if(settings["icarus/UseDatabase"].boolean()) {
|
||||||
|
auto digest = Hash::SHA256(buffer).digest();
|
||||||
|
for(auto game : Database::ColecoVision.find("game")) {
|
||||||
|
if(game["sha256"].text() == digest) return BML::serialize(game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(settings["icarus/UseHeuristics"].boolean()) {
|
||||||
|
Heuristics::ColecoVision game{buffer, location};
|
||||||
|
if(auto manifest = game.manifest()) return manifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Icarus::colecoVisionImport(vector<uint8_t>& buffer, string location) -> string {
|
||||||
|
auto name = Location::prefix(location);
|
||||||
|
auto source = Location::path(location);
|
||||||
|
string target{settings["Library/Location"].text(), "ColecoVision/", name, ".cv/"};
|
||||||
|
|
||||||
|
auto manifest = colecoVisionManifest(buffer, location);
|
||||||
|
if(!manifest) return failure("failed to parse ROM image");
|
||||||
|
|
||||||
|
if(!create(target)) return failure("library path unwritable");
|
||||||
|
if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) {
|
||||||
|
copy({source, name, ".sav"}, {target, "save.ram"});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest);
|
||||||
|
write({target, "program.rom"}, buffer);
|
||||||
|
return success(target);
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ Icarus::Icarus() {
|
||||||
Database::MegaDrive = BML::unserialize(string::read(locate("Database/Mega Drive.bml")));
|
Database::MegaDrive = BML::unserialize(string::read(locate("Database/Mega Drive.bml")));
|
||||||
Database::PCEngine = BML::unserialize(string::read(locate("Database/PC Engine.bml")));
|
Database::PCEngine = BML::unserialize(string::read(locate("Database/PC Engine.bml")));
|
||||||
Database::SuperGrafx = BML::unserialize(string::read(locate("Database/SuperGrafx.bml")));
|
Database::SuperGrafx = BML::unserialize(string::read(locate("Database/SuperGrafx.bml")));
|
||||||
|
Database::ColecoVision = BML::unserialize(string::read(locate("Database/ColecoVision.bml")));
|
||||||
Database::MSX = BML::unserialize(string::read(locate("Database/MSX.bml")));
|
Database::MSX = BML::unserialize(string::read(locate("Database/MSX.bml")));
|
||||||
Database::GameBoy = BML::unserialize(string::read(locate("Database/Game Boy.bml")));
|
Database::GameBoy = BML::unserialize(string::read(locate("Database/Game Boy.bml")));
|
||||||
Database::GameBoyColor = BML::unserialize(string::read(locate("Database/Game Boy Color.bml")));
|
Database::GameBoyColor = BML::unserialize(string::read(locate("Database/Game Boy Color.bml")));
|
||||||
|
@ -15,6 +16,8 @@ Icarus::Icarus() {
|
||||||
Database::WonderSwan = BML::unserialize(string::read(locate("Database/WonderSwan.bml")));
|
Database::WonderSwan = BML::unserialize(string::read(locate("Database/WonderSwan.bml")));
|
||||||
Database::WonderSwanColor = BML::unserialize(string::read(locate("Database/WonderSwan Color.bml")));
|
Database::WonderSwanColor = BML::unserialize(string::read(locate("Database/WonderSwan Color.bml")));
|
||||||
Database::PocketChallengeV2 = BML::unserialize(string::read(locate("Database/Pocket Challenge V2.bml")));
|
Database::PocketChallengeV2 = BML::unserialize(string::read(locate("Database/Pocket Challenge V2.bml")));
|
||||||
|
Database::NeoGeoPocket = BML::unserialize(string::read(locate("Database/Neo Geo Pocket.bml")));
|
||||||
|
Database::NeoGeoPocketColor = BML::unserialize(string::read(locate("Database/Neo Geo Pocket Color.bml")));
|
||||||
Database::BSMemory = BML::unserialize(string::read(locate("Database/BS Memory.bml")));
|
Database::BSMemory = BML::unserialize(string::read(locate("Database/BS Memory.bml")));
|
||||||
Database::SufamiTurbo = BML::unserialize(string::read(locate("Database/Sufami Turbo.bml")));
|
Database::SufamiTurbo = BML::unserialize(string::read(locate("Database/Sufami Turbo.bml")));
|
||||||
}
|
}
|
||||||
|
@ -50,6 +53,7 @@ auto Icarus::manifest(string location) -> string {
|
||||||
if(type == ".md") return megaDriveManifest(location);
|
if(type == ".md") return megaDriveManifest(location);
|
||||||
if(type == ".pce") return pcEngineManifest(location);
|
if(type == ".pce") return pcEngineManifest(location);
|
||||||
if(type == ".sgx") return superGrafxManifest(location);
|
if(type == ".sgx") return superGrafxManifest(location);
|
||||||
|
if(type == ".cv") return colecoVisionManifest(location);
|
||||||
if(type == ".msx") return msxManifest(location);
|
if(type == ".msx") return msxManifest(location);
|
||||||
if(type == ".gb") return gameBoyManifest(location);
|
if(type == ".gb") return gameBoyManifest(location);
|
||||||
if(type == ".gbc") return gameBoyColorManifest(location);
|
if(type == ".gbc") return gameBoyColorManifest(location);
|
||||||
|
@ -58,6 +62,8 @@ auto Icarus::manifest(string location) -> string {
|
||||||
if(type == ".ws") return wonderSwanManifest(location);
|
if(type == ".ws") return wonderSwanManifest(location);
|
||||||
if(type == ".wsc") return wonderSwanColorManifest(location);
|
if(type == ".wsc") return wonderSwanColorManifest(location);
|
||||||
if(type == ".pc2") return pocketChallengeV2Manifest(location);
|
if(type == ".pc2") return pocketChallengeV2Manifest(location);
|
||||||
|
if(type == ".ngp") return neoGeoPocketManifest(location);
|
||||||
|
if(type == ".ngpc") return neoGeoPocketColorManifest(location);
|
||||||
if(type == ".bs") return bsMemoryManifest(location);
|
if(type == ".bs") return bsMemoryManifest(location);
|
||||||
if(type == ".st") return sufamiTurboManifest(location);
|
if(type == ".st") return sufamiTurboManifest(location);
|
||||||
|
|
||||||
|
@ -97,6 +103,7 @@ auto Icarus::import(string location) -> string {
|
||||||
if(type == ".md" || type == ".smd" || type == ".gen") return megaDriveImport(buffer, location);
|
if(type == ".md" || type == ".smd" || type == ".gen") return megaDriveImport(buffer, location);
|
||||||
if(type == ".pce") return pcEngineImport(buffer, location);
|
if(type == ".pce") return pcEngineImport(buffer, location);
|
||||||
if(type == ".sgx") return superGrafxImport(buffer, location);
|
if(type == ".sgx") return superGrafxImport(buffer, location);
|
||||||
|
if(type == ".cv" || type == ".col") return colecoVisionImport(buffer, location);
|
||||||
if(type == ".msx") return msxImport(buffer, location);
|
if(type == ".msx") return msxImport(buffer, location);
|
||||||
if(type == ".gb") return gameBoyImport(buffer, location);
|
if(type == ".gb") return gameBoyImport(buffer, location);
|
||||||
if(type == ".gbc") return gameBoyColorImport(buffer, location);
|
if(type == ".gbc") return gameBoyColorImport(buffer, location);
|
||||||
|
@ -105,6 +112,8 @@ auto Icarus::import(string location) -> string {
|
||||||
if(type == ".ws") return wonderSwanImport(buffer, location);
|
if(type == ".ws") return wonderSwanImport(buffer, location);
|
||||||
if(type == ".wsc") return wonderSwanColorImport(buffer, location);
|
if(type == ".wsc") return wonderSwanColorImport(buffer, location);
|
||||||
if(type == ".pc2") return pocketChallengeV2Import(buffer, location);
|
if(type == ".pc2") return pocketChallengeV2Import(buffer, location);
|
||||||
|
if(type == ".ngp") return neoGeoPocketImport(buffer, location);
|
||||||
|
if(type == ".ngpc" || type == ".ngc") return neoGeoPocketColorImport(buffer, location);
|
||||||
if(type == ".bs") return bsMemoryImport(buffer, location);
|
if(type == ".bs") return bsMemoryImport(buffer, location);
|
||||||
if(type == ".st") return sufamiTurboImport(buffer, location);
|
if(type == ".st") return sufamiTurboImport(buffer, location);
|
||||||
|
|
||||||
|
|
|
@ -76,6 +76,11 @@ struct Icarus {
|
||||||
auto superGrafxManifest(vector<uint8_t>& buffer, string location) -> string;
|
auto superGrafxManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||||
auto superGrafxImport(vector<uint8_t>& buffer, string location) -> string;
|
auto superGrafxImport(vector<uint8_t>& buffer, string location) -> string;
|
||||||
|
|
||||||
|
//colecovision.cpp
|
||||||
|
auto colecoVisionManifest(string location) -> string;
|
||||||
|
auto colecoVisionManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||||
|
auto colecoVisionImport(vector<uint8_t>& buffer, string location) -> string;
|
||||||
|
|
||||||
//msx.cpp
|
//msx.cpp
|
||||||
auto msxManifest(string location) -> string;
|
auto msxManifest(string location) -> string;
|
||||||
auto msxManifest(vector<uint8_t>& buffer, string location) -> string;
|
auto msxManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||||
|
@ -116,6 +121,16 @@ struct Icarus {
|
||||||
auto pocketChallengeV2Manifest(vector<uint8_t>& buffer, string location) -> string;
|
auto pocketChallengeV2Manifest(vector<uint8_t>& buffer, string location) -> string;
|
||||||
auto pocketChallengeV2Import(vector<uint8_t>& buffer, string location) -> string;
|
auto pocketChallengeV2Import(vector<uint8_t>& buffer, string location) -> string;
|
||||||
|
|
||||||
|
//neo-geo-pocket.cpp
|
||||||
|
auto neoGeoPocketManifest(string location) -> string;
|
||||||
|
auto neoGeoPocketManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||||
|
auto neoGeoPocketImport(vector<uint8_t>& buffer, string location) -> string;
|
||||||
|
|
||||||
|
//neo-geo-pocket-color.cpp
|
||||||
|
auto neoGeoPocketColorManifest(string location) -> string;
|
||||||
|
auto neoGeoPocketColorManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||||
|
auto neoGeoPocketColorImport(vector<uint8_t>& buffer, string location) -> string;
|
||||||
|
|
||||||
//bs-memory.cpp
|
//bs-memory.cpp
|
||||||
auto bsMemoryManifest(string location) -> string;
|
auto bsMemoryManifest(string location) -> string;
|
||||||
auto bsMemoryManifest(vector<uint8_t>& buffer, string location) -> string;
|
auto bsMemoryManifest(vector<uint8_t>& buffer, string location) -> string;
|
||||||
|
@ -140,6 +155,7 @@ namespace Database {
|
||||||
Markup::Node MegaDrive;
|
Markup::Node MegaDrive;
|
||||||
Markup::Node PCEngine;
|
Markup::Node PCEngine;
|
||||||
Markup::Node SuperGrafx;
|
Markup::Node SuperGrafx;
|
||||||
|
Markup::Node ColecoVision;
|
||||||
Markup::Node MSX;
|
Markup::Node MSX;
|
||||||
Markup::Node GameBoy;
|
Markup::Node GameBoy;
|
||||||
Markup::Node GameBoyColor;
|
Markup::Node GameBoyColor;
|
||||||
|
@ -148,6 +164,8 @@ namespace Database {
|
||||||
Markup::Node WonderSwan;
|
Markup::Node WonderSwan;
|
||||||
Markup::Node WonderSwanColor;
|
Markup::Node WonderSwanColor;
|
||||||
Markup::Node PocketChallengeV2;
|
Markup::Node PocketChallengeV2;
|
||||||
|
Markup::Node NeoGeoPocket;
|
||||||
|
Markup::Node NeoGeoPocketColor;
|
||||||
Markup::Node BSMemory;
|
Markup::Node BSMemory;
|
||||||
Markup::Node SufamiTurbo;
|
Markup::Node SufamiTurbo;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
auto Icarus::neoGeoPocketColorManifest(string location) -> string {
|
||||||
|
vector<uint8_t> buffer;
|
||||||
|
concatenate(buffer, {location, "program.rom"});
|
||||||
|
return neoGeoPocketColorManifest(buffer, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Icarus::neoGeoPocketColorManifest(vector<uint8_t>& buffer, string location) -> string {
|
||||||
|
if(settings["icarus/UseDatabase"].boolean()) {
|
||||||
|
auto digest = Hash::SHA256(buffer).digest();
|
||||||
|
for(auto game : Database::NeoGeoPocketColor.find("game")) {
|
||||||
|
if(game["sha256"].text() == digest) return BML::serialize(game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(settings["icarus/UseHeuristics"].boolean()) {
|
||||||
|
Heuristics::NeoGeoPocketColor game{buffer, location};
|
||||||
|
if(auto manifest = game.manifest()) return manifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Icarus::neoGeoPocketColorImport(vector<uint8_t>& buffer, string location) -> string {
|
||||||
|
auto name = Location::prefix(location);
|
||||||
|
auto source = Location::path(location);
|
||||||
|
string target{settings["Library/Location"].text(), "Neo Geo Pocket Color/", name, ".ngpc/"};
|
||||||
|
|
||||||
|
auto manifest = neoGeoPocketColorManifest(buffer, location);
|
||||||
|
if(!manifest) return failure("failed to parse ROM image");
|
||||||
|
|
||||||
|
if(!create(target)) return failure("library path unwritable");
|
||||||
|
if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) {
|
||||||
|
copy({source, name, ".sav"}, {target, "save.ram"});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest);
|
||||||
|
write({target, "program.rom"}, buffer);
|
||||||
|
return success(target);
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
auto Icarus::neoGeoPocketManifest(string location) -> string {
|
||||||
|
vector<uint8_t> buffer;
|
||||||
|
concatenate(buffer, {location, "program.rom"});
|
||||||
|
return neoGeoPocketManifest(buffer, location);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Icarus::neoGeoPocketManifest(vector<uint8_t>& buffer, string location) -> string {
|
||||||
|
if(settings["icarus/UseDatabase"].boolean()) {
|
||||||
|
auto digest = Hash::SHA256(buffer).digest();
|
||||||
|
for(auto game : Database::NeoGeoPocket.find("game")) {
|
||||||
|
if(game["sha256"].text() == digest) return BML::serialize(game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(settings["icarus/UseHeuristics"].boolean()) {
|
||||||
|
Heuristics::NeoGeoPocket game{buffer, location};
|
||||||
|
if(auto manifest = game.manifest()) return manifest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Icarus::neoGeoPocketImport(vector<uint8_t>& buffer, string location) -> string {
|
||||||
|
auto name = Location::prefix(location);
|
||||||
|
auto source = Location::path(location);
|
||||||
|
string target{settings["Library/Location"].text(), "Neo Geo Pocket/", name, ".ngp/"};
|
||||||
|
|
||||||
|
auto manifest = neoGeoPocketManifest(buffer, location);
|
||||||
|
if(!manifest) return failure("failed to parse ROM image");
|
||||||
|
|
||||||
|
if(!create(target)) return failure("library path unwritable");
|
||||||
|
if(exists({source, name, ".sav"}) && !exists({target, "save.ram"})) {
|
||||||
|
copy({source, name, ".sav"}, {target, "save.ram"});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(settings["icarus/CreateManifests"].boolean()) write({target, "manifest.bml"}, manifest);
|
||||||
|
write({target, "program.rom"}, buffer);
|
||||||
|
return success(target);
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
namespace Heuristics {
|
||||||
|
|
||||||
|
struct ColecoVision {
|
||||||
|
ColecoVision(vector<uint8_t>& data, string location);
|
||||||
|
explicit operator bool() const;
|
||||||
|
auto manifest() const -> string;
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector<uint8_t>& data;
|
||||||
|
string location;
|
||||||
|
};
|
||||||
|
|
||||||
|
ColecoVision::ColecoVision(vector<uint8_t>& data, string location) : data(data), location(location) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ColecoVision::operator bool() const {
|
||||||
|
return (bool)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ColecoVision::manifest() const -> string {
|
||||||
|
string output;
|
||||||
|
output.append("game\n");
|
||||||
|
output.append(" sha256: ", Hash::SHA256(data).digest(), "\n");
|
||||||
|
output.append(" label: ", Location::prefix(location), "\n");
|
||||||
|
output.append(" name: ", Location::prefix(location), "\n");
|
||||||
|
output.append(" board\n");
|
||||||
|
output.append(Memory{}.type("ROM").size(data.size()).content("Program").text());
|
||||||
|
output.append(Memory{}.type("RAM").size(0x8000).content("Save").text());
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
namespace Heuristics {
|
||||||
|
|
||||||
|
struct NeoGeoPocketColor {
|
||||||
|
NeoGeoPocketColor(vector<uint8_t>& data, string location);
|
||||||
|
explicit operator bool() const;
|
||||||
|
auto manifest() const -> string;
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector<uint8_t>& data;
|
||||||
|
string location;
|
||||||
|
};
|
||||||
|
|
||||||
|
NeoGeoPocketColor::NeoGeoPocketColor(vector<uint8_t>& data, string location) : data(data), location(location) {
|
||||||
|
}
|
||||||
|
|
||||||
|
NeoGeoPocketColor::operator bool() const {
|
||||||
|
return (bool)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto NeoGeoPocketColor::manifest() const -> string {
|
||||||
|
string output;
|
||||||
|
output.append("game\n");
|
||||||
|
output.append(" sha256: ", Hash::SHA256(data).digest(), "\n");
|
||||||
|
output.append(" label: ", Location::prefix(location), "\n");
|
||||||
|
output.append(" name: ", Location::prefix(location), "\n");
|
||||||
|
output.append(" board\n");
|
||||||
|
output.append(Memory{}.type("ROM").size(data.size()).content("Program").text());
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
namespace Heuristics {
|
||||||
|
|
||||||
|
struct NeoGeoPocket {
|
||||||
|
NeoGeoPocket(vector<uint8_t>& data, string location);
|
||||||
|
explicit operator bool() const;
|
||||||
|
auto manifest() const -> string;
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector<uint8_t>& data;
|
||||||
|
string location;
|
||||||
|
};
|
||||||
|
|
||||||
|
NeoGeoPocket::NeoGeoPocket(vector<uint8_t>& data, string location) : data(data), location(location) {
|
||||||
|
}
|
||||||
|
|
||||||
|
NeoGeoPocket::operator bool() const {
|
||||||
|
return (bool)data;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto NeoGeoPocket::manifest() const -> string {
|
||||||
|
string output;
|
||||||
|
output.append("game\n");
|
||||||
|
output.append(" sha256: ", Hash::SHA256(data).digest(), "\n");
|
||||||
|
output.append(" label: ", Location::prefix(location), "\n");
|
||||||
|
output.append(" name: ", Location::prefix(location), "\n");
|
||||||
|
output.append(" board\n");
|
||||||
|
output.append(Memory{}.type("ROM").size(data.size()).content("Program").text());
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -254,7 +254,7 @@ auto SuperFamicom::board() const -> string {
|
||||||
if(serial() == "A9PJ") {
|
if(serial() == "A9PJ") {
|
||||||
//Sufami Turbo (JPN)
|
//Sufami Turbo (JPN)
|
||||||
board.append("ST-", mode);
|
board.append("ST-", mode);
|
||||||
} else if(serial() == "ZSBJ") {
|
} else if(serial() == "ZBSJ") {
|
||||||
//BS-X: Sore wa Namae o Nusumareta Machi no Monogatari (JPN)
|
//BS-X: Sore wa Namae o Nusumareta Machi no Monogatari (JPN)
|
||||||
board.append("BS-MCC-");
|
board.append("BS-MCC-");
|
||||||
} else if(serial() == "042J") {
|
} else if(serial() == "042J") {
|
||||||
|
|
|
@ -25,11 +25,14 @@ Settings settings;
|
||||||
#include "heuristics/mega-drive.cpp"
|
#include "heuristics/mega-drive.cpp"
|
||||||
#include "heuristics/pc-engine.cpp"
|
#include "heuristics/pc-engine.cpp"
|
||||||
#include "heuristics/supergrafx.cpp"
|
#include "heuristics/supergrafx.cpp"
|
||||||
|
#include "heuristics/colecovision.cpp"
|
||||||
#include "heuristics/msx.cpp"
|
#include "heuristics/msx.cpp"
|
||||||
#include "heuristics/game-boy.cpp"
|
#include "heuristics/game-boy.cpp"
|
||||||
#include "heuristics/game-boy-advance.cpp"
|
#include "heuristics/game-boy-advance.cpp"
|
||||||
#include "heuristics/game-gear.cpp"
|
#include "heuristics/game-gear.cpp"
|
||||||
#include "heuristics/wonderswan.cpp"
|
#include "heuristics/wonderswan.cpp"
|
||||||
|
#include "heuristics/neo-geo-pocket.cpp"
|
||||||
|
#include "heuristics/neo-geo-pocket-color.cpp"
|
||||||
#include "heuristics/bs-memory.cpp"
|
#include "heuristics/bs-memory.cpp"
|
||||||
#include "heuristics/sufami-turbo.cpp"
|
#include "heuristics/sufami-turbo.cpp"
|
||||||
|
|
||||||
|
@ -43,6 +46,7 @@ Settings settings;
|
||||||
#include "core/mega-drive.cpp"
|
#include "core/mega-drive.cpp"
|
||||||
#include "core/pc-engine.cpp"
|
#include "core/pc-engine.cpp"
|
||||||
#include "core/supergrafx.cpp"
|
#include "core/supergrafx.cpp"
|
||||||
|
#include "core/colecovision.cpp"
|
||||||
#include "core/msx.cpp"
|
#include "core/msx.cpp"
|
||||||
#include "core/game-boy.cpp"
|
#include "core/game-boy.cpp"
|
||||||
#include "core/game-boy-color.cpp"
|
#include "core/game-boy-color.cpp"
|
||||||
|
@ -50,6 +54,8 @@ Settings settings;
|
||||||
#include "core/game-gear.cpp"
|
#include "core/game-gear.cpp"
|
||||||
#include "core/wonderswan.cpp"
|
#include "core/wonderswan.cpp"
|
||||||
#include "core/wonderswan-color.cpp"
|
#include "core/wonderswan-color.cpp"
|
||||||
|
#include "core/neo-geo-pocket.cpp"
|
||||||
|
#include "core/neo-geo-pocket-color.cpp"
|
||||||
#include "core/pocket-challenge-v2.cpp"
|
#include "core/pocket-challenge-v2.cpp"
|
||||||
#include "core/bs-memory.cpp"
|
#include "core/bs-memory.cpp"
|
||||||
#include "core/sufami-turbo.cpp"
|
#include "core/sufami-turbo.cpp"
|
||||||
|
@ -97,6 +103,7 @@ auto nall::main(Arguments arguments) -> void {
|
||||||
"*.md:*.smd:*.gen:"
|
"*.md:*.smd:*.gen:"
|
||||||
"*.pce:"
|
"*.pce:"
|
||||||
"*.sgx:"
|
"*.sgx:"
|
||||||
|
"*.cv:*.col:"
|
||||||
"*.msx:"
|
"*.msx:"
|
||||||
"*.gb:"
|
"*.gb:"
|
||||||
"*.gbc:"
|
"*.gbc:"
|
||||||
|
@ -105,6 +112,8 @@ auto nall::main(Arguments arguments) -> void {
|
||||||
"*.ws:"
|
"*.ws:"
|
||||||
"*.wsc:"
|
"*.wsc:"
|
||||||
"*.pc2:"
|
"*.pc2:"
|
||||||
|
"*.ngp:"
|
||||||
|
"*.ngpc:*.ngc:"
|
||||||
"*.bs:"
|
"*.bs:"
|
||||||
"*.st:"
|
"*.st:"
|
||||||
"*.zip"
|
"*.zip"
|
||||||
|
@ -121,22 +130,24 @@ auto nall::main(Arguments arguments) -> void {
|
||||||
new SettingsDialog;
|
new SettingsDialog;
|
||||||
new ImportDialog;
|
new ImportDialog;
|
||||||
new ErrorDialog;
|
new ErrorDialog;
|
||||||
#if defined(PLATFORM_MACOS)
|
|
||||||
Application::Cocoa::onAbout([&] {
|
if constexpr(platform() == Platform::MacOS) {
|
||||||
MessageDialog().setTitle("About icarus").setText({
|
Application::Cocoa::onAbout([&] {
|
||||||
"icarus\n\n"
|
MessageDialog().setTitle("About icarus").setText({
|
||||||
"Author: byuu\n"
|
"icarus\n\n"
|
||||||
"License: GPLv3\n"
|
"Author: byuu\n"
|
||||||
"Website: https://byuu.org/\n"
|
"License: GPLv3\n"
|
||||||
}).information();
|
"Website: https://byuu.org/\n"
|
||||||
});
|
}).information();
|
||||||
Application::Cocoa::onPreferences([&] {
|
});
|
||||||
scanDialog->settingsButton.doActivate();
|
Application::Cocoa::onPreferences([&] {
|
||||||
});
|
scanDialog->settingsButton.doActivate();
|
||||||
Application::Cocoa::onQuit([&] {
|
});
|
||||||
Application::quit();
|
Application::Cocoa::onQuit([&] {
|
||||||
});
|
Application::quit();
|
||||||
#endif
|
});
|
||||||
|
}
|
||||||
|
|
||||||
scanDialog->show();
|
scanDialog->show();
|
||||||
Application::run();
|
Application::run();
|
||||||
settings.save();
|
settings.save();
|
||||||
|
|
|
@ -116,6 +116,8 @@ auto ScanDialog::gamePakType(const string& type) -> bool {
|
||||||
|| type == ".ws"
|
|| type == ".ws"
|
||||||
|| type == ".wsc"
|
|| type == ".wsc"
|
||||||
|| type == ".pc2"
|
|| type == ".pc2"
|
||||||
|
|| type == ".ngp"
|
||||||
|
|| type == ".ngpc"
|
||||||
|| type == ".bs"
|
|| type == ".bs"
|
||||||
|| type == ".st";
|
|| type == ".st";
|
||||||
}
|
}
|
||||||
|
@ -138,6 +140,8 @@ auto ScanDialog::gameRomType(const string& type) -> bool {
|
||||||
|| type == ".ws"
|
|| type == ".ws"
|
||||||
|| type == ".wsc"
|
|| type == ".wsc"
|
||||||
|| type == ".pc2"
|
|| type == ".pc2"
|
||||||
|
|| type == ".ngp"
|
||||||
|
|| type == ".ngpc" || type == ".ngc"
|
||||||
|| type == ".bs"
|
|| type == ".bs"
|
||||||
|| type == ".st";
|
|| type == ".st";
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,53 +3,53 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<typename T> struct iterator {
|
template<typename T> struct iterator {
|
||||||
iterator(T* self, uint offset) : self(self), offset(offset) {}
|
iterator(T* self, uint64_t offset) : self(self), offset(offset) {}
|
||||||
auto operator*() -> T& { return self[offset]; }
|
auto operator*() -> T& { return self[offset]; }
|
||||||
auto operator!=(const iterator& source) const -> bool { return offset != source.offset; }
|
auto operator!=(const iterator& source) const -> bool { return offset != source.offset; }
|
||||||
auto operator++() -> iterator& { return offset++, *this; }
|
auto operator++() -> iterator& { return offset++, *this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T* self;
|
T* self;
|
||||||
uint offset;
|
uint64_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T> struct iterator_const {
|
template<typename T> struct iterator_const {
|
||||||
iterator_const(const T* self, uint offset) : self(self), offset(offset) {}
|
iterator_const(const T* self, uint64_t offset) : self(self), offset(offset) {}
|
||||||
auto operator*() -> const T& { return self[offset]; }
|
auto operator*() -> const T& { return self[offset]; }
|
||||||
auto operator!=(const iterator_const& source) const -> bool { return offset != source.offset; }
|
auto operator!=(const iterator_const& source) const -> bool { return offset != source.offset; }
|
||||||
auto operator++() -> iterator_const& { return offset++, *this; }
|
auto operator++() -> iterator_const& { return offset++, *this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const T* self;
|
const T* self;
|
||||||
uint offset;
|
uint64_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T> struct reverse_iterator {
|
template<typename T> struct reverse_iterator {
|
||||||
reverse_iterator(T* self, uint offset) : self(self), offset(offset) {}
|
reverse_iterator(T* self, uint64_t offset) : self(self), offset(offset) {}
|
||||||
auto operator*() -> T& { return self[offset]; }
|
auto operator*() -> T& { return self[offset]; }
|
||||||
auto operator!=(const reverse_iterator& source) const -> bool { return offset != source.offset; }
|
auto operator!=(const reverse_iterator& source) const -> bool { return offset != source.offset; }
|
||||||
auto operator++() -> reverse_iterator& { return offset--, *this; }
|
auto operator++() -> reverse_iterator& { return offset--, *this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T* self;
|
T* self;
|
||||||
uint offset;
|
uint64_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T> struct reverse_iterator_const {
|
template<typename T> struct reverse_iterator_const {
|
||||||
reverse_iterator_const(const T* self, uint offset) : self(self), offset(offset) {}
|
reverse_iterator_const(const T* self, uint64_t offset) : self(self), offset(offset) {}
|
||||||
auto operator*() -> const T& { return self[offset]; }
|
auto operator*() -> const T& { return self[offset]; }
|
||||||
auto operator!=(const reverse_iterator_const& source) const -> bool { return offset != source.offset; }
|
auto operator!=(const reverse_iterator_const& source) const -> bool { return offset != source.offset; }
|
||||||
auto operator++() -> reverse_iterator_const& { return offset--, *this; }
|
auto operator++() -> reverse_iterator_const& { return offset--, *this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const T* self;
|
const T* self;
|
||||||
uint offset;
|
uint64_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
//std::rbegin(), std::rend() is missing from GCC 4.9; which I still target
|
//std::rbegin(), std::rend() is missing from GCC 4.9; which I still target
|
||||||
|
|
||||||
template<typename T, uint Size> auto rbegin(T (&array)[Size]) { return reverse_iterator<T>{array, Size - 1}; }
|
template<typename T, uint64_t Size> auto rbegin(T (&array)[Size]) { return reverse_iterator<T>{array, Size - 1}; }
|
||||||
template<typename T, uint Size> auto rend(T (&array)[Size]) { return reverse_iterator<T>{array, (uint)-1}; }
|
template<typename T, uint64_t Size> auto rend(T (&array)[Size]) { return reverse_iterator<T>{array, (uint64_t)-1}; }
|
||||||
|
|
||||||
template<typename T> auto rbegin(T& self) { return self.rbegin(); }
|
template<typename T> auto rbegin(T& self) { return self.rbegin(); }
|
||||||
template<typename T> auto rend(T& self) { return self.rend(); }
|
template<typename T> auto rend(T& self) { return self.rend(); }
|
||||||
|
|
|
@ -4,25 +4,25 @@ namespace nall {
|
||||||
|
|
||||||
struct range_t {
|
struct range_t {
|
||||||
struct iterator {
|
struct iterator {
|
||||||
iterator(int position, int step = 0) : position(position), step(step) {}
|
iterator(int64_t position, int64_t step = 0) : position(position), step(step) {}
|
||||||
auto operator*() const -> int { return position; }
|
auto operator*() const -> int64_t { return position; }
|
||||||
auto operator!=(const iterator& source) const -> bool { return step > 0 ? position < source.position : position > source.position; }
|
auto operator!=(const iterator& source) const -> bool { return step > 0 ? position < source.position : position > source.position; }
|
||||||
auto operator++() -> iterator& { position += step; return *this; }
|
auto operator++() -> iterator& { position += step; return *this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int position;
|
int64_t position;
|
||||||
const int step;
|
const int64_t step;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct reverse_iterator {
|
struct reverse_iterator {
|
||||||
reverse_iterator(int position, int step = 0) : position(position), step(step) {}
|
reverse_iterator(int64_t position, int64_t step = 0) : position(position), step(step) {}
|
||||||
auto operator*() const -> int { return position; }
|
auto operator*() const -> int64_t { return position; }
|
||||||
auto operator!=(const reverse_iterator& source) const -> bool { return step > 0 ? position > source.position : position < source.position; }
|
auto operator!=(const reverse_iterator& source) const -> bool { return step > 0 ? position > source.position : position < source.position; }
|
||||||
auto operator++() -> reverse_iterator& { position -= step; return *this; }
|
auto operator++() -> reverse_iterator& { position -= step; return *this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int position;
|
int64_t position;
|
||||||
const int step;
|
const int64_t step;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto begin() const -> iterator { return {origin, stride}; }
|
auto begin() const -> iterator { return {origin, stride}; }
|
||||||
|
@ -31,20 +31,20 @@ struct range_t {
|
||||||
auto rbegin() const -> reverse_iterator { return {target - stride, stride}; }
|
auto rbegin() const -> reverse_iterator { return {target - stride, stride}; }
|
||||||
auto rend() const -> reverse_iterator { return {origin - stride}; }
|
auto rend() const -> reverse_iterator { return {origin - stride}; }
|
||||||
|
|
||||||
int origin;
|
int64_t origin;
|
||||||
int target;
|
int64_t target;
|
||||||
int stride;
|
int64_t stride;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline auto range(int size) {
|
inline auto range(int64_t size) {
|
||||||
return range_t{0, size, 1};
|
return range_t{0, size, 1};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto range(int offset, int size) {
|
inline auto range(int64_t offset, int64_t size) {
|
||||||
return range_t{offset, size, 1};
|
return range_t{offset, size, 1};
|
||||||
}
|
}
|
||||||
|
|
||||||
inline auto range(int offset, int size, int step) {
|
inline auto range(int64_t offset, int64_t size, int64_t step) {
|
||||||
return range_t{offset, size, step};
|
return range_t{offset, size, step};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,11 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
|
template<typename T> struct vector_iterator;
|
||||||
|
template<typename T> struct vector_iterator_const;
|
||||||
|
template<typename T> struct vector_reverse_iterator;
|
||||||
|
template<typename T> struct vector_reverse_iterator_const;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct vector_base {
|
struct vector_base {
|
||||||
using type = vector_base;
|
using type = vector_base;
|
||||||
|
@ -30,8 +35,8 @@ struct vector_base {
|
||||||
explicit operator bool() const;
|
explicit operator bool() const;
|
||||||
operator array_span<T>();
|
operator array_span<T>();
|
||||||
operator array_view<T>() const;
|
operator array_view<T>() const;
|
||||||
template<typename Cast = T> auto capacity() const -> uint;
|
template<typename Cast = T> auto capacity() const -> uint64_t;
|
||||||
template<typename Cast = T> auto size() const -> uint;
|
template<typename Cast = T> auto size() const -> uint64_t;
|
||||||
template<typename Cast = T> auto data() -> Cast*;
|
template<typename Cast = T> auto data() -> Cast*;
|
||||||
template<typename Cast = T> auto data() const -> const Cast*;
|
template<typename Cast = T> auto data() const -> const Cast*;
|
||||||
|
|
||||||
|
@ -45,27 +50,27 @@ struct vector_base {
|
||||||
|
|
||||||
//memory.hpp
|
//memory.hpp
|
||||||
auto reset() -> void;
|
auto reset() -> void;
|
||||||
auto acquire(const T* data, uint size, uint capacity = 0) -> void;
|
auto acquire(const T* data, uint64_t size, uint64_t capacity = 0) -> void;
|
||||||
auto release() -> T*;
|
auto release() -> T*;
|
||||||
|
|
||||||
auto reserveLeft(uint capacity) -> bool;
|
auto reserveLeft(uint64_t capacity) -> bool;
|
||||||
auto reserveRight(uint capacity) -> bool;
|
auto reserveRight(uint64_t capacity) -> bool;
|
||||||
auto reserve(uint capacity) -> bool { return reserveRight(capacity); }
|
auto reserve(uint64_t capacity) -> bool { return reserveRight(capacity); }
|
||||||
|
|
||||||
auto reallocateLeft(uint size) -> bool;
|
auto reallocateLeft(uint64_t size) -> bool;
|
||||||
auto reallocateRight(uint size) -> bool;
|
auto reallocateRight(uint64_t size) -> bool;
|
||||||
auto reallocate(uint size) -> bool { return reallocateRight(size); }
|
auto reallocate(uint64_t size) -> bool { return reallocateRight(size); }
|
||||||
|
|
||||||
auto resizeLeft(uint size, const T& value = T()) -> bool;
|
auto resizeLeft(uint64_t size, const T& value = T()) -> bool;
|
||||||
auto resizeRight(uint size, const T& value = T()) -> bool;
|
auto resizeRight(uint64_t size, const T& value = T()) -> bool;
|
||||||
auto resize(uint size, const T& value = T()) -> bool { return resizeRight(size, value); }
|
auto resize(uint64_t size, const T& value = T()) -> bool { return resizeRight(size, value); }
|
||||||
|
|
||||||
//access.hpp
|
//access.hpp
|
||||||
alwaysinline auto operator[](uint offset) -> T&;
|
alwaysinline auto operator[](uint64_t offset) -> T&;
|
||||||
alwaysinline auto operator[](uint offset) const -> const T&;
|
alwaysinline auto operator[](uint64_t offset) const -> const T&;
|
||||||
|
|
||||||
alwaysinline auto operator()(uint offset) -> T&;
|
alwaysinline auto operator()(uint64_t offset) -> T&;
|
||||||
alwaysinline auto operator()(uint offset, const T& value) const -> const T&;
|
alwaysinline auto operator()(uint64_t offset, const T& value) const -> const T&;
|
||||||
|
|
||||||
alwaysinline auto left() -> T&;
|
alwaysinline auto left() -> T&;
|
||||||
alwaysinline auto first() -> T& { return left(); }
|
alwaysinline auto first() -> T& { return left(); }
|
||||||
|
@ -88,19 +93,19 @@ struct vector_base {
|
||||||
auto append(const type& values) -> void;
|
auto append(const type& values) -> void;
|
||||||
auto append(type&& values) -> void;
|
auto append(type&& values) -> void;
|
||||||
|
|
||||||
auto insert(uint offset, const T& value) -> void;
|
auto insert(uint64_t offset, const T& value) -> void;
|
||||||
|
|
||||||
auto removeLeft(uint length = 1) -> void;
|
auto removeLeft(uint64_t length = 1) -> void;
|
||||||
auto removeFirst(uint length = 1) -> void { return removeLeft(length); }
|
auto removeFirst(uint64_t length = 1) -> void { return removeLeft(length); }
|
||||||
auto removeRight(uint length = 1) -> void;
|
auto removeRight(uint64_t length = 1) -> void;
|
||||||
auto removeLast(uint length = 1) -> void { return removeRight(length); }
|
auto removeLast(uint64_t length = 1) -> void { return removeRight(length); }
|
||||||
auto remove(uint offset, uint length = 1) -> void;
|
auto remove(uint64_t offset, uint64_t length = 1) -> void;
|
||||||
|
|
||||||
auto takeLeft() -> T;
|
auto takeLeft() -> T;
|
||||||
auto takeFirst() -> T { return move(takeLeft()); }
|
auto takeFirst() -> T { return move(takeLeft()); }
|
||||||
auto takeRight() -> T;
|
auto takeRight() -> T;
|
||||||
auto takeLast() -> T { return move(takeRight()); }
|
auto takeLast() -> T { return move(takeRight()); }
|
||||||
auto take(uint offset) -> T;
|
auto take(uint64_t offset) -> T;
|
||||||
|
|
||||||
//iterator.hpp
|
//iterator.hpp
|
||||||
auto begin() -> iterator<T> { return {data(), 0}; }
|
auto begin() -> iterator<T> { return {data(), 0}; }
|
||||||
|
@ -110,26 +115,26 @@ struct vector_base {
|
||||||
auto end() const -> iterator_const<T> { return {data(), size()}; }
|
auto end() const -> iterator_const<T> { return {data(), size()}; }
|
||||||
|
|
||||||
auto rbegin() -> reverse_iterator<T> { return {data(), size() - 1}; }
|
auto rbegin() -> reverse_iterator<T> { return {data(), size() - 1}; }
|
||||||
auto rend() -> reverse_iterator<T> { return {data(), (uint)-1}; }
|
auto rend() -> reverse_iterator<T> { return {data(), (uint64_t)-1}; }
|
||||||
|
|
||||||
auto rbegin() const -> reverse_iterator_const<T> { return {data(), size() - 1}; }
|
auto rbegin() const -> reverse_iterator_const<T> { return {data(), size() - 1}; }
|
||||||
auto rend() const -> reverse_iterator_const<T> { return {data(), (uint)-1}; }
|
auto rend() const -> reverse_iterator_const<T> { return {data(), (uint64_t)-1}; }
|
||||||
|
|
||||||
//utility.hpp
|
//utility.hpp
|
||||||
auto fill(const T& value = {}) -> void;
|
auto fill(const T& value = {}) -> void;
|
||||||
auto sort(const function<bool (const T& lhs, const T& rhs)>& comparator = [](auto& lhs, auto& rhs) { return lhs < rhs; }) -> void;
|
auto sort(const function<bool (const T& lhs, const T& rhs)>& comparator = [](auto& lhs, auto& rhs) { return lhs < rhs; }) -> void;
|
||||||
auto reverse() -> void;
|
auto reverse() -> void;
|
||||||
auto find(const function<bool (const T& lhs)>& comparator) -> maybe<uint>;
|
auto find(const function<bool (const T& lhs)>& comparator) -> maybe<uint64_t>;
|
||||||
auto find(const T& value) const -> maybe<uint>;
|
auto find(const T& value) const -> maybe<uint64_t>;
|
||||||
auto findSorted(const T& value) const -> maybe<uint>;
|
auto findSorted(const T& value) const -> maybe<uint64_t>;
|
||||||
auto foreach(const function<void (const T&)>& callback) -> void;
|
auto foreach(const function<void (const T&)>& callback) -> void;
|
||||||
auto foreach(const function<void (uint, const T&)>& callback) -> void;
|
auto foreach(const function<void (uint, const T&)>& callback) -> void;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
T* _pool = nullptr; //pointer to first initialized element in pool
|
T* _pool = nullptr; //pointer to first initialized element in pool
|
||||||
uint _size = 0; //number of initialized elements in pool
|
uint64_t _size = 0; //number of initialized elements in pool
|
||||||
uint _left = 0; //number of allocated elements free on the left of pool
|
uint64_t _left = 0; //number of allocated elements free on the left of pool
|
||||||
uint _right = 0; //number of allocated elements free on the right of pool
|
uint64_t _right = 0; //number of allocated elements free on the right of pool
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<typename T> auto vector<T>::operator[](uint offset) -> T& {
|
template<typename T> auto vector<T>::operator[](uint64_t offset) -> T& {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
struct out_of_bounds {};
|
struct out_of_bounds {};
|
||||||
if(offset >= size()) throw out_of_bounds{};
|
if(offset >= size()) throw out_of_bounds{};
|
||||||
|
@ -10,7 +10,7 @@ template<typename T> auto vector<T>::operator[](uint offset) -> T& {
|
||||||
return _pool[offset];
|
return _pool[offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::operator[](uint offset) const -> const T& {
|
template<typename T> auto vector<T>::operator[](uint64_t offset) const -> const T& {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
struct out_of_bounds {};
|
struct out_of_bounds {};
|
||||||
if(offset >= size()) throw out_of_bounds{};
|
if(offset >= size()) throw out_of_bounds{};
|
||||||
|
@ -18,12 +18,12 @@ template<typename T> auto vector<T>::operator[](uint offset) const -> const T& {
|
||||||
return _pool[offset];
|
return _pool[offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::operator()(uint offset) -> T& {
|
template<typename T> auto vector<T>::operator()(uint64_t offset) -> T& {
|
||||||
while(offset >= size()) append(T());
|
while(offset >= size()) append(T());
|
||||||
return _pool[offset];
|
return _pool[offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::operator()(uint offset, const T& value) const -> const T& {
|
template<typename T> auto vector<T>::operator()(uint64_t offset, const T& value) const -> const T& {
|
||||||
if(offset >= size()) return value;
|
if(offset >= size()) return value;
|
||||||
return _pool[offset];
|
return _pool[offset];
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ template<typename T> auto vector<T>::operator=(const vector<T>& source) -> vecto
|
||||||
_size = source._size;
|
_size = source._size;
|
||||||
_left = 0;
|
_left = 0;
|
||||||
_right = 0;
|
_right = 0;
|
||||||
for(uint n : range(_size)) new(_pool + n) T(source._pool[n]);
|
for(uint64_t n : range(_size)) new(_pool + n) T(source._pool[n]);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace nall {
|
||||||
template<typename T> auto vector<T>::operator==(const vector<T>& source) const -> bool {
|
template<typename T> auto vector<T>::operator==(const vector<T>& source) const -> bool {
|
||||||
if(this == &source) return true;
|
if(this == &source) return true;
|
||||||
if(size() != source.size()) return false;
|
if(size() != source.size()) return false;
|
||||||
for(uint n = 0; n < size(); n++) {
|
for(uint64_t n = 0; n < size(); n++) {
|
||||||
if(operator[](n) != source[n]) return false;
|
if(operator[](n) != source[n]) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -31,11 +31,11 @@ template<typename T> vector<T>::operator array_view<T>() const {
|
||||||
return {data(), size()};
|
return {data(), size()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> template<typename Cast> auto vector<T>::capacity() const -> uint {
|
template<typename T> template<typename Cast> auto vector<T>::capacity() const -> uint64_t {
|
||||||
return (_left + _size + _right) * sizeof(T) / sizeof(Cast);
|
return (_left + _size + _right) * sizeof(T) / sizeof(Cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> template<typename Cast> auto vector<T>::size() const -> uint {
|
template<typename T> template<typename Cast> auto vector<T>::size() const -> uint64_t {
|
||||||
return _size * sizeof(T) / sizeof(Cast);
|
return _size * sizeof(T) / sizeof(Cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,50 +4,50 @@ namespace nall {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct vector_iterator {
|
struct vector_iterator {
|
||||||
vector_iterator(vector<T>& self, uint offset) : self(self), offset(offset) {}
|
vector_iterator(vector<T>& self, uint64_t offset) : self(self), offset(offset) {}
|
||||||
auto operator*() -> T& { return self.operator[](offset); }
|
auto operator*() -> T& { return self.operator[](offset); }
|
||||||
auto operator!=(const vector_iterator& source) const -> bool { return offset != source.offset; }
|
auto operator!=(const vector_iterator& source) const -> bool { return offset != source.offset; }
|
||||||
auto operator++() -> vector_iterator& { return offset++, *this; }
|
auto operator++() -> vector_iterator& { return offset++, *this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vector<T>& self;
|
vector<T>& self;
|
||||||
uint offset;
|
uint64_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct vector_iterator_const {
|
struct vector_iterator_const {
|
||||||
vector_iterator_const(const vector<T>& self, uint offset) : self(self), offset(offset) {}
|
vector_iterator_const(const vector<T>& self, uint64_t offset) : self(self), offset(offset) {}
|
||||||
auto operator*() -> const T& { return self.operator[](offset); }
|
auto operator*() -> const T& { return self.operator[](offset); }
|
||||||
auto operator!=(const vector_iterator_const& source) const -> bool { return offset != source.offset; }
|
auto operator!=(const vector_iterator_const& source) const -> bool { return offset != source.offset; }
|
||||||
auto operator++() -> vector_iterator_const& { return offset++, *this; }
|
auto operator++() -> vector_iterator_const& { return offset++, *this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const vector<T>& self;
|
const vector<T>& self;
|
||||||
uint offset;
|
uint64_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct vector_iterator_reverse {
|
struct vector_reverse_iterator {
|
||||||
vector_iterator_reverse(vector<T>& self, uint offset) : self(self), offset(offset) {}
|
vector_reverse_iterator(vector<T>& self, uint64_t offset) : self(self), offset(offset) {}
|
||||||
auto operator*() -> T& { return self.operator[](offset); }
|
auto operator*() -> T& { return self.operator[](offset); }
|
||||||
auto operator!=(const vector_iterator_reverse& source) const -> bool { return offset != source.offset; }
|
auto operator!=(const vector_reverse_iterator& source) const -> bool { return offset != source.offset; }
|
||||||
auto operator++() -> vector_iterator_reverse& { return offset--, *this; }
|
auto operator++() -> vector_reverse_iterator& { return offset--, *this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vector<T>& self;
|
vector<T>& self;
|
||||||
uint offset;
|
uint64_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct vector_iterator_reverse_const {
|
struct vector_reverse_iterator_const {
|
||||||
vector_iterator_reverse_const(const vector<T>& self, uint offset) : self(self), offset(offset) {}
|
vector_reverse_iterator_const(const vector<T>& self, uint64_t offset) : self(self), offset(offset) {}
|
||||||
auto operator*() -> const T& { return self.operator[](offset); }
|
auto operator*() -> const T& { return self.operator[](offset); }
|
||||||
auto operator!=(const vector_iterator_reverse_const& source) const -> bool { return offset != source.offset; }
|
auto operator!=(const vector_reverse_iterator_const& source) const -> bool { return offset != source.offset; }
|
||||||
auto operator++() -> vector_iterator_reverse_const& { return offset--, *this; }
|
auto operator++() -> vector_reverse_iterator_const& { return offset--, *this; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const vector<T>& self;
|
const vector<T>& self;
|
||||||
uint offset;
|
uint64_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace nall {
|
||||||
template<typename T> auto vector<T>::reset() -> void {
|
template<typename T> auto vector<T>::reset() -> void {
|
||||||
if(!_pool) return;
|
if(!_pool) return;
|
||||||
|
|
||||||
for(uint n : range(_size)) _pool[n].~T();
|
for(uint64_t n : range(_size)) _pool[n].~T();
|
||||||
memory::free(_pool - _left);
|
memory::free(_pool - _left);
|
||||||
|
|
||||||
_pool = nullptr;
|
_pool = nullptr;
|
||||||
|
@ -19,7 +19,7 @@ template<typename T> auto vector<T>::reset() -> void {
|
||||||
|
|
||||||
//acquire ownership of allocated memory
|
//acquire ownership of allocated memory
|
||||||
|
|
||||||
template<typename T> auto vector<T>::acquire(const T* data, uint size, uint capacity) -> void {
|
template<typename T> auto vector<T>::acquire(const T* data, uint64_t size, uint64_t capacity) -> void {
|
||||||
reset();
|
reset();
|
||||||
_pool = data;
|
_pool = data;
|
||||||
_size = size;
|
_size = size;
|
||||||
|
@ -43,12 +43,12 @@ template<typename T> auto vector<T>::release() -> T* {
|
||||||
//reserve will not actually shrink the capacity, only expand it
|
//reserve will not actually shrink the capacity, only expand it
|
||||||
//shrinking the capacity would destroy objects, and break amortized growth with reallocate and resize
|
//shrinking the capacity would destroy objects, and break amortized growth with reallocate and resize
|
||||||
|
|
||||||
template<typename T> auto vector<T>::reserveLeft(uint capacity) -> bool {
|
template<typename T> auto vector<T>::reserveLeft(uint64_t capacity) -> bool {
|
||||||
if(_size + _left >= capacity) return false;
|
if(_size + _left >= capacity) return false;
|
||||||
|
|
||||||
uint left = bit::round(capacity);
|
uint64_t left = bit::round(capacity);
|
||||||
auto pool = memory::allocate<T>(left + _right) + (left - _size);
|
auto pool = memory::allocate<T>(left + _right) + (left - _size);
|
||||||
for(uint n : range(_size)) new(pool + n) T(move(_pool[n]));
|
for(uint64_t n : range(_size)) new(pool + n) T(move(_pool[n]));
|
||||||
memory::free(_pool - _left);
|
memory::free(_pool - _left);
|
||||||
|
|
||||||
_pool = pool;
|
_pool = pool;
|
||||||
|
@ -57,12 +57,12 @@ template<typename T> auto vector<T>::reserveLeft(uint capacity) -> bool {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::reserveRight(uint capacity) -> bool {
|
template<typename T> auto vector<T>::reserveRight(uint64_t capacity) -> bool {
|
||||||
if(_size + _right >= capacity) return false;
|
if(_size + _right >= capacity) return false;
|
||||||
|
|
||||||
uint right = bit::round(capacity);
|
uint64_t right = bit::round(capacity);
|
||||||
auto pool = memory::allocate<T>(_left + right) + _left;
|
auto pool = memory::allocate<T>(_left + right) + _left;
|
||||||
for(uint n : range(_size)) new(pool + n) T(move(_pool[n]));
|
for(uint64_t n : range(_size)) new(pool + n) T(move(_pool[n]));
|
||||||
memory::free(_pool - _left);
|
memory::free(_pool - _left);
|
||||||
|
|
||||||
_pool = pool;
|
_pool = pool;
|
||||||
|
@ -74,7 +74,7 @@ template<typename T> auto vector<T>::reserveRight(uint capacity) -> bool {
|
||||||
//reallocation is meant for POD types, to avoid the overhead of initialization
|
//reallocation is meant for POD types, to avoid the overhead of initialization
|
||||||
//do not use with non-POD types, or they will not be properly constructed or destructed
|
//do not use with non-POD types, or they will not be properly constructed or destructed
|
||||||
|
|
||||||
template<typename T> auto vector<T>::reallocateLeft(uint size) -> bool {
|
template<typename T> auto vector<T>::reallocateLeft(uint64_t size) -> bool {
|
||||||
if(size < _size) { //shrink
|
if(size < _size) { //shrink
|
||||||
_pool += _size - size;
|
_pool += _size - size;
|
||||||
_left += _size - size;
|
_left += _size - size;
|
||||||
|
@ -91,7 +91,7 @@ template<typename T> auto vector<T>::reallocateLeft(uint size) -> bool {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::reallocateRight(uint size) -> bool {
|
template<typename T> auto vector<T>::reallocateRight(uint64_t size) -> bool {
|
||||||
if(size < _size) { //shrink
|
if(size < _size) { //shrink
|
||||||
_right += _size - size;
|
_right += _size - size;
|
||||||
_size = size;
|
_size = size;
|
||||||
|
@ -108,9 +108,9 @@ template<typename T> auto vector<T>::reallocateRight(uint size) -> bool {
|
||||||
|
|
||||||
//resize is meant for non-POD types, and will properly construct objects
|
//resize is meant for non-POD types, and will properly construct objects
|
||||||
|
|
||||||
template<typename T> auto vector<T>::resizeLeft(uint size, const T& value) -> bool {
|
template<typename T> auto vector<T>::resizeLeft(uint64_t size, const T& value) -> bool {
|
||||||
if(size < _size) { //shrink
|
if(size < _size) { //shrink
|
||||||
for(uint n : range(_size - size)) _pool[n].~T();
|
for(uint64_t n : range(_size - size)) _pool[n].~T();
|
||||||
_pool += _size - size;
|
_pool += _size - size;
|
||||||
_left += _size - size;
|
_left += _size - size;
|
||||||
_size = size;
|
_size = size;
|
||||||
|
@ -119,7 +119,7 @@ template<typename T> auto vector<T>::resizeLeft(uint size, const T& value) -> bo
|
||||||
if(size > _size) { //grow
|
if(size > _size) { //grow
|
||||||
reserveLeft(size);
|
reserveLeft(size);
|
||||||
_pool -= size - _size;
|
_pool -= size - _size;
|
||||||
for(uint n : nall::reverse(range(size - _size))) new(_pool + n) T(value);
|
for(uint64_t n : nall::reverse(range(size - _size))) new(_pool + n) T(value);
|
||||||
_left -= size - _size;
|
_left -= size - _size;
|
||||||
_size = size;
|
_size = size;
|
||||||
return true;
|
return true;
|
||||||
|
@ -127,16 +127,16 @@ template<typename T> auto vector<T>::resizeLeft(uint size, const T& value) -> bo
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::resizeRight(uint size, const T& value) -> bool {
|
template<typename T> auto vector<T>::resizeRight(uint64_t size, const T& value) -> bool {
|
||||||
if(size < _size) { //shrink
|
if(size < _size) { //shrink
|
||||||
for(uint n : range(size, _size)) _pool[n].~T();
|
for(uint64_t n : range(size, _size)) _pool[n].~T();
|
||||||
_right += _size - size;
|
_right += _size - size;
|
||||||
_size = size;
|
_size = size;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(size > _size) { //grow
|
if(size > _size) { //grow
|
||||||
reserveRight(size);
|
reserveRight(size);
|
||||||
for(uint n : range(_size, size)) new(_pool + n) T(value);
|
for(uint64_t n : range(_size, size)) new(_pool + n) T(value);
|
||||||
_right -= size - _size;
|
_right -= size - _size;
|
||||||
_size = size;
|
_size = size;
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -19,7 +19,7 @@ template<typename T> auto vector<T>::prepend(T&& value) -> void {
|
||||||
template<typename T> auto vector<T>::prepend(const vector<T>& values) -> void {
|
template<typename T> auto vector<T>::prepend(const vector<T>& values) -> void {
|
||||||
reserveLeft(size() + values.size());
|
reserveLeft(size() + values.size());
|
||||||
_pool -= values.size();
|
_pool -= values.size();
|
||||||
for(uint n : range(values)) new(_pool + n) T(values[n]);
|
for(uint64_t n : range(values)) new(_pool + n) T(values[n]);
|
||||||
_left -= values.size();
|
_left -= values.size();
|
||||||
_size += values.size();
|
_size += values.size();
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ template<typename T> auto vector<T>::prepend(const vector<T>& values) -> void {
|
||||||
template<typename T> auto vector<T>::prepend(vector<T>&& values) -> void {
|
template<typename T> auto vector<T>::prepend(vector<T>&& values) -> void {
|
||||||
reserveLeft(size() + values.size());
|
reserveLeft(size() + values.size());
|
||||||
_pool -= values.size();
|
_pool -= values.size();
|
||||||
for(uint n : range(values)) new(_pool + n) T(move(values[n]));
|
for(uint64_t n : range(values)) new(_pool + n) T(move(values[n]));
|
||||||
_left -= values.size();
|
_left -= values.size();
|
||||||
_size += values.size();
|
_size += values.size();
|
||||||
}
|
}
|
||||||
|
@ -50,26 +50,26 @@ template<typename T> auto vector<T>::append(T&& value) -> void {
|
||||||
|
|
||||||
template<typename T> auto vector<T>::append(const vector<T>& values) -> void {
|
template<typename T> auto vector<T>::append(const vector<T>& values) -> void {
|
||||||
reserveRight(size() + values.size());
|
reserveRight(size() + values.size());
|
||||||
for(uint n : range(values.size())) new(_pool + _size + n) T(values[n]);
|
for(uint64_t n : range(values.size())) new(_pool + _size + n) T(values[n]);
|
||||||
_right -= values.size();
|
_right -= values.size();
|
||||||
_size += values.size();
|
_size += values.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::append(vector<T>&& values) -> void {
|
template<typename T> auto vector<T>::append(vector<T>&& values) -> void {
|
||||||
reserveRight(size() + values.size());
|
reserveRight(size() + values.size());
|
||||||
for(uint n : range(values.size())) new(_pool + _size + n) T(move(values[n]));
|
for(uint64_t n : range(values.size())) new(_pool + _size + n) T(move(values[n]));
|
||||||
_right -= values.size();
|
_right -= values.size();
|
||||||
_size += values.size();
|
_size += values.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
template<typename T> auto vector<T>::insert(uint offset, const T& value) -> void {
|
template<typename T> auto vector<T>::insert(uint64_t offset, const T& value) -> void {
|
||||||
if(offset == 0) return prepend(value);
|
if(offset == 0) return prepend(value);
|
||||||
if(offset == size() - 1) return append(value);
|
if(offset == size() - 1) return append(value);
|
||||||
reserveRight(size() + 1);
|
reserveRight(size() + 1);
|
||||||
_size++;
|
_size++;
|
||||||
for(int n = size() - 1; n > offset; n--) {
|
for(int64_t n = size() - 1; n > offset; n--) {
|
||||||
_pool[n] = move(_pool[n - 1]);
|
_pool[n] = move(_pool[n - 1]);
|
||||||
}
|
}
|
||||||
new(_pool + offset) T(value);
|
new(_pool + offset) T(value);
|
||||||
|
@ -77,21 +77,21 @@ template<typename T> auto vector<T>::insert(uint offset, const T& value) -> void
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
template<typename T> auto vector<T>::removeLeft(uint length) -> void {
|
template<typename T> auto vector<T>::removeLeft(uint64_t length) -> void {
|
||||||
if(length > size()) length = size();
|
if(length > size()) length = size();
|
||||||
resizeLeft(size() - length);
|
resizeLeft(size() - length);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::removeRight(uint length) -> void {
|
template<typename T> auto vector<T>::removeRight(uint64_t length) -> void {
|
||||||
if(length > size()) length = size();
|
if(length > size()) length = size();
|
||||||
resizeRight(size() - length);
|
resizeRight(size() - length);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::remove(uint offset, uint length) -> void {
|
template<typename T> auto vector<T>::remove(uint64_t offset, uint64_t length) -> void {
|
||||||
if(offset == 0) return removeLeft(length);
|
if(offset == 0) return removeLeft(length);
|
||||||
if(offset == size() - 1) return removeRight(length);
|
if(offset == size() - 1) return removeRight(length);
|
||||||
|
|
||||||
for(uint n = offset; n < size(); n++) {
|
for(uint64_t n = offset; n < size(); n++) {
|
||||||
if(n + length < size()) {
|
if(n + length < size()) {
|
||||||
_pool[n] = move(_pool[n + length]);
|
_pool[n] = move(_pool[n + length]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -115,7 +115,7 @@ template<typename T> auto vector<T>::takeRight() -> T {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::take(uint offset) -> T {
|
template<typename T> auto vector<T>::take(uint64_t offset) -> T {
|
||||||
if(offset == 0) return takeLeft();
|
if(offset == 0) return takeLeft();
|
||||||
if(offset == size() - 1) return takeRight();
|
if(offset == size() - 1) return takeRight();
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
namespace nall {
|
namespace nall {
|
||||||
|
|
||||||
template<typename T> auto vector<T>::fill(const T& value) -> void {
|
template<typename T> auto vector<T>::fill(const T& value) -> void {
|
||||||
for(uint n : range(size())) _pool[n] = value;
|
for(uint64_t n : range(size())) _pool[n] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::sort(const function<bool (const T& lhs, const T& rhs)>& comparator) -> void {
|
template<typename T> auto vector<T>::sort(const function<bool (const T& lhs, const T& rhs)>& comparator) -> void {
|
||||||
|
@ -12,24 +12,24 @@ template<typename T> auto vector<T>::sort(const function<bool (const T& lhs, con
|
||||||
|
|
||||||
template<typename T> auto vector<T>::reverse() -> void {
|
template<typename T> auto vector<T>::reverse() -> void {
|
||||||
vector<T> reversed;
|
vector<T> reversed;
|
||||||
for(uint n : range(size())) reversed.prepend(_pool[n]);
|
for(uint64_t n : range(size())) reversed.prepend(_pool[n]);
|
||||||
operator=(move(reversed));
|
operator=(move(reversed));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::find(const function<bool (const T& lhs)>& comparator) -> maybe<uint> {
|
template<typename T> auto vector<T>::find(const function<bool (const T& lhs)>& comparator) -> maybe<uint64_t> {
|
||||||
for(uint n : range(size())) if(comparator(_pool[n])) return n;
|
for(uint64_t n : range(size())) if(comparator(_pool[n])) return n;
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::find(const T& value) const -> maybe<uint> {
|
template<typename T> auto vector<T>::find(const T& value) const -> maybe<uint64_t> {
|
||||||
for(uint n : range(size())) if(_pool[n] == value) return n;
|
for(uint64_t n : range(size())) if(_pool[n] == value) return n;
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::findSorted(const T& value) const -> maybe<uint> {
|
template<typename T> auto vector<T>::findSorted(const T& value) const -> maybe<uint64_t> {
|
||||||
int l = 0, r = size() - 1;
|
int64_t l = 0, r = size() - 1;
|
||||||
while(l <= r) {
|
while(l <= r) {
|
||||||
int m = l + (r - l >> 1);
|
int64_t m = l + (r - l >> 1);
|
||||||
if(value == _pool[m]) return m;
|
if(value == _pool[m]) return m;
|
||||||
value < _pool[m] ? r = m - 1 : l = m + 1;
|
value < _pool[m] ? r = m - 1 : l = m + 1;
|
||||||
}
|
}
|
||||||
|
@ -37,11 +37,11 @@ template<typename T> auto vector<T>::findSorted(const T& value) const -> maybe<u
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::foreach(const function<void (const T&)>& callback) -> void {
|
template<typename T> auto vector<T>::foreach(const function<void (const T&)>& callback) -> void {
|
||||||
for(uint n : range(size())) callback(_pool[n]);
|
for(uint64_t n : range(size())) callback(_pool[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> auto vector<T>::foreach(const function<void (uint, const T&)>& callback) -> void {
|
template<typename T> auto vector<T>::foreach(const function<void (uint, const T&)>& callback) -> void {
|
||||||
for(uint n : range(size())) callback(n, _pool[n]);
|
for(uint64_t n : range(size())) callback(n, _pool[n]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue