mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-20 20:51:35 +02:00
Compare commits
15 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
73ebe093b8 | ||
|
c3f9d421da | ||
|
689fc49047 | ||
|
cb97d98ad2 | ||
|
3cb04b101b | ||
|
5d273c5265 | ||
|
8703d57030 | ||
|
9ad8b7eaac | ||
|
76553756a2 | ||
|
4fd20f0ae0 | ||
|
bb4db22a7d | ||
|
67c13f749f | ||
|
616372e96b | ||
|
bba597fc6f | ||
|
abe639ea91 |
@@ -1,12 +1,12 @@
|
||||
include nall/Makefile
|
||||
|
||||
nes := nes
|
||||
snes := snes
|
||||
gb := gb
|
||||
gba := gba
|
||||
fc := fc
|
||||
sfc := sfc
|
||||
gb := gb
|
||||
gba := gba
|
||||
|
||||
profile := accuracy
|
||||
target := ui
|
||||
target := ethos
|
||||
|
||||
# options += console
|
||||
|
||||
|
218557
bsnes/data/cheats.xml
218557
bsnes/data/cheats.xml
File diff suppressed because it is too large
Load Diff
@@ -1,30 +1,36 @@
|
||||
#ifndef BASE_HPP
|
||||
#define BASE_HPP
|
||||
#ifndef EMULATOR_HPP
|
||||
#define EMULATOR_HPP
|
||||
|
||||
static const char Version[] = "088";
|
||||
namespace Emulator {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "089";
|
||||
static const char Author[] = "byuu";
|
||||
static const char License[] = "GPLv3";
|
||||
}
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/algorithm.hpp>
|
||||
#include <nall/any.hpp>
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/bitarray.hpp>
|
||||
#include <nall/dl.hpp>
|
||||
#include <nall/dsp.hpp>
|
||||
#include <nall/endian.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/moduloarray.hpp>
|
||||
#include <nall/priorityqueue.hpp>
|
||||
#include <nall/property.hpp>
|
||||
#include <nall/random.hpp>
|
||||
#include <nall/serializer.hpp>
|
||||
#include <nall/sha256.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
#include <nall/varint.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
#include <nall/stream/memory.hpp>
|
||||
#include <nall/stream/vector.hpp>
|
||||
using namespace nall;
|
||||
|
||||
#include "interface.hpp"
|
||||
|
||||
//debugging function hook:
|
||||
//no overhead (and no debugger invocation) if not compiled with -DDEBUGGER
|
||||
//wraps testing of function to allow invocation without a defined callback
|
||||
@@ -43,8 +49,8 @@ template<typename R, typename... P> struct hook<R (P...)> {
|
||||
hook(const hook &hook) { callback = hook.callback; }
|
||||
hook(void *function) { callback = function; }
|
||||
hook(R (*function)(P...)) { callback = function; }
|
||||
template<typename C> hook(R (C::*function)(P...), C *object) { callback = { function, object }; }
|
||||
template<typename C> hook(R (C::*function)(P...) const, C *object) { callback = { function, object }; }
|
||||
template<typename C> hook(R (C::*function)(P...), C *object) { callback = {function, object}; }
|
||||
template<typename C> hook(R (C::*function)(P...) const, C *object) { callback = {function, object}; }
|
||||
template<typename L> hook(const L& function) { callback = function; }
|
||||
|
||||
hook& operator=(const hook& hook) { callback = hook.callback; return *this; }
|
108
bsnes/emulator/interface.hpp
Executable file
108
bsnes/emulator/interface.hpp
Executable file
@@ -0,0 +1,108 @@
|
||||
#ifndef EMULATOR_INTERFACE_HPP
|
||||
#define EMULATOR_INTERFACE_HPP
|
||||
|
||||
namespace Emulator {
|
||||
|
||||
struct Interface {
|
||||
struct Information {
|
||||
string name;
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
bool overscan;
|
||||
double aspectRatio;
|
||||
bool resettable;
|
||||
} information;
|
||||
|
||||
struct Media {
|
||||
unsigned id;
|
||||
string name;
|
||||
string type;
|
||||
string path;
|
||||
string extension;
|
||||
};
|
||||
|
||||
vector<Media> firmware;
|
||||
vector<Media> media;
|
||||
|
||||
struct Memory {
|
||||
unsigned id;
|
||||
string name;
|
||||
};
|
||||
vector<Memory> memory;
|
||||
|
||||
struct Device {
|
||||
unsigned id;
|
||||
unsigned portmask;
|
||||
string name;
|
||||
struct Input {
|
||||
unsigned id;
|
||||
unsigned type; //0 = digital, 1 = analog
|
||||
string name;
|
||||
unsigned guid;
|
||||
};
|
||||
vector<Input> input;
|
||||
vector<unsigned> order;
|
||||
};
|
||||
|
||||
struct Port {
|
||||
unsigned id;
|
||||
string name;
|
||||
vector<Device> device;
|
||||
};
|
||||
vector<Port> port;
|
||||
|
||||
struct Bind {
|
||||
virtual void loadRequest(unsigned, const string&) {}
|
||||
virtual void loadRequest(unsigned, const string&, const string&, const string&) {}
|
||||
virtual uint32_t videoColor(unsigned, uint16_t, uint16_t, uint16_t) { return 0u; }
|
||||
virtual void videoRefresh(const uint32_t*, unsigned, unsigned, unsigned) {}
|
||||
virtual void audioSample(int16_t, int16_t) {}
|
||||
virtual int16_t inputPoll(unsigned, unsigned, unsigned) { return 0; }
|
||||
virtual unsigned dipSettings(const XML::Node&) { return 0; }
|
||||
virtual string path(unsigned) { return ""; }
|
||||
} *bind;
|
||||
|
||||
//callback bindings (provided by user interface)
|
||||
void loadRequest(unsigned id, const string &path) { return bind->loadRequest(id, path); }
|
||||
void loadRequest(unsigned id, const string &name, const string &type, const string &path) { return bind->loadRequest(id, name, type, path); }
|
||||
uint32_t videoColor(unsigned source, uint16_t red, uint16_t green, uint16_t blue) { return bind->videoColor(source, red, green, blue); }
|
||||
void videoRefresh(const uint32_t *data, unsigned pitch, unsigned width, unsigned height) { return bind->videoRefresh(data, pitch, width, height); }
|
||||
void audioSample(int16_t lsample, int16_t rsample) { return bind->audioSample(lsample, rsample); }
|
||||
int16_t inputPoll(unsigned port, unsigned device, unsigned input) { return bind->inputPoll(port, device, input); }
|
||||
unsigned dipSettings(const XML::Node &node) { return bind->dipSettings(node); }
|
||||
string path(unsigned group) { return bind->path(group); }
|
||||
|
||||
//information
|
||||
virtual double videoFrequency() = 0;
|
||||
virtual double audioFrequency() = 0;
|
||||
|
||||
//media interface
|
||||
virtual bool loaded() { return false; }
|
||||
virtual string sha256() { return ""; }
|
||||
virtual unsigned group(unsigned id) { return 0u; }
|
||||
virtual void load(unsigned id, const stream &memory, const string &markup = "") {}
|
||||
virtual void save(unsigned id, const stream &memory) {}
|
||||
virtual void unload() {}
|
||||
|
||||
//system interface
|
||||
virtual void connect(unsigned port, unsigned device) {}
|
||||
virtual void power() {}
|
||||
virtual void reset() {}
|
||||
virtual void run() {}
|
||||
|
||||
//state functions
|
||||
virtual serializer serialize() = 0;
|
||||
virtual bool unserialize(serializer&) = 0;
|
||||
|
||||
//cheat functions
|
||||
virtual void cheatSet(const lstring& = lstring{}) {}
|
||||
|
||||
//utility functions
|
||||
virtual void updatePalette() {}
|
||||
|
||||
Interface() : bind(nullptr) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
16
bsnes/fc/Makefile
Executable file
16
bsnes/fc/Makefile
Executable file
@@ -0,0 +1,16 @@
|
||||
fc_objects := fc-interface fc-system fc-scheduler fc-input
|
||||
fc_objects += fc-memory fc-cartridge fc-cpu fc-apu fc-ppu
|
||||
fc_objects += fc-cheat fc-video
|
||||
objects += $(fc_objects)
|
||||
|
||||
obj/fc-interface.o: $(fc)/interface/interface.cpp $(call rwildcard,$(fc)/interface/)
|
||||
obj/fc-system.o: $(fc)/system/system.cpp $(call rwildcard,$(fc)/system/)
|
||||
obj/fc-scheduler.o: $(fc)/scheduler/scheduler.cpp $(call rwildcard,$(fc)/scheduler/)
|
||||
obj/fc-input.o: $(fc)/input/input.cpp $(call rwildcard,$(fc)/input/)
|
||||
obj/fc-memory.o: $(fc)/memory/memory.cpp $(call rwildcard,$(fc)/memory/)
|
||||
obj/fc-cartridge.o: $(fc)/cartridge/cartridge.cpp $(call rwildcard,$(fc)/cartridge/)
|
||||
obj/fc-cpu.o: $(fc)/cpu/cpu.cpp $(call rwildcard,$(fc)/cpu/)
|
||||
obj/fc-apu.o: $(fc)/apu/apu.cpp $(call rwildcard,$(fc)/apu/)
|
||||
obj/fc-ppu.o: $(fc)/ppu/ppu.cpp $(call rwildcard,$(fc)/ppu/)
|
||||
obj/fc-cheat.o: $(fc)/cheat/cheat.cpp $(call rwildcard,$(fc)/cheat/)
|
||||
obj/fc-video.o: $(fc)/video/video.cpp $(call rwildcard,$(fc)/video/)
|
@@ -1,6 +1,6 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
#include "envelope.cpp"
|
||||
#include "sweep.cpp"
|
||||
@@ -60,7 +60,7 @@ void APU::main() {
|
||||
//output = filter.run_lopass(output);
|
||||
output = sclamp<16>(output);
|
||||
|
||||
interface->audioSample(output);
|
||||
interface->audioSample(output, output);
|
||||
|
||||
tick();
|
||||
}
|
@@ -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) {
|
||||
}
|
||||
|
||||
};
|
@@ -1,6 +1,6 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
#include "chip/chip.cpp"
|
||||
#include "board/board.cpp"
|
||||
@@ -14,18 +14,25 @@ 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;
|
||||
|
||||
interface->memory.append({ID::RAM, "save.ram"});
|
||||
|
||||
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,6 +1,6 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
Cheat cheat;
|
||||
|
@@ -1,40 +1,30 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
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;
|
||||
R6502::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;
|
||||
R6502::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::R6502, 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,27 +1,9 @@
|
||||
void CPU::serialize(serializer &s) {
|
||||
R6502::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);
|
63
bsnes/fc/cpu/timing.cpp
Executable file
63
bsnes/fc/cpu/timing.cpp
Executable 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;
|
||||
}
|
@@ -1,17 +1,18 @@
|
||||
#ifndef NES_HPP
|
||||
#define NES_HPP
|
||||
#ifndef FC_HPP
|
||||
#define FC_HPP
|
||||
|
||||
#include <base/base.hpp>
|
||||
#include <emulator/emulator.hpp>
|
||||
#include <processor/r6502/r6502.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
namespace Info {
|
||||
static const char Name[] = "bnes";
|
||||
static const unsigned SerializerVersion = 1;
|
||||
static const unsigned SerializerVersion = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bnes - NES emulator
|
||||
bnes - Famicom emulator
|
||||
authors: byuu, Ryphecha
|
||||
license: GPLv3
|
||||
project started: 2011-09-05
|
||||
@@ -19,7 +20,7 @@ namespace NES {
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
struct Thread {
|
||||
cothread_t thread;
|
||||
unsigned frequency;
|
||||
@@ -45,17 +46,17 @@ namespace NES {
|
||||
}
|
||||
};
|
||||
|
||||
#include <nes/system/system.hpp>
|
||||
#include <nes/scheduler/scheduler.hpp>
|
||||
#include <nes/input/input.hpp>
|
||||
#include <nes/memory/memory.hpp>
|
||||
#include <nes/cartridge/cartridge.hpp>
|
||||
#include <nes/cpu/cpu.hpp>
|
||||
#include <nes/apu/apu.hpp>
|
||||
#include <nes/ppu/ppu.hpp>
|
||||
#include <nes/cheat/cheat.hpp>
|
||||
#include <nes/video/video.hpp>
|
||||
#include <nes/interface/interface.hpp>
|
||||
#include <fc/system/system.hpp>
|
||||
#include <fc/scheduler/scheduler.hpp>
|
||||
#include <fc/input/input.hpp>
|
||||
#include <fc/memory/memory.hpp>
|
||||
#include <fc/cartridge/cartridge.hpp>
|
||||
#include <fc/cpu/cpu.hpp>
|
||||
#include <fc/apu/apu.hpp>
|
||||
#include <fc/ppu/ppu.hpp>
|
||||
#include <fc/cheat/cheat.hpp>
|
||||
#include <fc/video/video.hpp>
|
||||
#include <fc/interface/interface.hpp>
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,6 +1,6 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
#include "serialization.cpp"
|
||||
Input input;
|
121
bsnes/fc/interface/interface.cpp
Executable file
121
bsnes/fc/interface/interface.cpp
Executable file
@@ -0,0 +1,121 @@
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace Famicom {
|
||||
|
||||
Interface *interface = nullptr;
|
||||
|
||||
double Interface::videoFrequency() {
|
||||
return 21477272.0 / (262.0 * 1364.0 - 4.0);
|
||||
}
|
||||
|
||||
double Interface::audioFrequency() {
|
||||
return 21477272.0 / 12.0;
|
||||
}
|
||||
|
||||
bool Interface::loaded() {
|
||||
return cartridge.loaded();
|
||||
}
|
||||
|
||||
string Interface::sha256() {
|
||||
return cartridge.sha256();
|
||||
}
|
||||
|
||||
void Interface::load(unsigned id, const stream &stream, const string &markup) {
|
||||
if(id == ID::ROM) {
|
||||
cartridge.load(markup, stream);
|
||||
system.power();
|
||||
input.connect(0, Input::Device::Joypad);
|
||||
input.connect(1, Input::Device::Joypad);
|
||||
}
|
||||
|
||||
if(id == ID::RAM) {
|
||||
stream.read(cartridge.ram_data(), min(stream.size(), cartridge.ram_size()));
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::save(unsigned id, const stream &stream) {
|
||||
if(id == ID::RAM) {
|
||||
stream.write(cartridge.ram_data(), cartridge.ram_size());
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::unload() {
|
||||
cartridge.unload();
|
||||
}
|
||||
|
||||
void Interface::power() {
|
||||
system.power();
|
||||
}
|
||||
|
||||
void Interface::reset() {
|
||||
system.reset();
|
||||
}
|
||||
|
||||
void Interface::run() {
|
||||
system.run();
|
||||
}
|
||||
|
||||
serializer Interface::serialize() {
|
||||
system.runtosave();
|
||||
return system.serialize();
|
||||
}
|
||||
|
||||
bool Interface::unserialize(serializer &s) {
|
||||
return system.unserialize(s);
|
||||
}
|
||||
|
||||
void Interface::cheatSet(const lstring &list) {
|
||||
cheat.reset();
|
||||
for(auto &code : list) {
|
||||
lstring codelist = code.split("+");
|
||||
for(auto &part : codelist) {
|
||||
unsigned addr, data, comp;
|
||||
if(Cheat::decode(part, addr, data, comp)) cheat.append({addr, data, comp});
|
||||
}
|
||||
}
|
||||
cheat.synchronize();
|
||||
}
|
||||
|
||||
void Interface::updatePalette() {
|
||||
video.generate_palette();
|
||||
}
|
||||
|
||||
Interface::Interface() {
|
||||
interface = this;
|
||||
|
||||
information.name = "Famicom";
|
||||
information.width = 256;
|
||||
information.height = 240;
|
||||
information.overscan = true;
|
||||
information.aspectRatio = 8.0 / 7.0;
|
||||
information.resettable = true;
|
||||
|
||||
media.append({ID::ROM, "Famicom", "sys", "program.rom", "fc"});
|
||||
|
||||
{
|
||||
Device device{0, ID::Port1 | ID::Port2, "Controller"};
|
||||
device.input.append({0, 0, "A" });
|
||||
device.input.append({1, 0, "B" });
|
||||
device.input.append({2, 0, "Select"});
|
||||
device.input.append({3, 0, "Start" });
|
||||
device.input.append({4, 0, "Up" });
|
||||
device.input.append({5, 0, "Down" });
|
||||
device.input.append({6, 0, "Left" });
|
||||
device.input.append({7, 0, "Right" });
|
||||
device.order = {4, 5, 6, 7, 1, 0, 2, 3};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
port.append({0, "Port 1"});
|
||||
port.append({1, "Port 2"});
|
||||
|
||||
for(auto &device : this->device) {
|
||||
for(auto &port : this->port) {
|
||||
if(device.portmask & (1 << port.id)) {
|
||||
port.device.append(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
48
bsnes/fc/interface/interface.hpp
Executable file
48
bsnes/fc/interface/interface.hpp
Executable file
@@ -0,0 +1,48 @@
|
||||
#ifndef FC_HPP
|
||||
namespace Famicom {
|
||||
#endif
|
||||
|
||||
struct ID {
|
||||
enum : unsigned {
|
||||
ROM,
|
||||
RAM,
|
||||
};
|
||||
|
||||
enum : unsigned {
|
||||
Port1 = 1,
|
||||
Port2 = 2,
|
||||
};
|
||||
};
|
||||
|
||||
struct Interface : Emulator::Interface {
|
||||
double videoFrequency();
|
||||
double audioFrequency();
|
||||
|
||||
bool loaded();
|
||||
string sha256();
|
||||
void load(unsigned id, const stream &stream, const string &markup = "");
|
||||
void save(unsigned id, const stream &stream);
|
||||
void unload();
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
void run();
|
||||
|
||||
serializer serialize();
|
||||
bool unserialize(serializer&);
|
||||
|
||||
void cheatSet(const lstring&);
|
||||
|
||||
void updatePalette();
|
||||
|
||||
Interface();
|
||||
|
||||
private:
|
||||
vector<Device> device;
|
||||
};
|
||||
|
||||
extern Interface *interface;
|
||||
|
||||
#ifndef FC_HPP
|
||||
}
|
||||
#endif
|
@@ -1,6 +1,6 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
Bus bus;
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
#include "serialization.cpp"
|
||||
PPU ppu;
|
||||
@@ -47,7 +47,6 @@ void PPU::scanline() {
|
||||
|
||||
void PPU::frame() {
|
||||
status.field ^= 1;
|
||||
interface->videoRefresh(buffer);
|
||||
scheduler.exit(Scheduler::ExitReason::FrameEvent);
|
||||
}
|
||||
|
||||
@@ -282,7 +281,7 @@ void PPU::scrolly_increment() {
|
||||
//
|
||||
|
||||
void PPU::raster_pixel() {
|
||||
uint16 *output = buffer + status.ly * 256;
|
||||
uint32 *output = buffer + status.ly * 256;
|
||||
|
||||
unsigned mask = 0x8000 >> (status.xaddr + (status.lx & 7));
|
||||
unsigned palette = 0, object_palette = 0;
|
||||
@@ -325,7 +324,7 @@ void PPU::raster_pixel() {
|
||||
}
|
||||
|
||||
if(raster_enable() == false) palette = 0;
|
||||
output[status.lx] = (status.emphasis << 6) | cgram_read(palette);
|
||||
output[status.lx] = video.palette[(status.emphasis << 6) | cgram_read(palette)];
|
||||
}
|
||||
|
||||
void PPU::raster_sprite() {
|
@@ -98,7 +98,7 @@ struct PPU : Thread {
|
||||
} oam[8], soam[8];
|
||||
} raster;
|
||||
|
||||
uint16 buffer[256 * 262];
|
||||
uint32 buffer[256 * 262];
|
||||
uint8 ciram[2048];
|
||||
uint8 cgram[32];
|
||||
uint8 oam[256];
|
@@ -1,6 +1,6 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
Scheduler scheduler;
|
||||
|
@@ -1,13 +1,14 @@
|
||||
serializer System::serialize() {
|
||||
serializer s(serialize_size);
|
||||
|
||||
unsigned signature = 0x31545342, version = Info::SerializerVersion, crc32 = 0;
|
||||
char description[512];
|
||||
unsigned signature = 0x31545342, version = Info::SerializerVersion;
|
||||
char hash[64], description[512];
|
||||
memcpy(&hash, (const char*)cartridge.sha256(), 64);
|
||||
memset(&description, 0, sizeof description);
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.integer(crc32);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
serialize_all(s);
|
||||
@@ -15,17 +16,16 @@ serializer System::serialize() {
|
||||
}
|
||||
|
||||
bool System::unserialize(serializer &s) {
|
||||
unsigned signature, version, crc32;
|
||||
char description[512];
|
||||
unsigned signature, version;
|
||||
char hash[64], description[512];
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.integer(crc32);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
if(signature != 0x31545342) return false;
|
||||
if(version != Info::SerializerVersion) return false;
|
||||
//if(crc32 != 0) return false;
|
||||
|
||||
power();
|
||||
serialize_all(s);
|
||||
@@ -47,12 +47,12 @@ void System::serialize_all(serializer &s) {
|
||||
void System::serialize_init() {
|
||||
serializer s;
|
||||
|
||||
unsigned signature = 0, version = 0, crc32 = 0;
|
||||
char description[512];
|
||||
unsigned signature = 0, version = 0;
|
||||
char hash[64], description[512];
|
||||
|
||||
s.integer(signature);
|
||||
s.integer(version);
|
||||
s.integer(crc32);
|
||||
s.array(hash);
|
||||
s.array(description);
|
||||
|
||||
serialize_all(s);
|
@@ -1,12 +1,15 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
#include "serialization.cpp"
|
||||
System system;
|
||||
|
||||
void System::run() {
|
||||
scheduler.enter();
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
|
||||
interface->videoRefresh(ppu.buffer, 4 * 256, 256, 240);
|
||||
}
|
||||
}
|
||||
|
||||
void System::runtosave() {
|
||||
@@ -32,7 +35,9 @@ void System::runthreadtosave() {
|
||||
while(true) {
|
||||
scheduler.enter();
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::SynchronizeEvent) break;
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent);
|
||||
if(scheduler.exit_reason() == Scheduler::ExitReason::FrameEvent) {
|
||||
interface->videoRefresh(ppu.buffer, 4 * 256, 256, 240);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +1,23 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
#define VIDEO_CPP
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
Video video;
|
||||
|
||||
unsigned Video::palette30(
|
||||
void Video::generate_palette() {
|
||||
for(unsigned n = 0; n < (1 << 9); n++) palette[n] = generate_color(n, 2.0, 0.0, 1.0, 1.0, 1.8);
|
||||
}
|
||||
|
||||
Video::Video() {
|
||||
palette = new unsigned[1 << 9];
|
||||
}
|
||||
|
||||
Video::~Video() {
|
||||
delete[] palette;
|
||||
}
|
||||
|
||||
uint32_t Video::generate_color(
|
||||
unsigned n, double saturation, double hue,
|
||||
double contrast, double brightness, double gamma
|
||||
) {
|
||||
@@ -46,43 +58,11 @@ unsigned Video::palette30(
|
||||
q *= saturation;
|
||||
|
||||
auto gammaAdjust = [=](double f) { return f < 0.0 ? 0.0 : std::pow(f, 2.2 / gamma); };
|
||||
unsigned r = 1023.0 * gammaAdjust(y + 0.946882 * i + 0.623557 * q);
|
||||
unsigned g = 1023.0 * gammaAdjust(y + -0.274788 * i + -0.635691 * q);
|
||||
unsigned b = 1023.0 * gammaAdjust(y + -1.108545 * i + 1.709007 * q);
|
||||
return (uclamp<10>(r) << 20) + (uclamp<10>(g) << 10) + (uclamp<10>(b) << 0);
|
||||
}
|
||||
unsigned r = 65535.0 * gammaAdjust(y + 0.946882 * i + 0.623557 * q);
|
||||
unsigned g = 65535.0 * gammaAdjust(y + -0.274788 * i + -0.635691 * q);
|
||||
unsigned b = 65535.0 * gammaAdjust(y + -1.108545 * i + 1.709007 * q);
|
||||
|
||||
void Video::generate(Format format) {
|
||||
for(unsigned n = 0; n < (1 << 9); n++) palette[n] = palette30(n, 2.0, 0.0, 1.0, 1.0, 1.8);
|
||||
|
||||
if(format == Format::RGB24) {
|
||||
for(unsigned n = 0; n < (1 << 9); n++) {
|
||||
unsigned color = palette[n];
|
||||
palette[n] = ((color >> 6) & 0xff0000) + ((color >> 4) & 0x00ff00) + ((color >> 2) & 0x0000ff);
|
||||
}
|
||||
}
|
||||
|
||||
if(format == Format::RGB16) {
|
||||
for(unsigned n = 0; n < (1 << 9); n++) {
|
||||
unsigned color = palette[n];
|
||||
palette[n] = ((color >> 14) & 0xf800) + ((color >> 9) & 0x07e0) + ((color >> 5) & 0x001f);
|
||||
}
|
||||
}
|
||||
|
||||
if(format == Format::RGB15) {
|
||||
for(unsigned n = 0; n < (1 << 9); n++) {
|
||||
unsigned color = palette[n];
|
||||
palette[n] = ((color >> 15) & 0x7c00) + ((color >> 10) & 0x03e0) + ((color >> 5) & 0x001f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Video::Video() {
|
||||
palette = new unsigned[1 << 9];
|
||||
}
|
||||
|
||||
Video::~Video() {
|
||||
delete[] palette;
|
||||
return interface->videoColor(n, uclamp<16>(r), uclamp<16>(g), uclamp<16>(b));
|
||||
}
|
||||
|
||||
}
|
12
bsnes/fc/video/video.hpp
Executable file
12
bsnes/fc/video/video.hpp
Executable file
@@ -0,0 +1,12 @@
|
||||
struct Video {
|
||||
unsigned *palette;
|
||||
void generate_palette();
|
||||
|
||||
Video();
|
||||
~Video();
|
||||
|
||||
private:
|
||||
uint32_t generate_color(unsigned, double, double, double, double, double);
|
||||
};
|
||||
|
||||
extern Video video;
|
@@ -1,8 +1,6 @@
|
||||
options += gameboy
|
||||
|
||||
gb_objects := gb-interface gb-system gb-scheduler
|
||||
gb_objects += gb-memory gb-cartridge
|
||||
gb_objects += gb-cpu gb-apu gb-lcd
|
||||
gb_objects += gb-cpu gb-ppu gb-apu
|
||||
gb_objects += gb-cheat gb-video
|
||||
objects += $(gb_objects)
|
||||
|
||||
@@ -12,7 +10,7 @@ obj/gb-scheduler.o: $(gb)/scheduler/scheduler.cpp $(call rwildcard,$(gb)/schedul
|
||||
obj/gb-cartridge.o: $(gb)/cartridge/cartridge.cpp $(call rwildcard,$(gb)/cartridge/)
|
||||
obj/gb-memory.o: $(gb)/memory/memory.cpp $(call rwildcard,$(gb)/memory/)
|
||||
obj/gb-cpu.o: $(gb)/cpu/cpu.cpp $(call rwildcard,$(gb)/cpu/)
|
||||
obj/gb-ppu.o: $(gb)/ppu/ppu.cpp $(call rwildcard,$(gb)/ppu/)
|
||||
obj/gb-apu.o: $(gb)/apu/apu.cpp $(call rwildcard,$(gb)/apu/)
|
||||
obj/gb-lcd.o: $(gb)/lcd/lcd.cpp $(call rwildcard,$(gb)/lcd/)
|
||||
obj/gb-cheat.o: $(gb)/cheat/cheat.cpp $(call rwildcard,$(gb)/cheat/)
|
||||
obj/gb-video.o: $(gb)/video/video.cpp $(call rwildcard,$(gb)/video/)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
#define APU_CPP
|
||||
namespace GB {
|
||||
namespace GameBoy {
|
||||
|
||||
#include "square1/square1.cpp"
|
||||
#include "square2/square2.cpp"
|
||||
@@ -46,9 +46,9 @@ void APU::main() {
|
||||
noise.run();
|
||||
master.run();
|
||||
|
||||
interface->audioSample(master.center, master.left, master.right);
|
||||
interface->audioSample(master.left, master.right);
|
||||
|
||||
clock += 1 * cpu.frequency;
|
||||
clock += cpu.frequency;
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(scheduler.active_thread = cpu.thread);
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
#define CARTRIDGE_CPP
|
||||
namespace GB {
|
||||
namespace GameBoy {
|
||||
|
||||
#include "mbc0/mbc0.cpp"
|
||||
#include "mbc1/mbc1.cpp"
|
||||
@@ -14,10 +14,10 @@ namespace GB {
|
||||
#include "serialization.cpp"
|
||||
Cartridge cartridge;
|
||||
|
||||
void Cartridge::load(System::Revision revision, const string &markup, const uint8_t *data, unsigned size) {
|
||||
if(size == 0) size = 32768;
|
||||
romdata = allocate<uint8>(romsize = size, 0xff);
|
||||
if(data) memcpy(romdata, data, size);
|
||||
void Cartridge::load(System::Revision revision, const string &markup, const stream &memory) {
|
||||
romsize = memory.size() ? memory.size() : 32768u;
|
||||
romdata = allocate<uint8>(romsize, 0xff);
|
||||
memory.read(romdata, memory.size());
|
||||
|
||||
information.markup = markup;
|
||||
information.mapper = Mapper::Unknown;
|
||||
@@ -49,14 +49,14 @@ void Cartridge::load(System::Revision revision, const string &markup, const uint
|
||||
information.battery = document["cartridge"]["ram"]["nonvolatile"].data == "true";
|
||||
|
||||
switch(information.mapper) { default:
|
||||
case Mapper::MBC0: mapper = &mbc0; break;
|
||||
case Mapper::MBC1: mapper = &mbc1; break;
|
||||
case Mapper::MBC2: mapper = &mbc2; break;
|
||||
case Mapper::MBC3: mapper = &mbc3; break;
|
||||
case Mapper::MBC5: mapper = &mbc5; break;
|
||||
case Mapper::MMM01: mapper = &mmm01; break;
|
||||
case Mapper::HuC1: mapper = &huc1; break;
|
||||
case Mapper::HuC3: mapper = &huc3; break;
|
||||
case Mapper::MBC0: mapper = &mbc0; break;
|
||||
case Mapper::MBC1: mapper = &mbc1; break;
|
||||
case Mapper::MBC2: mapper = &mbc2; break;
|
||||
case Mapper::MBC3: mapper = &mbc3; break;
|
||||
case Mapper::MBC5: mapper = &mbc5; break;
|
||||
case Mapper::MMM01: mapper = &mmm01; break;
|
||||
case Mapper::HuC1: mapper = &huc1; break;
|
||||
case Mapper::HuC3: mapper = &huc3; break;
|
||||
}
|
||||
|
||||
ramdata = new uint8_t[ramsize = information.ramsize]();
|
||||
@@ -64,6 +64,7 @@ void Cartridge::load(System::Revision revision, const string &markup, const uint
|
||||
|
||||
loaded = true;
|
||||
sha256 = nall::sha256(romdata, romsize);
|
||||
if(ramsize) interface->memory.append({ID::RAM, "save.ram"});
|
||||
}
|
||||
|
||||
void Cartridge::unload() {
|
||||
@@ -141,8 +142,8 @@ void Cartridge::power() {
|
||||
|
||||
Cartridge::Cartridge() {
|
||||
loaded = false;
|
||||
romdata = 0;
|
||||
ramdata = 0;
|
||||
romdata = nullptr;
|
||||
ramdata = nullptr;
|
||||
}
|
||||
|
||||
Cartridge::~Cartridge() {
|
||||
|
@@ -45,7 +45,7 @@ struct Cartridge : MMIO, property<Cartridge> {
|
||||
MMIO *mapper;
|
||||
bool bootrom_enable;
|
||||
|
||||
void load(System::Revision revision, const string &markup, const uint8_t *data, unsigned size);
|
||||
void load(System::Revision revision, const string &markup, const stream &memory);
|
||||
void unload();
|
||||
|
||||
uint8 rom_read(unsigned addr);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
namespace GB {
|
||||
namespace GameBoy {
|
||||
|
||||
Cheat cheat;
|
||||
|
||||
|
@@ -1,145 +0,0 @@
|
||||
#include "registers.hpp"
|
||||
void (CPU::*opcode_table[256])();
|
||||
void (CPU::*opcode_table_cb[256])();
|
||||
void initialize_opcode_table();
|
||||
|
||||
void op_xx();
|
||||
void op_cb();
|
||||
|
||||
//8-bit load commands
|
||||
template<unsigned x, unsigned y> void op_ld_r_r();
|
||||
template<unsigned x> void op_ld_r_n();
|
||||
template<unsigned x> void op_ld_r_hl();
|
||||
template<unsigned x> void op_ld_hl_r();
|
||||
void op_ld_hl_n();
|
||||
template<unsigned x> void op_ld_a_rr();
|
||||
void op_ld_a_nn();
|
||||
template<unsigned x> void op_ld_rr_a();
|
||||
void op_ld_nn_a();
|
||||
void op_ld_a_ffn();
|
||||
void op_ld_ffn_a();
|
||||
void op_ld_a_ffc();
|
||||
void op_ld_ffc_a();
|
||||
void op_ldi_hl_a();
|
||||
void op_ldi_a_hl();
|
||||
void op_ldd_hl_a();
|
||||
void op_ldd_a_hl();
|
||||
|
||||
//16-bit load commands
|
||||
template<unsigned x> void op_ld_rr_nn();
|
||||
void op_ld_nn_sp();
|
||||
void op_ld_sp_hl();
|
||||
template<unsigned x> void op_push_rr();
|
||||
template<unsigned x> void op_pop_rr();
|
||||
|
||||
//8-bit arithmetic commands
|
||||
void opi_add_a(uint8 x);
|
||||
template<unsigned x> void op_add_a_r();
|
||||
void op_add_a_n();
|
||||
void op_add_a_hl();
|
||||
|
||||
void opi_adc_a(uint8 x);
|
||||
template<unsigned x> void op_adc_a_r();
|
||||
void op_adc_a_n();
|
||||
void op_adc_a_hl();
|
||||
|
||||
void opi_sub_a(uint8 x);
|
||||
template<unsigned x> void op_sub_a_r();
|
||||
void op_sub_a_n();
|
||||
void op_sub_a_hl();
|
||||
|
||||
void opi_sbc_a(uint8 x);
|
||||
template<unsigned x> void op_sbc_a_r();
|
||||
void op_sbc_a_n();
|
||||
void op_sbc_a_hl();
|
||||
|
||||
void opi_and_a(uint8 x);
|
||||
template<unsigned x> void op_and_a_r();
|
||||
void op_and_a_n();
|
||||
void op_and_a_hl();
|
||||
|
||||
void opi_xor_a(uint8 x);
|
||||
template<unsigned x> void op_xor_a_r();
|
||||
void op_xor_a_n();
|
||||
void op_xor_a_hl();
|
||||
|
||||
void opi_or_a(uint8 x);
|
||||
template<unsigned x> void op_or_a_r();
|
||||
void op_or_a_n();
|
||||
void op_or_a_hl();
|
||||
|
||||
void opi_cp_a(uint8 x);
|
||||
template<unsigned x> void op_cp_a_r();
|
||||
void op_cp_a_n();
|
||||
void op_cp_a_hl();
|
||||
|
||||
template<unsigned x> void op_inc_r();
|
||||
void op_inc_hl();
|
||||
template<unsigned x> void op_dec_r();
|
||||
void op_dec_hl();
|
||||
void op_daa();
|
||||
void op_cpl();
|
||||
|
||||
//16-bit arithmetic commands
|
||||
template<unsigned x> void op_add_hl_rr();
|
||||
template<unsigned x> void op_inc_rr();
|
||||
template<unsigned x> void op_dec_rr();
|
||||
void op_add_sp_n();
|
||||
void op_ld_hl_sp_n();
|
||||
|
||||
//rotate/shift commands
|
||||
void op_rlca();
|
||||
void op_rla();
|
||||
void op_rrca();
|
||||
void op_rra();
|
||||
template<unsigned x> void op_rlc_r();
|
||||
void op_rlc_hl();
|
||||
template<unsigned x> void op_rl_r();
|
||||
void op_rl_hl();
|
||||
template<unsigned x> void op_rrc_r();
|
||||
void op_rrc_hl();
|
||||
template<unsigned x> void op_rr_r();
|
||||
void op_rr_hl();
|
||||
template<unsigned x> void op_sla_r();
|
||||
void op_sla_hl();
|
||||
template<unsigned x> void op_swap_r();
|
||||
void op_swap_hl();
|
||||
template<unsigned x> void op_sra_r();
|
||||
void op_sra_hl();
|
||||
template<unsigned x> void op_srl_r();
|
||||
void op_srl_hl();
|
||||
|
||||
//single-bit commands
|
||||
template<unsigned b, unsigned x> void op_bit_n_r();
|
||||
template<unsigned b> void op_bit_n_hl();
|
||||
template<unsigned b, unsigned x> void op_set_n_r();
|
||||
template<unsigned b> void op_set_n_hl();
|
||||
template<unsigned b, unsigned x> void op_res_n_r();
|
||||
template<unsigned b> void op_res_n_hl();
|
||||
|
||||
//control commands
|
||||
void op_ccf();
|
||||
void op_scf();
|
||||
void op_nop();
|
||||
void op_halt();
|
||||
void op_stop();
|
||||
void op_di();
|
||||
void op_ei();
|
||||
|
||||
//jump commands
|
||||
void op_jp_nn();
|
||||
void op_jp_hl();
|
||||
template<unsigned x, bool y> void op_jp_f_nn();
|
||||
void op_jr_n();
|
||||
template<unsigned x, bool y> void op_jr_f_n();
|
||||
void op_call_nn();
|
||||
template<unsigned x, bool y> void op_call_f_nn();
|
||||
void op_ret();
|
||||
template<unsigned x, bool y> void op_ret_f();
|
||||
void op_reti();
|
||||
template<unsigned n> void op_rst_n();
|
||||
|
||||
//disassembler.cpp
|
||||
string disassemble(uint16 pc);
|
||||
string disassemble_opcode(uint16 pc);
|
||||
string disassemble_opcode_cb(uint16 pc);
|
@@ -1,519 +0,0 @@
|
||||
#ifdef CPU_CPP
|
||||
|
||||
void CPU::initialize_opcode_table() {
|
||||
opcode_table[0x00] = &CPU::op_nop;
|
||||
opcode_table[0x01] = &CPU::op_ld_rr_nn<BC>;
|
||||
opcode_table[0x02] = &CPU::op_ld_rr_a<BC>;
|
||||
opcode_table[0x03] = &CPU::op_inc_rr<BC>;
|
||||
opcode_table[0x04] = &CPU::op_inc_r<B>;
|
||||
opcode_table[0x05] = &CPU::op_dec_r<B>;
|
||||
opcode_table[0x06] = &CPU::op_ld_r_n<B>;
|
||||
opcode_table[0x07] = &CPU::op_rlca;
|
||||
opcode_table[0x08] = &CPU::op_ld_nn_sp;
|
||||
opcode_table[0x09] = &CPU::op_add_hl_rr<BC>;
|
||||
opcode_table[0x0a] = &CPU::op_ld_a_rr<BC>;
|
||||
opcode_table[0x0b] = &CPU::op_dec_rr<BC>;
|
||||
opcode_table[0x0c] = &CPU::op_inc_r<C>;
|
||||
opcode_table[0x0d] = &CPU::op_dec_r<C>;
|
||||
opcode_table[0x0e] = &CPU::op_ld_r_n<C>;
|
||||
opcode_table[0x0f] = &CPU::op_rrca;
|
||||
opcode_table[0x10] = &CPU::op_stop;
|
||||
opcode_table[0x11] = &CPU::op_ld_rr_nn<DE>;
|
||||
opcode_table[0x12] = &CPU::op_ld_rr_a<DE>;
|
||||
opcode_table[0x13] = &CPU::op_inc_rr<DE>;
|
||||
opcode_table[0x14] = &CPU::op_inc_r<D>;
|
||||
opcode_table[0x15] = &CPU::op_dec_r<D>;
|
||||
opcode_table[0x16] = &CPU::op_ld_r_n<D>;
|
||||
opcode_table[0x17] = &CPU::op_rla;
|
||||
opcode_table[0x18] = &CPU::op_jr_n;
|
||||
opcode_table[0x19] = &CPU::op_add_hl_rr<DE>;
|
||||
opcode_table[0x1a] = &CPU::op_ld_a_rr<DE>;
|
||||
opcode_table[0x1b] = &CPU::op_dec_rr<DE>;
|
||||
opcode_table[0x1c] = &CPU::op_inc_r<E>;
|
||||
opcode_table[0x1d] = &CPU::op_dec_r<E>;
|
||||
opcode_table[0x1e] = &CPU::op_ld_r_n<E>;
|
||||
opcode_table[0x1f] = &CPU::op_rra;
|
||||
opcode_table[0x20] = &CPU::op_jr_f_n<ZF, 0>;
|
||||
opcode_table[0x21] = &CPU::op_ld_rr_nn<HL>;
|
||||
opcode_table[0x22] = &CPU::op_ldi_hl_a;
|
||||
opcode_table[0x23] = &CPU::op_inc_rr<HL>;
|
||||
opcode_table[0x24] = &CPU::op_inc_r<H>;
|
||||
opcode_table[0x25] = &CPU::op_dec_r<H>;
|
||||
opcode_table[0x26] = &CPU::op_ld_r_n<H>;
|
||||
opcode_table[0x27] = &CPU::op_daa;
|
||||
opcode_table[0x28] = &CPU::op_jr_f_n<ZF, 1>;
|
||||
opcode_table[0x29] = &CPU::op_add_hl_rr<HL>;
|
||||
opcode_table[0x2a] = &CPU::op_ldi_a_hl;
|
||||
opcode_table[0x2b] = &CPU::op_dec_rr<HL>;
|
||||
opcode_table[0x2c] = &CPU::op_inc_r<L>;
|
||||
opcode_table[0x2d] = &CPU::op_dec_r<L>;
|
||||
opcode_table[0x2e] = &CPU::op_ld_r_n<L>;
|
||||
opcode_table[0x2f] = &CPU::op_cpl;
|
||||
opcode_table[0x30] = &CPU::op_jr_f_n<CF, 0>;
|
||||
opcode_table[0x31] = &CPU::op_ld_rr_nn<SP>;
|
||||
opcode_table[0x32] = &CPU::op_ldd_hl_a;
|
||||
opcode_table[0x33] = &CPU::op_inc_rr<SP>;
|
||||
opcode_table[0x34] = &CPU::op_inc_hl;
|
||||
opcode_table[0x35] = &CPU::op_dec_hl;
|
||||
opcode_table[0x36] = &CPU::op_ld_hl_n;
|
||||
opcode_table[0x37] = &CPU::op_scf;
|
||||
opcode_table[0x38] = &CPU::op_jr_f_n<CF, 1>;
|
||||
opcode_table[0x39] = &CPU::op_add_hl_rr<SP>;
|
||||
opcode_table[0x3a] = &CPU::op_ldd_a_hl;
|
||||
opcode_table[0x3b] = &CPU::op_dec_rr<SP>;
|
||||
opcode_table[0x3c] = &CPU::op_inc_r<A>;
|
||||
opcode_table[0x3d] = &CPU::op_dec_r<A>;
|
||||
opcode_table[0x3e] = &CPU::op_ld_r_n<A>;
|
||||
opcode_table[0x3f] = &CPU::op_ccf;
|
||||
opcode_table[0x40] = &CPU::op_ld_r_r<B, B>;
|
||||
opcode_table[0x41] = &CPU::op_ld_r_r<B, C>;
|
||||
opcode_table[0x42] = &CPU::op_ld_r_r<B, D>;
|
||||
opcode_table[0x43] = &CPU::op_ld_r_r<B, E>;
|
||||
opcode_table[0x44] = &CPU::op_ld_r_r<B, H>;
|
||||
opcode_table[0x45] = &CPU::op_ld_r_r<B, L>;
|
||||
opcode_table[0x46] = &CPU::op_ld_r_hl<B>;
|
||||
opcode_table[0x47] = &CPU::op_ld_r_r<B, A>;
|
||||
opcode_table[0x48] = &CPU::op_ld_r_r<C, B>;
|
||||
opcode_table[0x49] = &CPU::op_ld_r_r<C, C>;
|
||||
opcode_table[0x4a] = &CPU::op_ld_r_r<C, D>;
|
||||
opcode_table[0x4b] = &CPU::op_ld_r_r<C, E>;
|
||||
opcode_table[0x4c] = &CPU::op_ld_r_r<C, H>;
|
||||
opcode_table[0x4d] = &CPU::op_ld_r_r<C, L>;
|
||||
opcode_table[0x4e] = &CPU::op_ld_r_hl<C>;
|
||||
opcode_table[0x4f] = &CPU::op_ld_r_r<C, A>;
|
||||
opcode_table[0x50] = &CPU::op_ld_r_r<D, B>;
|
||||
opcode_table[0x51] = &CPU::op_ld_r_r<D, C>;
|
||||
opcode_table[0x52] = &CPU::op_ld_r_r<D, D>;
|
||||
opcode_table[0x53] = &CPU::op_ld_r_r<D, E>;
|
||||
opcode_table[0x54] = &CPU::op_ld_r_r<D, H>;
|
||||
opcode_table[0x55] = &CPU::op_ld_r_r<D, L>;
|
||||
opcode_table[0x56] = &CPU::op_ld_r_hl<D>;
|
||||
opcode_table[0x57] = &CPU::op_ld_r_r<D, A>;
|
||||
opcode_table[0x58] = &CPU::op_ld_r_r<E, B>;
|
||||
opcode_table[0x59] = &CPU::op_ld_r_r<E, C>;
|
||||
opcode_table[0x5a] = &CPU::op_ld_r_r<E, D>;
|
||||
opcode_table[0x5b] = &CPU::op_ld_r_r<E, E>;
|
||||
opcode_table[0x5c] = &CPU::op_ld_r_r<E, H>;
|
||||
opcode_table[0x5d] = &CPU::op_ld_r_r<E, L>;
|
||||
opcode_table[0x5e] = &CPU::op_ld_r_hl<E>;
|
||||
opcode_table[0x5f] = &CPU::op_ld_r_r<E, A>;
|
||||
opcode_table[0x60] = &CPU::op_ld_r_r<H, B>;
|
||||
opcode_table[0x61] = &CPU::op_ld_r_r<H, C>;
|
||||
opcode_table[0x62] = &CPU::op_ld_r_r<H, D>;
|
||||
opcode_table[0x63] = &CPU::op_ld_r_r<H, E>;
|
||||
opcode_table[0x64] = &CPU::op_ld_r_r<H, H>;
|
||||
opcode_table[0x65] = &CPU::op_ld_r_r<H, L>;
|
||||
opcode_table[0x66] = &CPU::op_ld_r_hl<H>;
|
||||
opcode_table[0x67] = &CPU::op_ld_r_r<H, A>;
|
||||
opcode_table[0x68] = &CPU::op_ld_r_r<L, B>;
|
||||
opcode_table[0x69] = &CPU::op_ld_r_r<L, C>;
|
||||
opcode_table[0x6a] = &CPU::op_ld_r_r<L, D>;
|
||||
opcode_table[0x6b] = &CPU::op_ld_r_r<L, E>;
|
||||
opcode_table[0x6c] = &CPU::op_ld_r_r<L, H>;
|
||||
opcode_table[0x6d] = &CPU::op_ld_r_r<L, L>;
|
||||
opcode_table[0x6e] = &CPU::op_ld_r_hl<L>;
|
||||
opcode_table[0x6f] = &CPU::op_ld_r_r<L, A>;
|
||||
opcode_table[0x70] = &CPU::op_ld_hl_r<B>;
|
||||
opcode_table[0x71] = &CPU::op_ld_hl_r<C>;
|
||||
opcode_table[0x72] = &CPU::op_ld_hl_r<D>;
|
||||
opcode_table[0x73] = &CPU::op_ld_hl_r<E>;
|
||||
opcode_table[0x74] = &CPU::op_ld_hl_r<H>;
|
||||
opcode_table[0x75] = &CPU::op_ld_hl_r<L>;
|
||||
opcode_table[0x76] = &CPU::op_halt;
|
||||
opcode_table[0x77] = &CPU::op_ld_hl_r<A>;
|
||||
opcode_table[0x78] = &CPU::op_ld_r_r<A, B>;
|
||||
opcode_table[0x79] = &CPU::op_ld_r_r<A, C>;
|
||||
opcode_table[0x7a] = &CPU::op_ld_r_r<A, D>;
|
||||
opcode_table[0x7b] = &CPU::op_ld_r_r<A, E>;
|
||||
opcode_table[0x7c] = &CPU::op_ld_r_r<A, H>;
|
||||
opcode_table[0x7d] = &CPU::op_ld_r_r<A, L>;
|
||||
opcode_table[0x7e] = &CPU::op_ld_r_hl<A>;
|
||||
opcode_table[0x7f] = &CPU::op_ld_r_r<A, A>;
|
||||
opcode_table[0x80] = &CPU::op_add_a_r<B>;
|
||||
opcode_table[0x81] = &CPU::op_add_a_r<C>;
|
||||
opcode_table[0x82] = &CPU::op_add_a_r<D>;
|
||||
opcode_table[0x83] = &CPU::op_add_a_r<E>;
|
||||
opcode_table[0x84] = &CPU::op_add_a_r<H>;
|
||||
opcode_table[0x85] = &CPU::op_add_a_r<L>;
|
||||
opcode_table[0x86] = &CPU::op_add_a_hl;
|
||||
opcode_table[0x87] = &CPU::op_add_a_r<A>;
|
||||
opcode_table[0x88] = &CPU::op_adc_a_r<B>;
|
||||
opcode_table[0x89] = &CPU::op_adc_a_r<C>;
|
||||
opcode_table[0x8a] = &CPU::op_adc_a_r<D>;
|
||||
opcode_table[0x8b] = &CPU::op_adc_a_r<E>;
|
||||
opcode_table[0x8c] = &CPU::op_adc_a_r<H>;
|
||||
opcode_table[0x8d] = &CPU::op_adc_a_r<L>;
|
||||
opcode_table[0x8e] = &CPU::op_adc_a_hl;
|
||||
opcode_table[0x8f] = &CPU::op_adc_a_r<A>;
|
||||
opcode_table[0x90] = &CPU::op_sub_a_r<B>;
|
||||
opcode_table[0x91] = &CPU::op_sub_a_r<C>;
|
||||
opcode_table[0x92] = &CPU::op_sub_a_r<D>;
|
||||
opcode_table[0x93] = &CPU::op_sub_a_r<E>;
|
||||
opcode_table[0x94] = &CPU::op_sub_a_r<H>;
|
||||
opcode_table[0x95] = &CPU::op_sub_a_r<L>;
|
||||
opcode_table[0x96] = &CPU::op_sub_a_hl;
|
||||
opcode_table[0x97] = &CPU::op_sub_a_r<A>;
|
||||
opcode_table[0x98] = &CPU::op_sbc_a_r<B>;
|
||||
opcode_table[0x99] = &CPU::op_sbc_a_r<C>;
|
||||
opcode_table[0x9a] = &CPU::op_sbc_a_r<D>;
|
||||
opcode_table[0x9b] = &CPU::op_sbc_a_r<E>;
|
||||
opcode_table[0x9c] = &CPU::op_sbc_a_r<H>;
|
||||
opcode_table[0x9d] = &CPU::op_sbc_a_r<L>;
|
||||
opcode_table[0x9e] = &CPU::op_sbc_a_hl;
|
||||
opcode_table[0x9f] = &CPU::op_sbc_a_r<A>;
|
||||
opcode_table[0xa0] = &CPU::op_and_a_r<B>;
|
||||
opcode_table[0xa1] = &CPU::op_and_a_r<C>;
|
||||
opcode_table[0xa2] = &CPU::op_and_a_r<D>;
|
||||
opcode_table[0xa3] = &CPU::op_and_a_r<E>;
|
||||
opcode_table[0xa4] = &CPU::op_and_a_r<H>;
|
||||
opcode_table[0xa5] = &CPU::op_and_a_r<L>;
|
||||
opcode_table[0xa6] = &CPU::op_and_a_hl;
|
||||
opcode_table[0xa7] = &CPU::op_and_a_r<A>;
|
||||
opcode_table[0xa8] = &CPU::op_xor_a_r<B>;
|
||||
opcode_table[0xa9] = &CPU::op_xor_a_r<C>;
|
||||
opcode_table[0xaa] = &CPU::op_xor_a_r<D>;
|
||||
opcode_table[0xab] = &CPU::op_xor_a_r<E>;
|
||||
opcode_table[0xac] = &CPU::op_xor_a_r<H>;
|
||||
opcode_table[0xad] = &CPU::op_xor_a_r<L>;
|
||||
opcode_table[0xae] = &CPU::op_xor_a_hl;
|
||||
opcode_table[0xaf] = &CPU::op_xor_a_r<A>;
|
||||
opcode_table[0xb0] = &CPU::op_or_a_r<B>;
|
||||
opcode_table[0xb1] = &CPU::op_or_a_r<C>;
|
||||
opcode_table[0xb2] = &CPU::op_or_a_r<D>;
|
||||
opcode_table[0xb3] = &CPU::op_or_a_r<E>;
|
||||
opcode_table[0xb4] = &CPU::op_or_a_r<H>;
|
||||
opcode_table[0xb5] = &CPU::op_or_a_r<L>;
|
||||
opcode_table[0xb6] = &CPU::op_or_a_hl;
|
||||
opcode_table[0xb7] = &CPU::op_or_a_r<A>;
|
||||
opcode_table[0xb8] = &CPU::op_cp_a_r<B>;
|
||||
opcode_table[0xb9] = &CPU::op_cp_a_r<C>;
|
||||
opcode_table[0xba] = &CPU::op_cp_a_r<D>;
|
||||
opcode_table[0xbb] = &CPU::op_cp_a_r<E>;
|
||||
opcode_table[0xbc] = &CPU::op_cp_a_r<H>;
|
||||
opcode_table[0xbd] = &CPU::op_cp_a_r<L>;
|
||||
opcode_table[0xbe] = &CPU::op_cp_a_hl;
|
||||
opcode_table[0xbf] = &CPU::op_cp_a_r<A>;
|
||||
opcode_table[0xc0] = &CPU::op_ret_f<ZF, 0>;
|
||||
opcode_table[0xc1] = &CPU::op_pop_rr<BC>;
|
||||
opcode_table[0xc2] = &CPU::op_jp_f_nn<ZF, 0>;
|
||||
opcode_table[0xc3] = &CPU::op_jp_nn;
|
||||
opcode_table[0xc4] = &CPU::op_call_f_nn<ZF, 0>;
|
||||
opcode_table[0xc5] = &CPU::op_push_rr<BC>;
|
||||
opcode_table[0xc6] = &CPU::op_add_a_n;
|
||||
opcode_table[0xc7] = &CPU::op_rst_n<0x00>;
|
||||
opcode_table[0xc8] = &CPU::op_ret_f<ZF, 1>;
|
||||
opcode_table[0xc9] = &CPU::op_ret;
|
||||
opcode_table[0xca] = &CPU::op_jp_f_nn<ZF, 1>;
|
||||
opcode_table[0xcb] = &CPU::op_cb;
|
||||
opcode_table[0xcc] = &CPU::op_call_f_nn<ZF, 1>;
|
||||
opcode_table[0xcd] = &CPU::op_call_nn;
|
||||
opcode_table[0xce] = &CPU::op_adc_a_n;
|
||||
opcode_table[0xcf] = &CPU::op_rst_n<0x08>;
|
||||
opcode_table[0xd0] = &CPU::op_ret_f<CF, 0>;
|
||||
opcode_table[0xd1] = &CPU::op_pop_rr<DE>;
|
||||
opcode_table[0xd2] = &CPU::op_jp_f_nn<CF, 0>;
|
||||
opcode_table[0xd3] = &CPU::op_xx;
|
||||
opcode_table[0xd4] = &CPU::op_call_f_nn<CF, 0>;
|
||||
opcode_table[0xd5] = &CPU::op_push_rr<DE>;
|
||||
opcode_table[0xd6] = &CPU::op_sub_a_n;
|
||||
opcode_table[0xd7] = &CPU::op_rst_n<0x10>;
|
||||
opcode_table[0xd8] = &CPU::op_ret_f<CF, 1>;
|
||||
opcode_table[0xd9] = &CPU::op_reti;
|
||||
opcode_table[0xda] = &CPU::op_jp_f_nn<CF, 1>;
|
||||
opcode_table[0xdb] = &CPU::op_xx;
|
||||
opcode_table[0xdc] = &CPU::op_call_f_nn<CF, 1>;
|
||||
opcode_table[0xdd] = &CPU::op_xx;
|
||||
opcode_table[0xde] = &CPU::op_sbc_a_n;
|
||||
opcode_table[0xdf] = &CPU::op_rst_n<0x18>;
|
||||
opcode_table[0xe0] = &CPU::op_ld_ffn_a;
|
||||
opcode_table[0xe1] = &CPU::op_pop_rr<HL>;
|
||||
opcode_table[0xe2] = &CPU::op_ld_ffc_a;
|
||||
opcode_table[0xe3] = &CPU::op_xx;
|
||||
opcode_table[0xe4] = &CPU::op_xx;
|
||||
opcode_table[0xe5] = &CPU::op_push_rr<HL>;
|
||||
opcode_table[0xe6] = &CPU::op_and_a_n;
|
||||
opcode_table[0xe7] = &CPU::op_rst_n<0x20>;
|
||||
opcode_table[0xe8] = &CPU::op_add_sp_n;
|
||||
opcode_table[0xe9] = &CPU::op_jp_hl;
|
||||
opcode_table[0xea] = &CPU::op_ld_nn_a;
|
||||
opcode_table[0xeb] = &CPU::op_xx;
|
||||
opcode_table[0xec] = &CPU::op_xx;
|
||||
opcode_table[0xed] = &CPU::op_xx;
|
||||
opcode_table[0xee] = &CPU::op_xor_a_n;
|
||||
opcode_table[0xef] = &CPU::op_rst_n<0x28>;
|
||||
opcode_table[0xf0] = &CPU::op_ld_a_ffn;
|
||||
opcode_table[0xf1] = &CPU::op_pop_rr<AF>;
|
||||
opcode_table[0xf2] = &CPU::op_ld_a_ffc;
|
||||
opcode_table[0xf3] = &CPU::op_di;
|
||||
opcode_table[0xf4] = &CPU::op_xx;
|
||||
opcode_table[0xf5] = &CPU::op_push_rr<AF>;
|
||||
opcode_table[0xf6] = &CPU::op_or_a_n;
|
||||
opcode_table[0xf7] = &CPU::op_rst_n<0x30>;
|
||||
opcode_table[0xf8] = &CPU::op_ld_hl_sp_n;
|
||||
opcode_table[0xf9] = &CPU::op_ld_sp_hl;
|
||||
opcode_table[0xfa] = &CPU::op_ld_a_nn;
|
||||
opcode_table[0xfb] = &CPU::op_ei;
|
||||
opcode_table[0xfc] = &CPU::op_xx;
|
||||
opcode_table[0xfd] = &CPU::op_xx;
|
||||
opcode_table[0xfe] = &CPU::op_cp_a_n;
|
||||
opcode_table[0xff] = &CPU::op_rst_n<0x38>;
|
||||
|
||||
opcode_table_cb[0x00] = &CPU::op_rlc_r<B>;
|
||||
opcode_table_cb[0x01] = &CPU::op_rlc_r<C>;
|
||||
opcode_table_cb[0x02] = &CPU::op_rlc_r<D>;
|
||||
opcode_table_cb[0x03] = &CPU::op_rlc_r<E>;
|
||||
opcode_table_cb[0x04] = &CPU::op_rlc_r<H>;
|
||||
opcode_table_cb[0x05] = &CPU::op_rlc_r<L>;
|
||||
opcode_table_cb[0x06] = &CPU::op_rlc_hl;
|
||||
opcode_table_cb[0x07] = &CPU::op_rlc_r<A>;
|
||||
opcode_table_cb[0x08] = &CPU::op_rrc_r<B>;
|
||||
opcode_table_cb[0x09] = &CPU::op_rrc_r<C>;
|
||||
opcode_table_cb[0x0a] = &CPU::op_rrc_r<D>;
|
||||
opcode_table_cb[0x0b] = &CPU::op_rrc_r<E>;
|
||||
opcode_table_cb[0x0c] = &CPU::op_rrc_r<H>;
|
||||
opcode_table_cb[0x0d] = &CPU::op_rrc_r<L>;
|
||||
opcode_table_cb[0x0e] = &CPU::op_rrc_hl;
|
||||
opcode_table_cb[0x0f] = &CPU::op_rrc_r<A>;
|
||||
opcode_table_cb[0x10] = &CPU::op_rl_r<B>;
|
||||
opcode_table_cb[0x11] = &CPU::op_rl_r<C>;
|
||||
opcode_table_cb[0x12] = &CPU::op_rl_r<D>;
|
||||
opcode_table_cb[0x13] = &CPU::op_rl_r<E>;
|
||||
opcode_table_cb[0x14] = &CPU::op_rl_r<H>;
|
||||
opcode_table_cb[0x15] = &CPU::op_rl_r<L>;
|
||||
opcode_table_cb[0x16] = &CPU::op_rl_hl;
|
||||
opcode_table_cb[0x17] = &CPU::op_rl_r<A>;
|
||||
opcode_table_cb[0x18] = &CPU::op_rr_r<B>;
|
||||
opcode_table_cb[0x19] = &CPU::op_rr_r<C>;
|
||||
opcode_table_cb[0x1a] = &CPU::op_rr_r<D>;
|
||||
opcode_table_cb[0x1b] = &CPU::op_rr_r<E>;
|
||||
opcode_table_cb[0x1c] = &CPU::op_rr_r<H>;
|
||||
opcode_table_cb[0x1d] = &CPU::op_rr_r<L>;
|
||||
opcode_table_cb[0x1e] = &CPU::op_rr_hl;
|
||||
opcode_table_cb[0x1f] = &CPU::op_rr_r<A>;
|
||||
opcode_table_cb[0x20] = &CPU::op_sla_r<B>;
|
||||
opcode_table_cb[0x21] = &CPU::op_sla_r<C>;
|
||||
opcode_table_cb[0x22] = &CPU::op_sla_r<D>;
|
||||
opcode_table_cb[0x23] = &CPU::op_sla_r<E>;
|
||||
opcode_table_cb[0x24] = &CPU::op_sla_r<H>;
|
||||
opcode_table_cb[0x25] = &CPU::op_sla_r<L>;
|
||||
opcode_table_cb[0x26] = &CPU::op_sla_hl;
|
||||
opcode_table_cb[0x27] = &CPU::op_sla_r<A>;
|
||||
opcode_table_cb[0x28] = &CPU::op_sra_r<B>;
|
||||
opcode_table_cb[0x29] = &CPU::op_sra_r<C>;
|
||||
opcode_table_cb[0x2a] = &CPU::op_sra_r<D>;
|
||||
opcode_table_cb[0x2b] = &CPU::op_sra_r<E>;
|
||||
opcode_table_cb[0x2c] = &CPU::op_sra_r<H>;
|
||||
opcode_table_cb[0x2d] = &CPU::op_sra_r<L>;
|
||||
opcode_table_cb[0x2e] = &CPU::op_sra_hl;
|
||||
opcode_table_cb[0x2f] = &CPU::op_sra_r<A>;
|
||||
opcode_table_cb[0x30] = &CPU::op_swap_r<B>;
|
||||
opcode_table_cb[0x31] = &CPU::op_swap_r<C>;
|
||||
opcode_table_cb[0x32] = &CPU::op_swap_r<D>;
|
||||
opcode_table_cb[0x33] = &CPU::op_swap_r<E>;
|
||||
opcode_table_cb[0x34] = &CPU::op_swap_r<H>;
|
||||
opcode_table_cb[0x35] = &CPU::op_swap_r<L>;
|
||||
opcode_table_cb[0x36] = &CPU::op_swap_hl;
|
||||
opcode_table_cb[0x37] = &CPU::op_swap_r<A>;
|
||||
opcode_table_cb[0x38] = &CPU::op_srl_r<B>;
|
||||
opcode_table_cb[0x39] = &CPU::op_srl_r<C>;
|
||||
opcode_table_cb[0x3a] = &CPU::op_srl_r<D>;
|
||||
opcode_table_cb[0x3b] = &CPU::op_srl_r<E>;
|
||||
opcode_table_cb[0x3c] = &CPU::op_srl_r<H>;
|
||||
opcode_table_cb[0x3d] = &CPU::op_srl_r<L>;
|
||||
opcode_table_cb[0x3e] = &CPU::op_srl_hl;
|
||||
opcode_table_cb[0x3f] = &CPU::op_srl_r<A>;
|
||||
opcode_table_cb[0x40] = &CPU::op_bit_n_r<0, B>;
|
||||
opcode_table_cb[0x41] = &CPU::op_bit_n_r<0, C>;
|
||||
opcode_table_cb[0x42] = &CPU::op_bit_n_r<0, D>;
|
||||
opcode_table_cb[0x43] = &CPU::op_bit_n_r<0, E>;
|
||||
opcode_table_cb[0x44] = &CPU::op_bit_n_r<0, H>;
|
||||
opcode_table_cb[0x45] = &CPU::op_bit_n_r<0, L>;
|
||||
opcode_table_cb[0x46] = &CPU::op_bit_n_hl<0>;
|
||||
opcode_table_cb[0x47] = &CPU::op_bit_n_r<0, A>;
|
||||
opcode_table_cb[0x48] = &CPU::op_bit_n_r<1, B>;
|
||||
opcode_table_cb[0x49] = &CPU::op_bit_n_r<1, C>;
|
||||
opcode_table_cb[0x4a] = &CPU::op_bit_n_r<1, D>;
|
||||
opcode_table_cb[0x4b] = &CPU::op_bit_n_r<1, E>;
|
||||
opcode_table_cb[0x4c] = &CPU::op_bit_n_r<1, H>;
|
||||
opcode_table_cb[0x4d] = &CPU::op_bit_n_r<1, L>;
|
||||
opcode_table_cb[0x4e] = &CPU::op_bit_n_hl<1>;
|
||||
opcode_table_cb[0x4f] = &CPU::op_bit_n_r<1, A>;
|
||||
opcode_table_cb[0x50] = &CPU::op_bit_n_r<2, B>;
|
||||
opcode_table_cb[0x51] = &CPU::op_bit_n_r<2, C>;
|
||||
opcode_table_cb[0x52] = &CPU::op_bit_n_r<2, D>;
|
||||
opcode_table_cb[0x53] = &CPU::op_bit_n_r<2, E>;
|
||||
opcode_table_cb[0x54] = &CPU::op_bit_n_r<2, H>;
|
||||
opcode_table_cb[0x55] = &CPU::op_bit_n_r<2, L>;
|
||||
opcode_table_cb[0x56] = &CPU::op_bit_n_hl<2>;
|
||||
opcode_table_cb[0x57] = &CPU::op_bit_n_r<2, A>;
|
||||
opcode_table_cb[0x58] = &CPU::op_bit_n_r<3, B>;
|
||||
opcode_table_cb[0x59] = &CPU::op_bit_n_r<3, C>;
|
||||
opcode_table_cb[0x5a] = &CPU::op_bit_n_r<3, D>;
|
||||
opcode_table_cb[0x5b] = &CPU::op_bit_n_r<3, E>;
|
||||
opcode_table_cb[0x5c] = &CPU::op_bit_n_r<3, H>;
|
||||
opcode_table_cb[0x5d] = &CPU::op_bit_n_r<3, L>;
|
||||
opcode_table_cb[0x5e] = &CPU::op_bit_n_hl<3>;
|
||||
opcode_table_cb[0x5f] = &CPU::op_bit_n_r<3, A>;
|
||||
opcode_table_cb[0x60] = &CPU::op_bit_n_r<4, B>;
|
||||
opcode_table_cb[0x61] = &CPU::op_bit_n_r<4, C>;
|
||||
opcode_table_cb[0x62] = &CPU::op_bit_n_r<4, D>;
|
||||
opcode_table_cb[0x63] = &CPU::op_bit_n_r<4, E>;
|
||||
opcode_table_cb[0x64] = &CPU::op_bit_n_r<4, H>;
|
||||
opcode_table_cb[0x65] = &CPU::op_bit_n_r<4, L>;
|
||||
opcode_table_cb[0x66] = &CPU::op_bit_n_hl<4>;
|
||||
opcode_table_cb[0x67] = &CPU::op_bit_n_r<4, A>;
|
||||
opcode_table_cb[0x68] = &CPU::op_bit_n_r<5, B>;
|
||||
opcode_table_cb[0x69] = &CPU::op_bit_n_r<5, C>;
|
||||
opcode_table_cb[0x6a] = &CPU::op_bit_n_r<5, D>;
|
||||
opcode_table_cb[0x6b] = &CPU::op_bit_n_r<5, E>;
|
||||
opcode_table_cb[0x6c] = &CPU::op_bit_n_r<5, H>;
|
||||
opcode_table_cb[0x6d] = &CPU::op_bit_n_r<5, L>;
|
||||
opcode_table_cb[0x6e] = &CPU::op_bit_n_hl<5>;
|
||||
opcode_table_cb[0x6f] = &CPU::op_bit_n_r<5, A>;
|
||||
opcode_table_cb[0x70] = &CPU::op_bit_n_r<6, B>;
|
||||
opcode_table_cb[0x71] = &CPU::op_bit_n_r<6, C>;
|
||||
opcode_table_cb[0x72] = &CPU::op_bit_n_r<6, D>;
|
||||
opcode_table_cb[0x73] = &CPU::op_bit_n_r<6, E>;
|
||||
opcode_table_cb[0x74] = &CPU::op_bit_n_r<6, H>;
|
||||
opcode_table_cb[0x75] = &CPU::op_bit_n_r<6, L>;
|
||||
opcode_table_cb[0x76] = &CPU::op_bit_n_hl<6>;
|
||||
opcode_table_cb[0x77] = &CPU::op_bit_n_r<6, A>;
|
||||
opcode_table_cb[0x78] = &CPU::op_bit_n_r<7, B>;
|
||||
opcode_table_cb[0x79] = &CPU::op_bit_n_r<7, C>;
|
||||
opcode_table_cb[0x7a] = &CPU::op_bit_n_r<7, D>;
|
||||
opcode_table_cb[0x7b] = &CPU::op_bit_n_r<7, E>;
|
||||
opcode_table_cb[0x7c] = &CPU::op_bit_n_r<7, H>;
|
||||
opcode_table_cb[0x7d] = &CPU::op_bit_n_r<7, L>;
|
||||
opcode_table_cb[0x7e] = &CPU::op_bit_n_hl<7>;
|
||||
opcode_table_cb[0x7f] = &CPU::op_bit_n_r<7, A>;
|
||||
opcode_table_cb[0x80] = &CPU::op_res_n_r<0, B>;
|
||||
opcode_table_cb[0x81] = &CPU::op_res_n_r<0, C>;
|
||||
opcode_table_cb[0x82] = &CPU::op_res_n_r<0, D>;
|
||||
opcode_table_cb[0x83] = &CPU::op_res_n_r<0, E>;
|
||||
opcode_table_cb[0x84] = &CPU::op_res_n_r<0, H>;
|
||||
opcode_table_cb[0x85] = &CPU::op_res_n_r<0, L>;
|
||||
opcode_table_cb[0x86] = &CPU::op_res_n_hl<0>;
|
||||
opcode_table_cb[0x87] = &CPU::op_res_n_r<0, A>;
|
||||
opcode_table_cb[0x88] = &CPU::op_res_n_r<1, B>;
|
||||
opcode_table_cb[0x89] = &CPU::op_res_n_r<1, C>;
|
||||
opcode_table_cb[0x8a] = &CPU::op_res_n_r<1, D>;
|
||||
opcode_table_cb[0x8b] = &CPU::op_res_n_r<1, E>;
|
||||
opcode_table_cb[0x8c] = &CPU::op_res_n_r<1, H>;
|
||||
opcode_table_cb[0x8d] = &CPU::op_res_n_r<1, L>;
|
||||
opcode_table_cb[0x8e] = &CPU::op_res_n_hl<1>;
|
||||
opcode_table_cb[0x8f] = &CPU::op_res_n_r<1, A>;
|
||||
opcode_table_cb[0x90] = &CPU::op_res_n_r<2, B>;
|
||||
opcode_table_cb[0x91] = &CPU::op_res_n_r<2, C>;
|
||||
opcode_table_cb[0x92] = &CPU::op_res_n_r<2, D>;
|
||||
opcode_table_cb[0x93] = &CPU::op_res_n_r<2, E>;
|
||||
opcode_table_cb[0x94] = &CPU::op_res_n_r<2, H>;
|
||||
opcode_table_cb[0x95] = &CPU::op_res_n_r<2, L>;
|
||||
opcode_table_cb[0x96] = &CPU::op_res_n_hl<2>;
|
||||
opcode_table_cb[0x97] = &CPU::op_res_n_r<2, A>;
|
||||
opcode_table_cb[0x98] = &CPU::op_res_n_r<3, B>;
|
||||
opcode_table_cb[0x99] = &CPU::op_res_n_r<3, C>;
|
||||
opcode_table_cb[0x9a] = &CPU::op_res_n_r<3, D>;
|
||||
opcode_table_cb[0x9b] = &CPU::op_res_n_r<3, E>;
|
||||
opcode_table_cb[0x9c] = &CPU::op_res_n_r<3, H>;
|
||||
opcode_table_cb[0x9d] = &CPU::op_res_n_r<3, L>;
|
||||
opcode_table_cb[0x9e] = &CPU::op_res_n_hl<3>;
|
||||
opcode_table_cb[0x9f] = &CPU::op_res_n_r<3, A>;
|
||||
opcode_table_cb[0xa0] = &CPU::op_res_n_r<4, B>;
|
||||
opcode_table_cb[0xa1] = &CPU::op_res_n_r<4, C>;
|
||||
opcode_table_cb[0xa2] = &CPU::op_res_n_r<4, D>;
|
||||
opcode_table_cb[0xa3] = &CPU::op_res_n_r<4, E>;
|
||||
opcode_table_cb[0xa4] = &CPU::op_res_n_r<4, H>;
|
||||
opcode_table_cb[0xa5] = &CPU::op_res_n_r<4, L>;
|
||||
opcode_table_cb[0xa6] = &CPU::op_res_n_hl<4>;
|
||||
opcode_table_cb[0xa7] = &CPU::op_res_n_r<4, A>;
|
||||
opcode_table_cb[0xa8] = &CPU::op_res_n_r<5, B>;
|
||||
opcode_table_cb[0xa9] = &CPU::op_res_n_r<5, C>;
|
||||
opcode_table_cb[0xaa] = &CPU::op_res_n_r<5, D>;
|
||||
opcode_table_cb[0xab] = &CPU::op_res_n_r<5, E>;
|
||||
opcode_table_cb[0xac] = &CPU::op_res_n_r<5, H>;
|
||||
opcode_table_cb[0xad] = &CPU::op_res_n_r<5, L>;
|
||||
opcode_table_cb[0xae] = &CPU::op_res_n_hl<5>;
|
||||
opcode_table_cb[0xaf] = &CPU::op_res_n_r<5, A>;
|
||||
opcode_table_cb[0xb0] = &CPU::op_res_n_r<6, B>;
|
||||
opcode_table_cb[0xb1] = &CPU::op_res_n_r<6, C>;
|
||||
opcode_table_cb[0xb2] = &CPU::op_res_n_r<6, D>;
|
||||
opcode_table_cb[0xb3] = &CPU::op_res_n_r<6, E>;
|
||||
opcode_table_cb[0xb4] = &CPU::op_res_n_r<6, H>;
|
||||
opcode_table_cb[0xb5] = &CPU::op_res_n_r<6, L>;
|
||||
opcode_table_cb[0xb6] = &CPU::op_res_n_hl<6>;
|
||||
opcode_table_cb[0xb7] = &CPU::op_res_n_r<6, A>;
|
||||
opcode_table_cb[0xb8] = &CPU::op_res_n_r<7, B>;
|
||||
opcode_table_cb[0xb9] = &CPU::op_res_n_r<7, C>;
|
||||
opcode_table_cb[0xba] = &CPU::op_res_n_r<7, D>;
|
||||
opcode_table_cb[0xbb] = &CPU::op_res_n_r<7, E>;
|
||||
opcode_table_cb[0xbc] = &CPU::op_res_n_r<7, H>;
|
||||
opcode_table_cb[0xbd] = &CPU::op_res_n_r<7, L>;
|
||||
opcode_table_cb[0xbe] = &CPU::op_res_n_hl<7>;
|
||||
opcode_table_cb[0xbf] = &CPU::op_res_n_r<7, A>;
|
||||
opcode_table_cb[0xc0] = &CPU::op_set_n_r<0, B>;
|
||||
opcode_table_cb[0xc1] = &CPU::op_set_n_r<0, C>;
|
||||
opcode_table_cb[0xc2] = &CPU::op_set_n_r<0, D>;
|
||||
opcode_table_cb[0xc3] = &CPU::op_set_n_r<0, E>;
|
||||
opcode_table_cb[0xc4] = &CPU::op_set_n_r<0, H>;
|
||||
opcode_table_cb[0xc5] = &CPU::op_set_n_r<0, L>;
|
||||
opcode_table_cb[0xc6] = &CPU::op_set_n_hl<0>;
|
||||
opcode_table_cb[0xc7] = &CPU::op_set_n_r<0, A>;
|
||||
opcode_table_cb[0xc8] = &CPU::op_set_n_r<1, B>;
|
||||
opcode_table_cb[0xc9] = &CPU::op_set_n_r<1, C>;
|
||||
opcode_table_cb[0xca] = &CPU::op_set_n_r<1, D>;
|
||||
opcode_table_cb[0xcb] = &CPU::op_set_n_r<1, E>;
|
||||
opcode_table_cb[0xcc] = &CPU::op_set_n_r<1, H>;
|
||||
opcode_table_cb[0xcd] = &CPU::op_set_n_r<1, L>;
|
||||
opcode_table_cb[0xce] = &CPU::op_set_n_hl<1>;
|
||||
opcode_table_cb[0xcf] = &CPU::op_set_n_r<1, A>;
|
||||
opcode_table_cb[0xd0] = &CPU::op_set_n_r<2, B>;
|
||||
opcode_table_cb[0xd1] = &CPU::op_set_n_r<2, C>;
|
||||
opcode_table_cb[0xd2] = &CPU::op_set_n_r<2, D>;
|
||||
opcode_table_cb[0xd3] = &CPU::op_set_n_r<2, E>;
|
||||
opcode_table_cb[0xd4] = &CPU::op_set_n_r<2, H>;
|
||||
opcode_table_cb[0xd5] = &CPU::op_set_n_r<2, L>;
|
||||
opcode_table_cb[0xd6] = &CPU::op_set_n_hl<2>;
|
||||
opcode_table_cb[0xd7] = &CPU::op_set_n_r<2, A>;
|
||||
opcode_table_cb[0xd8] = &CPU::op_set_n_r<3, B>;
|
||||
opcode_table_cb[0xd9] = &CPU::op_set_n_r<3, C>;
|
||||
opcode_table_cb[0xda] = &CPU::op_set_n_r<3, D>;
|
||||
opcode_table_cb[0xdb] = &CPU::op_set_n_r<3, E>;
|
||||
opcode_table_cb[0xdc] = &CPU::op_set_n_r<3, H>;
|
||||
opcode_table_cb[0xdd] = &CPU::op_set_n_r<3, L>;
|
||||
opcode_table_cb[0xde] = &CPU::op_set_n_hl<3>;
|
||||
opcode_table_cb[0xdf] = &CPU::op_set_n_r<3, A>;
|
||||
opcode_table_cb[0xe0] = &CPU::op_set_n_r<4, B>;
|
||||
opcode_table_cb[0xe1] = &CPU::op_set_n_r<4, C>;
|
||||
opcode_table_cb[0xe2] = &CPU::op_set_n_r<4, D>;
|
||||
opcode_table_cb[0xe3] = &CPU::op_set_n_r<4, E>;
|
||||
opcode_table_cb[0xe4] = &CPU::op_set_n_r<4, H>;
|
||||
opcode_table_cb[0xe5] = &CPU::op_set_n_r<4, L>;
|
||||
opcode_table_cb[0xe6] = &CPU::op_set_n_hl<4>;
|
||||
opcode_table_cb[0xe7] = &CPU::op_set_n_r<4, A>;
|
||||
opcode_table_cb[0xe8] = &CPU::op_set_n_r<5, B>;
|
||||
opcode_table_cb[0xe9] = &CPU::op_set_n_r<5, C>;
|
||||
opcode_table_cb[0xea] = &CPU::op_set_n_r<5, D>;
|
||||
opcode_table_cb[0xeb] = &CPU::op_set_n_r<5, E>;
|
||||
opcode_table_cb[0xec] = &CPU::op_set_n_r<5, H>;
|
||||
opcode_table_cb[0xed] = &CPU::op_set_n_r<5, L>;
|
||||
opcode_table_cb[0xee] = &CPU::op_set_n_hl<5>;
|
||||
opcode_table_cb[0xef] = &CPU::op_set_n_r<5, A>;
|
||||
opcode_table_cb[0xf0] = &CPU::op_set_n_r<6, B>;
|
||||
opcode_table_cb[0xf1] = &CPU::op_set_n_r<6, C>;
|
||||
opcode_table_cb[0xf2] = &CPU::op_set_n_r<6, D>;
|
||||
opcode_table_cb[0xf3] = &CPU::op_set_n_r<6, E>;
|
||||
opcode_table_cb[0xf4] = &CPU::op_set_n_r<6, H>;
|
||||
opcode_table_cb[0xf5] = &CPU::op_set_n_r<6, L>;
|
||||
opcode_table_cb[0xf6] = &CPU::op_set_n_hl<6>;
|
||||
opcode_table_cb[0xf7] = &CPU::op_set_n_r<6, A>;
|
||||
opcode_table_cb[0xf8] = &CPU::op_set_n_r<7, B>;
|
||||
opcode_table_cb[0xf9] = &CPU::op_set_n_r<7, C>;
|
||||
opcode_table_cb[0xfa] = &CPU::op_set_n_r<7, D>;
|
||||
opcode_table_cb[0xfb] = &CPU::op_set_n_r<7, E>;
|
||||
opcode_table_cb[0xfc] = &CPU::op_set_n_r<7, H>;
|
||||
opcode_table_cb[0xfd] = &CPU::op_set_n_r<7, L>;
|
||||
opcode_table_cb[0xfe] = &CPU::op_set_n_hl<7>;
|
||||
opcode_table_cb[0xff] = &CPU::op_set_n_r<7, A>;
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,11 +1,11 @@
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
#define CPU_CPP
|
||||
namespace GB {
|
||||
namespace GameBoy {
|
||||
|
||||
#include "core/core.cpp"
|
||||
#include "mmio/mmio.cpp"
|
||||
#include "timing/timing.cpp"
|
||||
#include "mmio.cpp"
|
||||
#include "memory.cpp"
|
||||
#include "timing.cpp"
|
||||
#include "serialization.cpp"
|
||||
CPU cpu;
|
||||
|
||||
@@ -20,42 +20,40 @@ void CPU::main() {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
if(trace) print(disassemble(r[PC]), "\n");
|
||||
interrupt_test();
|
||||
uint8 opcode = op_read(r[PC]++);
|
||||
(this->*opcode_table[opcode])();
|
||||
exec();
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::interrupt_raise(CPU::Interrupt id) {
|
||||
if(id == Interrupt::Vblank) {
|
||||
status.interrupt_request_vblank = 1;
|
||||
if(status.interrupt_enable_vblank) status.halt = false;
|
||||
if(status.interrupt_enable_vblank) r.halt = false;
|
||||
}
|
||||
|
||||
if(id == Interrupt::Stat) {
|
||||
status.interrupt_request_stat = 1;
|
||||
if(status.interrupt_enable_stat) status.halt = false;
|
||||
if(status.interrupt_enable_stat) r.halt = false;
|
||||
}
|
||||
|
||||
if(id == Interrupt::Timer) {
|
||||
status.interrupt_request_timer = 1;
|
||||
if(status.interrupt_enable_timer) status.halt = false;
|
||||
if(status.interrupt_enable_timer) r.halt = false;
|
||||
}
|
||||
|
||||
if(id == Interrupt::Serial) {
|
||||
status.interrupt_request_serial = 1;
|
||||
if(status.interrupt_enable_serial) status.halt = false;
|
||||
if(status.interrupt_enable_serial) r.halt = false;
|
||||
}
|
||||
|
||||
if(id == Interrupt::Joypad) {
|
||||
status.interrupt_request_joypad = 1;
|
||||
if(status.interrupt_enable_joypad) status.halt = status.stop = false;
|
||||
if(status.interrupt_enable_joypad) r.halt = r.stop = false;
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::interrupt_test() {
|
||||
if(status.ime) {
|
||||
if(r.ime) {
|
||||
if(status.interrupt_request_vblank && status.interrupt_enable_vblank) {
|
||||
status.interrupt_request_vblank = 0;
|
||||
return interrupt_exec(0x0040);
|
||||
@@ -84,7 +82,7 @@ void CPU::interrupt_test() {
|
||||
}
|
||||
|
||||
void CPU::interrupt_exec(uint16 pc) {
|
||||
status.ime = 0;
|
||||
r.ime = 0;
|
||||
op_write(--r[SP], r[PC] >> 8);
|
||||
op_write(--r[SP], r[PC] >> 0);
|
||||
r[PC] = pc;
|
||||
@@ -93,8 +91,20 @@ void CPU::interrupt_exec(uint16 pc) {
|
||||
op_io();
|
||||
}
|
||||
|
||||
bool CPU::stop() {
|
||||
if(status.speed_switch) {
|
||||
status.speed_switch = 0;
|
||||
status.speed_double ^= 1;
|
||||
if(status.speed_double == 0) frequency = 4 * 1024 * 1024;
|
||||
if(status.speed_double == 1) frequency = 8 * 1024 * 1024;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CPU::power() {
|
||||
create(Main, 4 * 1024 * 1024);
|
||||
LR35902::power();
|
||||
|
||||
for(unsigned n = 0xc000; n <= 0xdfff; n++) bus.mmio[n] = this; //WRAM
|
||||
for(unsigned n = 0xe000; n <= 0xfdff; n++) bus.mmio[n] = this; //WRAM (mirror)
|
||||
@@ -140,10 +150,6 @@ void CPU::power() {
|
||||
r[HL] = 0x0000;
|
||||
|
||||
status.clock = 0;
|
||||
status.halt = false;
|
||||
status.stop = false;
|
||||
status.ei = false;
|
||||
status.ime = 0;
|
||||
|
||||
status.p15 = 0;
|
||||
status.p14 = 0;
|
||||
@@ -195,8 +201,4 @@ void CPU::power() {
|
||||
status.interrupt_enable_vblank = 0;
|
||||
}
|
||||
|
||||
CPU::CPU() : trace(false) {
|
||||
initialize_opcode_table();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,10 +1,4 @@
|
||||
struct CPU : Thread, MMIO {
|
||||
#include "core/core.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "timing/timing.hpp"
|
||||
|
||||
bool trace;
|
||||
|
||||
struct CPU : Processor::LR35902, Thread, MMIO {
|
||||
enum class Interrupt : unsigned {
|
||||
Vblank,
|
||||
Stat,
|
||||
@@ -15,10 +9,6 @@ struct CPU : Thread, MMIO {
|
||||
|
||||
struct Status {
|
||||
unsigned clock;
|
||||
bool halt;
|
||||
bool stop;
|
||||
bool ei;
|
||||
bool ime;
|
||||
|
||||
//$ff00 JOYP
|
||||
bool p15;
|
||||
@@ -96,10 +86,32 @@ struct CPU : Thread, MMIO {
|
||||
void interrupt_raise(Interrupt id);
|
||||
void interrupt_test();
|
||||
void interrupt_exec(uint16 pc);
|
||||
bool stop();
|
||||
void power();
|
||||
|
||||
void serialize(serializer&);
|
||||
CPU();
|
||||
|
||||
//mmio.cpp
|
||||
unsigned wram_addr(uint16 addr) const;
|
||||
void mmio_joyp_poll();
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
|
||||
//memory.cpp
|
||||
void op_io();
|
||||
uint8 op_read(uint16 addr);
|
||||
void op_write(uint16 addr, uint8 data);
|
||||
void cycle_edge();
|
||||
uint8 debugger_read(uint16 addr);
|
||||
|
||||
//timing.cpp
|
||||
void add_clocks(unsigned clocks);
|
||||
void timer_262144hz();
|
||||
void timer_65536hz();
|
||||
void timer_16384hz();
|
||||
void timer_8192hz();
|
||||
void timer_4096hz();
|
||||
void hblank();
|
||||
};
|
||||
|
||||
extern CPU cpu;
|
||||
|
@@ -19,10 +19,14 @@ void CPU::op_write(uint16 addr, uint8 data) {
|
||||
}
|
||||
|
||||
void CPU::cycle_edge() {
|
||||
if(status.ei) {
|
||||
status.ei = false;
|
||||
status.ime = 1;
|
||||
if(r.ei) {
|
||||
r.ei = false;
|
||||
r.ime = 1;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 CPU::debugger_read(uint16 addr) {
|
||||
return bus.read(addr);
|
||||
}
|
||||
|
||||
#endif
|
@@ -10,15 +10,15 @@ unsigned CPU::wram_addr(uint16 addr) const {
|
||||
void CPU::mmio_joyp_poll() {
|
||||
unsigned button = 0, dpad = 0;
|
||||
|
||||
button |= interface->inputPoll((unsigned)Input::Start) << 3;
|
||||
button |= interface->inputPoll((unsigned)Input::Select) << 2;
|
||||
button |= interface->inputPoll((unsigned)Input::B) << 1;
|
||||
button |= interface->inputPoll((unsigned)Input::A) << 0;
|
||||
button |= interface->inputPoll(0, 0, (unsigned)Input::Start) << 3;
|
||||
button |= interface->inputPoll(0, 0, (unsigned)Input::Select) << 2;
|
||||
button |= interface->inputPoll(0, 0, (unsigned)Input::B) << 1;
|
||||
button |= interface->inputPoll(0, 0, (unsigned)Input::A) << 0;
|
||||
|
||||
dpad |= interface->inputPoll((unsigned)Input::Down) << 3;
|
||||
dpad |= interface->inputPoll((unsigned)Input::Up) << 2;
|
||||
dpad |= interface->inputPoll((unsigned)Input::Left) << 1;
|
||||
dpad |= interface->inputPoll((unsigned)Input::Right) << 0;
|
||||
dpad |= interface->inputPoll(0, 0, (unsigned)Input::Down) << 3;
|
||||
dpad |= interface->inputPoll(0, 0, (unsigned)Input::Up) << 2;
|
||||
dpad |= interface->inputPoll(0, 0, (unsigned)Input::Left) << 1;
|
||||
dpad |= interface->inputPoll(0, 0, (unsigned)Input::Right) << 0;
|
||||
|
||||
status.joyp = 0x0f;
|
||||
if(status.p15 == 1 && status.p14 == 1) status.joyp -= status.mlt_req;
|
@@ -1,4 +0,0 @@
|
||||
unsigned wram_addr(uint16 addr) const;
|
||||
void mmio_joyp_poll();
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
@@ -1,30 +1,13 @@
|
||||
#ifdef CPU_CPP
|
||||
|
||||
void CPU::serialize(serializer &s) {
|
||||
LR35902::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(wram);
|
||||
s.array(hram);
|
||||
|
||||
s.integer(r.a.data);
|
||||
s.integer(r.f.z);
|
||||
s.integer(r.f.n);
|
||||
s.integer(r.f.h);
|
||||
s.integer(r.f.c);
|
||||
s.integer(r.b.data);
|
||||
s.integer(r.c.data);
|
||||
s.integer(r.d.data);
|
||||
s.integer(r.e.data);
|
||||
s.integer(r.h.data);
|
||||
s.integer(r.l.data);
|
||||
s.integer(r.sp.data);
|
||||
s.integer(r.pc.data);
|
||||
|
||||
s.integer(status.clock);
|
||||
s.integer(status.halt);
|
||||
s.integer(status.stop);
|
||||
s.integer(status.ei);
|
||||
s.integer(status.ime);
|
||||
|
||||
s.integer(status.p15);
|
||||
s.integer(status.p14);
|
||||
|
@@ -4,8 +4,6 @@
|
||||
|
||||
#ifdef CPU_CPP
|
||||
|
||||
#include "opcode.cpp"
|
||||
|
||||
void CPU::add_clocks(unsigned clocks) {
|
||||
system.clocks_executed += clocks;
|
||||
if(system.sgb()) scheduler.exit(Scheduler::ExitReason::StepEvent);
|
||||
@@ -23,11 +21,11 @@ void CPU::add_clocks(unsigned clocks) {
|
||||
if((status.clock & 511) == 0) timer_8192hz();
|
||||
if((status.clock & 1023) == 0) timer_4096hz();
|
||||
|
||||
lcd.clock -= clocks * lcd.frequency;
|
||||
if(lcd.clock <= 0) co_switch(scheduler.active_thread = lcd.thread);
|
||||
ppu.clock -= clocks * ppu.frequency;
|
||||
if(ppu.clock < 0) co_switch(scheduler.active_thread = ppu.thread);
|
||||
|
||||
apu.clock -= clocks * apu.frequency;
|
||||
if(apu.clock <= 0) co_switch(scheduler.active_thread = apu.thread);
|
||||
if(apu.clock < 0) co_switch(scheduler.active_thread = apu.thread);
|
||||
}
|
||||
|
||||
void CPU::timer_262144hz() {
|
@@ -1,13 +0,0 @@
|
||||
void add_clocks(unsigned clocks);
|
||||
void timer_262144hz();
|
||||
void timer_65536hz();
|
||||
void timer_16384hz();
|
||||
void timer_8192hz();
|
||||
void timer_4096hz();
|
||||
void hblank();
|
||||
|
||||
//opcode.cpp
|
||||
void op_io();
|
||||
uint8 op_read(uint16 addr);
|
||||
void op_write(uint16 addr, uint8 data);
|
||||
void cycle_edge();
|
@@ -1,17 +1,18 @@
|
||||
#ifndef GB_HPP
|
||||
#define GB_HPP
|
||||
|
||||
#include <base/base.hpp>
|
||||
#include <emulator/emulator.hpp>
|
||||
#include <processor/lr35902/lr35902.hpp>
|
||||
|
||||
namespace GB {
|
||||
namespace GameBoy {
|
||||
namespace Info {
|
||||
static const char Name[] = "bgbc";
|
||||
static const unsigned SerializerVersion = 3;
|
||||
static const char Name[] = "bgb";
|
||||
static const unsigned SerializerVersion = 4;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bgbc - Game Boy, Super Game Boy, and Game Boy Color emulator
|
||||
bgb - Game Boy, Super Game Boy, and Game Boy Color emulator
|
||||
author: byuu
|
||||
license: GPLv3
|
||||
project started: 2010-12-27
|
||||
@@ -19,11 +20,11 @@ namespace GB {
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
namespace GB {
|
||||
namespace GameBoy {
|
||||
struct Thread {
|
||||
cothread_t thread;
|
||||
unsigned frequency;
|
||||
int64 clock;
|
||||
int64_t clock;
|
||||
|
||||
inline void create(void (*entrypoint)(), unsigned frequency) {
|
||||
if(thread) co_delete(thread);
|
||||
@@ -50,8 +51,8 @@ namespace GB {
|
||||
#include <gb/scheduler/scheduler.hpp>
|
||||
#include <gb/cartridge/cartridge.hpp>
|
||||
#include <gb/cpu/cpu.hpp>
|
||||
#include <gb/ppu/ppu.hpp>
|
||||
#include <gb/apu/apu.hpp>
|
||||
#include <gb/lcd/lcd.hpp>
|
||||
#include <gb/cheat/cheat.hpp>
|
||||
#include <gb/video/video.hpp>
|
||||
};
|
||||
|
@@ -1,27 +1,141 @@
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
namespace GB {
|
||||
namespace GameBoy {
|
||||
|
||||
Interface *interface = nullptr;
|
||||
|
||||
void Interface::lcdScanline() {
|
||||
if(hook) hook->lcdScanline();
|
||||
}
|
||||
|
||||
void Interface::joypWrite(bool p15, bool p14) {
|
||||
if(hook) hook->joypWrite(p15, p14);
|
||||
}
|
||||
|
||||
void Interface::videoRefresh(const uint16_t *data) {
|
||||
double Interface::videoFrequency() {
|
||||
return 4194304.0 / (154.0 * 456.0);
|
||||
}
|
||||
|
||||
void Interface::audioSample(int16_t center, int16_t left, int16_t right) {
|
||||
double Interface::audioFrequency() {
|
||||
return 4194304.0;
|
||||
}
|
||||
|
||||
bool Interface::inputPoll(unsigned id) {
|
||||
return false;
|
||||
bool Interface::loaded() {
|
||||
return cartridge.loaded();
|
||||
}
|
||||
|
||||
void Interface::message(const string &text) {
|
||||
print(text, "\n");
|
||||
string Interface::sha256() {
|
||||
return cartridge.sha256();
|
||||
}
|
||||
|
||||
void Interface::load(unsigned id, const stream &stream, const string &markup) {
|
||||
if(id == ID::GameBoyBootROM) {
|
||||
stream.read(system.bootROM.dmg, min( 256u, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::SuperGameBoyBootROM) {
|
||||
stream.read(system.bootROM.sgb, min( 256u, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::GameBoyColorBootROM) {
|
||||
stream.read(system.bootROM.cgb, min(2048u, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::GameBoyROM) {
|
||||
cartridge.load(System::Revision::GameBoy, markup, stream);
|
||||
system.power();
|
||||
}
|
||||
|
||||
if(id == ID::GameBoyColorROM) {
|
||||
cartridge.load(System::Revision::GameBoyColor, markup, stream);
|
||||
system.power();
|
||||
}
|
||||
|
||||
if(id == ID::RAM) {
|
||||
stream.read(cartridge.ramdata, min(stream.size(), cartridge.ramsize));
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::save(unsigned id, const stream &stream) {
|
||||
if(id == ID::RAM) {
|
||||
stream.write(cartridge.ramdata, cartridge.ramsize);
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::unload() {
|
||||
cartridge.unload();
|
||||
}
|
||||
|
||||
void Interface::power() {
|
||||
system.power();
|
||||
}
|
||||
|
||||
void Interface::reset() {
|
||||
system.power();
|
||||
}
|
||||
|
||||
void Interface::run() {
|
||||
system.run();
|
||||
}
|
||||
|
||||
serializer Interface::serialize() {
|
||||
system.runtosave();
|
||||
return system.serialize();
|
||||
}
|
||||
|
||||
bool Interface::unserialize(serializer &s) {
|
||||
return system.unserialize(s);
|
||||
}
|
||||
|
||||
void Interface::cheatSet(const lstring &list) {
|
||||
cheat.reset();
|
||||
for(auto &code : list) {
|
||||
lstring codelist = code.split("+");
|
||||
for(auto &part : codelist) {
|
||||
unsigned addr, data, comp;
|
||||
if(Cheat::decode(part, addr, data, comp)) cheat.append({addr, data, comp});
|
||||
}
|
||||
}
|
||||
cheat.synchronize();
|
||||
}
|
||||
|
||||
void Interface::updatePalette() {
|
||||
video.generate_palette();
|
||||
}
|
||||
|
||||
Interface::Interface() {
|
||||
interface = this;
|
||||
hook = nullptr;
|
||||
|
||||
information.name = "Game Boy";
|
||||
information.width = 160;
|
||||
information.height = 144;
|
||||
information.overscan = false;
|
||||
information.aspectRatio = 1.0;
|
||||
information.resettable = false;
|
||||
|
||||
firmware.append({ID::GameBoyBootROM, "Game Boy", "sys", "boot.rom"});
|
||||
firmware.append({ID::SuperGameBoyBootROM, "Super Game Boy", "sfc", "boot.rom"});
|
||||
firmware.append({ID::GameBoyColorBootROM, "Game Boy Color", "sys", "boot.rom"});
|
||||
|
||||
media.append({ID::GameBoyROM, "Game Boy", "sys", "program.rom", "gb" });
|
||||
media.append({ID::GameBoyColorROM, "Game Boy Color", "sys", "program.rom", "gbc"});
|
||||
|
||||
{
|
||||
Device device{0, ID::Device, "Controller"};
|
||||
device.input.append({0, 0, "Up" });
|
||||
device.input.append({1, 0, "Down" });
|
||||
device.input.append({2, 0, "Left" });
|
||||
device.input.append({3, 0, "Right" });
|
||||
device.input.append({4, 0, "B" });
|
||||
device.input.append({5, 0, "A" });
|
||||
device.input.append({6, 0, "Select"});
|
||||
device.input.append({7, 0, "Start" });
|
||||
device.order = {0, 1, 2, 3, 4, 5, 6, 7};
|
||||
this->device.append(device);
|
||||
}
|
||||
|
||||
port.append({0, "Device", {device[0]}});
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,12 +1,60 @@
|
||||
struct Interface {
|
||||
virtual void lcdScanline();
|
||||
virtual void joypWrite(bool p15, bool p14);
|
||||
#ifndef GB_HPP
|
||||
namespace GameBoy {
|
||||
#endif
|
||||
|
||||
virtual void videoRefresh(const uint16_t *data);
|
||||
virtual void audioSample(int16_t center, int16_t left, int16_t right);
|
||||
virtual bool inputPoll(unsigned id);
|
||||
struct ID {
|
||||
enum : unsigned {
|
||||
GameBoyBootROM,
|
||||
SuperGameBoyBootROM,
|
||||
GameBoyColorBootROM,
|
||||
GameBoyROM,
|
||||
GameBoyColorROM,
|
||||
RAM,
|
||||
};
|
||||
|
||||
virtual void message(const string &text);
|
||||
enum : unsigned {
|
||||
Device = 1,
|
||||
};
|
||||
};
|
||||
|
||||
struct Interface : Emulator::Interface {
|
||||
//Super Game Boy bindings
|
||||
struct Hook {
|
||||
virtual void lcdScanline() {}
|
||||
virtual void joypWrite(bool p15, bool p14) {}
|
||||
} *hook;
|
||||
|
||||
void lcdScanline();
|
||||
void joypWrite(bool p15, bool p14);
|
||||
|
||||
double videoFrequency();
|
||||
double audioFrequency();
|
||||
|
||||
bool loaded();
|
||||
string sha256();
|
||||
void load(unsigned id, const stream &stream, const string &markup = "");
|
||||
void save(unsigned id, const stream &stream);
|
||||
void unload();
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
void run();
|
||||
|
||||
serializer serialize();
|
||||
bool unserialize(serializer&);
|
||||
|
||||
void cheatSet(const lstring&);
|
||||
|
||||
void updatePalette();
|
||||
|
||||
Interface();
|
||||
|
||||
private:
|
||||
vector<Device> device;
|
||||
};
|
||||
|
||||
extern Interface *interface;
|
||||
|
||||
#ifndef GB_HPP
|
||||
}
|
||||
#endif
|
||||
|
@@ -1,3 +0,0 @@
|
||||
unsigned vram_addr(uint16 addr) const;
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
@@ -1,7 +1,7 @@
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
#define MEMORY_CPP
|
||||
namespace GB {
|
||||
namespace GameBoy {
|
||||
|
||||
Unmapped unmapped;
|
||||
Bus bus;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user