mirror of https://github.com/bsnes-emu/bsnes.git
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:
parent
616372e96b
commit
67c13f749f
|
@ -1,7 +1,7 @@
|
|||
#ifndef BASE_HPP
|
||||
#define BASE_HPP
|
||||
|
||||
static const char Version[] = "088.03";
|
||||
static const char Version[] = "088.04";
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/algorithm.hpp>
|
||||
|
|
|
@ -7,12 +7,14 @@ namespace GameBoyAdvance {
|
|||
#include "serialization.cpp"
|
||||
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;
|
||||
XML::Document document(markup);
|
||||
|
||||
for(unsigned addr = 0; addr < rom.size; addr++) {
|
||||
rom.data[addr] = data[Bus::mirror(addr, size)];
|
||||
unsigned size = memory.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;
|
||||
|
@ -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();
|
||||
return loaded = true;
|
||||
|
|
|
@ -12,7 +12,7 @@ struct Cartridge : property<Cartridge> {
|
|||
string markup;
|
||||
} information;
|
||||
|
||||
bool load(const string &markup, const uint8_t *data, unsigned size);
|
||||
bool load(const string &markup, const stream &memory);
|
||||
void unload();
|
||||
void power();
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ struct stream {
|
|||
return data;
|
||||
}
|
||||
|
||||
void read(uint8_t *data, unsigned length) const {
|
||||
virtual void read(uint8_t *data, unsigned length) const {
|
||||
while(length--) *data++ = read();
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ void serialize(serializer &s) {
|
|||
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) {
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -86,7 +86,7 @@ void Board::serialize(serializer &s) {
|
|||
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"];
|
||||
|
||||
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(chrram.size) chrram.data = new uint8[chrram.size]();
|
||||
|
||||
if(prgrom.size) memcpy(prgrom.data, data, prgrom.size);
|
||||
if(chrrom.size) memcpy(chrrom.data, data + prgrom.size, chrrom.size);
|
||||
if(prgrom.size) memory.read(prgrom.data, prgrom.size);
|
||||
if(chrrom.size) memory.read(chrrom.data, chrrom.size);
|
||||
|
||||
prgram.writable = true;
|
||||
chrram.writable = true;
|
||||
|
@ -112,56 +112,56 @@ Board::Board(XML::Document &document, const uint8_t *data, unsigned size) {
|
|||
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);
|
||||
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-2") return new KonamiVRC2(document, data, size);
|
||||
if(type == "KONAMI-VRC-3") return new KonamiVRC3(document, data, size);
|
||||
if(type == "KONAMI-VRC-4") return new KonamiVRC4(document, data, size);
|
||||
if(type == "KONAMI-VRC-6") return new KonamiVRC6(document, data, size);
|
||||
if(type == "KONAMI-VRC-7") return new KonamiVRC7(document, data, size);
|
||||
if(type == "KONAMI-VRC-1") return new KonamiVRC1(document, memory);
|
||||
if(type == "KONAMI-VRC-2") return new KonamiVRC2(document, memory);
|
||||
if(type == "KONAMI-VRC-3") return new KonamiVRC3(document, memory);
|
||||
if(type == "KONAMI-VRC-4") return new KonamiVRC4(document, memory);
|
||||
if(type == "KONAMI-VRC-6") return new KonamiVRC6(document, memory);
|
||||
if(type == "KONAMI-VRC-7") return new KonamiVRC7(document, memory);
|
||||
|
||||
if(type == "NES-AMROM" ) return new NES_AxROM(document, data, size);
|
||||
if(type == "NES-ANROM" ) return new NES_AxROM(document, data, size);
|
||||
if(type == "NES-AN1ROM" ) return new NES_AxROM(document, data, size);
|
||||
if(type == "NES-AOROM" ) 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, memory);
|
||||
if(type == "NES-AN1ROM" ) return new NES_AxROM(document, memory);
|
||||
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-ELROM" ) return new NES_ExROM(document, data, size);
|
||||
if(type == "NES-ETROM" ) return new NES_ExROM(document, data, size);
|
||||
if(type == "NES-EWROM" ) 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, memory);
|
||||
if(type == "NES-ETROM" ) return new NES_ExROM(document, memory);
|
||||
if(type == "NES-EWROM" ) return new NES_ExROM(document, memory);
|
||||
|
||||
if(type == "NES-FJROM" ) return new NES_FxROM(document, data, size);
|
||||
if(type == "NES-FKROM" ) 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, memory);
|
||||
|
||||
if(type == "NES-GNROM" ) return new NES_GxROM(document, data, size);
|
||||
if(type == "NES-MHROM" ) 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, 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-256") 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, memory);
|
||||
|
||||
if(type == "NES-PEEOROM" ) return new NES_PxROM(document, data, size);
|
||||
if(type == "NES-PNROM" ) 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, memory);
|
||||
|
||||
if(type == "NES-SNROM" ) return new NES_SxROM(document, data, size);
|
||||
if(type == "NES-SXROM" ) 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, 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-UOROM" ) 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, memory);
|
||||
|
||||
if(type == "SUNSOFT-5B" ) return new Sunsoft5B(document, data, size);
|
||||
if(type == "SUNSOFT-5B" ) return new Sunsoft5B(document, memory);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -31,10 +31,10 @@ struct Board {
|
|||
virtual void reset();
|
||||
|
||||
virtual void serialize(serializer&);
|
||||
Board(XML::Document &document, const uint8_t *data, unsigned size);
|
||||
Board(XML::Document &document, const stream &memory);
|
||||
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 {
|
||||
string type;
|
||||
|
|
|
@ -34,7 +34,7 @@ void serialize(serializer &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) {
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -49,7 +49,7 @@ void serialize(serializer &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.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ void serialize(serializer &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;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ void serialize(serializer &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.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ void main() { vrc6.main(); }
|
|||
void power() { vrc6.power(); }
|
||||
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) {
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -41,7 +41,7 @@ void serialize(serializer &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) {
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -45,7 +45,7 @@ void serialize(serializer &s) {
|
|||
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) {
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -45,7 +45,7 @@ void serialize(serializer &s) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ void serialize(serializer &s) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ void serialize(serializer &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;
|
||||
}
|
||||
|
||||
|
|
|
@ -84,7 +84,7 @@ void serialize(serializer &s) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ void serialize(serializer &s) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ void serialize(serializer &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) {
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -36,7 +36,7 @@ void serialize(serializer &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;
|
||||
}
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ void serialize(serializer &s) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ void serialize(serializer &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;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ void serialize(serializer &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;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ void serialize(serializer &s) {
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -220,7 +220,7 @@ void serialize(serializer &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) {
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -14,18 +14,23 @@ void Cartridge::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;
|
||||
|
||||
if((size & 0xff) == 0) {
|
||||
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);
|
||||
}
|
||||
board = Board::load(markup, memory);
|
||||
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();
|
||||
loaded = true;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ struct Cartridge : Thread, property<Cartridge> {
|
|||
static 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();
|
||||
|
||||
unsigned ram_size();
|
||||
|
|
|
@ -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
|
|
@ -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();
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -2,39 +2,29 @@
|
|||
|
||||
namespace Famicom {
|
||||
|
||||
#include "core/core.cpp"
|
||||
#include "memory/memory.cpp"
|
||||
#include "timing.cpp"
|
||||
#include "serialization.cpp"
|
||||
CPU cpu;
|
||||
|
||||
void CPU::Main() {
|
||||
cpu.main();
|
||||
}
|
||||
|
||||
void CPU::main() {
|
||||
//trace = true;
|
||||
//FILE *fp = fopen("/home/byuu/Desktop/log.txt", "wb");
|
||||
|
||||
unsigned lpc = 0xffff;
|
||||
void CPU::Enter() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
if(status.interrupt_pending) {
|
||||
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();
|
||||
cpu.main();
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::main() {
|
||||
if(status.interrupt_pending) {
|
||||
interrupt();
|
||||
return;
|
||||
}
|
||||
|
||||
exec();
|
||||
}
|
||||
|
||||
void CPU::add_clocks(unsigned clocks) {
|
||||
apu.clock -= clocks;
|
||||
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() {
|
||||
regs.a = 0x00;
|
||||
regs.x = 0x00;
|
||||
regs.y = 0x00;
|
||||
regs.s = 0x00;
|
||||
regs.p = 0x04;
|
||||
RP2A03::power();
|
||||
|
||||
for(unsigned addr = 0; addr < 0x0800; addr++) ram[addr] = 0xff;
|
||||
ram[0x0008] = 0xf7;
|
||||
|
@ -61,11 +47,8 @@ void CPU::power() {
|
|||
}
|
||||
|
||||
void CPU::reset() {
|
||||
create(CPU::Main, 21477272);
|
||||
|
||||
regs.mdr = 0x00;
|
||||
regs.s -= 3;
|
||||
regs.p.i = 1;
|
||||
RP2A03::reset();
|
||||
create(CPU::Enter, 21477272);
|
||||
|
||||
regs.pc = bus.read(0xfffc) << 0;
|
||||
regs.pc |= bus.read(0xfffd) << 8;
|
||||
|
@ -87,16 +70,8 @@ void CPU::reset() {
|
|||
status.controller_port1 = 0;
|
||||
}
|
||||
|
||||
uint8 CPU::mdr() const {
|
||||
return regs.mdr;
|
||||
}
|
||||
|
||||
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::debugger_read(uint16 addr) {
|
||||
return bus.read(addr);
|
||||
}
|
||||
|
||||
uint8 CPU::ram_read(uint16 addr) {
|
||||
|
@ -132,11 +107,4 @@ void CPU::write(uint16 addr, uint8 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
struct CPU : Thread {
|
||||
#include "core/core.hpp"
|
||||
#include "memory/memory.hpp"
|
||||
struct CPU : Processor::RP2A03, Thread {
|
||||
uint8 ram[0x0800];
|
||||
|
||||
struct Status {
|
||||
|
@ -21,16 +19,14 @@ struct CPU : Thread {
|
|||
unsigned controller_port1;
|
||||
} status;
|
||||
|
||||
static void Main();
|
||||
static void Enter();
|
||||
void main();
|
||||
void add_clocks(unsigned clocks);
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
uint8 mdr() const;
|
||||
void set_rdy_line(bool);
|
||||
void set_rdy_addr(optional<uint16>);
|
||||
uint8 debugger_read(uint16 addr);
|
||||
|
||||
uint8 ram_read(uint16 addr);
|
||||
void ram_write(uint16 addr, uint8 data);
|
||||
|
@ -38,12 +34,22 @@ struct CPU : Thread {
|
|||
uint8 read(uint16 addr);
|
||||
void write(uint16 addr, uint8 data);
|
||||
|
||||
void oam_dma();
|
||||
|
||||
void serialize(serializer&);
|
||||
|
||||
//internal:
|
||||
bool trace;
|
||||
//timing.cpp
|
||||
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;
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -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);
|
|
@ -1,27 +1,9 @@
|
|||
void CPU::serialize(serializer &s) {
|
||||
RP2A03::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
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.nmi_pending);
|
||||
s.integer(status.nmi_line);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -23,8 +23,4 @@ void Interface::message(const string &text) {
|
|||
print(text, "\n");
|
||||
}
|
||||
|
||||
void Interface::loadCartridge(const string &markup, const stream &memory) {
|
||||
cartridge.load(markup, memory.data(), memory.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,9 +3,8 @@ struct Interface {
|
|||
virtual void videoRefresh(const uint32_t *data);
|
||||
virtual void audioSample(int16_t sample);
|
||||
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;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define NES_HPP
|
||||
|
||||
#include <base/base.hpp>
|
||||
#include <processor/rp2a03/rp2a03.hpp>
|
||||
|
||||
namespace Famicom {
|
||||
namespace Info {
|
||||
|
|
|
@ -2,6 +2,7 @@ processor_objects :=
|
|||
processor_objects += $(if $(findstring arm,$(processors)),processor-arm)
|
||||
processor_objects += $(if $(findstring hg51b,$(processors)),processor-hg51b)
|
||||
processor_objects += $(if $(findstring lr35902,$(processors)),processor-lr35902)
|
||||
processor_objects += $(if $(findstring rp2a03,$(processors)),processor-rp2a03)
|
||||
processor_objects += $(if $(findstring upd96050,$(processors)),processor-upd96050)
|
||||
objects += $(processor_objects)
|
||||
|
||||
|
@ -9,4 +10,5 @@ processor := processor
|
|||
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-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)
|
||||
|
|
|
@ -1,24 +1,24 @@
|
|||
string CPU::disassemble() {
|
||||
string RP2A03::disassemble() {
|
||||
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 abx = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 2)), hex<2>(bus.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 iab = [&]() -> string { return { "($", hex<2>(bus.read(regs.pc + 2)), hex<2>(bus.read(regs.pc + 1)), ")" }; };
|
||||
auto imm = [&]() -> string { return { "#$", 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>(debugger_read(regs.pc + 2)), hex<2>(debugger_read(regs.pc + 1)), ",x" }; };
|
||||
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>(debugger_read(regs.pc + 2)), hex<2>(debugger_read(regs.pc + 1)), ")" }; };
|
||||
auto imm = [&]() -> string { return { "#$", hex<2>(debugger_read(regs.pc + 1)) }; };
|
||||
auto imp = [&]() -> string { return ""; };
|
||||
auto izx = [&]() -> string { return { "($", hex<2>(bus.read(regs.pc + 1)), ",x)" }; };
|
||||
auto izy = [&]() -> string { return { "($", hex<2>(bus.read(regs.pc + 1)), "),y" }; };
|
||||
auto rel = [&]() -> string { return { "$", hex<4>((regs.pc + 2) + (int8)bus.read(regs.pc + 1)) }; };
|
||||
auto zpg = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 1)) }; };
|
||||
auto zpx = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 1)), ",x" }; };
|
||||
auto zpy = [&]() -> string { return { "$", hex<2>(bus.read(regs.pc + 1)), ",y" }; };
|
||||
auto izx = [&]() -> string { return { "($", hex<2>(debugger_read(regs.pc + 1)), ",x)" }; };
|
||||
auto izy = [&]() -> string { return { "($", hex<2>(debugger_read(regs.pc + 1)), "),y" }; };
|
||||
auto rel = [&]() -> string { return { "$", hex<4>((regs.pc + 2) + (int8)debugger_read(regs.pc + 1)) }; };
|
||||
auto zpg = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 1)) }; };
|
||||
auto zpx = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 1)), ",x" }; };
|
||||
auto zpy = [&]() -> string { return { "$", hex<2>(debugger_read(regs.pc + 1)), ",y" }; };
|
||||
|
||||
#define op(byte, prefix, mode) \
|
||||
case byte: output.append(#prefix, " ", mode()); \
|
||||
break
|
||||
|
||||
uint8 opcode = bus.read(regs.pc);
|
||||
uint8 opcode = debugger_read(regs.pc);
|
||||
switch(opcode) {
|
||||
op(0x00, brk, imm);
|
||||
op(0x01, ora, izx);
|
|
@ -1,7 +1,7 @@
|
|||
//opcode functions
|
||||
//================
|
||||
|
||||
void CPU::opf_adc() {
|
||||
void RP2A03::opf_adc() {
|
||||
signed result = regs.a + rd + regs.p.c;
|
||||
regs.p.v = ~(regs.a ^ rd) & (regs.a ^ result) & 0x80;
|
||||
regs.p.c = (result > 0xff);
|
||||
|
@ -10,96 +10,96 @@ void CPU::opf_adc() {
|
|||
regs.a = result;
|
||||
}
|
||||
|
||||
void CPU::opf_and() {
|
||||
void RP2A03::opf_and() {
|
||||
regs.a &= rd;
|
||||
regs.p.n = (regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_asl() {
|
||||
void RP2A03::opf_asl() {
|
||||
regs.p.c = rd & 0x80;
|
||||
rd <<= 1;
|
||||
regs.p.n = (rd & 0x80);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_bit() {
|
||||
void RP2A03::opf_bit() {
|
||||
regs.p.n = (rd & 0x80);
|
||||
regs.p.v = (rd & 0x40);
|
||||
regs.p.z = ((rd & regs.a) == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_cmp() {
|
||||
void RP2A03::opf_cmp() {
|
||||
signed r = regs.a - rd;
|
||||
regs.p.n = (r & 0x80);
|
||||
regs.p.z = (uint8)(r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
}
|
||||
|
||||
void CPU::opf_cpx() {
|
||||
void RP2A03::opf_cpx() {
|
||||
signed r = regs.x - rd;
|
||||
regs.p.n = (r & 0x80);
|
||||
regs.p.z = (uint8)(r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
}
|
||||
|
||||
void CPU::opf_cpy() {
|
||||
void RP2A03::opf_cpy() {
|
||||
signed r = regs.y - rd;
|
||||
regs.p.n = (r & 0x80);
|
||||
regs.p.z = (uint8)(r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
}
|
||||
|
||||
void CPU::opf_dec() {
|
||||
void RP2A03::opf_dec() {
|
||||
rd--;
|
||||
regs.p.n = (rd & 0x80);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_eor() {
|
||||
void RP2A03::opf_eor() {
|
||||
regs.a ^= rd;
|
||||
regs.p.n = (regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_inc() {
|
||||
void RP2A03::opf_inc() {
|
||||
rd++;
|
||||
regs.p.n = (rd & 0x80);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_lda() {
|
||||
void RP2A03::opf_lda() {
|
||||
regs.a = rd;
|
||||
regs.p.n = (regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_ldx() {
|
||||
void RP2A03::opf_ldx() {
|
||||
regs.x = rd;
|
||||
regs.p.n = (regs.x & 0x80);
|
||||
regs.p.z = (regs.x == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_ldy() {
|
||||
void RP2A03::opf_ldy() {
|
||||
regs.y = rd;
|
||||
regs.p.n = (regs.y & 0x80);
|
||||
regs.p.z = (regs.y == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_lsr() {
|
||||
void RP2A03::opf_lsr() {
|
||||
regs.p.c = rd & 0x01;
|
||||
rd >>= 1;
|
||||
regs.p.n = (rd & 0x80);
|
||||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_ora() {
|
||||
void RP2A03::opf_ora() {
|
||||
regs.a |= rd;
|
||||
regs.p.n = (regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_rla() {
|
||||
void RP2A03::opf_rla() {
|
||||
unsigned carry = (unsigned)regs.p.c;
|
||||
regs.p.c = regs.a & 0x80;
|
||||
regs.a = (regs.a << 1) | carry;
|
||||
|
@ -107,7 +107,7 @@ void CPU::opf_rla() {
|
|||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_rol() {
|
||||
void RP2A03::opf_rol() {
|
||||
unsigned carry = (unsigned)regs.p.c;
|
||||
regs.p.c = rd & 0x80;
|
||||
rd = (rd << 1) | carry;
|
||||
|
@ -115,7 +115,7 @@ void CPU::opf_rol() {
|
|||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_ror() {
|
||||
void RP2A03::opf_ror() {
|
||||
unsigned carry = (unsigned)regs.p.c << 7;
|
||||
regs.p.c = rd & 0x01;
|
||||
rd = carry | (rd >> 1);
|
||||
|
@ -123,7 +123,7 @@ void CPU::opf_ror() {
|
|||
regs.p.z = (rd == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_rra() {
|
||||
void RP2A03::opf_rra() {
|
||||
unsigned carry = (unsigned)regs.p.c << 7;
|
||||
regs.p.c = regs.a & 0x01;
|
||||
regs.a = carry | (regs.a >> 1);
|
||||
|
@ -131,19 +131,19 @@ void CPU::opf_rra() {
|
|||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_sbc() {
|
||||
void RP2A03::opf_sbc() {
|
||||
rd ^= 0xff;
|
||||
return opf_adc();
|
||||
}
|
||||
|
||||
void CPU::opf_sla() {
|
||||
void RP2A03::opf_sla() {
|
||||
regs.p.c = regs.a & 0x80;
|
||||
regs.a <<= 1;
|
||||
regs.p.n = (regs.a & 0x80);
|
||||
regs.p.z = (regs.a == 0);
|
||||
}
|
||||
|
||||
void CPU::opf_sra() {
|
||||
void RP2A03::opf_sra() {
|
||||
regs.p.c = regs.a & 0x01;
|
||||
regs.a >>= 1;
|
||||
regs.p.n = (regs.a & 0x80);
|
||||
|
@ -153,7 +153,7 @@ void CPU::opf_sra() {
|
|||
//opcode implementations
|
||||
//======================
|
||||
|
||||
void CPU::opi_branch(bool condition) {
|
||||
void RP2A03::opi_branch(bool condition) {
|
||||
if(condition == false) {
|
||||
L rd = op_readpci();
|
||||
} 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();
|
||||
flag = 0;
|
||||
}
|
||||
|
||||
void CPU::opi_decrement(uint8 &r) {
|
||||
void RP2A03::opi_decrement(uint8 &r) {
|
||||
L op_readpc();
|
||||
r--;
|
||||
regs.p.n = (r & 0x80);
|
||||
regs.p.z = (r == 0);
|
||||
}
|
||||
|
||||
void CPU::opi_increment(uint8 &r) {
|
||||
void RP2A03::opi_increment(uint8 &r) {
|
||||
L op_readpc();
|
||||
r++;
|
||||
regs.p.n = (r & 0x80);
|
||||
regs.p.z = (r == 0);
|
||||
}
|
||||
|
||||
void CPU::opi_pull(uint8 &r) {
|
||||
void RP2A03::opi_pull(uint8 &r) {
|
||||
op_readpc();
|
||||
op_readpc();
|
||||
L r = op_readsp();
|
||||
|
@ -192,21 +192,21 @@ L r = op_readsp();
|
|||
regs.p.z = (r == 0);
|
||||
}
|
||||
|
||||
void CPU::opi_push(uint8 &r) {
|
||||
void RP2A03::opi_push(uint8 &r) {
|
||||
op_readpc();
|
||||
L op_writesp(r);
|
||||
}
|
||||
|
||||
template<void (CPU::*op)()>
|
||||
void CPU::opi_read_absolute() {
|
||||
template<void (RP2A03::*op)()>
|
||||
void RP2A03::opi_read_absolute() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
L rd = op_read(abs.w);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<void (CPU::*op)()>
|
||||
void CPU::opi_read_absolute_x() {
|
||||
template<void (RP2A03::*op)()>
|
||||
void RP2A03::opi_read_absolute_x() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_page(abs.w, abs.w + regs.x);
|
||||
|
@ -214,8 +214,8 @@ L rd = op_read(abs.w + regs.x);
|
|||
call(op);
|
||||
}
|
||||
|
||||
template<void (CPU::*op)()>
|
||||
void CPU::opi_read_absolute_y() {
|
||||
template<void (RP2A03::*op)()>
|
||||
void RP2A03::opi_read_absolute_y() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_page(abs.w, abs.w + regs.y);
|
||||
|
@ -223,14 +223,14 @@ L rd = op_read(abs.w + regs.y);
|
|||
call(op);
|
||||
}
|
||||
|
||||
template<void (CPU::*op)()>
|
||||
void CPU::opi_read_immediate() {
|
||||
template<void (RP2A03::*op)()>
|
||||
void RP2A03::opi_read_immediate() {
|
||||
L rd = op_readpci();
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<void (CPU::*op)()>
|
||||
void CPU::opi_read_indirect_zero_page_x() {
|
||||
template<void (RP2A03::*op)()>
|
||||
void RP2A03::opi_read_indirect_zero_page_x() {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
abs.l = op_readzp(zp++ + regs.x);
|
||||
|
@ -239,8 +239,8 @@ L rd = op_read(abs.w);
|
|||
call(op);
|
||||
}
|
||||
|
||||
template<void (CPU::*op)()>
|
||||
void CPU::opi_read_indirect_zero_page_y() {
|
||||
template<void (RP2A03::*op)()>
|
||||
void RP2A03::opi_read_indirect_zero_page_y() {
|
||||
rd = op_readpci();
|
||||
abs.l = op_readzp(rd++);
|
||||
abs.h = op_readzp(rd++);
|
||||
|
@ -249,31 +249,31 @@ L rd = op_read(abs.w + regs.y);
|
|||
call(op);
|
||||
}
|
||||
|
||||
template<void (CPU::*op)()>
|
||||
void CPU::opi_read_zero_page() {
|
||||
template<void (RP2A03::*op)()>
|
||||
void RP2A03::opi_read_zero_page() {
|
||||
zp = op_readpci();
|
||||
L rd = op_readzp(zp);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<void (CPU::*op)()>
|
||||
void CPU::opi_read_zero_page_x() {
|
||||
template<void (RP2A03::*op)()>
|
||||
void RP2A03::opi_read_zero_page_x() {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
L rd = op_readzp(zp + regs.x);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<void (CPU::*op)()>
|
||||
void CPU::opi_read_zero_page_y() {
|
||||
template<void (RP2A03::*op)()>
|
||||
void RP2A03::opi_read_zero_page_y() {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
L rd = op_readzp(zp + regs.y);
|
||||
call(op);
|
||||
}
|
||||
|
||||
template<void (CPU::*op)()>
|
||||
void CPU::opi_rmw_absolute() {
|
||||
template<void (RP2A03::*op)()>
|
||||
void RP2A03::opi_rmw_absolute() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
rd = op_read(abs.w);
|
||||
|
@ -282,8 +282,8 @@ void CPU::opi_rmw_absolute() {
|
|||
L op_write(abs.w, rd);
|
||||
}
|
||||
|
||||
template<void (CPU::*op)()>
|
||||
void CPU::opi_rmw_absolute_x() {
|
||||
template<void (RP2A03::*op)()>
|
||||
void RP2A03::opi_rmw_absolute_x() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
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);
|
||||
}
|
||||
|
||||
template<void (CPU::*op)()>
|
||||
void CPU::opi_rmw_zero_page() {
|
||||
template<void (RP2A03::*op)()>
|
||||
void RP2A03::opi_rmw_zero_page() {
|
||||
zp = op_readpci();
|
||||
rd = op_readzp(zp);
|
||||
op_writezp(zp, rd);
|
||||
|
@ -302,8 +302,8 @@ void CPU::opi_rmw_zero_page() {
|
|||
L op_writezp(zp, rd);
|
||||
}
|
||||
|
||||
template<void (CPU::*op)()>
|
||||
void CPU::opi_rmw_zero_page_x() {
|
||||
template<void (RP2A03::*op)()>
|
||||
void RP2A03::opi_rmw_zero_page_x() {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
rd = op_readzp(zp + regs.x);
|
||||
|
@ -312,38 +312,38 @@ void CPU::opi_rmw_zero_page_x() {
|
|||
L op_writezp(zp + regs.x, rd);
|
||||
}
|
||||
|
||||
void CPU::opi_set_flag(bool &flag) {
|
||||
void RP2A03::opi_set_flag(bool &flag) {
|
||||
L op_readpc();
|
||||
flag = 1;
|
||||
}
|
||||
|
||||
template<void (CPU::*op)()>
|
||||
void CPU::opi_shift() {
|
||||
template<void (RP2A03::*op)()>
|
||||
void RP2A03::opi_shift() {
|
||||
L op_readpc();
|
||||
call(op);
|
||||
}
|
||||
|
||||
void CPU::opi_store_absolute(uint8 &r) {
|
||||
void RP2A03::opi_store_absolute(uint8 &r) {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
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.h = op_readpci();
|
||||
op_page_always(abs.w, abs.w + regs.x);
|
||||
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.h = op_readpci();
|
||||
op_page_always(abs.w, abs.w + regs.y);
|
||||
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();
|
||||
op_readzp(zp);
|
||||
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);
|
||||
}
|
||||
|
||||
void CPU::opi_store_indirect_zero_page_y(uint8 &r) {
|
||||
void RP2A03::opi_store_indirect_zero_page_y(uint8 &r) {
|
||||
rd = op_readpci();
|
||||
abs.l = 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);
|
||||
}
|
||||
|
||||
void CPU::opi_store_zero_page(uint8 &r) {
|
||||
void RP2A03::opi_store_zero_page(uint8 &r) {
|
||||
zp = op_readpci();
|
||||
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();
|
||||
op_readzp(zp);
|
||||
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();
|
||||
op_readzp(zp);
|
||||
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();
|
||||
d = s;
|
||||
if(flag == false) return;
|
||||
|
@ -387,7 +387,7 @@ L op_readpc();
|
|||
//opcodes
|
||||
//=======
|
||||
|
||||
void CPU::op_brk() {
|
||||
void RP2A03::op_brk() {
|
||||
op_readpci();
|
||||
op_writesp(regs.pc >> 8);
|
||||
op_writesp(regs.pc >> 0);
|
||||
|
@ -399,13 +399,13 @@ L abs.h = op_read(0xffff);
|
|||
regs.pc = abs.w;
|
||||
}
|
||||
|
||||
void CPU::op_jmp_absolute() {
|
||||
void RP2A03::op_jmp_absolute() {
|
||||
abs.l = op_readpci();
|
||||
L abs.h = op_readpci();
|
||||
regs.pc = abs.w;
|
||||
}
|
||||
|
||||
void CPU::op_jmp_indirect_absolute() {
|
||||
void RP2A03::op_jmp_indirect_absolute() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
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;
|
||||
}
|
||||
|
||||
void CPU::op_jsr_absolute() {
|
||||
void RP2A03::op_jsr_absolute() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_readpc();
|
||||
|
@ -423,22 +423,22 @@ L op_writesp(regs.pc >> 0);
|
|||
regs.pc = abs.w;
|
||||
}
|
||||
|
||||
void CPU::op_nop() {
|
||||
void RP2A03::op_nop() {
|
||||
L op_readpc();
|
||||
}
|
||||
|
||||
void CPU::op_php() {
|
||||
void RP2A03::op_php() {
|
||||
op_readpc();
|
||||
L op_writesp(regs.p | 0x30);
|
||||
}
|
||||
|
||||
void CPU::op_plp() {
|
||||
void RP2A03::op_plp() {
|
||||
op_readpc();
|
||||
op_readpc();
|
||||
L regs.p = op_readsp();
|
||||
}
|
||||
|
||||
void CPU::op_rti() {
|
||||
void RP2A03::op_rti() {
|
||||
op_readpc();
|
||||
op_readpc();
|
||||
regs.p = op_readsp();
|
||||
|
@ -447,7 +447,7 @@ L abs.h = op_readsp();
|
|||
regs.pc = abs.w;
|
||||
}
|
||||
|
||||
void CPU::op_rts() {
|
||||
void RP2A03::op_rts() {
|
||||
op_readpc();
|
||||
op_readpc();
|
||||
abs.l = op_readsp();
|
||||
|
@ -459,7 +459,7 @@ L op_readpc();
|
|||
//illegal opcodes
|
||||
//===============
|
||||
|
||||
void CPU::opill_arr_immediate() {
|
||||
void RP2A03::opill_arr_immediate() {
|
||||
L rd = op_readpci();
|
||||
regs.a &= rd;
|
||||
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);
|
||||
}
|
||||
|
||||
void CPU::opill_nop_absolute() {
|
||||
void RP2A03::opill_nop_absolute() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
L op_readpc();
|
||||
}
|
||||
|
||||
void CPU::opill_nop_absolute_x() {
|
||||
void RP2A03::opill_nop_absolute_x() {
|
||||
abs.l = op_readpci();
|
||||
abs.h = op_readpci();
|
||||
op_page(abs.w, abs.w + regs.x);
|
||||
L op_readpc();
|
||||
}
|
||||
|
||||
void CPU::opill_nop_immediate() {
|
||||
void RP2A03::opill_nop_immediate() {
|
||||
L rd = op_readpc();
|
||||
}
|
||||
|
||||
void CPU::opill_nop_implied() {
|
||||
void RP2A03::opill_nop_implied() {
|
||||
L op_readpc();
|
||||
}
|
||||
|
||||
void CPU::opill_nop_zero_page() {
|
||||
void RP2A03::opill_nop_zero_page() {
|
||||
zp = op_readpci();
|
||||
L op_readzp(zp);
|
||||
}
|
||||
|
||||
void CPU::opill_nop_zero_page_x() {
|
||||
void RP2A03::opill_nop_zero_page_x() {
|
||||
zp = op_readpci();
|
||||
op_readzp(zp);
|
||||
L op_readzp(zp + regs.x);
|
|
@ -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));
|
||||
}
|
|
@ -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;
|
|
@ -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
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
processors := arm hg51b lr35902 upd96050
|
||||
processors := arm hg51b lr35902 rp2a03 upd96050
|
||||
include processor/Makefile
|
||||
|
||||
include $(nes)/Makefile
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace GBA = GameBoyAdvance;
|
|||
#include <nall/filemap.hpp>
|
||||
#include <nall/input.hpp>
|
||||
#include <nall/bps/patch.hpp>
|
||||
#include <nall/stream/file.hpp>
|
||||
#include <nall/stream/memory.hpp>
|
||||
#include <nall/stream/vector.hpp>
|
||||
#include <nall/nes/cartridge.hpp>
|
||||
|
|
|
@ -34,7 +34,7 @@ bool InterfaceGBA::loadCartridge(const string &filename) {
|
|||
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
||||
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();
|
||||
|
||||
if(GBA::cartridge.ram_size()) {
|
||||
|
|
|
@ -47,7 +47,7 @@ bool InterfaceNES::loadCartridge(const string &filename) {
|
|||
markup.readfile(interface->base.filename("manifest.xml", ".xml"));
|
||||
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();
|
||||
|
||||
if(NES::cartridge.ram_size()) {
|
||||
|
|
Loading…
Reference in New Issue