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:
Tim Allen 2015-11-08 20:09:18 +11:00
parent b42ab2fcb3
commit 0fe55e3f5b
32 changed files with 607 additions and 280 deletions

View File

@ -3,12 +3,11 @@
#include <nall/nall.hpp>
#include <nall/dsp.hpp>
#include <nall/priority-queue.hpp>
using namespace nall;
namespace Emulator {
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 License = "GPLv3";
static const string Website = "http://byuu.org/";

View File

@ -2,170 +2,128 @@
namespace GameBoyAdvance {
#include "mrom.cpp"
#include "sram.cpp"
#include "eeprom.cpp"
#include "flashrom.cpp"
#include "flash.cpp"
#include "serialization.cpp"
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;
}
void Cartridge::load() {
auto Cartridge::load() -> void {
interface->loadRequest(ID::Manifest, "manifest.bml", true);
auto document = BML::unserialize(information.markup);
information.title = document["information/title"].text();
unsigned rom_size = 0;
if(document["cartridge/rom"]) {
auto info = document["cartridge/rom"];
interface->loadRequest(ID::ROM, info["name"].text(), true);
rom_size = info["size"].decimal();
for(unsigned addr = rom_size; addr < rom.size; addr++) {
rom.data[addr] = rom.data[Bus::mirror(addr, rom_size)];
unsigned mrom_size = 0;
if(auto info = document["cartridge/mrom"]) {
interface->loadRequest(ID::MROM, info["name"].text(), true);
mrom_size = info["size"].decimal();
for(unsigned addr = mrom_size; addr < mrom.size; addr++) {
mrom.data[addr] = mrom.data[Bus::mirror(addr, mrom_size)];
}
}
has_sram = false;
has_eeprom = false;
has_flashrom = false;
has_sram = false;
has_eeprom = false;
has_flash = false;
if(document["cartridge/ram"]) {
auto info = document["cartridge/ram"];
if(auto info = document["cartridge/sram"]) {
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") {
has_sram = true;
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()});
}
interface->loadRequest(ID::SRAM, info["name"].text(), false);
memory.append({ID::SRAM, 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();
loaded = true;
}
void Cartridge::unload() {
if(loaded == false) return;
loaded = false;
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::unload() -> void {
if(loaded) {
loaded = false;
memory.reset();
}
}
auto Cartridge::power() -> void {
eeprom.power();
flash.power();
}
#define RAM_ANALYZE
auto Cartridge::rom_read(unsigned mode, uint32 addr) -> uint32 {
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.read();
return read(rom.data, mode, addr & 0x01ff'ffff);
auto Cartridge::read(unsigned mode, uint32 addr) -> uint32 {
if(addr < 0x0e00'0000) {
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 {
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.write(word & 1);
}
auto Cartridge::ram_read(unsigned mode, uint32 addr) -> uint32 {
if(has_sram) return read(ram.data, mode, addr & ram.mask);
if(has_flashrom) return flashrom.read(addr);
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;
auto Cartridge::write(unsigned mode, uint32 addr, uint32 word) -> void {
if(addr < 0x0e00'0000) {
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.write(word & 1);
return mrom.write(mode, addr, word);
} else {
if(has_sram) return sram.write(mode, addr, word);
if(has_flash) return flash.write(addr, word);
}
}
}

View File

@ -6,41 +6,32 @@ struct Cartridge : property<Cartridge> {
readonly<bool> has_sram;
readonly<bool> has_eeprom;
readonly<bool> has_flashrom;
readonly<bool> has_flash;
struct Information {
string markup;
string title;
} information;
string title();
struct Media {
unsigned id;
string name;
};
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();
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;

View File

@ -1,13 +1,13 @@
bool Cartridge::EEPROM::read(unsigned addr) {
auto Cartridge::EEPROM::read(unsigned addr) -> bool {
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 == 1) data[addr >> 3] |= (0x80 >> (addr & 7));
}
bool Cartridge::EEPROM::read() {
auto Cartridge::EEPROM::read() -> bool {
bool bit = 1;
//EEPROM size auto-detection
@ -28,7 +28,7 @@ bool Cartridge::EEPROM::read() {
return bit;
}
void Cartridge::EEPROM::write(bool bit) {
auto Cartridge::EEPROM::write(bool bit) -> void {
if(mode == Mode::Wait) {
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;
offset = 0;
address = 0;
}
void Cartridge::EEPROM::serialize(serializer& s) {
auto Cartridge::EEPROM::serialize(serializer& s) -> void {
s.array(data, size);
s.integer(size);
s.integer(mask);

View File

@ -7,7 +7,7 @@
//0x1362 128KB 32x4096 Sanyo
//0x09c2 128KB 32x4096 Macronix
uint8 Cartridge::FlashROM::read(uint16 addr) {
auto Cartridge::FLASH::read(uint16 addr) -> uint8 {
if(idmode) {
if(addr == 0x0000) return id >> 0;
if(addr == 0x0001) return id >> 8;
@ -17,7 +17,7 @@ uint8 Cartridge::FlashROM::read(uint16 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) {
bankselect = false;
//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;
unlocklo = false;
idmode = false;
@ -86,7 +86,7 @@ void Cartridge::FlashROM::power() {
bank = 0;
}
void Cartridge::FlashROM::serialize(serializer& s) {
auto Cartridge::FLASH::serialize(serializer& s) -> void {
s.array(data, size);
s.integer(size);
s.integer(id);

View File

@ -1,31 +1,53 @@
struct Memory {
auto ror(uint32 word, unsigned shift) -> uint32 {
return word << 32 - shift | word >> shift;
}
};
struct MROM : Memory {
uint8* data;
unsigned size;
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;
unsigned size;
unsigned mask;
unsigned test;
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 address;
unsigned addressbits;
bool read(unsigned addr);
void write(unsigned addr, bool bit);
auto read(unsigned addr) -> bool;
auto write(unsigned addr, bool bit) -> void;
bool read();
void write(bool bit);
void power();
void serialize(serializer&);
auto read() -> bool;
auto write(bool bit) -> void;
auto power() -> void;
auto serialize(serializer&) -> void;
} eeprom;
struct FlashROM {
struct FLASH : Memory {
uint8* data;
unsigned size;
uint16 id;
@ -38,8 +60,9 @@ struct FlashROM {
bool writeselect;
bool bank;
uint8 read(uint16 addr);
void write(uint16 addr, uint8 byte);
void power();
void serialize(serializer&);
} flashrom;
auto read(uint16 addr) -> uint8;
auto write(uint16 addr, uint8 byte) -> void;
auto power() -> void;
auto serialize(serializer&) -> void;
} flash;

12
gba/cartridge/mrom.cpp Normal file
View File

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

View File

@ -1,5 +1,5 @@
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_flashrom) flashrom.serialize(s);
if(has_flash) flash.serialize(s);
}

17
gba/cartridge/sram.cpp Normal file
View File

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

View File

@ -16,7 +16,7 @@ auto CPU::bus_read(unsigned mode, uint32 addr) -> uint32 {
} else {
if(!active.dma) prefetch_wait();
step(wait - 1);
word = addr < 0x0e00'0000 ? cartridge.rom_read(mode, addr) : cartridge.ram_read(mode, addr);
word = cartridge.read(mode, addr);
step(1);
}
} else {
@ -43,7 +43,7 @@ auto CPU::bus_write(unsigned mode, uint32 addr, uint32 word) -> void {
} else if(addr & 0x0800'0000) {
if(!active.dma) prefetch_wait();
step(wait);
addr < 0x0e00'0000 ? cartridge.rom_write(mode, addr, word) : cartridge.ram_write(mode, addr, word);
cartridge.write(mode, addr, word);
} else {
prefetch_step(wait);
if(addr < 0x0200'0000);

View File

@ -96,6 +96,7 @@ auto CPU::power() -> void {
dma.source = 0;
dma.target = 0;
dma.length = 0;
dma.data = 0;
dma.control = 0;
dma.pending = 0;
dma.run.target = 0;

View File

@ -33,8 +33,17 @@ auto CPU::dma_exec(Registers::DMA& dma) -> void {
}
}
uint32 word = bus_read(mode, dma.run.source);
bus_write(mode, dma.run.target, word);
if(dma.run.source < 0x0200'0000) {
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) {
case 0: dma.run.source += seek; break;

View File

@ -12,7 +12,7 @@ auto CPU::prefetch_step(unsigned clocks) -> void {
while(!prefetch.full() && clocks--) {
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.wait = bus_wait(Half | Sequential, prefetch.load);
}

View File

@ -18,6 +18,7 @@ struct Registers {
varuint source;
varuint target;
varuint length;
uint32 data;
DMAControl control;
//internal

View File

@ -9,6 +9,7 @@ auto CPU::serialize(serializer& s) -> void {
s.integer(dma.source);
s.integer(dma.target);
s.integer(dma.length);
s.integer(dma.data);
s.integer(dma.control.targetmode);
s.integer(dma.control.sourcemode);
s.integer(dma.control.repeat);

View File

@ -26,10 +26,10 @@ unsigned Interface::group(unsigned id) {
case ID::BIOS:
return ID::System;
case ID::Manifest:
case ID::ROM:
case ID::RAM:
case ID::MROM:
case ID::SRAM:
case ID::EEPROM:
case ID::FlashROM:
case ID::FLASH:
return ID::GameBoyAdvance;
}
@ -59,34 +59,34 @@ void Interface::load(unsigned id, const stream& stream) {
cartridge.information.markup = stream.text();
}
if(id == ID::ROM) {
stream.read(cartridge.rom.data, min(cartridge.rom.size, stream.size()));
if(id == ID::MROM) {
stream.read(cartridge.mrom.data, min(cartridge.mrom.size, stream.size()));
}
if(id == ID::RAM) {
stream.read(cartridge.ram.data, min(cartridge.ram.size, stream.size()));
if(id == ID::SRAM) {
stream.read(cartridge.sram.data, min(cartridge.sram.size, stream.size()));
}
if(id == ID::EEPROM) {
stream.read(cartridge.eeprom.data, min(cartridge.eeprom.size, stream.size()));
}
if(id == ID::FlashROM) {
stream.read(cartridge.flashrom.data, min(cartridge.flashrom.size, stream.size()));
if(id == ID::FLASH) {
stream.read(cartridge.flash.data, min(cartridge.flash.size, stream.size()));
}
}
void Interface::save(unsigned id, const stream& stream) {
if(id == ID::RAM) {
stream.write(cartridge.ram.data, cartridge.ram.size);
if(id == ID::SRAM) {
stream.write(cartridge.sram.data, cartridge.sram.size);
}
if(id == ID::EEPROM) {
stream.write(cartridge.eeprom.data, cartridge.eeprom.size);
}
if(id == ID::FlashROM) {
stream.write(cartridge.flashrom.data, cartridge.flashrom.size);
if(id == ID::FLASH) {
stream.write(cartridge.flash.data, cartridge.flash.size);
}
}

View File

@ -13,10 +13,10 @@ struct ID {
BIOS,
Manifest,
ROM,
RAM,
MROM,
SRAM,
EEPROM,
FlashROM,
FLASH,
};
enum : unsigned {

View File

@ -11,12 +11,21 @@ auto pLayout::destruct() -> 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 {
for(auto& sizable : state().sizables) {
if(auto self = sizable->self()) self->setFont(sizable->font(true));
}
}
auto pLayout::setVisible(bool visible) -> void {
for(auto& sizable : state().sizables) {
if(auto self = sizable->self()) self->setVisible(sizable->visible(true));
}
}
}

View File

@ -242,15 +242,15 @@ auto pWindow::setDroppable(bool droppable) -> void {
auto pWindow::setEnabled(bool enabled) -> void {
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(statusBar->self()) statusBar->self()->setEnabled(statusBar->enabled(true));
if(auto self = statusBar->self()) self->setEnabled(statusBar->enabled(true));
}
if(auto& layout = state().layout) {
if(layout->self()) layout->self()->setEnabled(layout->enabled(true));
if(auto self = layout->self()) self->setEnabled(layout->enabled(true));
}
}

View File

@ -38,13 +38,13 @@ GameBoyAdvanceCartridge::GameBoyAdvanceCartridge(const uint8_t *data, unsigned s
identifiers = list.merge(",");
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);
else if(identifiers.beginsWith("SRAM_V" )) markup.append(" ram name=save.ram type=SRAM 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("EEPROM_V" )) markup.append(" ram name=save.ram type=EEPROM size=0x0\n");
else if(identifiers.beginsWith("FLASH_V" )) markup.append(" ram name=save.ram type=FlashROM size=0x10000\n");
else if(identifiers.beginsWith("FLASH512_V")) markup.append(" ram name=save.ram type=FlashROM size=0x10000\n");
else if(identifiers.beginsWith("FLASH1M_V" )) markup.append(" ram name=save.ram type=FlashROM size=0x20000\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(" sram name=save.ram size=0x8000\n");
else if(identifiers.beginsWith("EEPROM_V" )) markup.append(" eeprom name=save.ram size=0x0\n");
else if(identifiers.beginsWith("FLASH_V" )) markup.append(" flash name=save.ram 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(" flash name=save.ram size=0x20000\n");
//if(identifiers.empty() == false) markup.append(" #detected: ", identifiers, "\n");
}

View File

@ -128,15 +128,18 @@ public:
auto size() const -> unsigned { return _size; }
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& 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& 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* s) const -> bool { return strcmp(data(), s) != 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> (const char* s) const -> bool { return strcmp(data(), s) > 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* source) const -> bool { return strcmp(data(), 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; }
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(string&& source) : string() { operator=(move(source)); }
@ -183,6 +186,9 @@ public:
//compare.hpp
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 icompare(rstring source) const -> signed;

View File

@ -8,12 +8,21 @@ auto string::_compare(const char* target, unsigned capacity, const char* source,
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 {
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 {
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 {

View File

@ -13,11 +13,23 @@ struct ManagedNode {
ManagedNode(const string& name, const string& value) : _name(name), _value(value) {}
auto clone() const -> SharedNode {
SharedNode clone(new ManagedNode(_name, _value));
for(auto& child : _children) clone->_children.append(child->clone());
SharedNode clone{new ManagedNode(_name, _value)};
for(auto& child : _children) {
clone->_children.append(child->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:
string _name;
string _value;
@ -40,6 +52,7 @@ struct Node {
auto unique() const -> bool { return shared.unique(); }
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; }
auto name() const -> string { return shared->_name; }
@ -50,8 +63,8 @@ struct Node {
auto integer() const -> intmax_t { return text().integer(); }
auto decimal() const -> uintmax_t { return text().decimal(); }
auto setName(const string& name = "") -> void { shared->_name = name; }
auto setValue(const string& value = "") -> void { shared->_value = value; }
auto setName(const string& name = "") -> Node& { shared->_name = name; return *this; }
auto setValue(const string& value = "") -> Node& { shared->_value = value; return *this; }
auto reset() -> void { shared->_children.reset(); }
auto size() const -> unsigned { return shared->_children.size(); }
@ -67,16 +80,6 @@ struct Node {
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 {
if(position > size()) return false; //used > instead of >= to allow indexed-equivalent of append()
return shared->_children.insert(position, node.shared), true;
@ -87,8 +90,26 @@ struct Node {
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) -> Node { return shared->_create(path); }
auto find(const string& query) const -> vector<Node> { return shared->_find(query); }
struct iterator {

View File

@ -160,12 +160,10 @@ template<typename T> struct vector {
}
}
auto sort() -> void {
nall::sort(pool + poolbase, objectsize);
}
template<typename Comparator> auto sort(const Comparator& lessthan) -> void {
nall::sort(pool + poolbase, objectsize, lessthan);
auto sort(const function<bool (const T& lhs, const T& rhs)>& comparator = [](const T& lhs, const T& rhs) -> bool {
return lhs < rhs;
}) -> void {
nall::sort(pool + poolbase, objectsize, comparator);
}
auto find(const T& data) const -> maybe<unsigned> {

View File

@ -42,14 +42,23 @@ auto ARM::load(unsigned mode, uint32 addr) -> uint32 {
pipeline.nonsequential = true;
uint32 word = bus_read(Load | mode, addr);
if(mode & Half) { word &= 0xffff; word |= word << 16; }
if(mode & Byte) { word &= 0xff; word |= word << 8; word |= word << 16; }
if(mode & Half) {
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();
if(mode & Half) word &= 0xffff;
if(mode & Byte) word &= 0xff;
return word;
}

View File

@ -17,6 +17,7 @@ struct ARM {
Word = 32, //32-bit access
Load = 64, //load operation
Store = 128, //store operation
Signed = 256, //sign extend
};
#include "registers.hpp"

View File

@ -164,13 +164,15 @@ auto ARM::arm_op_move_half_register() {
uint32 rn = r(n);
uint32 rm = r(m);
uint32 rd = r(d);
if(pre == 1) rn = up ? rn + rm : rn - rm;
if(l == 1) r(d) = load(Half | Nonsequential, rn);
if(l == 0) store(Half | Nonsequential, rn, r(d));
if(l == 1) rd = load(Half | Nonsequential, rn);
if(l == 0) store(Half | Nonsequential, rn, rd);
if(pre == 0) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback == 1) r(n) = rn;
if(l == 1) r(d) = rd;
}
//(ldr,str){condition}h rd,[rn{,+/-offset}]{!}
@ -196,14 +198,16 @@ auto ARM::arm_op_move_half_immediate() {
uint4 il = instruction();
uint32 rn = r(n);
uint32 rd = r(d);
uint8 immediate = (ih << 4) + (il << 0);
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
if(l == 1) r(d) = load(Half | Nonsequential, rn);
if(l == 0) store(Half | Nonsequential, rn, r(d));
if(l == 1) rd = load(Half | Nonsequential, rn);
if(l == 0) store(Half | Nonsequential, rn, rd);
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
if(pre == 0 || writeback == 1) r(n) = rn;
if(l == 1) r(d) = rd;
}
//ldr{condition}s(h,b) rd,[rn,rm]{!}
@ -228,13 +232,14 @@ auto ARM::arm_op_load_register() {
uint32 rn = r(n);
uint32 rm = r(m);
uint32 rd = r(d);
if(pre == 1) rn = up ? rn + rm : rn - rm;
uint32 word = load((half ? Half : Byte) | Nonsequential, rn);
r(d) = half ? (int16)word : (int8)word;
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
if(pre == 0) rn = up ? rn + rm : rn - rm;
if(pre == 0 || writeback == 1) r(n) = rn;
r(d) = rd;
}
//ldr{condition}s(h,b) rd,[rn{,+/-offset}]{!}
@ -260,14 +265,15 @@ auto ARM::arm_op_load_immediate() {
uint4 il = instruction();
uint32 rn = r(n);
uint32 rd = r(d);
uint8 immediate = (ih << 4) + (il << 0);
if(pre == 1) rn = up ? rn + immediate : rn - immediate;
uint32 word = load((half ? Half : Byte) | Nonsequential, rn);
r(d) = half ? (int16)word : (int8)word;
rd = load((half ? Half : Byte) | Nonsequential | Signed, rn);
if(pre == 0) rn = up ? rn + immediate : rn - immediate;
if(pre == 0 || writeback == 1) r(n) = rn;
r(d) = rd;
}
//mrs{condition} rd,(c,s)psr
@ -375,8 +381,8 @@ auto ARM::arm_op_data_register_shift() {
uint2 mode = instruction() >> 5;
uint4 m = instruction();
uint8 rs = r(s);
uint32 rm = r(m);
uint8 rs = r(s) + (s == 15 ? 4 : 0);
uint32 rm = r(m) + (m == 15 ? 4 : 0);
carryout() = cpsr().c;
if(mode == 0 ) rm = lsl(rm, rs < 33 ? rs : 33);
@ -434,7 +440,7 @@ auto ARM::arm_op_move_immediate_offset() {
uint12 rm = instruction();
uint32 rn = r(n);
auto& rd = r(d);
uint32 rd = r(d);
if(pre == 1) rn = up ? rn + rm : rn - rm;
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 || writeback == 1) r(n) = rn;
if(l == 1) r(d) = rd;
}
//(ldr,str){condition}{b} rd,[rn,rm {mode} #immediate]{!}
@ -471,7 +478,7 @@ auto ARM::arm_op_move_register_offset() {
uint4 m = instruction();
uint32 rn = r(n);
auto& rd = r(d);
uint32 rd = r(d);
uint32 rs = immediate;
uint32 rm = r(m);
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 || writeback == 1) r(n) = rn;
if(l == 1) r(d) = rd;
}
//(ldm,stm){condition}{mode} rn{!},{r...}

View File

@ -161,14 +161,14 @@ auto ARM::thumb_op_move_register_offset() {
uint3 d = instruction() >> 0;
switch(opcode) {
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 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 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 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 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 2: store(Byte | Nonsequential, r(n) + r(m), r(d)); break; //STRB
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 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 7: r(d) = load(Half | Nonsequential | Signed, r(n) + r(m)); break; //LDSH
}
}

View File

@ -43,6 +43,10 @@ using namespace ruby;
#include <ruby/video/glx.cpp>
#endif
#if defined(VIDEO_GLX2)
#include <ruby/video/glx2.cpp>
#endif
#if defined(VIDEO_SDL)
#include <ruby/video/sdl.cpp>
#endif
@ -93,6 +97,10 @@ auto Video::create(const string& driver) -> Video* {
if(driver == "OpenGL") return new VideoGLX;
#endif
#if defined(VIDEO_GLX2)
if(driver == "OpenGL2") return new VideoGLX2;
#endif
#if defined(VIDEO_SDL)
if(driver == "SDL") return new VideoSDL;
#endif
@ -125,6 +133,8 @@ auto Video::optimalDriver() -> string {
return "OpenGL";
#elif defined(VIDEO_GLX)
return "OpenGL";
#elif defined(VIDEO_GLX2)
return "OpenGL2";
#elif defined(VIDEO_XV)
return "X-Video";
#elif defined(VIDEO_XSHM)
@ -153,6 +163,8 @@ auto Video::safestDriver() -> string {
return "SDL";
#elif defined(VIDEO_XV)
return "X-Video";
#elif defined(VIDEO_GLX2)
return "OpenGL2";
#elif defined(VIDEO_GLX)
return "OpenGL";
#else
@ -187,6 +199,10 @@ auto Video::availableDrivers() -> lstring {
"OpenGL",
#endif
#if defined(VIDEO_GLX2)
"OpenGL2",
#endif
#if defined(VIDEO_XV)
"X-Video",
#endif

245
ruby/video/glx2.cpp Normal file
View File

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

View File

@ -1,13 +1,5 @@
template<typename T, unsigned size>
struct ModuloArray {
ModuloArray() {
buffer = new T[size * 3]();
}
~ModuloArray() {
delete[] buffer;
}
inline auto operator[](signed index) const -> T {
return buffer[size + index];
}
@ -27,5 +19,5 @@ struct ModuloArray {
}
private:
T* buffer;
T buffer[size * 3] = {0};
};

View File

@ -2,6 +2,7 @@
#error "bsnes: debugger not supported with performance profile."
#endif
#include <nall/priority-queue.hpp>
#include <sfc/alt/cpu/cpu.hpp>
#include <sfc/alt/smp/smp.hpp>
#include <sfc/alt/dsp/dsp.hpp>