Update to v088r04 release.

byuu says:

This will hopefully be a short-lived WIP, I just want to save
a breakpoint before I attempt something else.
NES, GB, GBC and GBA all load via const stream& now.
NES CPU core moved to Processor::RP2A03.
This commit is contained in:
Tim Allen 2012-04-28 16:35:51 +10:00
parent 616372e96b
commit 67c13f749f
53 changed files with 726 additions and 689 deletions

View File

@ -1,7 +1,7 @@
#ifndef BASE_HPP #ifndef BASE_HPP
#define BASE_HPP #define BASE_HPP
static const char Version[] = "088.03"; static const char Version[] = "088.04";
#include <nall/platform.hpp> #include <nall/platform.hpp>
#include <nall/algorithm.hpp> #include <nall/algorithm.hpp>

View File

@ -7,12 +7,14 @@ namespace GameBoyAdvance {
#include "serialization.cpp" #include "serialization.cpp"
Cartridge cartridge; Cartridge cartridge;
bool Cartridge::load(const string &markup, const uint8_t *data, unsigned size) { bool Cartridge::load(const string &markup, const stream &memory) {
information.markup = markup; information.markup = markup;
XML::Document document(markup); XML::Document document(markup);
for(unsigned addr = 0; addr < rom.size; addr++) { unsigned size = memory.size();
rom.data[addr] = data[Bus::mirror(addr, size)]; memory.read(rom.data, min(rom.size, size));
for(unsigned addr = size; addr < rom.size; addr++) {
rom.data[addr] = rom.data[Bus::mirror(addr, size)];
} }
has_sram = false; has_sram = false;
@ -47,7 +49,7 @@ bool Cartridge::load(const string &markup, const uint8_t *data, unsigned size) {
} }
} }
sha256 = nall::sha256(rom.data, rom.size); sha256 = nall::sha256(rom.data, size);
system.load(); system.load();
return loaded = true; return loaded = true;

View File

@ -12,7 +12,7 @@ struct Cartridge : property<Cartridge> {
string markup; string markup;
} information; } information;
bool load(const string &markup, const uint8_t *data, unsigned size); bool load(const string &markup, const stream &memory);
void unload(); void unload();
void power(); void power();

View File

@ -44,7 +44,7 @@ struct stream {
return data; return data;
} }
void read(uint8_t *data, unsigned length) const { virtual void read(uint8_t *data, unsigned length) const {
while(length--) *data++ = read(); while(length--) *data++ = read();
} }

View File

@ -111,7 +111,7 @@ void serialize(serializer &s) {
s.integer(irq_latch); s.integer(irq_latch);
} }
BandaiFCG(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size) { BandaiFCG(XML::Document &document, const stream &memory) : Board(document, memory) {
} }
}; };

View File

@ -86,7 +86,7 @@ void Board::serialize(serializer &s) {
if(chrram.size) s.array(chrram.data, chrram.size); if(chrram.size) s.array(chrram.data, chrram.size);
} }
Board::Board(XML::Document &document, const uint8_t *data, unsigned size) { Board::Board(XML::Document &document, const stream &memory) {
auto &cartridge = document["cartridge"]; auto &cartridge = document["cartridge"];
information.type = cartridge["board"]["type"].data; information.type = cartridge["board"]["type"].data;
@ -102,8 +102,8 @@ Board::Board(XML::Document &document, const uint8_t *data, unsigned size) {
if(chrrom.size) chrrom.data = new uint8[chrrom.size](); if(chrrom.size) chrrom.data = new uint8[chrrom.size]();
if(chrram.size) chrram.data = new uint8[chrram.size](); if(chrram.size) chrram.data = new uint8[chrram.size]();
if(prgrom.size) memcpy(prgrom.data, data, prgrom.size); if(prgrom.size) memory.read(prgrom.data, prgrom.size);
if(chrrom.size) memcpy(chrrom.data, data + prgrom.size, chrrom.size); if(chrrom.size) memory.read(chrrom.data, chrrom.size);
prgram.writable = true; prgram.writable = true;
chrram.writable = true; chrram.writable = true;
@ -112,56 +112,56 @@ Board::Board(XML::Document &document, const uint8_t *data, unsigned size) {
Board::~Board() { Board::~Board() {
} }
Board* Board::load(const string &markup, const uint8_t *data, unsigned size) { Board* Board::load(const string &markup, const stream &memory) {
XML::Document document(markup); XML::Document document(markup);
string type = document["cartridge"]["board"]["type"].data; string type = document["cartridge"]["board"]["type"].data;
if(type == "BANDAI-FCG") return new BandaiFCG(document, data, size); if(type == "BANDAI-FCG") return new BandaiFCG(document, memory);
if(type == "KONAMI-VRC-1") return new KonamiVRC1(document, data, size); if(type == "KONAMI-VRC-1") return new KonamiVRC1(document, memory);
if(type == "KONAMI-VRC-2") return new KonamiVRC2(document, data, size); if(type == "KONAMI-VRC-2") return new KonamiVRC2(document, memory);
if(type == "KONAMI-VRC-3") return new KonamiVRC3(document, data, size); if(type == "KONAMI-VRC-3") return new KonamiVRC3(document, memory);
if(type == "KONAMI-VRC-4") return new KonamiVRC4(document, data, size); if(type == "KONAMI-VRC-4") return new KonamiVRC4(document, memory);
if(type == "KONAMI-VRC-6") return new KonamiVRC6(document, data, size); if(type == "KONAMI-VRC-6") return new KonamiVRC6(document, memory);
if(type == "KONAMI-VRC-7") return new KonamiVRC7(document, data, size); if(type == "KONAMI-VRC-7") return new KonamiVRC7(document, memory);
if(type == "NES-AMROM" ) return new NES_AxROM(document, data, size); if(type == "NES-AMROM" ) return new NES_AxROM(document, memory);
if(type == "NES-ANROM" ) return new NES_AxROM(document, data, size); if(type == "NES-ANROM" ) return new NES_AxROM(document, memory);
if(type == "NES-AN1ROM" ) return new NES_AxROM(document, data, size); if(type == "NES-AN1ROM" ) return new NES_AxROM(document, memory);
if(type == "NES-AOROM" ) return new NES_AxROM(document, data, size); if(type == "NES-AOROM" ) return new NES_AxROM(document, memory);
if(type == "NES-BNROM" ) return new NES_BNROM(document, data, size); if(type == "NES-BNROM" ) return new NES_BNROM(document, memory);
if(type == "NES-CNROM" ) return new NES_CNROM(document, data, size); if(type == "NES-CNROM" ) return new NES_CNROM(document, memory);
if(type == "NES-EKROM" ) return new NES_ExROM(document, data, size); if(type == "NES-EKROM" ) return new NES_ExROM(document, memory);
if(type == "NES-ELROM" ) return new NES_ExROM(document, data, size); if(type == "NES-ELROM" ) return new NES_ExROM(document, memory);
if(type == "NES-ETROM" ) return new NES_ExROM(document, data, size); if(type == "NES-ETROM" ) return new NES_ExROM(document, memory);
if(type == "NES-EWROM" ) return new NES_ExROM(document, data, size); if(type == "NES-EWROM" ) return new NES_ExROM(document, memory);
if(type == "NES-FJROM" ) return new NES_FxROM(document, data, size); if(type == "NES-FJROM" ) return new NES_FxROM(document, memory);
if(type == "NES-FKROM" ) return new NES_FxROM(document, data, size); if(type == "NES-FKROM" ) return new NES_FxROM(document, memory);
if(type == "NES-GNROM" ) return new NES_GxROM(document, data, size); if(type == "NES-GNROM" ) return new NES_GxROM(document, memory);
if(type == "NES-MHROM" ) return new NES_GxROM(document, data, size); if(type == "NES-MHROM" ) return new NES_GxROM(document, memory);
if(type == "NES-HKROM" ) return new NES_HKROM(document, data, size); if(type == "NES-HKROM" ) return new NES_HKROM(document, memory);
if(type == "NES-NROM-128") return new NES_NROM(document, data, size); if(type == "NES-NROM-128") return new NES_NROM(document, memory);
if(type == "NES-NROM-256") return new NES_NROM(document, data, size); if(type == "NES-NROM-256") return new NES_NROM(document, memory);
if(type == "NES-PEEOROM" ) return new NES_PxROM(document, data, size); if(type == "NES-PEEOROM" ) return new NES_PxROM(document, memory);
if(type == "NES-PNROM" ) return new NES_PxROM(document, data, size); if(type == "NES-PNROM" ) return new NES_PxROM(document, memory);
if(type == "NES-SNROM" ) return new NES_SxROM(document, data, size); if(type == "NES-SNROM" ) return new NES_SxROM(document, memory);
if(type == "NES-SXROM" ) return new NES_SxROM(document, data, size); if(type == "NES-SXROM" ) return new NES_SxROM(document, memory);
if(type == "NES-TLROM" ) return new NES_TxROM(document, data, size); if(type == "NES-TLROM" ) return new NES_TxROM(document, memory);
if(type == "NES-UNROM" ) return new NES_UxROM(document, data, size); if(type == "NES-UNROM" ) return new NES_UxROM(document, memory);
if(type == "NES-UOROM" ) return new NES_UxROM(document, data, size); if(type == "NES-UOROM" ) return new NES_UxROM(document, memory);
if(type == "SUNSOFT-5B" ) return new Sunsoft5B(document, data, size); if(type == "SUNSOFT-5B" ) return new Sunsoft5B(document, memory);
return nullptr; return nullptr;
} }

View File

@ -31,10 +31,10 @@ struct Board {
virtual void reset(); virtual void reset();
virtual void serialize(serializer&); virtual void serialize(serializer&);
Board(XML::Document &document, const uint8_t *data, unsigned size); Board(XML::Document &document, const stream &memory);
virtual ~Board(); virtual ~Board();
static Board* load(const string &markup, const uint8_t *data, unsigned size); static Board* load(const string &markup, const stream &memory);
struct Information { struct Information {
string type; string type;

View File

@ -34,7 +34,7 @@ void serialize(serializer &s) {
vrc1.serialize(s); vrc1.serialize(s);
} }
KonamiVRC1(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size), vrc1(*this) { KonamiVRC1(XML::Document &document, const stream &memory) : Board(document, memory), vrc1(*this) {
} }
}; };

View File

@ -49,7 +49,7 @@ void serialize(serializer &s) {
vrc2.serialize(s); vrc2.serialize(s);
} }
KonamiVRC2(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size), vrc2(*this) { KonamiVRC2(XML::Document &document, const stream &memory) : Board(document, memory), vrc2(*this) {
settings.pinout.a0 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a0"].data); settings.pinout.a0 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a0"].data);
settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data); settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
} }

View File

@ -50,7 +50,7 @@ void serialize(serializer &s) {
vrc3.serialize(s); vrc3.serialize(s);
} }
KonamiVRC3(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size), vrc3(*this) { KonamiVRC3(XML::Document &document, const stream &memory) : Board(document, memory), vrc3(*this) {
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0; settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
} }

View File

@ -53,7 +53,7 @@ void serialize(serializer &s) {
vrc4.serialize(s); vrc4.serialize(s);
} }
KonamiVRC4(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size), vrc4(*this) { KonamiVRC4(XML::Document &document, const stream &memory) : Board(document, memory), vrc4(*this) {
settings.pinout.a0 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a0"].data); settings.pinout.a0 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a0"].data);
settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data); settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
} }

View File

@ -36,7 +36,7 @@ void main() { vrc6.main(); }
void power() { vrc6.power(); } void power() { vrc6.power(); }
void reset() { vrc6.reset(); } void reset() { vrc6.reset(); }
KonamiVRC6(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size), vrc6(*this) { KonamiVRC6(XML::Document &document, const stream &memory) : Board(document, memory), vrc6(*this) {
} }
}; };

View File

@ -41,7 +41,7 @@ void serialize(serializer &s) {
vrc7.serialize(s); vrc7.serialize(s);
} }
KonamiVRC7(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size), vrc7(*this) { KonamiVRC7(XML::Document &document, const stream &memory) : Board(document, memory), vrc7(*this) {
} }
}; };

View File

@ -45,7 +45,7 @@ void serialize(serializer &s) {
s.integer(mirror_select); s.integer(mirror_select);
} }
NES_AxROM(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size) { NES_AxROM(XML::Document &document, const stream &memory) : Board(document, memory) {
} }
}; };

View File

@ -45,7 +45,7 @@ void serialize(serializer &s) {
s.integer(prg_bank); s.integer(prg_bank);
} }
NES_BNROM(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size) { NES_BNROM(XML::Document &document, const stream &memory) : Board(document, memory) {
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0; settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
} }

View File

@ -47,7 +47,7 @@ void serialize(serializer &s) {
s.integer(chr_bank); s.integer(chr_bank);
} }
NES_CNROM(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size) { NES_CNROM(XML::Document &document, const stream &memory) : Board(document, memory) {
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0; settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
} }

View File

@ -46,7 +46,7 @@ void serialize(serializer &s) {
mmc5.serialize(s); mmc5.serialize(s);
} }
NES_ExROM(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size), mmc5(*this) { NES_ExROM(XML::Document &document, const stream &memory) : Board(document, memory), mmc5(*this) {
revision = Revision::ELROM; revision = Revision::ELROM;
} }

View File

@ -84,7 +84,7 @@ void serialize(serializer &s) {
s.array(latch); s.array(latch);
} }
NES_FxROM(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size) { NES_FxROM(XML::Document &document, const stream &memory) : Board(document, memory) {
revision = Revision::FKROM; revision = Revision::FKROM;
} }

View File

@ -54,7 +54,7 @@ void serialize(serializer &s) {
s.integer(chr_bank); s.integer(chr_bank);
} }
NES_GxROM(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size) { NES_GxROM(XML::Document &document, const stream &memory) : Board(document, memory) {
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0; settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
} }

View File

@ -42,7 +42,7 @@ void serialize(serializer &s) {
mmc6.serialize(s); mmc6.serialize(s);
} }
NES_HKROM(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size), mmc6(*this) { NES_HKROM(XML::Document &document, const stream &memory) : Board(document, memory), mmc6(*this) {
} }
}; };

View File

@ -36,7 +36,7 @@ void serialize(serializer &s) {
Board::serialize(s); Board::serialize(s);
} }
NES_NROM(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size) { NES_NROM(XML::Document &document, const stream &memory) : Board(document, memory) {
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0; settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
} }

View File

@ -90,7 +90,7 @@ void serialize(serializer &s) {
s.array(latch); s.array(latch);
} }
NES_PxROM(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size) { NES_PxROM(XML::Document &document, const stream &memory) : Board(document, memory) {
revision = Revision::PNROM; revision = Revision::PNROM;
} }

View File

@ -94,7 +94,7 @@ void serialize(serializer &s) {
mmc1.serialize(s); mmc1.serialize(s);
} }
NES_SxROM(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size), mmc1(*this) { NES_SxROM(XML::Document &document, const stream &memory) : Board(document, memory), mmc1(*this) {
revision = Revision::SXROM; revision = Revision::SXROM;
} }

View File

@ -60,7 +60,7 @@ void serialize(serializer &s) {
mmc3.serialize(s); mmc3.serialize(s);
} }
NES_TxROM(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size), mmc3(*this) { NES_TxROM(XML::Document &document, const stream &memory) : Board(document, memory), mmc3(*this) {
revision = Revision::TLROM; revision = Revision::TLROM;
} }

View File

@ -48,7 +48,7 @@ void serialize(serializer &s) {
s.integer(prg_bank); s.integer(prg_bank);
} }
NES_UxROM(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size) { NES_UxROM(XML::Document &document, const stream &memory) : Board(document, memory) {
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0; settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
} }

View File

@ -220,7 +220,7 @@ void serialize(serializer &s) {
pulse[2].serialize(s); pulse[2].serialize(s);
} }
Sunsoft5B(XML::Document &document, const uint8_t *data, unsigned size) : Board(document, data, size) { Sunsoft5B(XML::Document &document, const stream &memory) : Board(document, memory) {
} }
}; };

View File

@ -14,18 +14,23 @@ void Cartridge::main() {
board->main(); board->main();
} }
void Cartridge::load(const string &markup, const uint8_t *data, unsigned size) { void Cartridge::load(const string &markup, const stream &memory) {
information.markup = markup; information.markup = markup;
if((size & 0xff) == 0) { board = Board::load(markup, memory);
sha256 = nall::sha256(data, size);
board = Board::load(markup, data, size);
} else {
sha256 = nall::sha256(data + 16, size - 16);
board = Board::load(markup, data + 16, size - 16);
}
if(board == nullptr) return; if(board == nullptr) return;
sha256_ctx sha;
uint8_t hash[32];
sha256_init(&sha);
sha256_chunk(&sha, board->prgrom.data, board->prgrom.size);
sha256_chunk(&sha, board->chrrom.data, board->chrrom.size);
sha256_final(&sha);
sha256_hash(&sha, hash);
string result;
for(auto &byte : hash) result.append(hex<2>(byte));
sha256 = result;
system.load(); system.load();
loaded = true; loaded = true;
} }

View File

@ -5,7 +5,7 @@ struct Cartridge : Thread, property<Cartridge> {
static void Main(); static void Main();
void main(); void main();
void load(const string &markup, const uint8_t *data, unsigned size); void load(const string &markup, const stream &memory);
void unload(); void unload();
unsigned ram_size(); unsigned ram_size();

View File

@ -1,10 +0,0 @@
#define call(op) (this->*op)()
#define L interrupt_test();
#include "interrupt.cpp"
#include "opcodes.cpp"
#include "exec.cpp"
#include "disassembler.cpp"
#undef L
#undef call

View File

@ -1,117 +0,0 @@
struct Flags {
bool n, v, d, i, z, c;
inline operator unsigned() {
return (n << 7) | (v << 6) | (d << 3) | (i << 2) | (z << 1) | (c << 0);
}
inline Flags& operator=(uint8 data) {
n = data & 0x80; v = data & 0x40;
d = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01;
return *this;
}
};
struct Registers {
uint8 mdr;
uint16 pc;
uint8 a, x, y, s;
Flags p;
} regs;
struct Register16 {
union {
uint16 w;
struct { uint8 order_lsb2(l, h); };
};
} abs, iabs;
uint8 rd;
uint8 zp;
uint16 aa;
//interrupt.cpp
void interrupt();
void interrupt_test();
void set_nmi_line(bool);
void set_irq_line(bool);
void set_irq_apu_line(bool);
//opcodes.cpp
void opf_asl();
void opf_adc();
void opf_and();
void opf_bit();
void opf_cmp();
void opf_cpx();
void opf_cpy();
void opf_dec();
void opf_eor();
void opf_inc();
void opf_lda();
void opf_ldx();
void opf_ldy();
void opf_lsr();
void opf_ora();
void opf_rla();
void opf_rol();
void opf_ror();
void opf_rra();
void opf_sbc();
void opf_sla();
void opf_sra();
void opi_branch(bool condition);
void opi_clear_flag(bool &flag);
void opi_decrement(uint8 &r);
void opi_increment(uint8 &r);
void opi_pull(uint8 &r);
void opi_push(uint8 &r);
template<void (CPU::*op)()> void opi_read_absolute();
template<void (CPU::*op)()> void opi_read_absolute_x();
template<void (CPU::*op)()> void opi_read_absolute_y();
template<void (CPU::*op)()> void opi_read_immediate();
template<void (CPU::*op)()> void opi_read_indirect_zero_page_x();
template<void (CPU::*op)()> void opi_read_indirect_zero_page_y();
template<void (CPU::*op)()> void opi_read_zero_page();
template<void (CPU::*op)()> void opi_read_zero_page_x();
template<void (CPU::*op)()> void opi_read_zero_page_y();
template<void (CPU::*op)()> void opi_rmw_absolute();
template<void (CPU::*op)()> void opi_rmw_absolute_x();
template<void (CPU::*op)()> void opi_rmw_zero_page();
template<void (CPU::*op)()> void opi_rmw_zero_page_x();
void opi_set_flag(bool &flag);
template<void (CPU::*op)()> void opi_shift();
void opi_store_absolute(uint8 &r);
void opi_store_absolute_x(uint8 &r);
void opi_store_absolute_y(uint8 &r);
void opi_store_indirect_zero_page_x(uint8 &r);
void opi_store_indirect_zero_page_y(uint8 &r);
void opi_store_zero_page(uint8 &r);
void opi_store_zero_page_x(uint8 &r);
void opi_store_zero_page_y(uint8 &r);
void opi_transfer(uint8 &s, uint8 &d, bool flag);
void op_brk();
void op_jmp_absolute();
void op_jmp_indirect_absolute();
void op_jsr_absolute();
void op_nop();
void op_php();
void op_plp();
void op_rti();
void op_rts();
void opill_arr_immediate();
void opill_nop_absolute();
void opill_nop_absolute_x();
void opill_nop_immediate();
void opill_nop_implied();
void opill_nop_zero_page();
void opill_nop_zero_page_x();
//exec.cpp
void op_exec();
//disassembler.cpp
string disassemble();

View File

@ -1,196 +0,0 @@
//I = illegal instruction (only used as a visual indicator)
#define I
void CPU::op_exec() {
uint8 opcode = op_readpci();
switch(opcode) {
case 0x00: return op_brk();
case 0x01: return opi_read_indirect_zero_page_x<&CPU::opf_ora>();
I case 0x04: return opill_nop_zero_page();
case 0x05: return opi_read_zero_page<&CPU::opf_ora>();
case 0x06: return opi_rmw_zero_page<&CPU::opf_asl>();
case 0x08: return op_php();
case 0x09: return opi_read_immediate<&CPU::opf_ora>();
case 0x0a: return opi_shift<&CPU::opf_sla>();
I case 0x0c: return opill_nop_absolute();
case 0x0d: return opi_read_absolute<&CPU::opf_ora>();
case 0x0e: return opi_rmw_absolute<&CPU::opf_asl>();
case 0x10: return opi_branch(regs.p.n == 0);
case 0x11: return opi_read_indirect_zero_page_y<&CPU::opf_ora>();
I case 0x14: return opill_nop_zero_page_x();
case 0x15: return opi_read_zero_page_x<&CPU::opf_ora>();
case 0x16: return opi_rmw_zero_page_x<&CPU::opf_asl>();
case 0x18: return opi_clear_flag(regs.p.c);
case 0x19: return opi_read_absolute_y<&CPU::opf_ora>();
I case 0x1a: return opill_nop_implied();
I case 0x1c: return opill_nop_absolute_x();
case 0x1d: return opi_read_absolute_x<&CPU::opf_ora>();
case 0x1e: return opi_rmw_absolute_x<&CPU::opf_asl>();
case 0x20: return op_jsr_absolute();
case 0x21: return opi_read_indirect_zero_page_x<&CPU::opf_and>();
case 0x24: return opi_read_zero_page<&CPU::opf_bit>();
case 0x25: return opi_read_zero_page<&CPU::opf_and>();
case 0x26: return opi_rmw_zero_page<&CPU::opf_rol>();
case 0x28: return op_plp();
case 0x29: return opi_read_immediate<&CPU::opf_and>();
case 0x2a: return opi_shift<&CPU::opf_rla>();
case 0x2c: return opi_read_absolute<&CPU::opf_bit>();
case 0x2d: return opi_read_absolute<&CPU::opf_and>();
case 0x2e: return opi_rmw_absolute<&CPU::opf_rol>();
case 0x30: return opi_branch(regs.p.n == 1);
case 0x31: return opi_read_indirect_zero_page_y<&CPU::opf_and>();
I case 0x34: return opill_nop_zero_page_x();
case 0x35: return opi_read_zero_page_x<&CPU::opf_and>();
case 0x36: return opi_rmw_zero_page_x<&CPU::opf_rol>();
case 0x38: return opi_set_flag(regs.p.c);
case 0x39: return opi_read_absolute_y<&CPU::opf_and>();
I case 0x3a: return opill_nop_implied();
I case 0x3c: return opill_nop_absolute_x();
case 0x3d: return opi_read_absolute_x<&CPU::opf_and>();
case 0x3e: return opi_rmw_absolute_x<&CPU::opf_rol>();
case 0x40: return op_rti();
case 0x41: return opi_read_indirect_zero_page_x<&CPU::opf_eor>();
I case 0x44: return opill_nop_zero_page();
case 0x45: return opi_read_zero_page<&CPU::opf_eor>();
case 0x46: return opi_rmw_zero_page<&CPU::opf_lsr>();
case 0x48: return opi_push(regs.a);
case 0x49: return opi_read_immediate<&CPU::opf_eor>();
case 0x4a: return opi_shift<&CPU::opf_sra>();
case 0x4c: return op_jmp_absolute();
case 0x4d: return opi_read_absolute<&CPU::opf_eor>();
case 0x4e: return opi_rmw_absolute<&CPU::opf_lsr>();
case 0x50: return opi_branch(regs.p.v == 0);
case 0x51: return opi_read_indirect_zero_page_y<&CPU::opf_eor>();
I case 0x54: return opill_nop_zero_page_x();
case 0x55: return opi_read_zero_page_x<&CPU::opf_eor>();
case 0x56: return opi_rmw_zero_page_x<&CPU::opf_lsr>();
case 0x58: return opi_clear_flag(regs.p.i);
case 0x59: return opi_read_absolute_y<&CPU::opf_eor>();
I case 0x5a: return opill_nop_implied();
I case 0x5c: return opill_nop_absolute_x();
case 0x5d: return opi_read_absolute_x<&CPU::opf_eor>();
case 0x5e: return opi_rmw_absolute_x<&CPU::opf_lsr>();
case 0x60: return op_rts();
case 0x61: return opi_read_indirect_zero_page_x<&CPU::opf_adc>();
I case 0x64: return opill_nop_zero_page();
case 0x65: return opi_read_zero_page<&CPU::opf_adc>();
case 0x66: return opi_rmw_zero_page<&CPU::opf_ror>();
case 0x68: return opi_pull(regs.a);
case 0x69: return opi_read_immediate<&CPU::opf_adc>();
case 0x6a: return opi_shift<&CPU::opf_rra>();
I case 0x6b: return opill_arr_immediate();
case 0x6c: return op_jmp_indirect_absolute();
case 0x6d: return opi_read_absolute<&CPU::opf_adc>();
case 0x6e: return opi_rmw_absolute<&CPU::opf_ror>();
case 0x70: return opi_branch(regs.p.v == 1);
I case 0x74: return opill_nop_zero_page_x();
case 0x71: return opi_read_indirect_zero_page_y<&CPU::opf_adc>();
case 0x75: return opi_read_zero_page_x<&CPU::opf_adc>();
case 0x76: return opi_rmw_zero_page_x<&CPU::opf_ror>();
case 0x78: return opi_set_flag(regs.p.i);
case 0x79: return opi_read_absolute_y<&CPU::opf_adc>();
I case 0x7a: return opill_nop_implied();
I case 0x7c: return opill_nop_absolute_x();
case 0x7d: return opi_read_absolute_x<&CPU::opf_adc>();
case 0x7e: return opi_rmw_absolute_x<&CPU::opf_ror>();
I case 0x80: return opill_nop_absolute();
case 0x81: return opi_store_indirect_zero_page_x(regs.a);
I case 0x82: return opill_nop_immediate();
case 0x84: return opi_store_zero_page(regs.y);
case 0x85: return opi_store_zero_page(regs.a);
case 0x86: return opi_store_zero_page(regs.x);
case 0x88: return opi_decrement(regs.y);
I case 0x89: return opill_nop_immediate();
case 0x8a: return opi_transfer(regs.x, regs.a, 1);
case 0x8c: return opi_store_absolute(regs.y);
case 0x8d: return opi_store_absolute(regs.a);
case 0x8e: return opi_store_absolute(regs.x);
case 0x90: return opi_branch(regs.p.c == 0);
case 0x91: return opi_store_indirect_zero_page_y(regs.a);
case 0x94: return opi_store_zero_page_x(regs.y);
case 0x95: return opi_store_zero_page_x(regs.a);
case 0x96: return opi_store_zero_page_y(regs.x);
case 0x98: return opi_transfer(regs.y, regs.a, 1);
case 0x99: return opi_store_absolute_y(regs.a);
case 0x9a: return opi_transfer(regs.x, regs.s, 0);
case 0x9d: return opi_store_absolute_x(regs.a);
case 0xa0: return opi_read_immediate<&CPU::opf_ldy>();
case 0xa1: return opi_read_indirect_zero_page_x<&CPU::opf_lda>();
case 0xa2: return opi_read_immediate<&CPU::opf_ldx>();
case 0xa4: return opi_read_zero_page<&CPU::opf_ldy>();
case 0xa5: return opi_read_zero_page<&CPU::opf_lda>();
case 0xa6: return opi_read_zero_page<&CPU::opf_ldx>();
case 0xa8: return opi_transfer(regs.a, regs.y, 1);
case 0xa9: return opi_read_immediate<&CPU::opf_lda>();
case 0xaa: return opi_transfer(regs.a, regs.x, 1);
case 0xac: return opi_read_absolute<&CPU::opf_ldy>();
case 0xad: return opi_read_absolute<&CPU::opf_lda>();
case 0xae: return opi_read_absolute<&CPU::opf_ldx>();
case 0xb0: return opi_branch(regs.p.c == 1);
case 0xb1: return opi_read_indirect_zero_page_y<&CPU::opf_lda>();
case 0xb4: return opi_read_zero_page_x<&CPU::opf_ldy>();
case 0xb5: return opi_read_zero_page_x<&CPU::opf_lda>();
case 0xb6: return opi_read_zero_page_y<&CPU::opf_ldx>();
case 0xb8: return opi_clear_flag(regs.p.v);
case 0xb9: return opi_read_absolute_y<&CPU::opf_lda>();
case 0xba: return opi_transfer(regs.s, regs.x, 1);
case 0xbc: return opi_read_absolute_x<&CPU::opf_ldy>();
case 0xbd: return opi_read_absolute_x<&CPU::opf_lda>();
case 0xbe: return opi_read_absolute_y<&CPU::opf_ldx>();
case 0xc0: return opi_read_immediate<&CPU::opf_cpy>();
case 0xc1: return opi_read_indirect_zero_page_x<&CPU::opf_cmp>();
I case 0xc2: return opill_nop_immediate();
case 0xc4: return opi_read_zero_page<&CPU::opf_cpy>();
case 0xc5: return opi_read_zero_page<&CPU::opf_cmp>();
case 0xc6: return opi_rmw_zero_page<&CPU::opf_dec>();
case 0xc8: return opi_increment(regs.y);
case 0xc9: return opi_read_immediate<&CPU::opf_cmp>();
case 0xca: return opi_decrement(regs.x);
case 0xcc: return opi_read_absolute<&CPU::opf_cpy>();
case 0xcd: return opi_read_absolute<&CPU::opf_cmp>();
case 0xce: return opi_rmw_absolute<&CPU::opf_dec>();
case 0xd0: return opi_branch(regs.p.z == 0);
case 0xd1: return opi_read_indirect_zero_page_y<&CPU::opf_cmp>();
I case 0xd4: return opill_nop_zero_page_x();
case 0xd5: return opi_read_zero_page_x<&CPU::opf_cmp>();
case 0xd6: return opi_rmw_zero_page_x<&CPU::opf_dec>();
case 0xd8: return opi_clear_flag(regs.p.d);
case 0xd9: return opi_read_absolute_y<&CPU::opf_cmp>();
I case 0xda: return opill_nop_implied();
I case 0xdc: return opill_nop_absolute_x();
case 0xdd: return opi_read_absolute_x<&CPU::opf_cmp>();
case 0xde: return opi_rmw_absolute_x<&CPU::opf_dec>();
case 0xe0: return opi_read_immediate<&CPU::opf_cpx>();
case 0xe1: return opi_read_indirect_zero_page_x<&CPU::opf_sbc>();
I case 0xe2: return opill_nop_immediate();
case 0xe4: return opi_read_zero_page<&CPU::opf_cpx>();
case 0xe5: return opi_read_zero_page<&CPU::opf_sbc>();
case 0xe6: return opi_rmw_zero_page<&CPU::opf_inc>();
case 0xe8: return opi_increment(regs.x);
case 0xe9: return opi_read_immediate<&CPU::opf_sbc>();
case 0xea: return op_nop();
I case 0xeb: return opi_read_immediate<&CPU::opf_sbc>();
case 0xec: return opi_read_absolute<&CPU::opf_cpx>();
case 0xed: return opi_read_absolute<&CPU::opf_sbc>();
case 0xee: return opi_rmw_absolute<&CPU::opf_inc>();
case 0xf0: return opi_branch(regs.p.z == 1);
case 0xf1: return opi_read_indirect_zero_page_y<&CPU::opf_sbc>();
I case 0xf4: return opill_nop_zero_page_x();
case 0xf5: return opi_read_zero_page_x<&CPU::opf_sbc>();
case 0xf6: return opi_rmw_zero_page_x<&CPU::opf_inc>();
case 0xf8: return opi_set_flag(regs.p.d);
case 0xf9: return opi_read_absolute_y<&CPU::opf_sbc>();
I case 0xfa: return opill_nop_implied();
I case 0xfc: return opill_nop_absolute_x();
case 0xfd: return opi_read_absolute_x<&CPU::opf_sbc>();
case 0xfe: return opi_rmw_absolute_x<&CPU::opf_inc>();
}
//return op_nop();
regs.pc--;
print("Unimplemented opcode: ", hex<4>(regs.pc), " = ", hex<2>(bus.read(regs.pc)), "\n");
while(true) scheduler.exit(Scheduler::ExitReason::UnknownEvent);
}
#undef I

View File

@ -1,37 +0,0 @@
void CPU::interrupt() {
op_readpc();
op_readpc();
op_writesp(regs.pc >> 8);
op_writesp(regs.pc >> 0);
op_writesp(regs.p | 0x20);
uint16 vector = 0xfffe; //IRQ
if(status.nmi_pending) {
status.nmi_pending = false;
vector = 0xfffa;
}
abs.l = op_read(vector++);
regs.p.i = 1;
regs.p.d = 0;
L abs.h = op_read(vector++);
regs.pc = abs.w;
}
void CPU::interrupt_test() {
status.interrupt_pending = ((status.irq_line | status.irq_apu_line) & ~regs.p.i) | status.nmi_pending;
}
void CPU::set_nmi_line(bool line) {
//edge-sensitive (0->1)
if(!status.nmi_line && line) status.nmi_pending = true;
status.nmi_line = line;
}
void CPU::set_irq_line(bool line) {
//level-sensitive
status.irq_line = line;
}
void CPU::set_irq_apu_line(bool line) {
//level-sensitive
status.irq_apu_line = line;
}

View File

@ -2,39 +2,29 @@
namespace Famicom { namespace Famicom {
#include "core/core.cpp" #include "timing.cpp"
#include "memory/memory.cpp"
#include "serialization.cpp" #include "serialization.cpp"
CPU cpu; CPU cpu;
void CPU::Main() { void CPU::Enter() {
cpu.main();
}
void CPU::main() {
//trace = true;
//FILE *fp = fopen("/home/byuu/Desktop/log.txt", "wb");
unsigned lpc = 0xffff;
while(true) { while(true) {
if(scheduler.sync == Scheduler::SynchronizeMode::All) { if(scheduler.sync == Scheduler::SynchronizeMode::All) {
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
} }
if(status.interrupt_pending) { cpu.main();
interrupt();
continue;
}
if(trace) {
if(lpc != regs.pc) { print(disassemble(), "\n"); } lpc = regs.pc;
//if(lpc != regs.pc) { fprintf(fp, "%s\n", (const char*)disassemble()); fflush(fp); } lpc = regs.pc;
}
op_exec();
} }
} }
void CPU::main() {
if(status.interrupt_pending) {
interrupt();
return;
}
exec();
}
void CPU::add_clocks(unsigned clocks) { void CPU::add_clocks(unsigned clocks) {
apu.clock -= clocks; apu.clock -= clocks;
if(apu.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(apu.thread); if(apu.clock < 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(apu.thread);
@ -47,11 +37,7 @@ void CPU::add_clocks(unsigned clocks) {
} }
void CPU::power() { void CPU::power() {
regs.a = 0x00; RP2A03::power();
regs.x = 0x00;
regs.y = 0x00;
regs.s = 0x00;
regs.p = 0x04;
for(unsigned addr = 0; addr < 0x0800; addr++) ram[addr] = 0xff; for(unsigned addr = 0; addr < 0x0800; addr++) ram[addr] = 0xff;
ram[0x0008] = 0xf7; ram[0x0008] = 0xf7;
@ -61,11 +47,8 @@ void CPU::power() {
} }
void CPU::reset() { void CPU::reset() {
create(CPU::Main, 21477272); RP2A03::reset();
create(CPU::Enter, 21477272);
regs.mdr = 0x00;
regs.s -= 3;
regs.p.i = 1;
regs.pc = bus.read(0xfffc) << 0; regs.pc = bus.read(0xfffc) << 0;
regs.pc |= bus.read(0xfffd) << 8; regs.pc |= bus.read(0xfffd) << 8;
@ -87,16 +70,8 @@ void CPU::reset() {
status.controller_port1 = 0; status.controller_port1 = 0;
} }
uint8 CPU::mdr() const { uint8 CPU::debugger_read(uint16 addr) {
return regs.mdr; return bus.read(addr);
}
void CPU::set_rdy_line(bool line) {
status.rdy_line = line;
}
void CPU::set_rdy_addr(optional<uint16> addr) {
status.rdy_addr = addr;
} }
uint8 CPU::ram_read(uint16 addr) { uint8 CPU::ram_read(uint16 addr) {
@ -132,11 +107,4 @@ void CPU::write(uint16 addr, uint8 data) {
return apu.write(addr, data); return apu.write(addr, data);
} }
void CPU::oam_dma() {
for(unsigned n = 0; n < 256; n++) {
uint8 data = op_read((status.oam_dma_page << 8) + n);
op_write(0x2004, data);
}
}
} }

View File

@ -1,6 +1,4 @@
struct CPU : Thread { struct CPU : Processor::RP2A03, Thread {
#include "core/core.hpp"
#include "memory/memory.hpp"
uint8 ram[0x0800]; uint8 ram[0x0800];
struct Status { struct Status {
@ -21,16 +19,14 @@ struct CPU : Thread {
unsigned controller_port1; unsigned controller_port1;
} status; } status;
static void Main(); static void Enter();
void main(); void main();
void add_clocks(unsigned clocks); void add_clocks(unsigned clocks);
void power(); void power();
void reset(); void reset();
uint8 mdr() const; uint8 debugger_read(uint16 addr);
void set_rdy_line(bool);
void set_rdy_addr(optional<uint16>);
uint8 ram_read(uint16 addr); uint8 ram_read(uint16 addr);
void ram_write(uint16 addr, uint8 data); void ram_write(uint16 addr, uint8 data);
@ -38,12 +34,22 @@ struct CPU : Thread {
uint8 read(uint16 addr); uint8 read(uint16 addr);
void write(uint16 addr, uint8 data); void write(uint16 addr, uint8 data);
void oam_dma();
void serialize(serializer&); void serialize(serializer&);
//internal: //timing.cpp
bool trace; uint8 op_read(uint16 addr);
void op_write(uint16 addr, uint8 data);
void last_cycle();
void nmi(uint16 &vector);
void oam_dma();
void set_nmi_line(bool);
void set_irq_line(bool);
void set_irq_apu_line(bool);
void set_rdy_line(bool);
void set_rdy_addr(optional<uint16>);
}; };
extern CPU cpu; extern CPU cpu;

View File

@ -1,59 +0,0 @@
uint8 CPU::op_read(uint16 addr) {
if(status.oam_dma_pending) {
status.oam_dma_pending = false;
op_read(addr);
oam_dma();
}
while(status.rdy_line == 0) {
regs.mdr = bus.read(status.rdy_addr ? status.rdy_addr() : addr);
add_clocks(12);
}
regs.mdr = bus.read(addr);
add_clocks(12);
return regs.mdr;
}
void CPU::op_write(uint16 addr, uint8 data) {
bus.write(addr, regs.mdr = data);
add_clocks(12);
}
//
uint8 CPU::op_readpc() {
return op_read(regs.pc);
}
uint8 CPU::op_readpci() {
return op_read(regs.pc++);
}
uint8 CPU::op_readsp() {
return op_read(0x0100 | ++regs.s);
}
uint8 CPU::op_readzp(uint8 addr) {
return op_read(addr);
}
//
void CPU::op_writesp(uint8 data) {
op_write(0x0100 | regs.s--, data);
}
void CPU::op_writezp(uint8 addr, uint8 data) {
op_write(addr, data);
}
//
void CPU::op_page(uint16 x, uint16 y) {
if((x & 0xff00) != (y & 0xff00)) op_read((x & 0xff00) | (y & 0x00ff));
}
void CPU::op_page_always(uint16 x, uint16 y) {
op_read((x & 0xff00) | (y & 0x00ff));
}

View File

@ -1,13 +0,0 @@
uint8 op_read(uint16 addr);
void op_write(uint16 addr, uint8 data);
uint8 op_readpc();
uint8 op_readpci();
uint8 op_readsp();
uint8 op_readzp(uint8 addr);
void op_writesp(uint8 data);
void op_writezp(uint8 addr, uint8 data);
void op_page(uint16 x, uint16 y);
void op_page_always(uint16 x, uint16 y);

View File

@ -1,27 +1,9 @@
void CPU::serialize(serializer &s) { void CPU::serialize(serializer &s) {
RP2A03::serialize(s);
Thread::serialize(s); Thread::serialize(s);
s.array(ram); s.array(ram);
s.integer(regs.mdr);
s.integer(regs.pc);
s.integer(regs.a);
s.integer(regs.x);
s.integer(regs.y);
s.integer(regs.s);
s.integer(regs.p.n);
s.integer(regs.p.v);
s.integer(regs.p.d);
s.integer(regs.p.i);
s.integer(regs.p.z);
s.integer(regs.p.c);
s.integer(abs.w);
s.integer(iabs.w);
s.integer(rd);
s.integer(zp);
s.integer(aa);
s.integer(status.interrupt_pending); s.integer(status.interrupt_pending);
s.integer(status.nmi_pending); s.integer(status.nmi_pending);
s.integer(status.nmi_line); s.integer(status.nmi_line);

63
bsnes/nes/cpu/timing.cpp Executable file
View File

@ -0,0 +1,63 @@
uint8 CPU::op_read(uint16 addr) {
if(status.oam_dma_pending) {
status.oam_dma_pending = false;
op_read(addr);
oam_dma();
}
while(status.rdy_line == 0) {
regs.mdr = bus.read(status.rdy_addr ? status.rdy_addr() : addr);
add_clocks(12);
}
regs.mdr = bus.read(addr);
add_clocks(12);
return regs.mdr;
}
void CPU::op_write(uint16 addr, uint8 data) {
bus.write(addr, regs.mdr = data);
add_clocks(12);
}
void CPU::last_cycle() {
status.interrupt_pending = ((status.irq_line | status.irq_apu_line) & ~regs.p.i) | status.nmi_pending;
}
void CPU::nmi(uint16 &vector) {
if(status.nmi_pending) {
status.nmi_pending = false;
vector = 0xfffa;
}
}
void CPU::oam_dma() {
for(unsigned n = 0; n < 256; n++) {
uint8 data = op_read((status.oam_dma_page << 8) + n);
op_write(0x2004, data);
}
}
void CPU::set_nmi_line(bool line) {
//edge-sensitive (0->1)
if(!status.nmi_line && line) status.nmi_pending = true;
status.nmi_line = line;
}
void CPU::set_irq_line(bool line) {
//level-sensitive
status.irq_line = line;
}
void CPU::set_irq_apu_line(bool line) {
//level-sensitive
status.irq_apu_line = line;
}
void CPU::set_rdy_line(bool line) {
status.rdy_line = line;
}
void CPU::set_rdy_addr(optional<uint16> addr) {
status.rdy_addr = addr;
}

View File

@ -23,8 +23,4 @@ void Interface::message(const string &text) {
print(text, "\n"); print(text, "\n");
} }
void Interface::loadCartridge(const string &markup, const stream &memory) {
cartridge.load(markup, memory.data(), memory.size());
}
} }

View File

@ -3,9 +3,8 @@ struct Interface {
virtual void videoRefresh(const uint32_t *data); virtual void videoRefresh(const uint32_t *data);
virtual void audioSample(int16_t sample); virtual void audioSample(int16_t sample);
virtual int16_t inputPoll(bool port, unsigned device, unsigned id); virtual int16_t inputPoll(bool port, unsigned device, unsigned id);
virtual void message(const string &text);
void loadCartridge(const string &markup, const stream &memory); virtual void message(const string &text);
}; };
extern Interface *interface; extern Interface *interface;

View File

@ -2,6 +2,7 @@
#define NES_HPP #define NES_HPP
#include <base/base.hpp> #include <base/base.hpp>
#include <processor/rp2a03/rp2a03.hpp>
namespace Famicom { namespace Famicom {
namespace Info { namespace Info {

View File

@ -2,6 +2,7 @@ processor_objects :=
processor_objects += $(if $(findstring arm,$(processors)),processor-arm) processor_objects += $(if $(findstring arm,$(processors)),processor-arm)
processor_objects += $(if $(findstring hg51b,$(processors)),processor-hg51b) processor_objects += $(if $(findstring hg51b,$(processors)),processor-hg51b)
processor_objects += $(if $(findstring lr35902,$(processors)),processor-lr35902) processor_objects += $(if $(findstring lr35902,$(processors)),processor-lr35902)
processor_objects += $(if $(findstring rp2a03,$(processors)),processor-rp2a03)
processor_objects += $(if $(findstring upd96050,$(processors)),processor-upd96050) processor_objects += $(if $(findstring upd96050,$(processors)),processor-upd96050)
objects += $(processor_objects) objects += $(processor_objects)
@ -9,4 +10,5 @@ processor := processor
obj/processor-arm.o: $(processor)/arm/arm.cpp $(call rwildcard,$(processor)/arm) obj/processor-arm.o: $(processor)/arm/arm.cpp $(call rwildcard,$(processor)/arm)
obj/processor-hg51b.o: $(processor)/hg51b/hg51b.cpp $(call rwildcard,$(processor)/hg51b) obj/processor-hg51b.o: $(processor)/hg51b/hg51b.cpp $(call rwildcard,$(processor)/hg51b)
obj/processor-lr35902.o: $(processor)/lr35902/lr35902.cpp $(call rwildcard,$(processor)/lr35902) obj/processor-lr35902.o: $(processor)/lr35902/lr35902.cpp $(call rwildcard,$(processor)/lr35902)
obj/processor-rp2a03.o: $(processor)/rp2a03/rp2a03.cpp $(call rwildcard,$(processor)/rp2a03)
obj/processor-upd96050.o: $(processor)/upd96050/upd96050.cpp $(call rwildcard,$(processor)/upd96050) obj/processor-upd96050.o: $(processor)/upd96050/upd96050.cpp $(call rwildcard,$(processor)/upd96050)

View File

@ -1,24 +1,24 @@
string CPU::disassemble() { string RP2A03::disassemble() {
string output = { hex<4>(regs.pc), " " }; string output = { hex<4>(regs.pc), " " };
auto abs = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 2)), hex<2>(bus.read(regs.pc + 1)) }; }; auto abs = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 2)), hex<2>(debugger_read(regs.pc + 1)) }; };
auto abx = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 2)), hex<2>(bus.read(regs.pc + 1)), ",x" }; }; auto abx = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 2)), hex<2>(debugger_read(regs.pc + 1)), ",x" }; };
auto aby = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 2)), hex<2>(bus.read(regs.pc + 1)), ",y" }; }; auto aby = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 2)), hex<2>(debugger_read(regs.pc + 1)), ",y" }; };
auto iab = [&]() -> string { return { "($", hex<2>(bus.read(regs.pc + 2)), hex<2>(bus.read(regs.pc + 1)), ")" }; }; auto iab = [&]() -> string { return { "($", hex<2>(debugger_read(regs.pc + 2)), hex<2>(debugger_read(regs.pc + 1)), ")" }; };
auto imm = [&]() -> string { return { "#$", hex<2>(bus.read(regs.pc + 1)) }; }; auto imm = [&]() -> string { return { "#$", hex<2>(debugger_read(regs.pc + 1)) }; };
auto imp = [&]() -> string { return ""; }; auto imp = [&]() -> string { return ""; };
auto izx = [&]() -> string { return { "($", hex<2>(bus.read(regs.pc + 1)), ",x)" }; }; auto izx = [&]() -> string { return { "($", hex<2>(debugger_read(regs.pc + 1)), ",x)" }; };
auto izy = [&]() -> string { return { "($", hex<2>(bus.read(regs.pc + 1)), "),y" }; }; auto izy = [&]() -> string { return { "($", hex<2>(debugger_read(regs.pc + 1)), "),y" }; };
auto rel = [&]() -> string { return { "$", hex<4>((regs.pc + 2) + (int8)bus.read(regs.pc + 1)) }; }; auto rel = [&]() -> string { return { "$", hex<4>((regs.pc + 2) + (int8)debugger_read(regs.pc + 1)) }; };
auto zpg = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 1)) }; }; auto zpg = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 1)) }; };
auto zpx = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 1)), ",x" }; }; auto zpx = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 1)), ",x" }; };
auto zpy = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 1)), ",y" }; }; auto zpy = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 1)), ",y" }; };
#define op(byte, prefix, mode) \ #define op(byte, prefix, mode) \
case byte: output.append(#prefix, " ", mode()); \ case byte: output.append(#prefix, " ", mode()); \
break break
uint8 opcode = bus.read(regs.pc); uint8 opcode = debugger_read(regs.pc);
switch(opcode) { switch(opcode) {
op(0x00, brk, imm); op(0x00, brk, imm);
op(0x01, ora, izx); op(0x01, ora, izx);

View File

@ -1,7 +1,7 @@
//opcode functions //opcode functions
//================ //================
void CPU::opf_adc() { void RP2A03::opf_adc() {
signed result = regs.a + rd + regs.p.c; signed result = regs.a + rd + regs.p.c;
regs.p.v = ~(regs.a ^ rd) & (regs.a ^ result) & 0x80; regs.p.v = ~(regs.a ^ rd) & (regs.a ^ result) & 0x80;
regs.p.c = (result > 0xff); regs.p.c = (result > 0xff);
@ -10,96 +10,96 @@ void CPU::opf_adc() {
regs.a = result; regs.a = result;
} }
void CPU::opf_and() { void RP2A03::opf_and() {
regs.a &= rd; regs.a &= rd;
regs.p.n = (regs.a & 0x80); regs.p.n = (regs.a & 0x80);
regs.p.z = (regs.a == 0); regs.p.z = (regs.a == 0);
} }
void CPU::opf_asl() { void RP2A03::opf_asl() {
regs.p.c = rd & 0x80; regs.p.c = rd & 0x80;
rd <<= 1; rd <<= 1;
regs.p.n = (rd & 0x80); regs.p.n = (rd & 0x80);
regs.p.z = (rd == 0); regs.p.z = (rd == 0);
} }
void CPU::opf_bit() { void RP2A03::opf_bit() {
regs.p.n = (rd & 0x80); regs.p.n = (rd & 0x80);
regs.p.v = (rd & 0x40); regs.p.v = (rd & 0x40);
regs.p.z = ((rd & regs.a) == 0); regs.p.z = ((rd & regs.a) == 0);
} }
void CPU::opf_cmp() { void RP2A03::opf_cmp() {
signed r = regs.a - rd; signed r = regs.a - rd;
regs.p.n = (r & 0x80); regs.p.n = (r & 0x80);
regs.p.z = (uint8)(r == 0); regs.p.z = (uint8)(r == 0);
regs.p.c = (r >= 0); regs.p.c = (r >= 0);
} }
void CPU::opf_cpx() { void RP2A03::opf_cpx() {
signed r = regs.x - rd; signed r = regs.x - rd;
regs.p.n = (r & 0x80); regs.p.n = (r & 0x80);
regs.p.z = (uint8)(r == 0); regs.p.z = (uint8)(r == 0);
regs.p.c = (r >= 0); regs.p.c = (r >= 0);
} }
void CPU::opf_cpy() { void RP2A03::opf_cpy() {
signed r = regs.y - rd; signed r = regs.y - rd;
regs.p.n = (r & 0x80); regs.p.n = (r & 0x80);
regs.p.z = (uint8)(r == 0); regs.p.z = (uint8)(r == 0);
regs.p.c = (r >= 0); regs.p.c = (r >= 0);
} }
void CPU::opf_dec() { void RP2A03::opf_dec() {
rd--; rd--;
regs.p.n = (rd & 0x80); regs.p.n = (rd & 0x80);
regs.p.z = (rd == 0); regs.p.z = (rd == 0);
} }
void CPU::opf_eor() { void RP2A03::opf_eor() {
regs.a ^= rd; regs.a ^= rd;
regs.p.n = (regs.a & 0x80); regs.p.n = (regs.a & 0x80);
regs.p.z = (regs.a == 0); regs.p.z = (regs.a == 0);
} }
void CPU::opf_inc() { void RP2A03::opf_inc() {
rd++; rd++;
regs.p.n = (rd & 0x80); regs.p.n = (rd & 0x80);
regs.p.z = (rd == 0); regs.p.z = (rd == 0);
} }
void CPU::opf_lda() { void RP2A03::opf_lda() {
regs.a = rd; regs.a = rd;
regs.p.n = (regs.a & 0x80); regs.p.n = (regs.a & 0x80);
regs.p.z = (regs.a == 0); regs.p.z = (regs.a == 0);
} }
void CPU::opf_ldx() { void RP2A03::opf_ldx() {
regs.x = rd; regs.x = rd;
regs.p.n = (regs.x & 0x80); regs.p.n = (regs.x & 0x80);
regs.p.z = (regs.x == 0); regs.p.z = (regs.x == 0);
} }
void CPU::opf_ldy() { void RP2A03::opf_ldy() {
regs.y = rd; regs.y = rd;
regs.p.n = (regs.y & 0x80); regs.p.n = (regs.y & 0x80);
regs.p.z = (regs.y == 0); regs.p.z = (regs.y == 0);
} }
void CPU::opf_lsr() { void RP2A03::opf_lsr() {
regs.p.c = rd & 0x01; regs.p.c = rd & 0x01;
rd >>= 1; rd >>= 1;
regs.p.n = (rd & 0x80); regs.p.n = (rd & 0x80);
regs.p.z = (rd == 0); regs.p.z = (rd == 0);
} }
void CPU::opf_ora() { void RP2A03::opf_ora() {
regs.a |= rd; regs.a |= rd;
regs.p.n = (regs.a & 0x80); regs.p.n = (regs.a & 0x80);
regs.p.z = (regs.a == 0); regs.p.z = (regs.a == 0);
} }
void CPU::opf_rla() { void RP2A03::opf_rla() {
unsigned carry = (unsigned)regs.p.c; unsigned carry = (unsigned)regs.p.c;
regs.p.c = regs.a & 0x80; regs.p.c = regs.a & 0x80;
regs.a = (regs.a << 1) | carry; regs.a = (regs.a << 1) | carry;
@ -107,7 +107,7 @@ void CPU::opf_rla() {
regs.p.z = (regs.a == 0); regs.p.z = (regs.a == 0);
} }
void CPU::opf_rol() { void RP2A03::opf_rol() {
unsigned carry = (unsigned)regs.p.c; unsigned carry = (unsigned)regs.p.c;
regs.p.c = rd & 0x80; regs.p.c = rd & 0x80;
rd = (rd << 1) | carry; rd = (rd << 1) | carry;
@ -115,7 +115,7 @@ void CPU::opf_rol() {
regs.p.z = (rd == 0); regs.p.z = (rd == 0);
} }
void CPU::opf_ror() { void RP2A03::opf_ror() {
unsigned carry = (unsigned)regs.p.c << 7; unsigned carry = (unsigned)regs.p.c << 7;
regs.p.c = rd & 0x01; regs.p.c = rd & 0x01;
rd = carry | (rd >> 1); rd = carry | (rd >> 1);
@ -123,7 +123,7 @@ void CPU::opf_ror() {
regs.p.z = (rd == 0); regs.p.z = (rd == 0);
} }
void CPU::opf_rra() { void RP2A03::opf_rra() {
unsigned carry = (unsigned)regs.p.c << 7; unsigned carry = (unsigned)regs.p.c << 7;
regs.p.c = regs.a & 0x01; regs.p.c = regs.a & 0x01;
regs.a = carry | (regs.a >> 1); regs.a = carry | (regs.a >> 1);
@ -131,19 +131,19 @@ void CPU::opf_rra() {
regs.p.z = (regs.a == 0); regs.p.z = (regs.a == 0);
} }
void CPU::opf_sbc() { void RP2A03::opf_sbc() {
rd ^= 0xff; rd ^= 0xff;
return opf_adc(); return opf_adc();
} }
void CPU::opf_sla() { void RP2A03::opf_sla() {
regs.p.c = regs.a & 0x80; regs.p.c = regs.a & 0x80;
regs.a <<= 1; regs.a <<= 1;
regs.p.n = (regs.a & 0x80); regs.p.n = (regs.a & 0x80);
regs.p.z = (regs.a == 0); regs.p.z = (regs.a == 0);
} }
void CPU::opf_sra() { void RP2A03::opf_sra() {
regs.p.c = regs.a & 0x01; regs.p.c = regs.a & 0x01;
regs.a >>= 1; regs.a >>= 1;
regs.p.n = (regs.a & 0x80); regs.p.n = (regs.a & 0x80);
@ -153,7 +153,7 @@ void CPU::opf_sra() {
//opcode implementations //opcode implementations
//====================== //======================
void CPU::opi_branch(bool condition) { void RP2A03::opi_branch(bool condition) {
if(condition == false) { if(condition == false) {
L rd = op_readpci(); L rd = op_readpci();
} else { } else {
@ -165,26 +165,26 @@ L op_readpc();
} }
} }
void CPU::opi_clear_flag(bool &flag) { void RP2A03::opi_clear_flag(bool &flag) {
L op_readpc(); L op_readpc();
flag = 0; flag = 0;
} }
void CPU::opi_decrement(uint8 &r) { void RP2A03::opi_decrement(uint8 &r) {
L op_readpc(); L op_readpc();
r--; r--;
regs.p.n = (r & 0x80); regs.p.n = (r & 0x80);
regs.p.z = (r == 0); regs.p.z = (r == 0);
} }
void CPU::opi_increment(uint8 &r) { void RP2A03::opi_increment(uint8 &r) {
L op_readpc(); L op_readpc();
r++; r++;
regs.p.n = (r & 0x80); regs.p.n = (r & 0x80);
regs.p.z = (r == 0); regs.p.z = (r == 0);
} }
void CPU::opi_pull(uint8 &r) { void RP2A03::opi_pull(uint8 &r) {
op_readpc(); op_readpc();
op_readpc(); op_readpc();
L r = op_readsp(); L r = op_readsp();
@ -192,21 +192,21 @@ L r = op_readsp();
regs.p.z = (r == 0); regs.p.z = (r == 0);
} }
void CPU::opi_push(uint8 &r) { void RP2A03::opi_push(uint8 &r) {
op_readpc(); op_readpc();
L op_writesp(r); L op_writesp(r);
} }
template<void (CPU::*op)()> template<void (RP2A03::*op)()>
void CPU::opi_read_absolute() { void RP2A03::opi_read_absolute() {
abs.l = op_readpci(); abs.l = op_readpci();
abs.h = op_readpci(); abs.h = op_readpci();
L rd = op_read(abs.w); L rd = op_read(abs.w);
call(op); call(op);
} }
template<void (CPU::*op)()> template<void (RP2A03::*op)()>
void CPU::opi_read_absolute_x() { void RP2A03::opi_read_absolute_x() {
abs.l = op_readpci(); abs.l = op_readpci();
abs.h = op_readpci(); abs.h = op_readpci();
op_page(abs.w, abs.w + regs.x); op_page(abs.w, abs.w + regs.x);
@ -214,8 +214,8 @@ L rd = op_read(abs.w + regs.x);
call(op); call(op);
} }
template<void (CPU::*op)()> template<void (RP2A03::*op)()>
void CPU::opi_read_absolute_y() { void RP2A03::opi_read_absolute_y() {
abs.l = op_readpci(); abs.l = op_readpci();
abs.h = op_readpci(); abs.h = op_readpci();
op_page(abs.w, abs.w + regs.y); op_page(abs.w, abs.w + regs.y);
@ -223,14 +223,14 @@ L rd = op_read(abs.w + regs.y);
call(op); call(op);
} }
template<void (CPU::*op)()> template<void (RP2A03::*op)()>
void CPU::opi_read_immediate() { void RP2A03::opi_read_immediate() {
L rd = op_readpci(); L rd = op_readpci();
call(op); call(op);
} }
template<void (CPU::*op)()> template<void (RP2A03::*op)()>
void CPU::opi_read_indirect_zero_page_x() { void RP2A03::opi_read_indirect_zero_page_x() {
zp = op_readpci(); zp = op_readpci();
op_readzp(zp); op_readzp(zp);
abs.l = op_readzp(zp++ + regs.x); abs.l = op_readzp(zp++ + regs.x);
@ -239,8 +239,8 @@ L rd = op_read(abs.w);
call(op); call(op);
} }
template<void (CPU::*op)()> template<void (RP2A03::*op)()>
void CPU::opi_read_indirect_zero_page_y() { void RP2A03::opi_read_indirect_zero_page_y() {
rd = op_readpci(); rd = op_readpci();
abs.l = op_readzp(rd++); abs.l = op_readzp(rd++);
abs.h = op_readzp(rd++); abs.h = op_readzp(rd++);
@ -249,31 +249,31 @@ L rd = op_read(abs.w + regs.y);
call(op); call(op);
} }
template<void (CPU::*op)()> template<void (RP2A03::*op)()>
void CPU::opi_read_zero_page() { void RP2A03::opi_read_zero_page() {
zp = op_readpci(); zp = op_readpci();
L rd = op_readzp(zp); L rd = op_readzp(zp);
call(op); call(op);
} }
template<void (CPU::*op)()> template<void (RP2A03::*op)()>
void CPU::opi_read_zero_page_x() { void RP2A03::opi_read_zero_page_x() {
zp = op_readpci(); zp = op_readpci();
op_readzp(zp); op_readzp(zp);
L rd = op_readzp(zp + regs.x); L rd = op_readzp(zp + regs.x);
call(op); call(op);
} }
template<void (CPU::*op)()> template<void (RP2A03::*op)()>
void CPU::opi_read_zero_page_y() { void RP2A03::opi_read_zero_page_y() {
zp = op_readpci(); zp = op_readpci();
op_readzp(zp); op_readzp(zp);
L rd = op_readzp(zp + regs.y); L rd = op_readzp(zp + regs.y);
call(op); call(op);
} }
template<void (CPU::*op)()> template<void (RP2A03::*op)()>
void CPU::opi_rmw_absolute() { void RP2A03::opi_rmw_absolute() {
abs.l = op_readpci(); abs.l = op_readpci();
abs.h = op_readpci(); abs.h = op_readpci();
rd = op_read(abs.w); rd = op_read(abs.w);
@ -282,8 +282,8 @@ void CPU::opi_rmw_absolute() {
L op_write(abs.w, rd); L op_write(abs.w, rd);
} }
template<void (CPU::*op)()> template<void (RP2A03::*op)()>
void CPU::opi_rmw_absolute_x() { void RP2A03::opi_rmw_absolute_x() {
abs.l = op_readpci(); abs.l = op_readpci();
abs.h = op_readpci(); abs.h = op_readpci();
op_page_always(abs.w, abs.w + regs.x); op_page_always(abs.w, abs.w + regs.x);
@ -293,8 +293,8 @@ void CPU::opi_rmw_absolute_x() {
L op_write(abs.w + regs.x, rd); L op_write(abs.w + regs.x, rd);
} }
template<void (CPU::*op)()> template<void (RP2A03::*op)()>
void CPU::opi_rmw_zero_page() { void RP2A03::opi_rmw_zero_page() {
zp = op_readpci(); zp = op_readpci();
rd = op_readzp(zp); rd = op_readzp(zp);
op_writezp(zp, rd); op_writezp(zp, rd);
@ -302,8 +302,8 @@ void CPU::opi_rmw_zero_page() {
L op_writezp(zp, rd); L op_writezp(zp, rd);
} }
template<void (CPU::*op)()> template<void (RP2A03::*op)()>
void CPU::opi_rmw_zero_page_x() { void RP2A03::opi_rmw_zero_page_x() {
zp = op_readpci(); zp = op_readpci();
op_readzp(zp); op_readzp(zp);
rd = op_readzp(zp + regs.x); rd = op_readzp(zp + regs.x);
@ -312,38 +312,38 @@ void CPU::opi_rmw_zero_page_x() {
L op_writezp(zp + regs.x, rd); L op_writezp(zp + regs.x, rd);
} }
void CPU::opi_set_flag(bool &flag) { void RP2A03::opi_set_flag(bool &flag) {
L op_readpc(); L op_readpc();
flag = 1; flag = 1;
} }
template<void (CPU::*op)()> template<void (RP2A03::*op)()>
void CPU::opi_shift() { void RP2A03::opi_shift() {
L op_readpc(); L op_readpc();
call(op); call(op);
} }
void CPU::opi_store_absolute(uint8 &r) { void RP2A03::opi_store_absolute(uint8 &r) {
abs.l = op_readpci(); abs.l = op_readpci();
abs.h = op_readpci(); abs.h = op_readpci();
L op_write(abs.w, r); L op_write(abs.w, r);
} }
void CPU::opi_store_absolute_x(uint8 &r) { void RP2A03::opi_store_absolute_x(uint8 &r) {
abs.l = op_readpci(); abs.l = op_readpci();
abs.h = op_readpci(); abs.h = op_readpci();
op_page_always(abs.w, abs.w + regs.x); op_page_always(abs.w, abs.w + regs.x);
L op_write(abs.w + regs.x, r); L op_write(abs.w + regs.x, r);
} }
void CPU::opi_store_absolute_y(uint8 &r) { void RP2A03::opi_store_absolute_y(uint8 &r) {
abs.l = op_readpci(); abs.l = op_readpci();
abs.h = op_readpci(); abs.h = op_readpci();
op_page_always(abs.w, abs.w + regs.y); op_page_always(abs.w, abs.w + regs.y);
L op_write(abs.w + regs.y, r); L op_write(abs.w + regs.y, r);
} }
void CPU::opi_store_indirect_zero_page_x(uint8 &r) { void RP2A03::opi_store_indirect_zero_page_x(uint8 &r) {
zp = op_readpci(); zp = op_readpci();
op_readzp(zp); op_readzp(zp);
abs.l = op_readzp(zp++ + regs.x); abs.l = op_readzp(zp++ + regs.x);
@ -351,7 +351,7 @@ void CPU::opi_store_indirect_zero_page_x(uint8 &r) {
L op_write(abs.w, r); L op_write(abs.w, r);
} }
void CPU::opi_store_indirect_zero_page_y(uint8 &r) { void RP2A03::opi_store_indirect_zero_page_y(uint8 &r) {
rd = op_readpci(); rd = op_readpci();
abs.l = op_readzp(rd++); abs.l = op_readzp(rd++);
abs.h = op_readzp(rd++); abs.h = op_readzp(rd++);
@ -359,24 +359,24 @@ void CPU::opi_store_indirect_zero_page_y(uint8 &r) {
L op_write(abs.w + regs.y, r); L op_write(abs.w + regs.y, r);
} }
void CPU::opi_store_zero_page(uint8 &r) { void RP2A03::opi_store_zero_page(uint8 &r) {
zp = op_readpci(); zp = op_readpci();
L op_writezp(zp, r); L op_writezp(zp, r);
} }
void CPU::opi_store_zero_page_x(uint8 &r) { void RP2A03::opi_store_zero_page_x(uint8 &r) {
zp = op_readpci(); zp = op_readpci();
op_readzp(zp); op_readzp(zp);
L op_writezp(zp + regs.x, r); L op_writezp(zp + regs.x, r);
} }
void CPU::opi_store_zero_page_y(uint8 &r) { void RP2A03::opi_store_zero_page_y(uint8 &r) {
zp = op_readpci(); zp = op_readpci();
op_readzp(zp); op_readzp(zp);
L op_writezp(zp + regs.y, r); L op_writezp(zp + regs.y, r);
} }
void CPU::opi_transfer(uint8 &s, uint8 &d, bool flag) { void RP2A03::opi_transfer(uint8 &s, uint8 &d, bool flag) {
L op_readpc(); L op_readpc();
d = s; d = s;
if(flag == false) return; if(flag == false) return;
@ -387,7 +387,7 @@ L op_readpc();
//opcodes //opcodes
//======= //=======
void CPU::op_brk() { void RP2A03::op_brk() {
op_readpci(); op_readpci();
op_writesp(regs.pc >> 8); op_writesp(regs.pc >> 8);
op_writesp(regs.pc >> 0); op_writesp(regs.pc >> 0);
@ -399,13 +399,13 @@ L abs.h = op_read(0xffff);
regs.pc = abs.w; regs.pc = abs.w;
} }
void CPU::op_jmp_absolute() { void RP2A03::op_jmp_absolute() {
abs.l = op_readpci(); abs.l = op_readpci();
L abs.h = op_readpci(); L abs.h = op_readpci();
regs.pc = abs.w; regs.pc = abs.w;
} }
void CPU::op_jmp_indirect_absolute() { void RP2A03::op_jmp_indirect_absolute() {
abs.l = op_readpci(); abs.l = op_readpci();
abs.h = op_readpci(); abs.h = op_readpci();
iabs.l = op_read(abs.w); abs.l++; iabs.l = op_read(abs.w); abs.l++;
@ -413,7 +413,7 @@ L iabs.h = op_read(abs.w); abs.l++;
regs.pc = iabs.w; regs.pc = iabs.w;
} }
void CPU::op_jsr_absolute() { void RP2A03::op_jsr_absolute() {
abs.l = op_readpci(); abs.l = op_readpci();
abs.h = op_readpci(); abs.h = op_readpci();
op_readpc(); op_readpc();
@ -423,22 +423,22 @@ L op_writesp(regs.pc >> 0);
regs.pc = abs.w; regs.pc = abs.w;
} }
void CPU::op_nop() { void RP2A03::op_nop() {
L op_readpc(); L op_readpc();
} }
void CPU::op_php() { void RP2A03::op_php() {
op_readpc(); op_readpc();
L op_writesp(regs.p | 0x30); L op_writesp(regs.p | 0x30);
} }
void CPU::op_plp() { void RP2A03::op_plp() {
op_readpc(); op_readpc();
op_readpc(); op_readpc();
L regs.p = op_readsp(); L regs.p = op_readsp();
} }
void CPU::op_rti() { void RP2A03::op_rti() {
op_readpc(); op_readpc();
op_readpc(); op_readpc();
regs.p = op_readsp(); regs.p = op_readsp();
@ -447,7 +447,7 @@ L abs.h = op_readsp();
regs.pc = abs.w; regs.pc = abs.w;
} }
void CPU::op_rts() { void RP2A03::op_rts() {
op_readpc(); op_readpc();
op_readpc(); op_readpc();
abs.l = op_readsp(); abs.l = op_readsp();
@ -459,7 +459,7 @@ L op_readpc();
//illegal opcodes //illegal opcodes
//=============== //===============
void CPU::opill_arr_immediate() { void RP2A03::opill_arr_immediate() {
L rd = op_readpci(); L rd = op_readpci();
regs.a &= rd; regs.a &= rd;
regs.a = (regs.p.c << 7) | (regs.a >> 1); regs.a = (regs.p.c << 7) | (regs.a >> 1);
@ -469,33 +469,33 @@ L rd = op_readpci();
regs.p.v = regs.p.c ^ ((regs.a >> 5) & 1); regs.p.v = regs.p.c ^ ((regs.a >> 5) & 1);
} }
void CPU::opill_nop_absolute() { void RP2A03::opill_nop_absolute() {
abs.l = op_readpci(); abs.l = op_readpci();
abs.h = op_readpci(); abs.h = op_readpci();
L op_readpc(); L op_readpc();
} }
void CPU::opill_nop_absolute_x() { void RP2A03::opill_nop_absolute_x() {
abs.l = op_readpci(); abs.l = op_readpci();
abs.h = op_readpci(); abs.h = op_readpci();
op_page(abs.w, abs.w + regs.x); op_page(abs.w, abs.w + regs.x);
L op_readpc(); L op_readpc();
} }
void CPU::opill_nop_immediate() { void RP2A03::opill_nop_immediate() {
L rd = op_readpc(); L rd = op_readpc();
} }
void CPU::opill_nop_implied() { void RP2A03::opill_nop_implied() {
L op_readpc(); L op_readpc();
} }
void CPU::opill_nop_zero_page() { void RP2A03::opill_nop_zero_page() {
zp = op_readpci(); zp = op_readpci();
L op_readzp(zp); L op_readzp(zp);
} }
void CPU::opill_nop_zero_page_x() { void RP2A03::opill_nop_zero_page_x() {
zp = op_readpci(); zp = op_readpci();
op_readzp(zp); op_readzp(zp);
L op_readzp(zp + regs.x); L op_readzp(zp + regs.x);

View File

@ -0,0 +1,35 @@
uint8 RP2A03::op_readpc() {
return op_read(regs.pc);
}
uint8 RP2A03::op_readpci() {
return op_read(regs.pc++);
}
uint8 RP2A03::op_readsp() {
return op_read(0x0100 | ++regs.s);
}
uint8 RP2A03::op_readzp(uint8 addr) {
return op_read(addr);
}
//
void RP2A03::op_writesp(uint8 data) {
op_write(0x0100 | regs.s--, data);
}
void RP2A03::op_writezp(uint8 addr, uint8 data) {
op_write(addr, data);
}
//
void RP2A03::op_page(uint16 x, uint16 y) {
if((x & 0xff00) != (y & 0xff00)) op_read((x & 0xff00) | (y & 0x00ff));
}
void RP2A03::op_page_always(uint16 x, uint16 y) {
op_read((x & 0xff00) | (y & 0x00ff));
}

View File

@ -0,0 +1,31 @@
struct Flags {
bool n, v, d, i, z, c;
inline operator unsigned() {
return (n << 7) | (v << 6) | (d << 3) | (i << 2) | (z << 1) | (c << 0);
}
inline Flags& operator=(uint8 data) {
n = data & 0x80; v = data & 0x40;
d = data & 0x08; i = data & 0x04; z = data & 0x02; c = data & 0x01;
return *this;
}
};
struct Registers {
uint8 mdr;
uint16 pc;
uint8 a, x, y, s;
Flags p;
} regs;
struct Register16 {
union {
uint16 w;
struct { uint8 order_lsb2(l, h); };
};
} abs, iabs;
uint8 rd;
uint8 zp;
uint16 aa;

241
bsnes/processor/rp2a03/rp2a03.cpp Executable file
View File

@ -0,0 +1,241 @@
#include <processor/processor.hpp>
#include "rp2a03.hpp"
namespace Processor {
#define I
#define L last_cycle();
#define call(op) (this->*op)()
#include "memory.cpp"
#include "instructions.cpp"
#include "disassembler.cpp"
#include "serialization.cpp"
uint8 RP2A03::mdr() const {
return regs.mdr;
}
void RP2A03::power() {
regs.a = 0x00;
regs.x = 0x00;
regs.y = 0x00;
regs.s = 0x00;
regs.p = 0x04;
}
void RP2A03::reset() {
regs.mdr = 0x00;
regs.s -= 3;
regs.p.i = 1;
}
void RP2A03::interrupt() {
op_readpc();
op_readpc();
op_writesp(regs.pc >> 8);
op_writesp(regs.pc >> 0);
op_writesp(regs.p | 0x20);
uint16 vector = 0xfffe; //IRQ
nmi(vector);
abs.l = op_read(vector++);
regs.p.i = 1;
regs.p.d = 0;
L abs.h = op_read(vector++);
regs.pc = abs.w;
}
void RP2A03::exec() {
uint8 opcode = op_readpci();
switch(opcode) {
case 0x00: return op_brk();
case 0x01: return opi_read_indirect_zero_page_x<&RP2A03::opf_ora>();
I case 0x04: return opill_nop_zero_page();
case 0x05: return opi_read_zero_page<&RP2A03::opf_ora>();
case 0x06: return opi_rmw_zero_page<&RP2A03::opf_asl>();
case 0x08: return op_php();
case 0x09: return opi_read_immediate<&RP2A03::opf_ora>();
case 0x0a: return opi_shift<&RP2A03::opf_sla>();
I case 0x0c: return opill_nop_absolute();
case 0x0d: return opi_read_absolute<&RP2A03::opf_ora>();
case 0x0e: return opi_rmw_absolute<&RP2A03::opf_asl>();
case 0x10: return opi_branch(regs.p.n == 0);
case 0x11: return opi_read_indirect_zero_page_y<&RP2A03::opf_ora>();
I case 0x14: return opill_nop_zero_page_x();
case 0x15: return opi_read_zero_page_x<&RP2A03::opf_ora>();
case 0x16: return opi_rmw_zero_page_x<&RP2A03::opf_asl>();
case 0x18: return opi_clear_flag(regs.p.c);
case 0x19: return opi_read_absolute_y<&RP2A03::opf_ora>();
I case 0x1a: return opill_nop_implied();
I case 0x1c: return opill_nop_absolute_x();
case 0x1d: return opi_read_absolute_x<&RP2A03::opf_ora>();
case 0x1e: return opi_rmw_absolute_x<&RP2A03::opf_asl>();
case 0x20: return op_jsr_absolute();
case 0x21: return opi_read_indirect_zero_page_x<&RP2A03::opf_and>();
case 0x24: return opi_read_zero_page<&RP2A03::opf_bit>();
case 0x25: return opi_read_zero_page<&RP2A03::opf_and>();
case 0x26: return opi_rmw_zero_page<&RP2A03::opf_rol>();
case 0x28: return op_plp();
case 0x29: return opi_read_immediate<&RP2A03::opf_and>();
case 0x2a: return opi_shift<&RP2A03::opf_rla>();
case 0x2c: return opi_read_absolute<&RP2A03::opf_bit>();
case 0x2d: return opi_read_absolute<&RP2A03::opf_and>();
case 0x2e: return opi_rmw_absolute<&RP2A03::opf_rol>();
case 0x30: return opi_branch(regs.p.n == 1);
case 0x31: return opi_read_indirect_zero_page_y<&RP2A03::opf_and>();
I case 0x34: return opill_nop_zero_page_x();
case 0x35: return opi_read_zero_page_x<&RP2A03::opf_and>();
case 0x36: return opi_rmw_zero_page_x<&RP2A03::opf_rol>();
case 0x38: return opi_set_flag(regs.p.c);
case 0x39: return opi_read_absolute_y<&RP2A03::opf_and>();
I case 0x3a: return opill_nop_implied();
I case 0x3c: return opill_nop_absolute_x();
case 0x3d: return opi_read_absolute_x<&RP2A03::opf_and>();
case 0x3e: return opi_rmw_absolute_x<&RP2A03::opf_rol>();
case 0x40: return op_rti();
case 0x41: return opi_read_indirect_zero_page_x<&RP2A03::opf_eor>();
I case 0x44: return opill_nop_zero_page();
case 0x45: return opi_read_zero_page<&RP2A03::opf_eor>();
case 0x46: return opi_rmw_zero_page<&RP2A03::opf_lsr>();
case 0x48: return opi_push(regs.a);
case 0x49: return opi_read_immediate<&RP2A03::opf_eor>();
case 0x4a: return opi_shift<&RP2A03::opf_sra>();
case 0x4c: return op_jmp_absolute();
case 0x4d: return opi_read_absolute<&RP2A03::opf_eor>();
case 0x4e: return opi_rmw_absolute<&RP2A03::opf_lsr>();
case 0x50: return opi_branch(regs.p.v == 0);
case 0x51: return opi_read_indirect_zero_page_y<&RP2A03::opf_eor>();
I case 0x54: return opill_nop_zero_page_x();
case 0x55: return opi_read_zero_page_x<&RP2A03::opf_eor>();
case 0x56: return opi_rmw_zero_page_x<&RP2A03::opf_lsr>();
case 0x58: return opi_clear_flag(regs.p.i);
case 0x59: return opi_read_absolute_y<&RP2A03::opf_eor>();
I case 0x5a: return opill_nop_implied();
I case 0x5c: return opill_nop_absolute_x();
case 0x5d: return opi_read_absolute_x<&RP2A03::opf_eor>();
case 0x5e: return opi_rmw_absolute_x<&RP2A03::opf_lsr>();
case 0x60: return op_rts();
case 0x61: return opi_read_indirect_zero_page_x<&RP2A03::opf_adc>();
I case 0x64: return opill_nop_zero_page();
case 0x65: return opi_read_zero_page<&RP2A03::opf_adc>();
case 0x66: return opi_rmw_zero_page<&RP2A03::opf_ror>();
case 0x68: return opi_pull(regs.a);
case 0x69: return opi_read_immediate<&RP2A03::opf_adc>();
case 0x6a: return opi_shift<&RP2A03::opf_rra>();
I case 0x6b: return opill_arr_immediate();
case 0x6c: return op_jmp_indirect_absolute();
case 0x6d: return opi_read_absolute<&RP2A03::opf_adc>();
case 0x6e: return opi_rmw_absolute<&RP2A03::opf_ror>();
case 0x70: return opi_branch(regs.p.v == 1);
I case 0x74: return opill_nop_zero_page_x();
case 0x71: return opi_read_indirect_zero_page_y<&RP2A03::opf_adc>();
case 0x75: return opi_read_zero_page_x<&RP2A03::opf_adc>();
case 0x76: return opi_rmw_zero_page_x<&RP2A03::opf_ror>();
case 0x78: return opi_set_flag(regs.p.i);
case 0x79: return opi_read_absolute_y<&RP2A03::opf_adc>();
I case 0x7a: return opill_nop_implied();
I case 0x7c: return opill_nop_absolute_x();
case 0x7d: return opi_read_absolute_x<&RP2A03::opf_adc>();
case 0x7e: return opi_rmw_absolute_x<&RP2A03::opf_ror>();
I case 0x80: return opill_nop_absolute();
case 0x81: return opi_store_indirect_zero_page_x(regs.a);
I case 0x82: return opill_nop_immediate();
case 0x84: return opi_store_zero_page(regs.y);
case 0x85: return opi_store_zero_page(regs.a);
case 0x86: return opi_store_zero_page(regs.x);
case 0x88: return opi_decrement(regs.y);
I case 0x89: return opill_nop_immediate();
case 0x8a: return opi_transfer(regs.x, regs.a, 1);
case 0x8c: return opi_store_absolute(regs.y);
case 0x8d: return opi_store_absolute(regs.a);
case 0x8e: return opi_store_absolute(regs.x);
case 0x90: return opi_branch(regs.p.c == 0);
case 0x91: return opi_store_indirect_zero_page_y(regs.a);
case 0x94: return opi_store_zero_page_x(regs.y);
case 0x95: return opi_store_zero_page_x(regs.a);
case 0x96: return opi_store_zero_page_y(regs.x);
case 0x98: return opi_transfer(regs.y, regs.a, 1);
case 0x99: return opi_store_absolute_y(regs.a);
case 0x9a: return opi_transfer(regs.x, regs.s, 0);
case 0x9d: return opi_store_absolute_x(regs.a);
case 0xa0: return opi_read_immediate<&RP2A03::opf_ldy>();
case 0xa1: return opi_read_indirect_zero_page_x<&RP2A03::opf_lda>();
case 0xa2: return opi_read_immediate<&RP2A03::opf_ldx>();
case 0xa4: return opi_read_zero_page<&RP2A03::opf_ldy>();
case 0xa5: return opi_read_zero_page<&RP2A03::opf_lda>();
case 0xa6: return opi_read_zero_page<&RP2A03::opf_ldx>();
case 0xa8: return opi_transfer(regs.a, regs.y, 1);
case 0xa9: return opi_read_immediate<&RP2A03::opf_lda>();
case 0xaa: return opi_transfer(regs.a, regs.x, 1);
case 0xac: return opi_read_absolute<&RP2A03::opf_ldy>();
case 0xad: return opi_read_absolute<&RP2A03::opf_lda>();
case 0xae: return opi_read_absolute<&RP2A03::opf_ldx>();
case 0xb0: return opi_branch(regs.p.c == 1);
case 0xb1: return opi_read_indirect_zero_page_y<&RP2A03::opf_lda>();
case 0xb4: return opi_read_zero_page_x<&RP2A03::opf_ldy>();
case 0xb5: return opi_read_zero_page_x<&RP2A03::opf_lda>();
case 0xb6: return opi_read_zero_page_y<&RP2A03::opf_ldx>();
case 0xb8: return opi_clear_flag(regs.p.v);
case 0xb9: return opi_read_absolute_y<&RP2A03::opf_lda>();
case 0xba: return opi_transfer(regs.s, regs.x, 1);
case 0xbc: return opi_read_absolute_x<&RP2A03::opf_ldy>();
case 0xbd: return opi_read_absolute_x<&RP2A03::opf_lda>();
case 0xbe: return opi_read_absolute_y<&RP2A03::opf_ldx>();
case 0xc0: return opi_read_immediate<&RP2A03::opf_cpy>();
case 0xc1: return opi_read_indirect_zero_page_x<&RP2A03::opf_cmp>();
I case 0xc2: return opill_nop_immediate();
case 0xc4: return opi_read_zero_page<&RP2A03::opf_cpy>();
case 0xc5: return opi_read_zero_page<&RP2A03::opf_cmp>();
case 0xc6: return opi_rmw_zero_page<&RP2A03::opf_dec>();
case 0xc8: return opi_increment(regs.y);
case 0xc9: return opi_read_immediate<&RP2A03::opf_cmp>();
case 0xca: return opi_decrement(regs.x);
case 0xcc: return opi_read_absolute<&RP2A03::opf_cpy>();
case 0xcd: return opi_read_absolute<&RP2A03::opf_cmp>();
case 0xce: return opi_rmw_absolute<&RP2A03::opf_dec>();
case 0xd0: return opi_branch(regs.p.z == 0);
case 0xd1: return opi_read_indirect_zero_page_y<&RP2A03::opf_cmp>();
I case 0xd4: return opill_nop_zero_page_x();
case 0xd5: return opi_read_zero_page_x<&RP2A03::opf_cmp>();
case 0xd6: return opi_rmw_zero_page_x<&RP2A03::opf_dec>();
case 0xd8: return opi_clear_flag(regs.p.d);
case 0xd9: return opi_read_absolute_y<&RP2A03::opf_cmp>();
I case 0xda: return opill_nop_implied();
I case 0xdc: return opill_nop_absolute_x();
case 0xdd: return opi_read_absolute_x<&RP2A03::opf_cmp>();
case 0xde: return opi_rmw_absolute_x<&RP2A03::opf_dec>();
case 0xe0: return opi_read_immediate<&RP2A03::opf_cpx>();
case 0xe1: return opi_read_indirect_zero_page_x<&RP2A03::opf_sbc>();
I case 0xe2: return opill_nop_immediate();
case 0xe4: return opi_read_zero_page<&RP2A03::opf_cpx>();
case 0xe5: return opi_read_zero_page<&RP2A03::opf_sbc>();
case 0xe6: return opi_rmw_zero_page<&RP2A03::opf_inc>();
case 0xe8: return opi_increment(regs.x);
case 0xe9: return opi_read_immediate<&RP2A03::opf_sbc>();
case 0xea: return op_nop();
I case 0xeb: return opi_read_immediate<&RP2A03::opf_sbc>();
case 0xec: return opi_read_absolute<&RP2A03::opf_cpx>();
case 0xed: return opi_read_absolute<&RP2A03::opf_sbc>();
case 0xee: return opi_rmw_absolute<&RP2A03::opf_inc>();
case 0xf0: return opi_branch(regs.p.z == 1);
case 0xf1: return opi_read_indirect_zero_page_y<&RP2A03::opf_sbc>();
I case 0xf4: return opill_nop_zero_page_x();
case 0xf5: return opi_read_zero_page_x<&RP2A03::opf_sbc>();
case 0xf6: return opi_rmw_zero_page_x<&RP2A03::opf_inc>();
case 0xf8: return opi_set_flag(regs.p.d);
case 0xf9: return opi_read_absolute_y<&RP2A03::opf_sbc>();
I case 0xfa: return opill_nop_implied();
I case 0xfc: return opill_nop_absolute_x();
case 0xfd: return opi_read_absolute_x<&RP2A03::opf_sbc>();
case 0xfe: return opi_rmw_absolute_x<&RP2A03::opf_inc>();
}
//unimplemented opcode
return op_nop();
}
#undef I
#undef L
#undef call
}

117
bsnes/processor/rp2a03/rp2a03.hpp Executable file
View File

@ -0,0 +1,117 @@
#ifndef PROCESSOR_RP2A03_HPP
#define PROCESSOR_RP2A03_HPP
namespace Processor {
//Ricoh RP2A03
//Ricoh RP2A07
struct RP2A03 {
#include "registers.hpp"
virtual uint8 op_read(uint16 addr) = 0;
virtual void op_write(uint16 addr, uint8 data) = 0;
virtual void last_cycle() = 0;
virtual void nmi(uint16 &vector) = 0;
virtual uint8 debugger_read(uint16 addr) { return 0u; }
uint8 mdr() const;
void power();
void reset();
void interrupt();
void exec();
void serialize(serializer&);
//memory.cpp
uint8 op_readpc();
uint8 op_readpci();
uint8 op_readsp();
uint8 op_readzp(uint8 addr);
void op_writesp(uint8 data);
void op_writezp(uint8 addr, uint8 data);
void op_page(uint16 x, uint16 y);
void op_page_always(uint16 x, uint16 y);
//instructions.cpp
void opf_asl();
void opf_adc();
void opf_and();
void opf_bit();
void opf_cmp();
void opf_cpx();
void opf_cpy();
void opf_dec();
void opf_eor();
void opf_inc();
void opf_lda();
void opf_ldx();
void opf_ldy();
void opf_lsr();
void opf_ora();
void opf_rla();
void opf_rol();
void opf_ror();
void opf_rra();
void opf_sbc();
void opf_sla();
void opf_sra();
void opi_branch(bool condition);
void opi_clear_flag(bool &flag);
void opi_decrement(uint8 &r);
void opi_increment(uint8 &r);
void opi_pull(uint8 &r);
void opi_push(uint8 &r);
template<void (RP2A03::*op)()> void opi_read_absolute();
template<void (RP2A03::*op)()> void opi_read_absolute_x();
template<void (RP2A03::*op)()> void opi_read_absolute_y();
template<void (RP2A03::*op)()> void opi_read_immediate();
template<void (RP2A03::*op)()> void opi_read_indirect_zero_page_x();
template<void (RP2A03::*op)()> void opi_read_indirect_zero_page_y();
template<void (RP2A03::*op)()> void opi_read_zero_page();
template<void (RP2A03::*op)()> void opi_read_zero_page_x();
template<void (RP2A03::*op)()> void opi_read_zero_page_y();
template<void (RP2A03::*op)()> void opi_rmw_absolute();
template<void (RP2A03::*op)()> void opi_rmw_absolute_x();
template<void (RP2A03::*op)()> void opi_rmw_zero_page();
template<void (RP2A03::*op)()> void opi_rmw_zero_page_x();
void opi_set_flag(bool &flag);
template<void (RP2A03::*op)()> void opi_shift();
void opi_store_absolute(uint8 &r);
void opi_store_absolute_x(uint8 &r);
void opi_store_absolute_y(uint8 &r);
void opi_store_indirect_zero_page_x(uint8 &r);
void opi_store_indirect_zero_page_y(uint8 &r);
void opi_store_zero_page(uint8 &r);
void opi_store_zero_page_x(uint8 &r);
void opi_store_zero_page_y(uint8 &r);
void opi_transfer(uint8 &s, uint8 &d, bool flag);
void op_brk();
void op_jmp_absolute();
void op_jmp_indirect_absolute();
void op_jsr_absolute();
void op_nop();
void op_php();
void op_plp();
void op_rti();
void op_rts();
void opill_arr_immediate();
void opill_nop_absolute();
void opill_nop_absolute_x();
void opill_nop_immediate();
void opill_nop_implied();
void opill_nop_zero_page();
void opill_nop_zero_page_x();
//disassembler.cpp
string disassemble();
};
}
#endif

View File

@ -0,0 +1,20 @@
void RP2A03::serialize(serializer &s) {
s.integer(regs.mdr);
s.integer(regs.pc);
s.integer(regs.a);
s.integer(regs.x);
s.integer(regs.y);
s.integer(regs.s);
s.integer(regs.p.n);
s.integer(regs.p.v);
s.integer(regs.p.d);
s.integer(regs.p.i);
s.integer(regs.p.z);
s.integer(regs.p.c);
s.integer(abs.w);
s.integer(iabs.w);
s.integer(rd);
s.integer(zp);
s.integer(aa);
}

View File

@ -1,4 +1,4 @@
processors := arm hg51b lr35902 upd96050 processors := arm hg51b lr35902 rp2a03 upd96050
include processor/Makefile include processor/Makefile
include $(nes)/Makefile include $(nes)/Makefile

View File

@ -16,6 +16,7 @@ namespace GBA = GameBoyAdvance;
#include <nall/filemap.hpp> #include <nall/filemap.hpp>
#include <nall/input.hpp> #include <nall/input.hpp>
#include <nall/bps/patch.hpp> #include <nall/bps/patch.hpp>
#include <nall/stream/file.hpp>
#include <nall/stream/memory.hpp> #include <nall/stream/memory.hpp>
#include <nall/stream/vector.hpp> #include <nall/stream/vector.hpp>
#include <nall/nes/cartridge.hpp> #include <nall/nes/cartridge.hpp>

View File

@ -34,7 +34,7 @@ bool InterfaceGBA::loadCartridge(const string &filename) {
markup.readfile(interface->base.filename("manifest.xml", ".xml")); markup.readfile(interface->base.filename("manifest.xml", ".xml"));
if(markup.empty()) markup = GameBoyAdvanceCartridge(memory.data(), memory.size()).markup; if(markup.empty()) markup = GameBoyAdvanceCartridge(memory.data(), memory.size()).markup;
GBA::cartridge.load(markup, memory.data(), memory.size()); GBA::cartridge.load(markup, vectorstream{memory});
GBA::system.power(); GBA::system.power();
if(GBA::cartridge.ram_size()) { if(GBA::cartridge.ram_size()) {

View File

@ -47,7 +47,7 @@ bool InterfaceNES::loadCartridge(const string &filename) {
markup.readfile(interface->base.filename("manifest.xml", ".xml")); markup.readfile(interface->base.filename("manifest.xml", ".xml"));
if(markup.empty()) markup = FamicomCartridge(memory.data(), memory.size()).markup; if(markup.empty()) markup = FamicomCartridge(memory.data(), memory.size()).markup;
NES::cartridge.load(markup, memory.data(), memory.size()); NES::cartridge.load(markup, vectorstream{memory});
NES::system.power(); NES::system.power();
if(NES::cartridge.ram_size()) { if(NES::cartridge.ram_size()) {