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:
Tim Allen 2018-12-22 21:28:15 +11:00
parent 90da691717
commit 3159285eaa
83 changed files with 1265 additions and 192 deletions

View File

@ -34,7 +34,7 @@ endif
$(call delete,obj/*)
$(call delete,out/*)
install:
install: all
ifeq ($(platform),macos)
cp -R out/$(name).app /Applications/$(name).app
else ifneq ($(filter $(platform),linux bsd),)

View File

@ -34,16 +34,13 @@ else
$(error "unsupported platform")
endif
objects := libco emulator audio video resource
objects := libco emulator
obj/libco.o: ../libco/libco.c
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)
cores := fc sfc ms md pce gb gba ws
cores := fc sfc ms md pce msx gb gba ws ngp
endif
ifeq ($(target),bsnes)
@ -70,6 +67,10 @@ ifneq ($(filter $(cores),pce),)
include pce/GNUmakefile
endif
ifneq ($(filter $(cores),msx),)
include msx/GNUmakefile
endif
ifneq ($(filter $(cores),gb),)
include gb/GNUmakefile
endif
@ -82,6 +83,10 @@ ifneq ($(filter $(cores),ws),)
include ws/GNUmakefile
endif
ifneq ($(filter $(cores),ngp),)
include ngp/GNUmakefile
endif
include processor/GNUmakefile
flags += $(foreach c,$(call strupper,$(cores)),-DCORE_$c)

View File

@ -1,5 +1,3 @@
#include <emulator/emulator.hpp>
namespace Emulator {
#include "stream.cpp"

View File

@ -1,5 +1,9 @@
#include <emulator/emulator.hpp>
#include <emulator/audio/audio.cpp>
#include <emulator/video/video.cpp>
#include <emulator/resource/resource.cpp>
namespace Emulator {
Platform* platform = nullptr;

View File

@ -20,15 +20,15 @@
#include <nall/hash/sha256.hpp>
using namespace nall;
#include "types.hpp"
#include <libco/libco.h>
#include <audio/audio.hpp>
#include <video/video.hpp>
#include <resource/resource.hpp>
#include <emulator/types.hpp>
#include <emulator/audio/audio.hpp>
#include <emulator/video/video.hpp>
#include <emulator/resource/resource.hpp>
namespace Emulator {
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 License = "GPLv3";
static const string Website = "https://byuu.org/";

46
higan/emulator/memory.hpp Normal file
View File

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

View File

Before

Width:  |  Height:  |  Size: 332 B

After

Width:  |  Height:  |  Size: 332 B

View File

Before

Width:  |  Height:  |  Size: 329 B

After

Width:  |  Height:  |  Size: 329 B

View File

Before

Width:  |  Height:  |  Size: 342 B

After

Width:  |  Height:  |  Size: 342 B

View File

@ -1,5 +1,3 @@
#include <emulator/emulator.hpp>
namespace Emulator {
#include "sprite.cpp"

View File

@ -41,7 +41,7 @@ auto System::load(Emulator::Interface* interface) -> bool {
if(auto name = document["system/cpu/rom/name"].text()) {
if(auto fp = platform->open(ID::System, name, File::Read, File::Required)) {
fp->read(bios.data, bios.size);
}
} else return false;
}
if(!cartridge.load()) return false;

View File

@ -9,6 +9,13 @@ Cartridge cartridge;
auto Cartridge::load() -> bool {
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(auto loaded = platform->load(ID::SG1000, "SG-1000", "sg1000", {"NTSC", "PAL"})) {
information.pathID = loaded.pathID;

View File

@ -18,7 +18,7 @@ struct Cartridge {
//serialization.cpp
auto serialize(serializer&) -> void;
private:
//private:
struct Information {
uint pathID = 0;
string region;

View File

@ -4,6 +4,7 @@ namespace MasterSystem {
ControllerPort controllerPort1;
ControllerPort controllerPort2;
#include "numberpad/numberpad.cpp"
#include "gamepad/gamepad.cpp"
Controller::Controller(uint port) : port(port) {
@ -36,6 +37,7 @@ auto ControllerPort::connect(uint deviceID) -> void {
switch(deviceID) { default:
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;
}

View File

@ -5,7 +5,8 @@ struct Controller : Thread {
static auto Enter() -> 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;
};
@ -24,4 +25,5 @@ struct ControllerPort {
extern ControllerPort controllerPort1;
extern ControllerPort controllerPort2;
#include "numberpad/numberpad.hpp"
#include "gamepad/gamepad.hpp"

View File

@ -1,8 +1,8 @@
Gamepad::Gamepad(uint port) : Controller(port) {
}
auto Gamepad::readData() -> uint7 {
uint7 data = 0x7f;
auto Gamepad::readData() -> uint8 {
uint8 data = 0xff;
data.bit(0) = !platform->inputPoll(port, ID::Device::Gamepad, Up);
data.bit(1) = !platform->inputPoll(port, ID::Device::Gamepad, Down);
data.bit(2) = !platform->inputPoll(port, ID::Device::Gamepad, Left);

View File

@ -5,5 +5,5 @@ struct Gamepad : Controller {
Gamepad(uint port);
auto readData() -> uint7 override;
auto readData() -> uint8 override;
};

View File

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

View File

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

33
higan/ms/cpu/coleco.cpp Normal file
View File

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

View File

@ -3,7 +3,8 @@
namespace MasterSystem {
CPU cpu;
#include "bus.cpp"
#include "coleco.cpp"
#include "sega.cpp"
#include "serialization.cpp"
auto CPU::Enter() -> void {
@ -60,14 +61,36 @@ auto CPU::setINT(bool value) -> void {
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 {
Z80::bus = this;
Z80::power();
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
state = {};
coleco = {};
}
}

View File

@ -11,14 +11,27 @@ struct CPU : Processor::Z80, Processor::Z80::Bus, Thread {
auto setNMI(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;
//bus.cpp
auto read(uint16 addr) -> uint8 override;
auto write(uint16 addr, uint8 data) -> void override;
//coleco.cpp
auto readColeco(uint16 address) -> uint8;
auto writeColeco(uint16 address, uint8 data) -> void;
auto in(uint8 addr) -> uint8 override;
auto out(uint8 addr, uint8 data) -> void override;
auto inColeco(uint8 address) -> uint8;
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
auto serialize(serializer&) -> void;
@ -26,12 +39,18 @@ struct CPU : Processor::Z80, Processor::Z80::Bus, Thread {
vector<Thread*> peripherals;
private:
uint8 ram[8 * 1024];
Emulator::WritableMemory<uint8> ram;
Emulator::WritableMemory<uint8> expansion;
struct State {
bool nmiLine = 0;
bool intLine = 0;
} state;
struct Coleco {
uint1 replaceBIOS;
uint1 replaceRAM;
} coleco;
};
extern CPU cpu;

View File

@ -1,27 +1,22 @@
auto CPU::read(uint16 addr) -> uint8 {
uint8 data;
if(auto result = cartridge.read(addr)) {
auto CPU::readSega(uint16 address) -> uint8 {
uint8 data = 0xff;
if(auto result = cartridge.read(address)) {
data = result();
} else if(addr >= 0xc000) {
data = ram[addr & 0x1fff];
} else if(address >= 0xc000) {
data = ram.read(address);
}
if(auto result = cheat.find(addr, data)) {
data = result();
}
if(auto result = cheat.find(address, data)) data = result();
return data;
}
auto CPU::write(uint16 addr, uint8 data) -> void {
if(cartridge.write(addr, data)) {
} else if(addr >= 0xc000) {
ram[addr & 0x1fff] = data;
auto CPU::writeSega(uint16 address, uint8 data) -> void {
if(cartridge.write(address, data)) {
} else if(address >= 0xc000) {
ram.write(address, data);
}
}
auto CPU::in(uint8 addr) -> uint8 {
auto CPU::inSega(uint8 addr) -> uint8 {
switch(addr >> 6) {
case 0: {
@ -87,7 +82,7 @@ auto CPU::in(uint8 addr) -> uint8 {
return 0xff;
}
auto CPU::out(uint8 addr, uint8 data) -> void {
auto CPU::outSega(uint8 addr, uint8 data) -> void {
if(addr == 0x06) {
if(Model::GameGear()) return psg.balance(data);
}

View File

@ -3,7 +3,7 @@ auto CPU::serialize(serializer& s) -> void {
Z80::Bus::serialize(s);
Thread::serialize(s);
s.array(ram);
s.array(ram.data(), ram.size());
s.integer(state.nmiLine);
s.integer(state.intLine);

View File

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

View File

@ -3,6 +3,7 @@
namespace MasterSystem {
Settings settings;
#include "colecovision.cpp"
#include "sg-1000.cpp"
#include "sc-3000.cpp"
#include "master-system.cpp"

View File

@ -5,6 +5,7 @@ namespace MasterSystem {
struct ID {
enum : uint {
System,
ColecoVision,
SG1000,
SC3000,
MasterSystem,
@ -23,6 +24,7 @@ struct ID {
SC3000Controls,
MasterSystemControls,
GameGearControls,
NumberPad,
Gamepad,
};};
};
@ -48,6 +50,22 @@ struct Interface : Emulator::Interface {
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 {
auto information() -> Information override;

View File

@ -6,6 +6,7 @@
#include <emulator/emulator.hpp>
#include <emulator/thread.hpp>
#include <emulator/scheduler.hpp>
#include <emulator/memory.hpp>
#include <emulator/cheat.hpp>
#include <processor/z80/z80.hpp>
@ -30,6 +31,7 @@ namespace MasterSystem {
};
struct Model {
inline static auto ColecoVision() -> bool;
inline static auto SG1000() -> bool;
inline static auto SC3000() -> bool;
inline static auto MasterSystem() -> bool;

View File

@ -29,6 +29,13 @@ auto System::load(Emulator::Interface* interface, Model model) -> bool {
} else return false;
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.region() == "NTSC") {

View File

@ -1,5 +1,5 @@
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 };
auto loaded() const -> bool { return information.loaded; }
@ -23,6 +23,8 @@ struct System {
auto serializeAll(serializer&) -> void;
auto serialize(serializer&) -> void;
uint8 bios[0x2000];
private:
Emulator::Interface* interface = nullptr;
@ -38,6 +40,7 @@ private:
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::SC3000() -> bool { return system.model() == System::Model::SC3000; }
auto Model::MasterSystem() -> bool { return system.model() == System::Model::MasterSystem; }

View File

@ -38,10 +38,10 @@ auto VDP::Background::graphics1(uint8 hoffset, uint9 voffset) -> void {
uint8 color = vdp.vram[colorAddress];
uint3 index = hoffset ^ 7;
if(vdp.vram[patternAddress].bit(index)) {
output.color = color.bits(4,7);
} else {
if(!vdp.vram[patternAddress].bit(index)) {
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);
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;
if(vdp.vram[patternAddress].bit(index)) {
output.color = color.bits(4,7);
} else {
if(!vdp.vram[patternAddress].bit(index)) {
output.color = color.bits(0,3);
} else {
output.color = color.bits(4,7);
}
}

View File

@ -76,7 +76,7 @@ auto VDP::registerWrite(uint4 addr, uint8 data) -> void {
case 0x0: {
io.externalSync = data.bit(0);
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.lineInterrupts = data.bit(4);
io.leftClip = data.bit(5);

View File

@ -72,7 +72,7 @@ auto VDP::step(uint clocks) -> void {
}
auto VDP::refresh() -> void {
if(Model::SG1000() || Model::SC3000()) {
if(Model::ColecoVision() || Model::SG1000() || Model::SC3000()) {
uint32* screen = buffer;
screen += 24 * 256;
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);
memory::fill<uint32>(buffer, 256 * 264);
for(auto& byte : vram) byte = 0x00;
for(auto& byte : cram) byte = 0x00;
io = {};
background.power();
@ -115,7 +117,7 @@ auto VDP::power() -> void {
}
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
static uint6 palette[16] = {
0x00, 0x00, 0x08, 0x0c, 0x10, 0x30, 0x01, 0x3c,

6
higan/msx/GNUmakefile Normal file
View File

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

View File

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

View File

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

47
higan/msx/msx.hpp Normal file
View File

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

View File

@ -0,0 +1,9 @@
#include <msx/msx.hpp>
namespace MSX {
System system;
Scheduler scheduler;
Cheat cheat;
}

View File

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

6
higan/ngp/GNUmakefile Normal file
View File

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

View File

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

View File

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

View File

@ -0,0 +1,7 @@
auto NeoGeoPocketColorInterface::information() -> Information {
Information information;
information.manufacturer = "SNK";
information.name = "Neo Geo Pocket Color";
information.extension = "ngpc";
return information;
}

View File

@ -0,0 +1,7 @@
auto NeoGeoPocketInterface::information() -> Information {
Information information;
information.manufacturer = "SNK";
information.name = "Neo Geo Pocket";
information.extension = "ngp";
return information;
}

40
higan/ngp/ngp.hpp Normal file
View File

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

View File

@ -0,0 +1,9 @@
#include <ngp/ngp.hpp>
namespace NeoGeoPocket {
System system;
Scheduler scheduler;
Cheat cheat;
}

View File

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

View File

@ -0,0 +1 @@
system name:ColecoVision

View File

@ -0,0 +1 @@
system name:MSX

View File

@ -0,0 +1 @@
system name:Neo Geo Pocket Color

View File

@ -0,0 +1 @@
system name:Neo Geo Pocket

View File

@ -63,7 +63,7 @@ auto Program::loadState(string filename) -> bool {
if(filename != "Quick/Undo") saveUndoState();
if(filename == "Quick/Undo") saveRedoState();
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;
return showMessage({"Loaded [", prefix, "]"}), true;
} else {

View File

@ -4,9 +4,11 @@
#include <ms/interface/interface.hpp>
#include <md/interface/interface.hpp>
#include <pce/interface/interface.hpp>
#include <msx/interface/interface.hpp>
#include <gb/interface/interface.hpp>
#include <gba/interface/interface.hpp>
#include <ws/interface/interface.hpp>
#include <ngp/interface/interface.hpp>
#include "platform.cpp"
#include "game.cpp"
#include "state.cpp"
@ -42,6 +44,12 @@ Program::Program(Arguments arguments) {
#ifdef CORE_PCE
emulators.append(new PCEngine::SuperGrafxInterface);
#endif
#ifdef CORE_MS
emulators.append(new MasterSystem::ColecoVisionInterface);
#endif
#ifdef CORE_MSX
emulators.append(new MSX::Interface);
#endif
#ifdef CORE_GB
emulators.append(new GameBoy::GameBoyInterface);
#endif
@ -63,6 +71,12 @@ Program::Program(Arguments arguments) {
#ifdef CORE_WS
emulators.append(new WonderSwan::PocketChallengeV2Interface);
#endif
#ifdef CORE_NGP
emulators.append(new NeoGeoPocket::NeoGeoPocketInterface);
#endif
#ifdef CORE_NGP
emulators.append(new NeoGeoPocket::NeoGeoPocketColorInterface);
#endif
new Presentation;
presentation->setVisible();

View File

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

View File

@ -7,6 +7,7 @@ Icarus::Icarus() {
Database::MegaDrive = BML::unserialize(string::read(locate("Database/Mega Drive.bml")));
Database::PCEngine = BML::unserialize(string::read(locate("Database/PC Engine.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::GameBoy = BML::unserialize(string::read(locate("Database/Game Boy.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::WonderSwanColor = BML::unserialize(string::read(locate("Database/WonderSwan Color.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::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 == ".pce") return pcEngineManifest(location);
if(type == ".sgx") return superGrafxManifest(location);
if(type == ".cv") return colecoVisionManifest(location);
if(type == ".msx") return msxManifest(location);
if(type == ".gb") return gameBoyManifest(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 == ".wsc") return wonderSwanColorManifest(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 == ".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 == ".pce") return pcEngineImport(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 == ".gb") return gameBoyImport(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 == ".wsc") return wonderSwanColorImport(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 == ".st") return sufamiTurboImport(buffer, location);

View File

@ -76,6 +76,11 @@ struct Icarus {
auto superGrafxManifest(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
auto msxManifest(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 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
auto bsMemoryManifest(string location) -> string;
auto bsMemoryManifest(vector<uint8_t>& buffer, string location) -> string;
@ -140,6 +155,7 @@ namespace Database {
Markup::Node MegaDrive;
Markup::Node PCEngine;
Markup::Node SuperGrafx;
Markup::Node ColecoVision;
Markup::Node MSX;
Markup::Node GameBoy;
Markup::Node GameBoyColor;
@ -148,6 +164,8 @@ namespace Database {
Markup::Node WonderSwan;
Markup::Node WonderSwanColor;
Markup::Node PocketChallengeV2;
Markup::Node NeoGeoPocket;
Markup::Node NeoGeoPocketColor;
Markup::Node BSMemory;
Markup::Node SufamiTurbo;
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -254,7 +254,7 @@ auto SuperFamicom::board() const -> string {
if(serial() == "A9PJ") {
//Sufami Turbo (JPN)
board.append("ST-", mode);
} else if(serial() == "ZSBJ") {
} else if(serial() == "ZBSJ") {
//BS-X: Sore wa Namae o Nusumareta Machi no Monogatari (JPN)
board.append("BS-MCC-");
} else if(serial() == "042J") {

View File

@ -25,11 +25,14 @@ Settings settings;
#include "heuristics/mega-drive.cpp"
#include "heuristics/pc-engine.cpp"
#include "heuristics/supergrafx.cpp"
#include "heuristics/colecovision.cpp"
#include "heuristics/msx.cpp"
#include "heuristics/game-boy.cpp"
#include "heuristics/game-boy-advance.cpp"
#include "heuristics/game-gear.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/sufami-turbo.cpp"
@ -43,6 +46,7 @@ Settings settings;
#include "core/mega-drive.cpp"
#include "core/pc-engine.cpp"
#include "core/supergrafx.cpp"
#include "core/colecovision.cpp"
#include "core/msx.cpp"
#include "core/game-boy.cpp"
#include "core/game-boy-color.cpp"
@ -50,6 +54,8 @@ Settings settings;
#include "core/game-gear.cpp"
#include "core/wonderswan.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/bs-memory.cpp"
#include "core/sufami-turbo.cpp"
@ -97,6 +103,7 @@ auto nall::main(Arguments arguments) -> void {
"*.md:*.smd:*.gen:"
"*.pce:"
"*.sgx:"
"*.cv:*.col:"
"*.msx:"
"*.gb:"
"*.gbc:"
@ -105,6 +112,8 @@ auto nall::main(Arguments arguments) -> void {
"*.ws:"
"*.wsc:"
"*.pc2:"
"*.ngp:"
"*.ngpc:*.ngc:"
"*.bs:"
"*.st:"
"*.zip"
@ -121,22 +130,24 @@ auto nall::main(Arguments arguments) -> void {
new SettingsDialog;
new ImportDialog;
new ErrorDialog;
#if defined(PLATFORM_MACOS)
Application::Cocoa::onAbout([&] {
MessageDialog().setTitle("About icarus").setText({
"icarus\n\n"
"Author: byuu\n"
"License: GPLv3\n"
"Website: https://byuu.org/\n"
}).information();
});
Application::Cocoa::onPreferences([&] {
scanDialog->settingsButton.doActivate();
});
Application::Cocoa::onQuit([&] {
Application::quit();
});
#endif
if constexpr(platform() == Platform::MacOS) {
Application::Cocoa::onAbout([&] {
MessageDialog().setTitle("About icarus").setText({
"icarus\n\n"
"Author: byuu\n"
"License: GPLv3\n"
"Website: https://byuu.org/\n"
}).information();
});
Application::Cocoa::onPreferences([&] {
scanDialog->settingsButton.doActivate();
});
Application::Cocoa::onQuit([&] {
Application::quit();
});
}
scanDialog->show();
Application::run();
settings.save();

View File

@ -116,6 +116,8 @@ auto ScanDialog::gamePakType(const string& type) -> bool {
|| type == ".ws"
|| type == ".wsc"
|| type == ".pc2"
|| type == ".ngp"
|| type == ".ngpc"
|| type == ".bs"
|| type == ".st";
}
@ -138,6 +140,8 @@ auto ScanDialog::gameRomType(const string& type) -> bool {
|| type == ".ws"
|| type == ".wsc"
|| type == ".pc2"
|| type == ".ngp"
|| type == ".ngpc" || type == ".ngc"
|| type == ".bs"
|| type == ".st";
}

View File

@ -3,53 +3,53 @@
namespace nall {
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!=(const iterator& source) const -> bool { return offset != source.offset; }
auto operator++() -> iterator& { return offset++, *this; }
private:
T* self;
uint offset;
uint64_t offset;
};
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 iterator_const& source) const -> bool { return offset != source.offset; }
auto operator++() -> iterator_const& { return offset++, *this; }
private:
const T* self;
uint offset;
uint64_t offset;
};
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!=(const reverse_iterator& source) const -> bool { return offset != source.offset; }
auto operator++() -> reverse_iterator& { return offset--, *this; }
private:
T* self;
uint offset;
uint64_t offset;
};
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 reverse_iterator_const& source) const -> bool { return offset != source.offset; }
auto operator++() -> reverse_iterator_const& { return offset--, *this; }
private:
const T* self;
uint offset;
uint64_t offset;
};
//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, uint Size> auto rend(T (&array)[Size]) { return reverse_iterator<T>{array, (uint)-1}; }
template<typename T, uint64_t Size> auto rbegin(T (&array)[Size]) { return reverse_iterator<T>{array, Size - 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 rend(T& self) { return self.rend(); }

View File

@ -4,25 +4,25 @@ namespace nall {
struct range_t {
struct iterator {
iterator(int position, int step = 0) : position(position), step(step) {}
auto operator*() const -> int { return position; }
iterator(int64_t position, int64_t step = 0) : position(position), step(step) {}
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++() -> iterator& { position += step; return *this; }
private:
int position;
const int step;
int64_t position;
const int64_t step;
};
struct reverse_iterator {
reverse_iterator(int position, int step = 0) : position(position), step(step) {}
auto operator*() const -> int { return position; }
reverse_iterator(int64_t position, int64_t step = 0) : position(position), step(step) {}
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++() -> reverse_iterator& { position -= step; return *this; }
private:
int position;
const int step;
int64_t position;
const int64_t step;
};
auto begin() const -> iterator { return {origin, stride}; }
@ -31,20 +31,20 @@ struct range_t {
auto rbegin() const -> reverse_iterator { return {target - stride, stride}; }
auto rend() const -> reverse_iterator { return {origin - stride}; }
int origin;
int target;
int stride;
int64_t origin;
int64_t target;
int64_t stride;
};
inline auto range(int size) {
inline auto range(int64_t size) {
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};
}
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};
}

View File

@ -16,6 +16,11 @@
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>
struct vector_base {
using type = vector_base;
@ -30,8 +35,8 @@ struct vector_base {
explicit operator bool() const;
operator array_span<T>();
operator array_view<T>() const;
template<typename Cast = T> auto capacity() const -> uint;
template<typename Cast = T> auto size() const -> uint;
template<typename Cast = T> auto capacity() const -> uint64_t;
template<typename Cast = T> auto size() const -> uint64_t;
template<typename Cast = T> auto data() -> Cast*;
template<typename Cast = T> auto data() const -> const Cast*;
@ -45,27 +50,27 @@ struct vector_base {
//memory.hpp
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 reserveLeft(uint capacity) -> bool;
auto reserveRight(uint capacity) -> bool;
auto reserve(uint capacity) -> bool { return reserveRight(capacity); }
auto reserveLeft(uint64_t capacity) -> bool;
auto reserveRight(uint64_t capacity) -> bool;
auto reserve(uint64_t capacity) -> bool { return reserveRight(capacity); }
auto reallocateLeft(uint size) -> bool;
auto reallocateRight(uint size) -> bool;
auto reallocate(uint size) -> bool { return reallocateRight(size); }
auto reallocateLeft(uint64_t size) -> bool;
auto reallocateRight(uint64_t size) -> bool;
auto reallocate(uint64_t size) -> bool { return reallocateRight(size); }
auto resizeLeft(uint size, const T& value = T()) -> bool;
auto resizeRight(uint size, const T& value = T()) -> bool;
auto resize(uint size, const T& value = T()) -> bool { return resizeRight(size, value); }
auto resizeLeft(uint64_t size, const T& value = T()) -> bool;
auto resizeRight(uint64_t size, const T& value = T()) -> bool;
auto resize(uint64_t size, const T& value = T()) -> bool { return resizeRight(size, value); }
//access.hpp
alwaysinline auto operator[](uint offset) -> T&;
alwaysinline auto operator[](uint offset) const -> const T&;
alwaysinline auto operator[](uint64_t offset) -> T&;
alwaysinline auto operator[](uint64_t offset) const -> const T&;
alwaysinline auto operator()(uint offset) -> T&;
alwaysinline auto operator()(uint offset, const T& value) const -> const T&;
alwaysinline auto operator()(uint64_t offset) -> T&;
alwaysinline auto operator()(uint64_t offset, const T& value) const -> const T&;
alwaysinline auto left() -> T&;
alwaysinline auto first() -> T& { return left(); }
@ -88,19 +93,19 @@ struct vector_base {
auto append(const 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 removeFirst(uint length = 1) -> void { return removeLeft(length); }
auto removeRight(uint length = 1) -> void;
auto removeLast(uint length = 1) -> void { return removeRight(length); }
auto remove(uint offset, uint length = 1) -> void;
auto removeLeft(uint64_t length = 1) -> void;
auto removeFirst(uint64_t length = 1) -> void { return removeLeft(length); }
auto removeRight(uint64_t length = 1) -> void;
auto removeLast(uint64_t length = 1) -> void { return removeRight(length); }
auto remove(uint64_t offset, uint64_t length = 1) -> void;
auto takeLeft() -> T;
auto takeFirst() -> T { return move(takeLeft()); }
auto takeRight() -> T;
auto takeLast() -> T { return move(takeRight()); }
auto take(uint offset) -> T;
auto take(uint64_t offset) -> T;
//iterator.hpp
auto begin() -> iterator<T> { return {data(), 0}; }
@ -110,26 +115,26 @@ struct vector_base {
auto end() const -> iterator_const<T> { return {data(), size()}; }
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 rend() const -> reverse_iterator_const<T> { return {data(), (uint)-1}; }
auto rend() const -> reverse_iterator_const<T> { return {data(), (uint64_t)-1}; }
//utility.hpp
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 reverse() -> void;
auto find(const function<bool (const T& lhs)>& comparator) -> maybe<uint>;
auto find(const T& value) const -> maybe<uint>;
auto findSorted(const T& value) const -> maybe<uint>;
auto find(const function<bool (const T& lhs)>& comparator) -> maybe<uint64_t>;
auto find(const T& value) const -> maybe<uint64_t>;
auto findSorted(const T& value) const -> maybe<uint64_t>;
auto foreach(const function<void (const T&)>& callback) -> void;
auto foreach(const function<void (uint, const T&)>& callback) -> void;
protected:
T* _pool = nullptr; //pointer to first initialized element in pool
uint _size = 0; //number of initialized elements in pool
uint _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
T* _pool = nullptr; //pointer to first initialized element in pool
uint64_t _size = 0; //number of initialized elements in pool
uint64_t _left = 0; //number of allocated elements free on the left of pool
uint64_t _right = 0; //number of allocated elements free on the right of pool
};
}

View File

@ -2,7 +2,7 @@
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
struct 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];
}
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
struct 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];
}
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());
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;
return _pool[offset];
}

View File

@ -8,7 +8,7 @@ template<typename T> auto vector<T>::operator=(const vector<T>& source) -> vecto
_size = source._size;
_left = 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;
}

View File

@ -5,7 +5,7 @@ namespace nall {
template<typename T> auto vector<T>::operator==(const vector<T>& source) const -> bool {
if(this == &source) return true;
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;
}
return true;

View File

@ -31,11 +31,11 @@ template<typename T> vector<T>::operator array_view<T>() const {
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);
}
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);
}

View File

@ -4,50 +4,50 @@ namespace nall {
template<typename T>
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!=(const vector_iterator& source) const -> bool { return offset != source.offset; }
auto operator++() -> vector_iterator& { return offset++, *this; }
private:
vector<T>& self;
uint offset;
uint64_t offset;
};
template<typename T>
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 vector_iterator_const& source) const -> bool { return offset != source.offset; }
auto operator++() -> vector_iterator_const& { return offset++, *this; }
private:
const vector<T>& self;
uint offset;
uint64_t offset;
};
template<typename T>
struct vector_iterator_reverse {
vector_iterator_reverse(vector<T>& self, uint offset) : self(self), offset(offset) {}
struct vector_reverse_iterator {
vector_reverse_iterator(vector<T>& self, uint64_t offset) : self(self), offset(offset) {}
auto operator*() -> T& { return self.operator[](offset); }
auto operator!=(const vector_iterator_reverse& source) const -> bool { return offset != source.offset; }
auto operator++() -> vector_iterator_reverse& { return offset--, *this; }
auto operator!=(const vector_reverse_iterator& source) const -> bool { return offset != source.offset; }
auto operator++() -> vector_reverse_iterator& { return offset--, *this; }
private:
vector<T>& self;
uint offset;
uint64_t offset;
};
template<typename T>
struct vector_iterator_reverse_const {
vector_iterator_reverse_const(const vector<T>& self, uint offset) : self(self), offset(offset) {}
struct vector_reverse_iterator_const {
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 vector_iterator_reverse_const& source) const -> bool { return offset != source.offset; }
auto operator++() -> vector_iterator_reverse_const& { return offset--, *this; }
auto operator!=(const vector_reverse_iterator_const& source) const -> bool { return offset != source.offset; }
auto operator++() -> vector_reverse_iterator_const& { return offset--, *this; }
private:
const vector<T>& self;
uint offset;
uint64_t offset;
};
}

View File

@ -8,7 +8,7 @@ namespace nall {
template<typename T> auto vector<T>::reset() -> void {
if(!_pool) return;
for(uint n : range(_size)) _pool[n].~T();
for(uint64_t n : range(_size)) _pool[n].~T();
memory::free(_pool - _left);
_pool = nullptr;
@ -19,7 +19,7 @@ template<typename T> auto vector<T>::reset() -> void {
//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();
_pool = data;
_size = size;
@ -43,12 +43,12 @@ template<typename T> auto vector<T>::release() -> T* {
//reserve will not actually shrink the capacity, only expand it
//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;
uint left = bit::round(capacity);
uint64_t left = bit::round(capacity);
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);
_pool = pool;
@ -57,12 +57,12 @@ template<typename T> auto vector<T>::reserveLeft(uint capacity) -> bool {
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;
uint right = bit::round(capacity);
uint64_t right = bit::round(capacity);
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);
_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
//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
_pool += _size - size;
_left += _size - size;
@ -91,7 +91,7 @@ template<typename T> auto vector<T>::reallocateLeft(uint size) -> bool {
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
_right += _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
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
for(uint n : range(_size - size)) _pool[n].~T();
for(uint64_t n : range(_size - size)) _pool[n].~T();
_pool += _size - size;
_left += _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
reserveLeft(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;
_size = size;
return true;
@ -127,16 +127,16 @@ template<typename T> auto vector<T>::resizeLeft(uint size, const T& value) -> bo
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
for(uint n : range(size, _size)) _pool[n].~T();
for(uint64_t n : range(size, _size)) _pool[n].~T();
_right += _size - size;
_size = size;
return true;
}
if(size > _size) { //grow
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;
_size = size;
return true;

View File

@ -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 {
reserveLeft(size() + 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();
_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 {
reserveLeft(size() + 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();
_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 {
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();
_size += values.size();
}
template<typename T> auto vector<T>::append(vector<T>&& values) -> void {
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();
_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 == size() - 1) return append(value);
reserveRight(size() + 1);
_size++;
for(int n = size() - 1; n > offset; n--) {
for(int64_t n = size() - 1; n > offset; n--) {
_pool[n] = move(_pool[n - 1]);
}
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();
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();
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 == size() - 1) return removeRight(length);
for(uint n = offset; n < size(); n++) {
for(uint64_t n = offset; n < size(); n++) {
if(n + length < size()) {
_pool[n] = move(_pool[n + length]);
} else {
@ -115,7 +115,7 @@ template<typename T> auto vector<T>::takeRight() -> T {
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 == size() - 1) return takeRight();

View File

@ -3,7 +3,7 @@
namespace nall {
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 {
@ -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 {
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));
}
template<typename T> auto vector<T>::find(const function<bool (const T& lhs)>& comparator) -> maybe<uint> {
for(uint n : range(size())) if(comparator(_pool[n])) return n;
template<typename T> auto vector<T>::find(const function<bool (const T& lhs)>& comparator) -> maybe<uint64_t> {
for(uint64_t n : range(size())) if(comparator(_pool[n])) return n;
return nothing;
}
template<typename T> auto vector<T>::find(const T& value) const -> maybe<uint> {
for(uint n : range(size())) if(_pool[n] == value) return n;
template<typename T> auto vector<T>::find(const T& value) const -> maybe<uint64_t> {
for(uint64_t n : range(size())) if(_pool[n] == value) return n;
return nothing;
}
template<typename T> auto vector<T>::findSorted(const T& value) const -> maybe<uint> {
int l = 0, r = size() - 1;
template<typename T> auto vector<T>::findSorted(const T& value) const -> maybe<uint64_t> {
int64_t l = 0, r = size() - 1;
while(l <= r) {
int m = l + (r - l >> 1);
int64_t m = l + (r - l >> 1);
if(value == _pool[m]) return m;
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 {
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 {
for(uint n : range(size())) callback(n, _pool[n]);
for(uint64_t n : range(size())) callback(n, _pool[n]);
}
}