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/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/";
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ struct Registers {
|
|||
varuint source;
|
||||
varuint target;
|
||||
varuint length;
|
||||
uint32 data;
|
||||
DMAControl control;
|
||||
|
||||
//internal
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,10 +13,10 @@ struct ID {
|
|||
BIOS,
|
||||
|
||||
Manifest,
|
||||
ROM,
|
||||
RAM,
|
||||
MROM,
|
||||
SRAM,
|
||||
EEPROM,
|
||||
FlashROM,
|
||||
FLASH,
|
||||
};
|
||||
|
||||
enum : unsigned {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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...}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
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};
|
||||
};
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue