mirror of https://github.com/bsnes-emu/bsnes.git
Update to v095r03 release and icarus 20151107.
byuu says: Note: you will need the new icarus (and please use the "no manifest" system) to run GBA games with this WIP. Changelog: - fixed caching of r(d) to pass armwrestler tests [Jonas Quinn] - DMA to/from GBA BIOS should fail [Cydrak] - fixed sign-extend and rotate on ldrs instructions [Cydrak] - fixed 8-bit SRAM reading/writing [byuu] - refactored GBA/cartridge - cartridge/rom,ram.type is now cartridge/mrom,sram,eeprom,flash - things won't crash horribly if you specify a RAM size larger than the largest legal size in the manifest - specialized MROM / SRAM classes replace all the shared read/write functions that didn't work right anyway - there's a new ruby/video.glx2 driver, which is not enabled by default - use this if you are running Linux/BSD, but don't have OpenGL 3.2 yet - I'm not going to support OpenGL2 on Windows/OS X, because these OSes don't ship ancient video card drivers - probably more. What am I, clairvoyant? :P For endrift's tests, this gets us to 1348/1552 memory and 1016/1260 timing. Overall, this puts us back in second place. Only no$ is ahead on memory, but bgba is even more ahead on timing.
This commit is contained in:
parent
b42ab2fcb3
commit
0fe55e3f5b
|
@ -3,12 +3,11 @@
|
||||||
|
|
||||||
#include <nall/nall.hpp>
|
#include <nall/nall.hpp>
|
||||||
#include <nall/dsp.hpp>
|
#include <nall/dsp.hpp>
|
||||||
#include <nall/priority-queue.hpp>
|
|
||||||
using namespace nall;
|
using namespace nall;
|
||||||
|
|
||||||
namespace Emulator {
|
namespace Emulator {
|
||||||
static const string Name = "higan";
|
static const string Name = "higan";
|
||||||
static const string Version = "095.02";
|
static const string Version = "095.03";
|
||||||
static const string Author = "byuu";
|
static const string Author = "byuu";
|
||||||
static const string License = "GPLv3";
|
static const string License = "GPLv3";
|
||||||
static const string Website = "http://byuu.org/";
|
static const string Website = "http://byuu.org/";
|
||||||
|
|
|
@ -2,170 +2,128 @@
|
||||||
|
|
||||||
namespace GameBoyAdvance {
|
namespace GameBoyAdvance {
|
||||||
|
|
||||||
|
#include "mrom.cpp"
|
||||||
|
#include "sram.cpp"
|
||||||
#include "eeprom.cpp"
|
#include "eeprom.cpp"
|
||||||
#include "flashrom.cpp"
|
#include "flash.cpp"
|
||||||
#include "serialization.cpp"
|
#include "serialization.cpp"
|
||||||
Cartridge cartridge;
|
Cartridge cartridge;
|
||||||
|
|
||||||
string Cartridge::title() {
|
Cartridge::Cartridge() {
|
||||||
|
loaded = false;
|
||||||
|
mrom.data = new uint8[mrom.size = 32 * 1024 * 1024];
|
||||||
|
sram.data = new uint8[sram.size = 32 * 1024];
|
||||||
|
eeprom.data = new uint8[eeprom.size = 8 * 1024];
|
||||||
|
flash.data = new uint8[flash.size = 128 * 1024];
|
||||||
|
}
|
||||||
|
|
||||||
|
Cartridge::~Cartridge() {
|
||||||
|
delete[] mrom.data;
|
||||||
|
delete[] sram.data;
|
||||||
|
delete[] eeprom.data;
|
||||||
|
delete[] flash.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::title() const -> string {
|
||||||
return information.title;
|
return information.title;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::load() {
|
auto Cartridge::load() -> void {
|
||||||
interface->loadRequest(ID::Manifest, "manifest.bml", true);
|
interface->loadRequest(ID::Manifest, "manifest.bml", true);
|
||||||
|
|
||||||
auto document = BML::unserialize(information.markup);
|
auto document = BML::unserialize(information.markup);
|
||||||
information.title = document["information/title"].text();
|
information.title = document["information/title"].text();
|
||||||
|
|
||||||
unsigned rom_size = 0;
|
unsigned mrom_size = 0;
|
||||||
if(document["cartridge/rom"]) {
|
if(auto info = document["cartridge/mrom"]) {
|
||||||
auto info = document["cartridge/rom"];
|
interface->loadRequest(ID::MROM, info["name"].text(), true);
|
||||||
interface->loadRequest(ID::ROM, info["name"].text(), true);
|
mrom_size = info["size"].decimal();
|
||||||
rom_size = info["size"].decimal();
|
for(unsigned addr = mrom_size; addr < mrom.size; addr++) {
|
||||||
for(unsigned addr = rom_size; addr < rom.size; addr++) {
|
mrom.data[addr] = mrom.data[Bus::mirror(addr, mrom_size)];
|
||||||
rom.data[addr] = rom.data[Bus::mirror(addr, rom_size)];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
has_sram = false;
|
has_sram = false;
|
||||||
has_eeprom = false;
|
has_eeprom = false;
|
||||||
has_flashrom = false;
|
has_flash = false;
|
||||||
|
|
||||||
if(document["cartridge/ram"]) {
|
if(auto info = document["cartridge/sram"]) {
|
||||||
auto info = document["cartridge/ram"];
|
has_sram = true;
|
||||||
|
sram.size = min(32 * 1024, info["size"].decimal());
|
||||||
|
sram.mask = sram.size - 1;
|
||||||
|
for(auto n : range(sram.size)) sram.data[n] = 0xff;
|
||||||
|
|
||||||
if(info["type"].text() == "SRAM" || info["type"].text() == "FRAM") {
|
interface->loadRequest(ID::SRAM, info["name"].text(), false);
|
||||||
has_sram = true;
|
memory.append({ID::SRAM, info["name"].text()});
|
||||||
ram.size = info["size"].decimal();
|
|
||||||
ram.mask = ram.size - 1;
|
|
||||||
for(unsigned n = 0; n < ram.size; n++) ram.data[n] = 0xff;
|
|
||||||
|
|
||||||
interface->loadRequest(ID::RAM, info["name"].text(), false);
|
|
||||||
memory.append({ID::RAM, info["name"].text()});
|
|
||||||
}
|
|
||||||
|
|
||||||
if(info["type"].text() == "EEPROM") {
|
|
||||||
has_eeprom = true;
|
|
||||||
eeprom.size = info["size"].decimal();
|
|
||||||
eeprom.bits = eeprom.size <= 512 ? 6 : 14;
|
|
||||||
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
|
|
||||||
eeprom.mask = rom_size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
|
|
||||||
eeprom.test = rom_size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
|
||||||
for(unsigned n = 0; n < eeprom.size; n++) eeprom.data[n] = 0xff;
|
|
||||||
|
|
||||||
interface->loadRequest(ID::EEPROM, info["name"].text(), false);
|
|
||||||
memory.append({ID::EEPROM, info["name"].text()});
|
|
||||||
}
|
|
||||||
|
|
||||||
if(info["type"].text() == "FlashROM") {
|
|
||||||
has_flashrom = true;
|
|
||||||
flashrom.id = info["id"].decimal();
|
|
||||||
flashrom.size = info["size"].decimal();
|
|
||||||
for(unsigned n = 0; n < flashrom.size; n++) flashrom.data[n] = 0xff;
|
|
||||||
|
|
||||||
//if FlashROM ID not provided; guess that it's a Macronix chip
|
|
||||||
//this will not work for all games; in which case, the ID must be specified manually
|
|
||||||
if(!flashrom.id && flashrom.size == 64 * 1024) flashrom.id = 0x1cc2;
|
|
||||||
if(!flashrom.id && flashrom.size == 128 * 1024) flashrom.id = 0x09c2;
|
|
||||||
|
|
||||||
interface->loadRequest(ID::FlashROM, info["name"].text(), false);
|
|
||||||
memory.append({ID::FlashROM, info["name"].text()});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sha256 = Hash::SHA256(rom.data, rom_size).digest();
|
if(auto info = document["cartridge/eeprom"]) {
|
||||||
|
has_eeprom = true;
|
||||||
|
eeprom.size = min(8 * 1024, info["size"].decimal());
|
||||||
|
eeprom.bits = eeprom.size <= 512 ? 6 : 14;
|
||||||
|
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
|
||||||
|
eeprom.mask = mrom_size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
|
||||||
|
eeprom.test = mrom_size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
||||||
|
for(auto n : range(eeprom.size)) eeprom.data[n] = 0xff;
|
||||||
|
|
||||||
|
interface->loadRequest(ID::EEPROM, info["name"].text(), false);
|
||||||
|
memory.append({ID::EEPROM, info["name"].text()});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(auto info = document["cartridge/flash"]) {
|
||||||
|
has_flash = true;
|
||||||
|
flash.id = info["id"].decimal();
|
||||||
|
flash.size = min(128 * 1024, info["size"].decimal());
|
||||||
|
for(auto n : range(flash.size)) flash.data[n] = 0xff;
|
||||||
|
|
||||||
|
//if flash ID not provided; guess that it's a Macronix chip
|
||||||
|
//this will not work for all games; in which case, the ID must be specified manually
|
||||||
|
if(!flash.id && flash.size == 64 * 1024) flash.id = 0x1cc2;
|
||||||
|
if(!flash.id && flash.size == 128 * 1024) flash.id = 0x09c2;
|
||||||
|
|
||||||
|
interface->loadRequest(ID::FLASH, info["name"].text(), false);
|
||||||
|
memory.append({ID::FLASH, info["name"].text()});
|
||||||
|
}
|
||||||
|
|
||||||
|
sha256 = Hash::SHA256(mrom.data, mrom_size).digest();
|
||||||
|
|
||||||
system.load();
|
system.load();
|
||||||
loaded = true;
|
loaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::unload() {
|
auto Cartridge::unload() -> void {
|
||||||
if(loaded == false) return;
|
if(loaded) {
|
||||||
loaded = false;
|
loaded = false;
|
||||||
memory.reset();
|
memory.reset();
|
||||||
}
|
|
||||||
|
|
||||||
void Cartridge::power() {
|
|
||||||
eeprom.power();
|
|
||||||
flashrom.power();
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8* Cartridge::ram_data() {
|
|
||||||
if(has_sram) return ram.data;
|
|
||||||
if(has_eeprom) return eeprom.data;
|
|
||||||
if(has_flashrom) return flashrom.data;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned Cartridge::ram_size() {
|
|
||||||
if(has_sram) return ram.size;
|
|
||||||
if(has_eeprom) return eeprom.size;
|
|
||||||
if(has_flashrom) return flashrom.size;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Cartridge::read(uint8 *data, unsigned mode, uint32 addr) -> uint32 {
|
|
||||||
if(mode & Word) addr &= ~3;
|
|
||||||
if(mode & Half) addr &= ~1;
|
|
||||||
data += addr;
|
|
||||||
if(mode & Word) return data[0] << 0 | data[1] << 8 | data[2] << 16 | data[3] << 24;
|
|
||||||
if(mode & Half) return data[0] << 0 | data[1] << 8;
|
|
||||||
if(mode & Byte) return data[0];
|
|
||||||
return 0; //should never occur
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Cartridge::write(uint8 *data, unsigned mode, uint32 addr, uint32 word) -> void {
|
|
||||||
if(mode & Word) addr &= ~3;
|
|
||||||
if(mode & Half) addr &= ~1;
|
|
||||||
data += addr;
|
|
||||||
if(mode & Word) {
|
|
||||||
data[0] = word >> 0;
|
|
||||||
data[1] = word >> 8;
|
|
||||||
data[2] = word >> 16;
|
|
||||||
data[3] = word >> 24;
|
|
||||||
} else if(mode & Half) {
|
|
||||||
data[0] = word >> 0;
|
|
||||||
data[1] = word >> 8;
|
|
||||||
} else if(mode & Byte) {
|
|
||||||
data[0] = word >> 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto Cartridge::power() -> void {
|
||||||
|
eeprom.power();
|
||||||
|
flash.power();
|
||||||
|
}
|
||||||
|
|
||||||
#define RAM_ANALYZE
|
#define RAM_ANALYZE
|
||||||
|
|
||||||
auto Cartridge::rom_read(unsigned mode, uint32 addr) -> uint32 {
|
auto Cartridge::read(unsigned mode, uint32 addr) -> uint32 {
|
||||||
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.read();
|
if(addr < 0x0e00'0000) {
|
||||||
return read(rom.data, mode, addr & 0x01ff'ffff);
|
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.read();
|
||||||
|
return mrom.read(mode, addr);
|
||||||
|
} else {
|
||||||
|
if(has_sram) return sram.read(mode, addr);
|
||||||
|
if(has_flash) return flash.read(addr);
|
||||||
|
return cpu.pipeline.fetch.instruction;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Cartridge::rom_write(unsigned mode, uint32 addr, uint32 word) -> void {
|
auto Cartridge::write(unsigned mode, uint32 addr, uint32 word) -> void {
|
||||||
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.write(word & 1);
|
if(addr < 0x0e00'0000) {
|
||||||
}
|
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.write(word & 1);
|
||||||
|
return mrom.write(mode, addr, word);
|
||||||
auto Cartridge::ram_read(unsigned mode, uint32 addr) -> uint32 {
|
} else {
|
||||||
if(has_sram) return read(ram.data, mode, addr & ram.mask);
|
if(has_sram) return sram.write(mode, addr, word);
|
||||||
if(has_flashrom) return flashrom.read(addr);
|
if(has_flash) return flash.write(addr, word);
|
||||||
return cpu.pipeline.fetch.instruction;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
auto Cartridge::ram_write(unsigned mode, uint32 addr, uint32 word) -> void {
|
|
||||||
if(has_sram) return write(ram.data, mode, addr & ram.mask, word);
|
|
||||||
if(has_flashrom) return flashrom.write(addr, word);
|
|
||||||
}
|
|
||||||
|
|
||||||
Cartridge::Cartridge() {
|
|
||||||
loaded = false;
|
|
||||||
rom.data = new uint8[rom.size = 32 * 1024 * 1024];
|
|
||||||
ram.data = new uint8[ram.size = 32 * 1024];
|
|
||||||
eeprom.data = new uint8[eeprom.size = 8 * 1024];
|
|
||||||
flashrom.data = new uint8[flashrom.size = 128 * 1024];
|
|
||||||
}
|
|
||||||
|
|
||||||
Cartridge::~Cartridge() {
|
|
||||||
delete[] rom.data;
|
|
||||||
delete[] ram.data;
|
|
||||||
delete[] eeprom.data;
|
|
||||||
delete[] flashrom.data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,41 +6,32 @@ struct Cartridge : property<Cartridge> {
|
||||||
|
|
||||||
readonly<bool> has_sram;
|
readonly<bool> has_sram;
|
||||||
readonly<bool> has_eeprom;
|
readonly<bool> has_eeprom;
|
||||||
readonly<bool> has_flashrom;
|
readonly<bool> has_flash;
|
||||||
|
|
||||||
struct Information {
|
struct Information {
|
||||||
string markup;
|
string markup;
|
||||||
string title;
|
string title;
|
||||||
} information;
|
} information;
|
||||||
|
|
||||||
string title();
|
|
||||||
|
|
||||||
struct Media {
|
struct Media {
|
||||||
unsigned id;
|
unsigned id;
|
||||||
string name;
|
string name;
|
||||||
};
|
};
|
||||||
vector<Media> memory;
|
vector<Media> memory;
|
||||||
|
|
||||||
void load();
|
|
||||||
void unload();
|
|
||||||
void power();
|
|
||||||
|
|
||||||
uint8* ram_data();
|
|
||||||
unsigned ram_size();
|
|
||||||
|
|
||||||
auto read(uint8* data, unsigned mode, uint32 addr) -> uint32;
|
|
||||||
auto write(uint8* data, unsigned mode, uint32 addr, uint32 word) -> void;
|
|
||||||
|
|
||||||
auto rom_read(unsigned mode, uint32 addr) -> uint32;
|
|
||||||
auto rom_write(unsigned mode, uint32 addr, uint32 word) -> void;
|
|
||||||
|
|
||||||
auto ram_read(unsigned mode, uint32 addr) -> uint32;
|
|
||||||
auto ram_write(unsigned mode, uint32 addr, uint32 word) -> void;
|
|
||||||
|
|
||||||
void serialize(serializer&);
|
|
||||||
|
|
||||||
Cartridge();
|
Cartridge();
|
||||||
~Cartridge();
|
~Cartridge();
|
||||||
|
|
||||||
|
auto title() const -> string;
|
||||||
|
|
||||||
|
auto load() -> void;
|
||||||
|
auto unload() -> void;
|
||||||
|
auto power() -> void;
|
||||||
|
|
||||||
|
auto read(unsigned mode, uint32 addr) -> uint32;
|
||||||
|
auto write(unsigned mode, uint32 addr, uint32 word) -> void;
|
||||||
|
|
||||||
|
auto serialize(serializer&) -> void;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Cartridge cartridge;
|
extern Cartridge cartridge;
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
bool Cartridge::EEPROM::read(unsigned addr) {
|
auto Cartridge::EEPROM::read(unsigned addr) -> bool {
|
||||||
return data[addr >> 3] & 0x80 >> (addr & 7);
|
return data[addr >> 3] & 0x80 >> (addr & 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::EEPROM::write(unsigned addr, bool bit) {
|
auto Cartridge::EEPROM::write(unsigned addr, bool bit) -> void {
|
||||||
if(bit == 0) data[addr >> 3] &=~ (0x80 >> (addr & 7));
|
if(bit == 0) data[addr >> 3] &=~ (0x80 >> (addr & 7));
|
||||||
if(bit == 1) data[addr >> 3] |= (0x80 >> (addr & 7));
|
if(bit == 1) data[addr >> 3] |= (0x80 >> (addr & 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Cartridge::EEPROM::read() {
|
auto Cartridge::EEPROM::read() -> bool {
|
||||||
bool bit = 1;
|
bool bit = 1;
|
||||||
|
|
||||||
//EEPROM size auto-detection
|
//EEPROM size auto-detection
|
||||||
|
@ -28,7 +28,7 @@ bool Cartridge::EEPROM::read() {
|
||||||
return bit;
|
return bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::EEPROM::write(bool bit) {
|
auto Cartridge::EEPROM::write(bool bit) -> void {
|
||||||
if(mode == Mode::Wait) {
|
if(mode == Mode::Wait) {
|
||||||
if(bit == 1) mode = Mode::Command;
|
if(bit == 1) mode = Mode::Command;
|
||||||
}
|
}
|
||||||
|
@ -76,13 +76,13 @@ void Cartridge::EEPROM::write(bool bit) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::EEPROM::power() {
|
auto Cartridge::EEPROM::power() -> void {
|
||||||
mode = Mode::Wait;
|
mode = Mode::Wait;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
address = 0;
|
address = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::EEPROM::serialize(serializer& s) {
|
auto Cartridge::EEPROM::serialize(serializer& s) -> void {
|
||||||
s.array(data, size);
|
s.array(data, size);
|
||||||
s.integer(size);
|
s.integer(size);
|
||||||
s.integer(mask);
|
s.integer(mask);
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
//0x1362 128KB 32x4096 Sanyo
|
//0x1362 128KB 32x4096 Sanyo
|
||||||
//0x09c2 128KB 32x4096 Macronix
|
//0x09c2 128KB 32x4096 Macronix
|
||||||
|
|
||||||
uint8 Cartridge::FlashROM::read(uint16 addr) {
|
auto Cartridge::FLASH::read(uint16 addr) -> uint8 {
|
||||||
if(idmode) {
|
if(idmode) {
|
||||||
if(addr == 0x0000) return id >> 0;
|
if(addr == 0x0000) return id >> 0;
|
||||||
if(addr == 0x0001) return id >> 8;
|
if(addr == 0x0001) return id >> 8;
|
||||||
|
@ -17,7 +17,7 @@ uint8 Cartridge::FlashROM::read(uint16 addr) {
|
||||||
return data[bank << 16 | addr];
|
return data[bank << 16 | addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::FlashROM::write(uint16 addr, uint8 byte) {
|
auto Cartridge::FLASH::write(uint16 addr, uint8 byte) -> void {
|
||||||
if(bankselect) {
|
if(bankselect) {
|
||||||
bankselect = false;
|
bankselect = false;
|
||||||
//bank select is only applicable on 128KB chips
|
//bank select is only applicable on 128KB chips
|
||||||
|
@ -77,7 +77,7 @@ void Cartridge::FlashROM::write(uint16 addr, uint8 byte) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::FlashROM::power() {
|
auto Cartridge::FLASH::power() -> void {
|
||||||
unlockhi = false;
|
unlockhi = false;
|
||||||
unlocklo = false;
|
unlocklo = false;
|
||||||
idmode = false;
|
idmode = false;
|
||||||
|
@ -86,7 +86,7 @@ void Cartridge::FlashROM::power() {
|
||||||
bank = 0;
|
bank = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Cartridge::FlashROM::serialize(serializer& s) {
|
auto Cartridge::FLASH::serialize(serializer& s) -> void {
|
||||||
s.array(data, size);
|
s.array(data, size);
|
||||||
s.integer(size);
|
s.integer(size);
|
||||||
s.integer(id);
|
s.integer(id);
|
|
@ -1,31 +1,53 @@
|
||||||
struct Memory {
|
struct Memory {
|
||||||
|
auto ror(uint32 word, unsigned shift) -> uint32 {
|
||||||
|
return word << 32 - shift | word >> shift;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MROM : Memory {
|
||||||
uint8* data;
|
uint8* data;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
unsigned mask;
|
unsigned mask;
|
||||||
} rom, ram;
|
|
||||||
|
|
||||||
struct EEPROM {
|
auto read(unsigned mode, uint32 addr) -> uint32;
|
||||||
|
auto write(unsigned mode, uint32 addr, uint32 word) -> void;
|
||||||
|
} mrom;
|
||||||
|
|
||||||
|
struct SRAM : Memory {
|
||||||
|
uint8* data;
|
||||||
|
unsigned size;
|
||||||
|
unsigned mask;
|
||||||
|
|
||||||
|
auto read(unsigned mode, uint32 addr) -> uint32;
|
||||||
|
auto write(unsigned mode, uint32 addr, uint32 word) -> void;
|
||||||
|
|
||||||
|
auto serialize(serializer&) -> void;
|
||||||
|
} sram;
|
||||||
|
|
||||||
|
struct EEPROM : Memory {
|
||||||
uint8* data;
|
uint8* data;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
unsigned mask;
|
unsigned mask;
|
||||||
unsigned test;
|
unsigned test;
|
||||||
unsigned bits;
|
unsigned bits;
|
||||||
|
|
||||||
enum class Mode : unsigned { Wait, Command, ReadAddress, ReadValidate, ReadData, WriteAddress, WriteData, WriteValidate } mode;
|
enum class Mode : unsigned {
|
||||||
|
Wait, Command, ReadAddress, ReadValidate, ReadData, WriteAddress, WriteData, WriteValidate
|
||||||
|
} mode;
|
||||||
unsigned offset;
|
unsigned offset;
|
||||||
unsigned address;
|
unsigned address;
|
||||||
unsigned addressbits;
|
unsigned addressbits;
|
||||||
|
|
||||||
bool read(unsigned addr);
|
auto read(unsigned addr) -> bool;
|
||||||
void write(unsigned addr, bool bit);
|
auto write(unsigned addr, bool bit) -> void;
|
||||||
|
|
||||||
bool read();
|
auto read() -> bool;
|
||||||
void write(bool bit);
|
auto write(bool bit) -> void;
|
||||||
void power();
|
auto power() -> void;
|
||||||
void serialize(serializer&);
|
auto serialize(serializer&) -> void;
|
||||||
} eeprom;
|
} eeprom;
|
||||||
|
|
||||||
struct FlashROM {
|
struct FLASH : Memory {
|
||||||
uint8* data;
|
uint8* data;
|
||||||
unsigned size;
|
unsigned size;
|
||||||
uint16 id;
|
uint16 id;
|
||||||
|
@ -38,8 +60,9 @@ struct FlashROM {
|
||||||
bool writeselect;
|
bool writeselect;
|
||||||
bool bank;
|
bool bank;
|
||||||
|
|
||||||
uint8 read(uint16 addr);
|
auto read(uint16 addr) -> uint8;
|
||||||
void write(uint16 addr, uint8 byte);
|
auto write(uint16 addr, uint8 byte) -> void;
|
||||||
void power();
|
|
||||||
void serialize(serializer&);
|
auto power() -> void;
|
||||||
} flashrom;
|
auto serialize(serializer&) -> void;
|
||||||
|
} flash;
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
auto Cartridge::MROM::read(unsigned mode, uint32 addr) -> uint32 {
|
||||||
|
if(mode & Word) addr &= ~3;
|
||||||
|
if(mode & Half) addr &= ~1;
|
||||||
|
auto p = data + (addr & 0x01ff'ffff);
|
||||||
|
if(mode & Word) return p[0] << 0 | p[1] << 8 | p[2] << 16 | p[3] << 24;
|
||||||
|
if(mode & Half) return p[0] << 0 | p[1] << 8;
|
||||||
|
if(mode & Byte) return p[0] << 0;
|
||||||
|
return 0; //should never occur
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::MROM::write(unsigned mode, uint32 addr, uint32 word) -> void {
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
void Cartridge::serialize(serializer& s) {
|
void Cartridge::serialize(serializer& s) {
|
||||||
if(has_sram) s.array(ram.data, ram.size);
|
if(has_sram) sram.serialize(s);
|
||||||
if(has_eeprom) eeprom.serialize(s);
|
if(has_eeprom) eeprom.serialize(s);
|
||||||
if(has_flashrom) flashrom.serialize(s);
|
if(has_flash) flash.serialize(s);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
auto Cartridge::SRAM::read(unsigned mode, uint32 addr) -> uint32 {
|
||||||
|
if(mode & Word) addr &= ~3;
|
||||||
|
if(mode & Half) addr &= ~1;
|
||||||
|
uint32 word = data[addr & mask];
|
||||||
|
word = ror(word, 8 * (addr & 3));
|
||||||
|
if(mode & Word) { word &= 0xff; word |= word << 8; word |= word << 16; }
|
||||||
|
if(mode & Half) { word &= 0xff; word |= word << 8; }
|
||||||
|
return word;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::SRAM::write(unsigned mode, uint32 addr, uint32 word) -> void {
|
||||||
|
data[addr & mask] = ror(word, 8 * (addr & 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Cartridge::SRAM::serialize(serializer& s) -> void {
|
||||||
|
s.array(data, size);
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ auto CPU::bus_read(unsigned mode, uint32 addr) -> uint32 {
|
||||||
} else {
|
} else {
|
||||||
if(!active.dma) prefetch_wait();
|
if(!active.dma) prefetch_wait();
|
||||||
step(wait - 1);
|
step(wait - 1);
|
||||||
word = addr < 0x0e00'0000 ? cartridge.rom_read(mode, addr) : cartridge.ram_read(mode, addr);
|
word = cartridge.read(mode, addr);
|
||||||
step(1);
|
step(1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -43,7 +43,7 @@ auto CPU::bus_write(unsigned mode, uint32 addr, uint32 word) -> void {
|
||||||
} else if(addr & 0x0800'0000) {
|
} else if(addr & 0x0800'0000) {
|
||||||
if(!active.dma) prefetch_wait();
|
if(!active.dma) prefetch_wait();
|
||||||
step(wait);
|
step(wait);
|
||||||
addr < 0x0e00'0000 ? cartridge.rom_write(mode, addr, word) : cartridge.ram_write(mode, addr, word);
|
cartridge.write(mode, addr, word);
|
||||||
} else {
|
} else {
|
||||||
prefetch_step(wait);
|
prefetch_step(wait);
|
||||||
if(addr < 0x0200'0000);
|
if(addr < 0x0200'0000);
|
||||||
|
|
|
@ -96,6 +96,7 @@ auto CPU::power() -> void {
|
||||||
dma.source = 0;
|
dma.source = 0;
|
||||||
dma.target = 0;
|
dma.target = 0;
|
||||||
dma.length = 0;
|
dma.length = 0;
|
||||||
|
dma.data = 0;
|
||||||
dma.control = 0;
|
dma.control = 0;
|
||||||
dma.pending = 0;
|
dma.pending = 0;
|
||||||
dma.run.target = 0;
|
dma.run.target = 0;
|
||||||
|
|
|
@ -33,8 +33,17 @@ auto CPU::dma_exec(Registers::DMA& dma) -> void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 word = bus_read(mode, dma.run.source);
|
if(dma.run.source < 0x0200'0000) {
|
||||||
bus_write(mode, dma.run.target, word);
|
idle(); //cannot access BIOS
|
||||||
|
} else {
|
||||||
|
dma.data = bus_read(mode, dma.run.source);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dma.run.target < 0x0200'0000) {
|
||||||
|
idle(); //cannot access BIOS
|
||||||
|
} else {
|
||||||
|
bus_write(mode, dma.run.target, dma.data);
|
||||||
|
}
|
||||||
|
|
||||||
switch(dma.control.sourcemode) {
|
switch(dma.control.sourcemode) {
|
||||||
case 0: dma.run.source += seek; break;
|
case 0: dma.run.source += seek; break;
|
||||||
|
|
|
@ -12,7 +12,7 @@ auto CPU::prefetch_step(unsigned clocks) -> void {
|
||||||
|
|
||||||
while(!prefetch.full() && clocks--) {
|
while(!prefetch.full() && clocks--) {
|
||||||
if(--prefetch.wait) continue;
|
if(--prefetch.wait) continue;
|
||||||
prefetch.slot[prefetch.load >> 1 & 7] = cartridge.rom_read(Half, prefetch.load);
|
prefetch.slot[prefetch.load >> 1 & 7] = cartridge.read(Half, prefetch.load);
|
||||||
prefetch.load += 2;
|
prefetch.load += 2;
|
||||||
prefetch.wait = bus_wait(Half | Sequential, prefetch.load);
|
prefetch.wait = bus_wait(Half | Sequential, prefetch.load);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ struct Registers {
|
||||||
varuint source;
|
varuint source;
|
||||||
varuint target;
|
varuint target;
|
||||||
varuint length;
|
varuint length;
|
||||||
|
uint32 data;
|
||||||
DMAControl control;
|
DMAControl control;
|
||||||
|
|
||||||
//internal
|
//internal
|
||||||
|
|
|
@ -9,6 +9,7 @@ auto CPU::serialize(serializer& s) -> void {
|
||||||
s.integer(dma.source);
|
s.integer(dma.source);
|
||||||
s.integer(dma.target);
|
s.integer(dma.target);
|
||||||
s.integer(dma.length);
|
s.integer(dma.length);
|
||||||
|
s.integer(dma.data);
|
||||||
s.integer(dma.control.targetmode);
|
s.integer(dma.control.targetmode);
|
||||||
s.integer(dma.control.sourcemode);
|
s.integer(dma.control.sourcemode);
|
||||||
s.integer(dma.control.repeat);
|
s.integer(dma.control.repeat);
|
||||||
|
|
|
@ -26,10 +26,10 @@ unsigned Interface::group(unsigned id) {
|
||||||
case ID::BIOS:
|
case ID::BIOS:
|
||||||
return ID::System;
|
return ID::System;
|
||||||
case ID::Manifest:
|
case ID::Manifest:
|
||||||
case ID::ROM:
|
case ID::MROM:
|
||||||
case ID::RAM:
|
case ID::SRAM:
|
||||||
case ID::EEPROM:
|
case ID::EEPROM:
|
||||||
case ID::FlashROM:
|
case ID::FLASH:
|
||||||
return ID::GameBoyAdvance;
|
return ID::GameBoyAdvance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,34 +59,34 @@ void Interface::load(unsigned id, const stream& stream) {
|
||||||
cartridge.information.markup = stream.text();
|
cartridge.information.markup = stream.text();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::ROM) {
|
if(id == ID::MROM) {
|
||||||
stream.read(cartridge.rom.data, min(cartridge.rom.size, stream.size()));
|
stream.read(cartridge.mrom.data, min(cartridge.mrom.size, stream.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::RAM) {
|
if(id == ID::SRAM) {
|
||||||
stream.read(cartridge.ram.data, min(cartridge.ram.size, stream.size()));
|
stream.read(cartridge.sram.data, min(cartridge.sram.size, stream.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::EEPROM) {
|
if(id == ID::EEPROM) {
|
||||||
stream.read(cartridge.eeprom.data, min(cartridge.eeprom.size, stream.size()));
|
stream.read(cartridge.eeprom.data, min(cartridge.eeprom.size, stream.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::FlashROM) {
|
if(id == ID::FLASH) {
|
||||||
stream.read(cartridge.flashrom.data, min(cartridge.flashrom.size, stream.size()));
|
stream.read(cartridge.flash.data, min(cartridge.flash.size, stream.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interface::save(unsigned id, const stream& stream) {
|
void Interface::save(unsigned id, const stream& stream) {
|
||||||
if(id == ID::RAM) {
|
if(id == ID::SRAM) {
|
||||||
stream.write(cartridge.ram.data, cartridge.ram.size);
|
stream.write(cartridge.sram.data, cartridge.sram.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::EEPROM) {
|
if(id == ID::EEPROM) {
|
||||||
stream.write(cartridge.eeprom.data, cartridge.eeprom.size);
|
stream.write(cartridge.eeprom.data, cartridge.eeprom.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(id == ID::FlashROM) {
|
if(id == ID::FLASH) {
|
||||||
stream.write(cartridge.flashrom.data, cartridge.flashrom.size);
|
stream.write(cartridge.flash.data, cartridge.flash.size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,10 +13,10 @@ struct ID {
|
||||||
BIOS,
|
BIOS,
|
||||||
|
|
||||||
Manifest,
|
Manifest,
|
||||||
ROM,
|
MROM,
|
||||||
RAM,
|
SRAM,
|
||||||
EEPROM,
|
EEPROM,
|
||||||
FlashROM,
|
FLASH,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum : unsigned {
|
enum : unsigned {
|
||||||
|
|
|
@ -11,12 +11,21 @@ auto pLayout::destruct() -> void {
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pLayout::setEnabled(bool enabled) -> void {
|
auto pLayout::setEnabled(bool enabled) -> void {
|
||||||
|
for(auto& sizable : state().sizables) {
|
||||||
|
if(auto self = sizable->self()) self->setEnabled(sizable->enabled(true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pLayout::setFont(const Font& font) -> void {
|
auto pLayout::setFont(const Font& font) -> void {
|
||||||
|
for(auto& sizable : state().sizables) {
|
||||||
|
if(auto self = sizable->self()) self->setFont(sizable->font(true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pLayout::setVisible(bool visible) -> void {
|
auto pLayout::setVisible(bool visible) -> void {
|
||||||
|
for(auto& sizable : state().sizables) {
|
||||||
|
if(auto self = sizable->self()) self->setVisible(sizable->visible(true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,15 +242,15 @@ auto pWindow::setDroppable(bool droppable) -> void {
|
||||||
|
|
||||||
auto pWindow::setEnabled(bool enabled) -> void {
|
auto pWindow::setEnabled(bool enabled) -> void {
|
||||||
if(auto& menuBar = state().menuBar) {
|
if(auto& menuBar = state().menuBar) {
|
||||||
if(menuBar->self()) menuBar->self()->setEnabled(menuBar->enabled(true));
|
if(auto self = menuBar->self()) self->setEnabled(menuBar->enabled(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(auto& statusBar = state().statusBar) {
|
if(auto& statusBar = state().statusBar) {
|
||||||
if(statusBar->self()) statusBar->self()->setEnabled(statusBar->enabled(true));
|
if(auto self = statusBar->self()) self->setEnabled(statusBar->enabled(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
if(auto& layout = state().layout) {
|
if(auto& layout = state().layout) {
|
||||||
if(layout->self()) layout->self()->setEnabled(layout->enabled(true));
|
if(auto self = layout->self()) self->setEnabled(layout->enabled(true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,13 +38,13 @@ GameBoyAdvanceCartridge::GameBoyAdvanceCartridge(const uint8_t *data, unsigned s
|
||||||
identifiers = list.merge(",");
|
identifiers = list.merge(",");
|
||||||
|
|
||||||
markup.append("cartridge\n");
|
markup.append("cartridge\n");
|
||||||
markup.append(" rom name=program.rom size=0x", hex(size), "\n");
|
markup.append(" mrom name=program.rom size=0x", hex(size), "\n");
|
||||||
if(0);
|
if(0);
|
||||||
else if(identifiers.beginsWith("SRAM_V" )) markup.append(" ram name=save.ram type=SRAM size=0x8000\n");
|
else if(identifiers.beginsWith("SRAM_V" )) markup.append(" sram name=save.ram size=0x8000\n");
|
||||||
else if(identifiers.beginsWith("SRAM_F_V" )) markup.append(" ram name=save.ram type=FRAM size=0x8000\n");
|
else if(identifiers.beginsWith("SRAM_F_V" )) markup.append(" sram name=save.ram size=0x8000\n");
|
||||||
else if(identifiers.beginsWith("EEPROM_V" )) markup.append(" ram name=save.ram type=EEPROM size=0x0\n");
|
else if(identifiers.beginsWith("EEPROM_V" )) markup.append(" eeprom name=save.ram size=0x0\n");
|
||||||
else if(identifiers.beginsWith("FLASH_V" )) markup.append(" ram name=save.ram type=FlashROM size=0x10000\n");
|
else if(identifiers.beginsWith("FLASH_V" )) markup.append(" flash name=save.ram size=0x10000\n");
|
||||||
else if(identifiers.beginsWith("FLASH512_V")) markup.append(" ram name=save.ram type=FlashROM size=0x10000\n");
|
else if(identifiers.beginsWith("FLASH512_V")) markup.append(" flash name=save.ram size=0x10000\n");
|
||||||
else if(identifiers.beginsWith("FLASH1M_V" )) markup.append(" ram name=save.ram type=FlashROM size=0x20000\n");
|
else if(identifiers.beginsWith("FLASH1M_V" )) markup.append(" flash name=save.ram size=0x20000\n");
|
||||||
//if(identifiers.empty() == false) markup.append(" #detected: ", identifiers, "\n");
|
//if(identifiers.empty() == false) markup.append(" #detected: ", identifiers, "\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,15 +128,18 @@ public:
|
||||||
auto size() const -> unsigned { return _size; }
|
auto size() const -> unsigned { return _size; }
|
||||||
auto capacity() const -> unsigned { return _capacity; }
|
auto capacity() const -> unsigned { return _capacity; }
|
||||||
|
|
||||||
auto operator==(const string& s) const -> bool { return size() == s.size() && memory::compare(data(), s.data(), s.size()) == 0; }
|
auto operator==(const string& source) const -> bool { return size() == source.size() && memory::compare(data(), source.data(), size()) == 0; }
|
||||||
auto operator!=(const string& s) const -> bool { return size() != s.size() || memory::compare(data(), s.data(), s.size()) != 0; }
|
auto operator!=(const string& source) const -> bool { return size() != source.size() || memory::compare(data(), source.data(), size()) != 0; }
|
||||||
|
|
||||||
auto operator==(const char* s) const -> bool { return strcmp(data(), s) == 0; }
|
auto operator==(const char* source) const -> bool { return strcmp(data(), source) == 0; }
|
||||||
auto operator!=(const char* s) const -> bool { return strcmp(data(), s) != 0; }
|
auto operator!=(const char* source) const -> bool { return strcmp(data(), source) != 0; }
|
||||||
auto operator< (const char* s) const -> bool { return strcmp(data(), s) < 0; }
|
|
||||||
auto operator<=(const char* s) const -> bool { return strcmp(data(), s) <= 0; }
|
auto operator==(rstring source) const -> bool { return compare(source) == 0; }
|
||||||
auto operator> (const char* s) const -> bool { return strcmp(data(), s) > 0; }
|
auto operator!=(rstring source) const -> bool { return compare(source) != 0; }
|
||||||
auto operator>=(const char* s) const -> bool { return strcmp(data(), s) >= 0; }
|
auto operator< (rstring source) const -> bool { return compare(source) < 0; }
|
||||||
|
auto operator<=(rstring source) const -> bool { return compare(source) <= 0; }
|
||||||
|
auto operator> (rstring source) const -> bool { return compare(source) > 0; }
|
||||||
|
auto operator>=(rstring source) const -> bool { return compare(source) >= 0; }
|
||||||
|
|
||||||
string(const string& source) : string() { operator=(source); }
|
string(const string& source) : string() { operator=(source); }
|
||||||
string(string&& source) : string() { operator=(move(source)); }
|
string(string&& source) : string() { operator=(move(source)); }
|
||||||
|
@ -183,6 +186,9 @@ public:
|
||||||
//compare.hpp
|
//compare.hpp
|
||||||
template<bool> inline static auto _compare(const char*, unsigned, const char*, unsigned) -> signed;
|
template<bool> inline static auto _compare(const char*, unsigned, const char*, unsigned) -> signed;
|
||||||
|
|
||||||
|
inline static auto compare(rstring, rstring) -> signed;
|
||||||
|
inline static auto icompare(rstring, rstring) -> signed;
|
||||||
|
|
||||||
inline auto compare(rstring source) const -> signed;
|
inline auto compare(rstring source) const -> signed;
|
||||||
inline auto icompare(rstring source) const -> signed;
|
inline auto icompare(rstring source) const -> signed;
|
||||||
|
|
||||||
|
|
|
@ -8,12 +8,21 @@ auto string::_compare(const char* target, unsigned capacity, const char* source,
|
||||||
return memory::compare(target, capacity, source, size);
|
return memory::compare(target, capacity, source, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//size() + 1 includes null-terminator; required to properly compare strings of differing lengths
|
||||||
|
auto string::compare(rstring x, rstring y) -> signed {
|
||||||
|
return memory::compare(x.data(), x.size() + 1, y.data(), y.size() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto string::icompare(rstring x, rstring y) -> signed {
|
||||||
|
return memory::icompare(x.data(), x.size() + 1, y.data(), y.size() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
auto string::compare(rstring source) const -> signed {
|
auto string::compare(rstring source) const -> signed {
|
||||||
return memory::compare(data(), size(), source.data(), source.size());
|
return memory::compare(data(), size() + 1, source.data(), source.size() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::icompare(rstring source) const -> signed {
|
auto string::icompare(rstring source) const -> signed {
|
||||||
return memory::icompare(data(), size(), source.data(), source.size());
|
return memory::icompare(data(), size() + 1, source.data(), source.size() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto string::equals(rstring source) const -> bool {
|
auto string::equals(rstring source) const -> bool {
|
||||||
|
|
|
@ -13,11 +13,23 @@ struct ManagedNode {
|
||||||
ManagedNode(const string& name, const string& value) : _name(name), _value(value) {}
|
ManagedNode(const string& name, const string& value) : _name(name), _value(value) {}
|
||||||
|
|
||||||
auto clone() const -> SharedNode {
|
auto clone() const -> SharedNode {
|
||||||
SharedNode clone(new ManagedNode(_name, _value));
|
SharedNode clone{new ManagedNode(_name, _value)};
|
||||||
for(auto& child : _children) clone->_children.append(child->clone());
|
for(auto& child : _children) {
|
||||||
|
clone->_children.append(child->clone());
|
||||||
|
}
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto copy(SharedNode source) -> void {
|
||||||
|
_name = source->_name;
|
||||||
|
_value = source->_value;
|
||||||
|
_metadata = source->_metadata;
|
||||||
|
_children.reset();
|
||||||
|
for(auto child : source->_children) {
|
||||||
|
_children.append(child->clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
string _name;
|
string _name;
|
||||||
string _value;
|
string _value;
|
||||||
|
@ -40,6 +52,7 @@ struct Node {
|
||||||
|
|
||||||
auto unique() const -> bool { return shared.unique(); }
|
auto unique() const -> bool { return shared.unique(); }
|
||||||
auto clone() const -> Node { return shared->clone(); }
|
auto clone() const -> Node { return shared->clone(); }
|
||||||
|
auto copy(Node source) -> void { return shared->copy(source.shared); }
|
||||||
|
|
||||||
explicit operator bool() const { return shared->_name || shared->_children; }
|
explicit operator bool() const { return shared->_name || shared->_children; }
|
||||||
auto name() const -> string { return shared->_name; }
|
auto name() const -> string { return shared->_name; }
|
||||||
|
@ -50,8 +63,8 @@ struct Node {
|
||||||
auto integer() const -> intmax_t { return text().integer(); }
|
auto integer() const -> intmax_t { return text().integer(); }
|
||||||
auto decimal() const -> uintmax_t { return text().decimal(); }
|
auto decimal() const -> uintmax_t { return text().decimal(); }
|
||||||
|
|
||||||
auto setName(const string& name = "") -> void { shared->_name = name; }
|
auto setName(const string& name = "") -> Node& { shared->_name = name; return *this; }
|
||||||
auto setValue(const string& value = "") -> void { shared->_value = value; }
|
auto setValue(const string& value = "") -> Node& { shared->_value = value; return *this; }
|
||||||
|
|
||||||
auto reset() -> void { shared->_children.reset(); }
|
auto reset() -> void { shared->_children.reset(); }
|
||||||
auto size() const -> unsigned { return shared->_children.size(); }
|
auto size() const -> unsigned { return shared->_children.size(); }
|
||||||
|
@ -67,16 +80,6 @@ struct Node {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto at(unsigned position) const -> Node {
|
|
||||||
if(position >= size()) return {};
|
|
||||||
return shared->_children[position];
|
|
||||||
}
|
|
||||||
|
|
||||||
auto swap(unsigned x, unsigned y) -> bool {
|
|
||||||
if(x >= size() || y >= size()) return false;
|
|
||||||
return std::swap(shared->_children[x], shared->_children[y]), true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto insert(unsigned position, const Node& node) -> bool {
|
auto insert(unsigned position, const Node& node) -> bool {
|
||||||
if(position > size()) return false; //used > instead of >= to allow indexed-equivalent of append()
|
if(position > size()) return false; //used > instead of >= to allow indexed-equivalent of append()
|
||||||
return shared->_children.insert(position, node.shared), true;
|
return shared->_children.insert(position, node.shared), true;
|
||||||
|
@ -87,8 +90,26 @@ struct Node {
|
||||||
return shared->_children.remove(position), true;
|
return shared->_children.remove(position), true;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto operator()(const string& path) -> Node { return shared->_create(path); }
|
auto swap(unsigned x, unsigned y) -> bool {
|
||||||
|
if(x >= size() || y >= size()) return false;
|
||||||
|
return std::swap(shared->_children[x], shared->_children[y]), true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sort(function<bool (Node, Node)> comparator = [](auto x, auto y) {
|
||||||
|
return string::compare(x.shared->_name, y.shared->_name) < 0;
|
||||||
|
}) -> void {
|
||||||
|
nall::sort(shared->_children.data(), shared->_children.size(), [&](auto x, auto y) {
|
||||||
|
return comparator(x, y); //this call converts SharedNode objects to Node objects
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto operator[](signed position) -> Node {
|
||||||
|
if(position >= size()) return {};
|
||||||
|
return shared->_children[position];
|
||||||
|
}
|
||||||
|
|
||||||
auto operator[](const string& path) const -> Node { return shared->_lookup(path); }
|
auto operator[](const string& path) const -> Node { return shared->_lookup(path); }
|
||||||
|
auto operator()(const string& path) -> Node { return shared->_create(path); }
|
||||||
auto find(const string& query) const -> vector<Node> { return shared->_find(query); }
|
auto find(const string& query) const -> vector<Node> { return shared->_find(query); }
|
||||||
|
|
||||||
struct iterator {
|
struct iterator {
|
||||||
|
|
|
@ -160,12 +160,10 @@ template<typename T> struct vector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sort() -> void {
|
auto sort(const function<bool (const T& lhs, const T& rhs)>& comparator = [](const T& lhs, const T& rhs) -> bool {
|
||||||
nall::sort(pool + poolbase, objectsize);
|
return lhs < rhs;
|
||||||
}
|
}) -> void {
|
||||||
|
nall::sort(pool + poolbase, objectsize, comparator);
|
||||||
template<typename Comparator> auto sort(const Comparator& lessthan) -> void {
|
|
||||||
nall::sort(pool + poolbase, objectsize, lessthan);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto find(const T& data) const -> maybe<unsigned> {
|
auto find(const T& data) const -> maybe<unsigned> {
|
||||||
|
|
|
@ -42,14 +42,23 @@ auto ARM::load(unsigned mode, uint32 addr) -> uint32 {
|
||||||
pipeline.nonsequential = true;
|
pipeline.nonsequential = true;
|
||||||
uint32 word = bus_read(Load | mode, addr);
|
uint32 word = bus_read(Load | mode, addr);
|
||||||
|
|
||||||
if(mode & Half) { word &= 0xffff; word |= word << 16; }
|
if(mode & Half) {
|
||||||
if(mode & Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
|
addr &= 1;
|
||||||
|
word = mode & Signed ? (int16)word : (uint16)word;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode & Byte) {
|
||||||
|
addr &= 0;
|
||||||
|
word = mode & Signed ? (int8)word : (uint8)word;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mode & Signed) {
|
||||||
|
word = asr(word, 8 * (addr & 3));
|
||||||
|
} else {
|
||||||
|
word = ror(word, 8 * (addr & 3));
|
||||||
|
}
|
||||||
|
|
||||||
word = ror(word, 8 * (addr & 3));
|
|
||||||
idle();
|
idle();
|
||||||
|
|
||||||
if(mode & Half) word &= 0xffff;
|
|
||||||
if(mode & Byte) word &= 0xff;
|
|
||||||
return word;
|
return word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ struct ARM {
|
||||||
Word = 32, //32-bit access
|
Word = 32, //32-bit access
|
||||||
Load = 64, //load operation
|
Load = 64, //load operation
|
||||||
Store = 128, //store operation
|
Store = 128, //store operation
|
||||||
|
Signed = 256, //sign extend
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "registers.hpp"
|
#include "registers.hpp"
|
||||||
|
|
|
@ -164,13 +164,15 @@ auto ARM::arm_op_move_half_register() {
|
||||||
|
|
||||||
uint32 rn = r(n);
|
uint32 rn = r(n);
|
||||||
uint32 rm = r(m);
|
uint32 rm = r(m);
|
||||||
|
uint32 rd = r(d);
|
||||||
|
|
||||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||||
if(l == 1) r(d) = load(Half | Nonsequential, rn);
|
if(l == 1) rd = load(Half | Nonsequential, rn);
|
||||||
if(l == 0) store(Half | Nonsequential, rn, r(d));
|
if(l == 0) store(Half | Nonsequential, rn, rd);
|
||||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||||
|
|
||||||
if(pre == 0 || writeback == 1) r(n) = rn;
|
if(pre == 0 || writeback == 1) r(n) = rn;
|
||||||
|
if(l == 1) r(d) = rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
//(ldr,str){condition}h rd,[rn{,+/-offset}]{!}
|
//(ldr,str){condition}h rd,[rn{,+/-offset}]{!}
|
||||||
|
@ -196,14 +198,16 @@ auto ARM::arm_op_move_half_immediate() {
|
||||||
uint4 il = instruction();
|
uint4 il = instruction();
|
||||||
|
|
||||||
uint32 rn = r(n);
|
uint32 rn = r(n);
|
||||||
|
uint32 rd = r(d);
|
||||||
uint8 immediate = (ih << 4) + (il << 0);
|
uint8 immediate = (ih << 4) + (il << 0);
|
||||||
|
|
||||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||||
if(l == 1) r(d) = load(Half | Nonsequential, rn);
|
if(l == 1) rd = load(Half | Nonsequential, rn);
|
||||||
if(l == 0) store(Half | Nonsequential, rn, r(d));
|
if(l == 0) store(Half | Nonsequential, rn, rd);
|
||||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||||
|
|
||||||
if(pre == 0 || writeback == 1) r(n) = rn;
|
if(pre == 0 || writeback == 1) r(n) = rn;
|
||||||
|
if(l == 1) r(d) = rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
//ldr{condition}s(h,b) rd,[rn,rm]{!}
|
//ldr{condition}s(h,b) rd,[rn,rm]{!}
|
||||||
|
@ -228,13 +232,14 @@ auto ARM::arm_op_load_register() {
|
||||||
|
|
||||||
uint32 rn = r(n);
|
uint32 rn = r(n);
|
||||||
uint32 rm = r(m);
|
uint32 rm = r(m);
|
||||||
|
uint32 rd = r(d);
|
||||||
|
|
||||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||||
uint32 word = load((half ? Half : Byte) | Nonsequential, rn);
|
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
|
||||||
r(d) = half ? (int16)word : (int8)word;
|
|
||||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||||
|
|
||||||
if(pre == 0 || writeback == 1) r(n) = rn;
|
if(pre == 0 || writeback == 1) r(n) = rn;
|
||||||
|
r(d) = rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
//ldr{condition}s(h,b) rd,[rn{,+/-offset}]{!}
|
//ldr{condition}s(h,b) rd,[rn{,+/-offset}]{!}
|
||||||
|
@ -260,14 +265,15 @@ auto ARM::arm_op_load_immediate() {
|
||||||
uint4 il = instruction();
|
uint4 il = instruction();
|
||||||
|
|
||||||
uint32 rn = r(n);
|
uint32 rn = r(n);
|
||||||
|
uint32 rd = r(d);
|
||||||
uint8 immediate = (ih << 4) + (il << 0);
|
uint8 immediate = (ih << 4) + (il << 0);
|
||||||
|
|
||||||
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
|
||||||
uint32 word = load((half ? Half : Byte) | Nonsequential, rn);
|
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
|
||||||
r(d) = half ? (int16)word : (int8)word;
|
|
||||||
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
|
||||||
|
|
||||||
if(pre == 0 || writeback == 1) r(n) = rn;
|
if(pre == 0 || writeback == 1) r(n) = rn;
|
||||||
|
r(d) = rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
//mrs{condition} rd,(c,s)psr
|
//mrs{condition} rd,(c,s)psr
|
||||||
|
@ -375,8 +381,8 @@ auto ARM::arm_op_data_register_shift() {
|
||||||
uint2 mode = instruction() >> 5;
|
uint2 mode = instruction() >> 5;
|
||||||
uint4 m = instruction();
|
uint4 m = instruction();
|
||||||
|
|
||||||
uint8 rs = r(s);
|
uint8 rs = r(s) + (s == 15 ? 4 : 0);
|
||||||
uint32 rm = r(m);
|
uint32 rm = r(m) + (m == 15 ? 4 : 0);
|
||||||
carryout() = cpsr().c;
|
carryout() = cpsr().c;
|
||||||
|
|
||||||
if(mode == 0 ) rm = lsl(rm, rs < 33 ? rs : 33);
|
if(mode == 0 ) rm = lsl(rm, rs < 33 ? rs : 33);
|
||||||
|
@ -434,7 +440,7 @@ auto ARM::arm_op_move_immediate_offset() {
|
||||||
uint12 rm = instruction();
|
uint12 rm = instruction();
|
||||||
|
|
||||||
uint32 rn = r(n);
|
uint32 rn = r(n);
|
||||||
auto& rd = r(d);
|
uint32 rd = r(d);
|
||||||
|
|
||||||
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
if(pre == 1) rn = up ? rn + rm : rn - rm;
|
||||||
if(l == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn);
|
if(l == 1) rd = load((byte ? Byte : Word) | Nonsequential, rn);
|
||||||
|
@ -442,6 +448,7 @@ auto ARM::arm_op_move_immediate_offset() {
|
||||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||||
|
|
||||||
if(pre == 0 || writeback == 1) r(n) = rn;
|
if(pre == 0 || writeback == 1) r(n) = rn;
|
||||||
|
if(l == 1) r(d) = rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
//(ldr,str){condition}{b} rd,[rn,rm {mode} #immediate]{!}
|
//(ldr,str){condition}{b} rd,[rn,rm {mode} #immediate]{!}
|
||||||
|
@ -471,7 +478,7 @@ auto ARM::arm_op_move_register_offset() {
|
||||||
uint4 m = instruction();
|
uint4 m = instruction();
|
||||||
|
|
||||||
uint32 rn = r(n);
|
uint32 rn = r(n);
|
||||||
auto& rd = r(d);
|
uint32 rd = r(d);
|
||||||
uint32 rs = immediate;
|
uint32 rs = immediate;
|
||||||
uint32 rm = r(m);
|
uint32 rm = r(m);
|
||||||
bool c = cpsr().c;
|
bool c = cpsr().c;
|
||||||
|
@ -487,6 +494,7 @@ auto ARM::arm_op_move_register_offset() {
|
||||||
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
if(pre == 0) rn = up ? rn + rm : rn - rm;
|
||||||
|
|
||||||
if(pre == 0 || writeback == 1) r(n) = rn;
|
if(pre == 0 || writeback == 1) r(n) = rn;
|
||||||
|
if(l == 1) r(d) = rd;
|
||||||
}
|
}
|
||||||
|
|
||||||
//(ldm,stm){condition}{mode} rn{!},{r...}
|
//(ldm,stm){condition}{mode} rn{!},{r...}
|
||||||
|
|
|
@ -161,14 +161,14 @@ auto ARM::thumb_op_move_register_offset() {
|
||||||
uint3 d = instruction() >> 0;
|
uint3 d = instruction() >> 0;
|
||||||
|
|
||||||
switch(opcode) {
|
switch(opcode) {
|
||||||
case 0: store(Word | Nonsequential, r(n) + r(m), r(d)); break; //STR
|
case 0: store(Word | Nonsequential, r(n) + r(m), r(d)); break; //STR
|
||||||
case 1: store(Half | Nonsequential, r(n) + r(m), r(d)); break; //STRH
|
case 1: store(Half | Nonsequential, r(n) + r(m), r(d)); break; //STRH
|
||||||
case 2: store(Byte | Nonsequential, r(n) + r(m), r(d)); break; //STRB
|
case 2: store(Byte | Nonsequential, r(n) + r(m), r(d)); break; //STRB
|
||||||
case 3: r(d) = (int8)load(Byte | Nonsequential, r(n) + r(m)); break; //LDSB
|
case 3: r(d) = load(Byte | Nonsequential | Signed, r(n) + r(m)); break; //LDSB
|
||||||
case 4: r(d) = load(Word | Nonsequential, r(n) + r(m)); break; //LDR
|
case 4: r(d) = load(Word | Nonsequential, r(n) + r(m)); break; //LDR
|
||||||
case 5: r(d) = load(Half | Nonsequential, r(n) + r(m)); break; //LDRH
|
case 5: r(d) = load(Half | Nonsequential, r(n) + r(m)); break; //LDRH
|
||||||
case 6: r(d) = load(Byte | Nonsequential, r(n) + r(m)); break; //LDRB
|
case 6: r(d) = load(Byte | Nonsequential, r(n) + r(m)); break; //LDRB
|
||||||
case 7: r(d) = (int16)load(Half | Nonsequential, r(n) + r(m)); break; //LDSH
|
case 7: r(d) = load(Half | Nonsequential | Signed, r(n) + r(m)); break; //LDSH
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,10 @@ using namespace ruby;
|
||||||
#include <ruby/video/glx.cpp>
|
#include <ruby/video/glx.cpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(VIDEO_GLX2)
|
||||||
|
#include <ruby/video/glx2.cpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_SDL)
|
#if defined(VIDEO_SDL)
|
||||||
#include <ruby/video/sdl.cpp>
|
#include <ruby/video/sdl.cpp>
|
||||||
#endif
|
#endif
|
||||||
|
@ -93,6 +97,10 @@ auto Video::create(const string& driver) -> Video* {
|
||||||
if(driver == "OpenGL") return new VideoGLX;
|
if(driver == "OpenGL") return new VideoGLX;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(VIDEO_GLX2)
|
||||||
|
if(driver == "OpenGL2") return new VideoGLX2;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_SDL)
|
#if defined(VIDEO_SDL)
|
||||||
if(driver == "SDL") return new VideoSDL;
|
if(driver == "SDL") return new VideoSDL;
|
||||||
#endif
|
#endif
|
||||||
|
@ -125,6 +133,8 @@ auto Video::optimalDriver() -> string {
|
||||||
return "OpenGL";
|
return "OpenGL";
|
||||||
#elif defined(VIDEO_GLX)
|
#elif defined(VIDEO_GLX)
|
||||||
return "OpenGL";
|
return "OpenGL";
|
||||||
|
#elif defined(VIDEO_GLX2)
|
||||||
|
return "OpenGL2";
|
||||||
#elif defined(VIDEO_XV)
|
#elif defined(VIDEO_XV)
|
||||||
return "X-Video";
|
return "X-Video";
|
||||||
#elif defined(VIDEO_XSHM)
|
#elif defined(VIDEO_XSHM)
|
||||||
|
@ -153,6 +163,8 @@ auto Video::safestDriver() -> string {
|
||||||
return "SDL";
|
return "SDL";
|
||||||
#elif defined(VIDEO_XV)
|
#elif defined(VIDEO_XV)
|
||||||
return "X-Video";
|
return "X-Video";
|
||||||
|
#elif defined(VIDEO_GLX2)
|
||||||
|
return "OpenGL2";
|
||||||
#elif defined(VIDEO_GLX)
|
#elif defined(VIDEO_GLX)
|
||||||
return "OpenGL";
|
return "OpenGL";
|
||||||
#else
|
#else
|
||||||
|
@ -187,6 +199,10 @@ auto Video::availableDrivers() -> lstring {
|
||||||
"OpenGL",
|
"OpenGL",
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(VIDEO_GLX2)
|
||||||
|
"OpenGL2",
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(VIDEO_XV)
|
#if defined(VIDEO_XV)
|
||||||
"X-Video",
|
"X-Video",
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,245 @@
|
||||||
|
//Xorg/GLX OpenGL 2.0 driver
|
||||||
|
|
||||||
|
//note: this is a fallback driver for use when OpenGL 3.2 is not available.
|
||||||
|
//see glx.cpp for comments on how this driver operates (they are very similar.)
|
||||||
|
|
||||||
|
struct VideoGLX2 : Video {
|
||||||
|
~VideoGLX2() { term(); }
|
||||||
|
|
||||||
|
auto (*glXSwapInterval)(signed) -> signed = nullptr;
|
||||||
|
Display* display = nullptr;
|
||||||
|
signed screen = 0;
|
||||||
|
Window xwindow = 0;
|
||||||
|
Colormap colormap = 0;
|
||||||
|
GLXContext glxcontext = nullptr;
|
||||||
|
GLXWindow glxwindow = 0;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
Window handle = 0;
|
||||||
|
bool synchronize = false;
|
||||||
|
unsigned filter = 1; //linear
|
||||||
|
|
||||||
|
unsigned width = 256;
|
||||||
|
unsigned height = 256;
|
||||||
|
|
||||||
|
bool isDoubleBuffered = false;
|
||||||
|
bool isDirect = false;
|
||||||
|
} settings;
|
||||||
|
|
||||||
|
auto cap(const string& name) -> bool {
|
||||||
|
if(name == Video::Handle) return true;
|
||||||
|
if(name == Video::Synchronize) return true;
|
||||||
|
if(name == Video::Filter) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto get(const string& name) -> any {
|
||||||
|
if(name == Video::Handle) return (uintptr_t)settings.handle;
|
||||||
|
if(name == Video::Synchronize) return settings.synchronize;
|
||||||
|
if(name == Video::Filter) return settings.filter;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto set(const string& name, const any& value) -> bool {
|
||||||
|
if(name == Video::Handle && value.is<uintptr_t>()) {
|
||||||
|
settings.handle = value.get<uintptr_t>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(name == Video::Synchronize && value.is<bool>()) {
|
||||||
|
if(settings.synchronize != value.get<bool>()) {
|
||||||
|
settings.synchronize = value.get<bool>();
|
||||||
|
if(glXSwapInterval) glXSwapInterval(settings.synchronize);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(name == Video::Filter && value.is<unsigned>()) {
|
||||||
|
settings.filter = value.get<unsigned>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lock(uint32_t*& data, unsigned& pitch, unsigned width, unsigned height) -> bool {
|
||||||
|
if(width != settings.width || height != settings.height) resize(width, height);
|
||||||
|
pitch = glwidth * sizeof(uint32_t);
|
||||||
|
return data = glbuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto unlock() -> void {
|
||||||
|
}
|
||||||
|
|
||||||
|
auto clear() -> void {
|
||||||
|
memory::fill(glbuffer, glwidth * glheight * sizeof(uint32_t));
|
||||||
|
glClearColor(0.0, 0.0, 0.0, 1.0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
glFlush();
|
||||||
|
if(settings.isDoubleBuffered) glXSwapBuffers(display, glxwindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto refresh() -> void {
|
||||||
|
XWindowAttributes parent, child;
|
||||||
|
XGetWindowAttributes(display, settings.handle, &parent);
|
||||||
|
XGetWindowAttributes(display, xwindow, &child);
|
||||||
|
if(child.width != parent.width || child.height != parent.height) {
|
||||||
|
XResizeWindow(display, xwindow, parent.width, parent.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, settings.filter ? GL_LINEAR : GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, settings.filter ? GL_LINEAR : GL_NEAREST);
|
||||||
|
|
||||||
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
glLoadIdentity();
|
||||||
|
glOrtho(0, parent.width, 0, parent.height, -1.0, 1.0);
|
||||||
|
glViewport(0, 0, parent.width, parent.height);
|
||||||
|
|
||||||
|
glMatrixMode(GL_MODELVIEW);
|
||||||
|
glLoadIdentity();
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, glwidth);
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, settings.width, settings.height,
|
||||||
|
GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, glbuffer);
|
||||||
|
|
||||||
|
double w = (double)settings.width / (double)glwidth;
|
||||||
|
double h = (double)settings.height / (double)glheight;
|
||||||
|
signed u = parent.width;
|
||||||
|
signed v = parent.height;
|
||||||
|
|
||||||
|
glBegin(GL_TRIANGLE_STRIP);
|
||||||
|
glTexCoord2f(0, 0); glVertex3i(0, v, 0);
|
||||||
|
glTexCoord2f(w, 0); glVertex3i(u, v, 0);
|
||||||
|
glTexCoord2f(0, h); glVertex3i(0, 0, 0);
|
||||||
|
glTexCoord2f(w, h); glVertex3i(u, 0, 0);
|
||||||
|
glEnd();
|
||||||
|
glFlush();
|
||||||
|
|
||||||
|
if(settings.isDoubleBuffered) glXSwapBuffers(display, glxwindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto init() -> bool {
|
||||||
|
display = XOpenDisplay(0);
|
||||||
|
screen = DefaultScreen(display);
|
||||||
|
|
||||||
|
signed versionMajor = 0, versionMinor = 0;
|
||||||
|
glXQueryVersion(display, &versionMajor, &versionMinor);
|
||||||
|
if(versionMajor < 1 || (versionMajor == 1 && versionMinor < 2)) return false;
|
||||||
|
|
||||||
|
XWindowAttributes windowAttributes;
|
||||||
|
XGetWindowAttributes(display, settings.handle, &windowAttributes);
|
||||||
|
|
||||||
|
signed attributeList[] = {
|
||||||
|
GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
|
||||||
|
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
||||||
|
GLX_DOUBLEBUFFER, True,
|
||||||
|
GLX_RED_SIZE, 8,
|
||||||
|
GLX_GREEN_SIZE, 8,
|
||||||
|
GLX_BLUE_SIZE, 8,
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
signed fbCount = 0;
|
||||||
|
auto fbConfig = glXChooseFBConfig(display, screen, attributeList, &fbCount);
|
||||||
|
if(fbCount == 0) return false;
|
||||||
|
|
||||||
|
auto vi = glXGetVisualFromFBConfig(display, fbConfig[0]);
|
||||||
|
colormap = XCreateColormap(display, RootWindow(display, vi->screen), vi->visual, AllocNone);
|
||||||
|
XSetWindowAttributes attributes;
|
||||||
|
attributes.colormap = colormap;
|
||||||
|
attributes.border_pixel = 0;
|
||||||
|
xwindow = XCreateWindow(display, settings.handle, 0, 0, windowAttributes.width, windowAttributes.height,
|
||||||
|
0, vi->depth, InputOutput, vi->visual, CWColormap | CWBorderPixel, &attributes);
|
||||||
|
XSetWindowBackground(display, xwindow, 0);
|
||||||
|
XMapWindow(display, xwindow);
|
||||||
|
XFlush(display);
|
||||||
|
|
||||||
|
while(XPending(display)) {
|
||||||
|
XEvent event;
|
||||||
|
XNextEvent(display, &event);
|
||||||
|
}
|
||||||
|
|
||||||
|
glxcontext = glXCreateContext(display, vi, 0, GL_TRUE);
|
||||||
|
glXMakeCurrent(display, glxwindow = xwindow, glxcontext);
|
||||||
|
|
||||||
|
glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalEXT");
|
||||||
|
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalMESA");
|
||||||
|
if(!glXSwapInterval) glXSwapInterval = (signed (*)(signed))glGetProcAddress("glXSwapIntervalSGI");
|
||||||
|
|
||||||
|
if(glXSwapInterval) glXSwapInterval(settings.synchronize);
|
||||||
|
|
||||||
|
signed value = 0;
|
||||||
|
glXGetConfig(display, vi, GLX_DOUBLEBUFFER, &value);
|
||||||
|
settings.isDoubleBuffered = value;
|
||||||
|
settings.isDirect = glXIsDirect(display, glxcontext);
|
||||||
|
|
||||||
|
glDisable(GL_ALPHA_TEST);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_POLYGON_SMOOTH);
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
|
||||||
|
glEnable(GL_DITHER);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
resize(256, 256);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto term() -> void {
|
||||||
|
if(gltexture) {
|
||||||
|
glDeleteTextures(1, &gltexture);
|
||||||
|
gltexture = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(glbuffer) {
|
||||||
|
delete[] glbuffer;
|
||||||
|
glbuffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
glwidth = 0;
|
||||||
|
glheight = 0;
|
||||||
|
|
||||||
|
if(glxcontext) {
|
||||||
|
glXDestroyContext(display, glxcontext);
|
||||||
|
glxcontext = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(xwindow) {
|
||||||
|
XUnmapWindow(display, xwindow);
|
||||||
|
xwindow = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(colormap) {
|
||||||
|
XFreeColormap(display, colormap);
|
||||||
|
colormap = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(display) {
|
||||||
|
XCloseDisplay(display);
|
||||||
|
display = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
GLuint gltexture = 0;
|
||||||
|
uint32_t* glbuffer = nullptr;
|
||||||
|
unsigned glwidth = 0;
|
||||||
|
unsigned glheight = 0;
|
||||||
|
|
||||||
|
auto resize(unsigned width, unsigned height) -> void {
|
||||||
|
settings.width = width;
|
||||||
|
settings.height = height;
|
||||||
|
|
||||||
|
if(gltexture == 0) glGenTextures(1, &gltexture);
|
||||||
|
glwidth = max(glwidth, width);
|
||||||
|
glheight = max(glheight, height);
|
||||||
|
if(glbuffer) delete[] glbuffer;
|
||||||
|
glbuffer = new uint32_t[glwidth * glheight]();
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, gltexture);
|
||||||
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, glwidth);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glwidth, glheight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, glbuffer);
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,13 +1,5 @@
|
||||||
template<typename T, unsigned size>
|
template<typename T, unsigned size>
|
||||||
struct ModuloArray {
|
struct ModuloArray {
|
||||||
ModuloArray() {
|
|
||||||
buffer = new T[size * 3]();
|
|
||||||
}
|
|
||||||
|
|
||||||
~ModuloArray() {
|
|
||||||
delete[] buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto operator[](signed index) const -> T {
|
inline auto operator[](signed index) const -> T {
|
||||||
return buffer[size + index];
|
return buffer[size + index];
|
||||||
}
|
}
|
||||||
|
@ -27,5 +19,5 @@ struct ModuloArray {
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
T* buffer;
|
T buffer[size * 3] = {0};
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#error "bsnes: debugger not supported with performance profile."
|
#error "bsnes: debugger not supported with performance profile."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <nall/priority-queue.hpp>
|
||||||
#include <sfc/alt/cpu/cpu.hpp>
|
#include <sfc/alt/cpu/cpu.hpp>
|
||||||
#include <sfc/alt/smp/smp.hpp>
|
#include <sfc/alt/smp/smp.hpp>
|
||||||
#include <sfc/alt/dsp/dsp.hpp>
|
#include <sfc/alt/dsp/dsp.hpp>
|
||||||
|
|
Loading…
Reference in New Issue