mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-17 23:42:08 +02:00
Compare commits
113 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
47dffcae85 | ||
|
be625cc0fb | ||
|
4cb8b51606 | ||
|
87cb164f7c | ||
|
c1318961d8 | ||
|
791e64951b | ||
|
27af50099f | ||
|
fbd52c7e5f | ||
|
36795e8061 | ||
|
ec8350794a | ||
|
4545e7c62d | ||
|
3302398907 | ||
|
189e707594 | ||
|
9a8a54c75e | ||
|
d418eda97c | ||
|
5dbd5f4d0f | ||
|
d6001a2df4 | ||
|
bd61432322 | ||
|
0611fefefa | ||
|
6ac7b733bd | ||
|
a1e4c67a05 | ||
|
73ebe093b8 | ||
|
c3f9d421da | ||
|
689fc49047 | ||
|
cb97d98ad2 | ||
|
3cb04b101b | ||
|
5d273c5265 | ||
|
8703d57030 | ||
|
9ad8b7eaac | ||
|
76553756a2 | ||
|
4fd20f0ae0 | ||
|
bb4db22a7d | ||
|
67c13f749f | ||
|
616372e96b | ||
|
bba597fc6f | ||
|
abe639ea91 | ||
|
77bb5b7891 | ||
|
4b2944c39b | ||
|
4c29e6fbab | ||
|
a454e9d927 | ||
|
d2241f1931 | ||
|
0cd0dcd811 | ||
|
1c18812f47 | ||
|
28885db586 | ||
|
d423ae0a29 | ||
|
303a0a67d0 | ||
|
01b4cb9919 | ||
|
17b5bae86a | ||
|
6189c93f3d | ||
|
1de484262c | ||
|
b8d0ec29b2 | ||
|
79a47d133a | ||
|
c8bb4949b1 | ||
|
f587cb0dcc | ||
|
ea086fe33f | ||
|
c66cc73374 | ||
|
5a1dcf5079 | ||
|
e16dd58184 | ||
|
395e5a5639 | ||
|
ec939065bd | ||
|
77578cd0a4 | ||
|
04087a74b0 | ||
|
6701403745 | ||
|
95c62f92ac | ||
|
0f54be93b7 | ||
|
8db134843f | ||
|
06e83c6154 | ||
|
cbfbec4dc3 | ||
|
386ac87d21 | ||
|
533aa97011 | ||
|
d118b70b30 | ||
|
aa8ac7bbb8 | ||
|
ad71e18e02 | ||
|
a00c7cb639 | ||
|
112520cf45 | ||
|
11d6f09359 | ||
|
3ed42af8a1 | ||
|
482b4119f6 | ||
|
f1d6325bcd | ||
|
e48671694e | ||
|
338f13e57b | ||
|
6cbc312f11 | ||
|
7a96321e78 | ||
|
6cfb9e89e7 | ||
|
a37ce1cb2f | ||
|
10fd29e7bb | ||
|
0370229444 | ||
|
82afd511fc | ||
|
ad3eafd735 | ||
|
4bc5f66aa5 | ||
|
730e6ae4cc | ||
|
892bb3ab01 | ||
|
e4e50308d2 | ||
|
cc518dcc3c | ||
|
ba081d309e | ||
|
1bf9265b7c | ||
|
f947d84309 | ||
|
0bd21185b8 | ||
|
6227974bf6 | ||
|
ea95eaca3c | ||
|
ad0805b168 | ||
|
2cc077e12b | ||
|
ae6c3c377d | ||
|
01750e9c83 | ||
|
891f1ab7af | ||
|
bf78e66027 | ||
|
483f9f8f20 | ||
|
f3feaa3e86 | ||
|
aaffd000a4 | ||
|
118a393c4c | ||
|
6b708de893 | ||
|
db5e2107b4 | ||
|
13ac6104e3 |
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
purify/*.o
|
||||
purify/purify
|
||||
purify/analyze-gba
|
61
bsnes/Makefile
Executable file → Normal file
61
bsnes/Makefile
Executable file → Normal file
@@ -1,19 +1,23 @@
|
||||
include nall/Makefile
|
||||
|
||||
nes := nes
|
||||
snes := snes
|
||||
gameboy := gameboy
|
||||
profile := accuracy
|
||||
ui := ui
|
||||
fc := fc
|
||||
sfc := sfc
|
||||
gb := gb
|
||||
gba := gba
|
||||
nds := nds
|
||||
|
||||
profile := accuracy
|
||||
target := ethos
|
||||
|
||||
# options += console
|
||||
# options += debugger
|
||||
# arch := win32
|
||||
# console := true
|
||||
|
||||
# compiler
|
||||
c := $(compiler) -std=gnu99
|
||||
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
|
||||
flags := -O3 -fomit-frame-pointer -I.
|
||||
link :=
|
||||
flags := -I. -O3 -fomit-frame-pointer
|
||||
link := -s
|
||||
objects := libco
|
||||
|
||||
# profile-guided optimization mode
|
||||
@@ -29,19 +33,26 @@ endif
|
||||
|
||||
# platform
|
||||
ifeq ($(platform),x)
|
||||
# tree vectorization causes code generation errors with Linux/GCC 4.6.1
|
||||
flags += -fno-tree-vectorize
|
||||
link += -s -ldl -lX11 -lXext
|
||||
flags += -march=native
|
||||
link += -ldl -lX11 -lXext
|
||||
else ifeq ($(platform),osx)
|
||||
else ifeq ($(platform),win)
|
||||
link += $(if $(findstring console,$(options)),-mconsole,-mwindows)
|
||||
link += -mthreads -s -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32
|
||||
ifeq ($(arch),win32)
|
||||
flags += -m32
|
||||
link += -m32
|
||||
endif
|
||||
ifeq ($(console),true)
|
||||
link += -mconsole
|
||||
else
|
||||
link += -mwindows
|
||||
endif
|
||||
link += -mthreads -luuid -lkernel32 -luser32 -lgdi32 -lcomctl32 -lcomdlg32 -lshell32 -lole32
|
||||
link += -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
|
||||
else
|
||||
unknown_platform: help;
|
||||
endif
|
||||
|
||||
flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o)
|
||||
ui := target-$(target)
|
||||
|
||||
# implicit rules
|
||||
compile = \
|
||||
@@ -61,6 +72,7 @@ all: build;
|
||||
obj/libco.o: libco/libco.c libco/*
|
||||
|
||||
include $(ui)/Makefile
|
||||
flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o)
|
||||
|
||||
# targets
|
||||
clean:
|
||||
@@ -76,7 +88,24 @@ clean:
|
||||
-@$(call delete,*.pdb)
|
||||
-@$(call delete,*.manifest)
|
||||
|
||||
archive-all:
|
||||
tar -cjf bsnes.tar.bz2 data gameboy libco nall nes obj out phoenix ruby snes ui ui-libsnes Makefile cc.bat clean.bat sync.sh
|
||||
sync:
|
||||
if [ -d ./libco ]; then rm -r ./libco; fi
|
||||
if [ -d ./nall ]; then rm -r ./nall; fi
|
||||
if [ -d ./ruby ]; then rm -r ./ruby; fi
|
||||
if [ -d ./phoenix ]; then rm -r ./phoenix; fi
|
||||
cp -r ../libco ./libco
|
||||
cp -r ../nall ./nall
|
||||
cp -r ../ruby ./ruby
|
||||
cp -r ../phoenix ./phoenix
|
||||
rm -r libco/doc
|
||||
rm -r libco/test
|
||||
rm -r nall/test
|
||||
rm -r ruby/_test
|
||||
rm -r phoenix/nall
|
||||
rm -r phoenix/test
|
||||
|
||||
archive:
|
||||
if [ -f bsnes.tar.xz ]; then rm bsnes.tar.xz; fi
|
||||
tar -cJf bsnes.tar.xz `ls`
|
||||
|
||||
help:;
|
||||
|
@@ -1,2 +0,0 @@
|
||||
@mingw32-make -j 8
|
||||
@pause
|
@@ -1 +0,0 @@
|
||||
@mingw32-make clean
|
0
bsnes/data/bsnes.Manifest
Executable file → Normal file
0
bsnes/data/bsnes.Manifest
Executable file → Normal file
0
bsnes/data/bsnes.desktop
Executable file → Normal file
0
bsnes/data/bsnes.desktop
Executable file → Normal file
0
bsnes/data/bsnes.ico
Executable file → Normal file
0
bsnes/data/bsnes.ico
Executable file → Normal file
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
0
bsnes/data/bsnes.png
Executable file → Normal file
0
bsnes/data/bsnes.png
Executable file → Normal file
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
79635
bsnes/data/cheats.bml
79635
bsnes/data/cheats.bml
File diff suppressed because it is too large
Load Diff
106582
bsnes/data/cheats.xml
Normal file
106582
bsnes/data/cheats.xml
Normal file
File diff suppressed because it is too large
Load Diff
3812
bsnes/data/laevateinn.hpp
Normal file
3812
bsnes/data/laevateinn.hpp
Normal file
File diff suppressed because it is too large
Load Diff
137
bsnes/emulator/emulator.hpp
Normal file
137
bsnes/emulator/emulator.hpp
Normal file
@@ -0,0 +1,137 @@
|
||||
#ifndef EMULATOR_HPP
|
||||
#define EMULATOR_HPP
|
||||
|
||||
namespace Emulator {
|
||||
static const char Name[] = "bsnes";
|
||||
static const char Version[] = "090";
|
||||
static const char Author[] = "byuu";
|
||||
static const char License[] = "GPLv3";
|
||||
}
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/algorithm.hpp>
|
||||
#include <nall/directory.hpp>
|
||||
#include <nall/dl.hpp>
|
||||
#include <nall/dsp.hpp>
|
||||
#include <nall/endian.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/priority-queue.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
|
||||
template<typename T> struct hook;
|
||||
template<typename R, typename... P> struct hook<R (P...)> {
|
||||
function<R (P...)> callback;
|
||||
|
||||
R operator()(P... p) const {
|
||||
#if defined(DEBUGGER)
|
||||
if(callback) return callback(std::forward<P>(p)...);
|
||||
#endif
|
||||
return R();
|
||||
}
|
||||
|
||||
hook() {}
|
||||
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 L> hook(const L& function) { callback = function; }
|
||||
|
||||
hook& operator=(const hook& hook) { callback = hook.callback; return *this; }
|
||||
};
|
||||
|
||||
#if defined(DEBUGGER)
|
||||
#define privileged public
|
||||
#else
|
||||
#define privileged private
|
||||
#endif
|
||||
|
||||
typedef int1_t int1;
|
||||
typedef int2_t int2;
|
||||
typedef int3_t int3;
|
||||
typedef int4_t int4;
|
||||
typedef int5_t int5;
|
||||
typedef int6_t int6;
|
||||
typedef int7_t int7;
|
||||
typedef int8_t int8;
|
||||
typedef int9_t int9;
|
||||
typedef int10_t int10;
|
||||
typedef int11_t int11;
|
||||
typedef int12_t int12;
|
||||
typedef int13_t int13;
|
||||
typedef int14_t int14;
|
||||
typedef int15_t int15;
|
||||
typedef int16_t int16;
|
||||
typedef int17_t int17;
|
||||
typedef int18_t int18;
|
||||
typedef int19_t int19;
|
||||
typedef int20_t int20;
|
||||
typedef int21_t int21;
|
||||
typedef int22_t int22;
|
||||
typedef int23_t int23;
|
||||
typedef int24_t int24;
|
||||
typedef int25_t int25;
|
||||
typedef int26_t int26;
|
||||
typedef int27_t int27;
|
||||
typedef int28_t int28;
|
||||
typedef int29_t int29;
|
||||
typedef int30_t int30;
|
||||
typedef int31_t int31;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
typedef uint1_t uint1;
|
||||
typedef uint2_t uint2;
|
||||
typedef uint3_t uint3;
|
||||
typedef uint4_t uint4;
|
||||
typedef uint5_t uint5;
|
||||
typedef uint6_t uint6;
|
||||
typedef uint7_t uint7;
|
||||
typedef uint8_t uint8;
|
||||
typedef uint9_t uint9;
|
||||
typedef uint10_t uint10;
|
||||
typedef uint11_t uint11;
|
||||
typedef uint12_t uint12;
|
||||
typedef uint13_t uint13;
|
||||
typedef uint14_t uint14;
|
||||
typedef uint15_t uint15;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint17_t uint17;
|
||||
typedef uint18_t uint18;
|
||||
typedef uint19_t uint19;
|
||||
typedef uint20_t uint20;
|
||||
typedef uint21_t uint21;
|
||||
typedef uint22_t uint22;
|
||||
typedef uint23_t uint23;
|
||||
typedef uint24_t uint24;
|
||||
typedef uint25_t uint25;
|
||||
typedef uint26_t uint26;
|
||||
typedef uint27_t uint27;
|
||||
typedef uint28_t uint28;
|
||||
typedef uint29_t uint29;
|
||||
typedef uint30_t uint30;
|
||||
typedef uint31_t uint31;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint_t<33> uint33;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
typedef varuint_t<unsigned> varuint;
|
||||
|
||||
#endif
|
118
bsnes/emulator/interface.hpp
Normal file
118
bsnes/emulator/interface.hpp
Normal file
@@ -0,0 +1,118 @@
|
||||
#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;
|
||||
struct Capability {
|
||||
bool states;
|
||||
bool cheats;
|
||||
} capability;
|
||||
} information;
|
||||
|
||||
struct Media {
|
||||
unsigned id;
|
||||
string name;
|
||||
string type;
|
||||
string load;
|
||||
};
|
||||
|
||||
vector<Media> media;
|
||||
|
||||
struct Device {
|
||||
unsigned id;
|
||||
unsigned portmask;
|
||||
string name;
|
||||
struct Input {
|
||||
unsigned id;
|
||||
unsigned type; //0 = digital, 1 = analog (relative), 2 = analog (absolute)
|
||||
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&, const string&) {}
|
||||
virtual void loadRequest(unsigned, const string&) {}
|
||||
virtual void saveRequest(unsigned, 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 ""; }
|
||||
virtual void notify(const string &text) { print(text, "\n"); }
|
||||
} *bind;
|
||||
|
||||
//callback bindings (provided by user interface)
|
||||
void loadRequest(unsigned id, const string &name, const string &type) { return bind->loadRequest(id, name, type); }
|
||||
void loadRequest(unsigned id, const string &path) { return bind->loadRequest(id, path); }
|
||||
void saveRequest(unsigned id, const string &path) { return bind->saveRequest(id, 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); }
|
||||
template<typename... Args> void notify(Args&... args) { return bind->notify({std::forward<Args>(args)...}); }
|
||||
|
||||
//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) = 0;
|
||||
virtual void load(unsigned id, const string &manifest) {}
|
||||
virtual void save() {}
|
||||
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() {}
|
||||
|
||||
//time functions
|
||||
virtual bool rtc() { return false; }
|
||||
virtual void rtcsync() {}
|
||||
|
||||
//state functions
|
||||
virtual serializer serialize() = 0;
|
||||
virtual bool unserialize(serializer&) = 0;
|
||||
|
||||
//cheat functions
|
||||
virtual void cheatSet(const lstring& = lstring{}) {}
|
||||
|
||||
//utility functions
|
||||
virtual void paletteUpdate() {}
|
||||
|
||||
//debugger functions
|
||||
virtual bool tracerEnable(bool) { return false; }
|
||||
virtual void exportMemory() {}
|
||||
|
||||
Interface() : bind(nullptr) {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
16
bsnes/fc/Makefile
Normal file
16
bsnes/fc/Makefile
Normal 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/)
|
8
bsnes/nes/apu/apu.cpp → bsnes/fc/apu/apu.cpp
Executable file → Normal file
8
bsnes/nes/apu/apu.cpp → bsnes/fc/apu/apu.cpp
Executable file → Normal file
@@ -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();
|
||||
}
|
||||
@@ -92,7 +92,7 @@ void APU::power() {
|
||||
}
|
||||
|
||||
void APU::reset() {
|
||||
Processor::create(APU::Main, 21477272);
|
||||
create(APU::Main, 21477272);
|
||||
|
||||
pulse[0].reset();
|
||||
pulse[1].reset();
|
2
bsnes/nes/apu/apu.hpp → bsnes/fc/apu/apu.hpp
Executable file → Normal file
2
bsnes/nes/apu/apu.hpp → bsnes/fc/apu/apu.hpp
Executable file → Normal file
@@ -1,4 +1,4 @@
|
||||
struct APU : Processor {
|
||||
struct APU : Thread {
|
||||
static void Main();
|
||||
void main();
|
||||
void tick();
|
0
bsnes/nes/apu/dmc.cpp → bsnes/fc/apu/dmc.cpp
Executable file → Normal file
0
bsnes/nes/apu/dmc.cpp → bsnes/fc/apu/dmc.cpp
Executable file → Normal file
0
bsnes/nes/apu/dmc.hpp → bsnes/fc/apu/dmc.hpp
Executable file → Normal file
0
bsnes/nes/apu/dmc.hpp → bsnes/fc/apu/dmc.hpp
Executable file → Normal file
0
bsnes/nes/apu/envelope.cpp → bsnes/fc/apu/envelope.cpp
Executable file → Normal file
0
bsnes/nes/apu/envelope.cpp → bsnes/fc/apu/envelope.cpp
Executable file → Normal file
0
bsnes/nes/apu/envelope.hpp → bsnes/fc/apu/envelope.hpp
Executable file → Normal file
0
bsnes/nes/apu/envelope.hpp → bsnes/fc/apu/envelope.hpp
Executable file → Normal file
0
bsnes/nes/apu/noise.cpp → bsnes/fc/apu/noise.cpp
Executable file → Normal file
0
bsnes/nes/apu/noise.cpp → bsnes/fc/apu/noise.cpp
Executable file → Normal file
0
bsnes/nes/apu/noise.hpp → bsnes/fc/apu/noise.hpp
Executable file → Normal file
0
bsnes/nes/apu/noise.hpp → bsnes/fc/apu/noise.hpp
Executable file → Normal file
0
bsnes/nes/apu/pulse.cpp → bsnes/fc/apu/pulse.cpp
Executable file → Normal file
0
bsnes/nes/apu/pulse.cpp → bsnes/fc/apu/pulse.cpp
Executable file → Normal file
0
bsnes/nes/apu/pulse.hpp → bsnes/fc/apu/pulse.hpp
Executable file → Normal file
0
bsnes/nes/apu/pulse.hpp → bsnes/fc/apu/pulse.hpp
Executable file → Normal file
2
bsnes/nes/apu/serialization.cpp → bsnes/fc/apu/serialization.cpp
Executable file → Normal file
2
bsnes/nes/apu/serialization.cpp → bsnes/fc/apu/serialization.cpp
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
void APU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
filter.serialize(s);
|
||||
|
0
bsnes/nes/apu/sweep.cpp → bsnes/fc/apu/sweep.cpp
Executable file → Normal file
0
bsnes/nes/apu/sweep.cpp → bsnes/fc/apu/sweep.cpp
Executable file → Normal file
0
bsnes/nes/apu/sweep.hpp → bsnes/fc/apu/sweep.hpp
Executable file → Normal file
0
bsnes/nes/apu/sweep.hpp → bsnes/fc/apu/sweep.hpp
Executable file → Normal file
0
bsnes/nes/apu/triangle.cpp → bsnes/fc/apu/triangle.cpp
Executable file → Normal file
0
bsnes/nes/apu/triangle.cpp → bsnes/fc/apu/triangle.cpp
Executable file → Normal file
0
bsnes/nes/apu/triangle.hpp → bsnes/fc/apu/triangle.hpp
Executable file → Normal file
0
bsnes/nes/apu/triangle.hpp → bsnes/fc/apu/triangle.hpp
Executable file → Normal file
2
bsnes/nes/cartridge/board/bandai-fcg.cpp → bsnes/fc/cartridge/board/bandai-fcg.cpp
Executable file → Normal file
2
bsnes/nes/cartridge/board/bandai-fcg.cpp → bsnes/fc/cartridge/board/bandai-fcg.cpp
Executable file → Normal file
@@ -111,7 +111,7 @@ void serialize(serializer &s) {
|
||||
s.integer(irq_latch);
|
||||
}
|
||||
|
||||
BandaiFCG(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||
BandaiFCG(XML::Document &document) : Board(document) {
|
||||
}
|
||||
|
||||
};
|
174
bsnes/fc/cartridge/board/board.cpp
Normal file
174
bsnes/fc/cartridge/board/board.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
#include "bandai-fcg.cpp"
|
||||
#include "konami-vrc1.cpp"
|
||||
#include "konami-vrc2.cpp"
|
||||
#include "konami-vrc3.cpp"
|
||||
#include "konami-vrc4.cpp"
|
||||
#include "konami-vrc6.cpp"
|
||||
#include "konami-vrc7.cpp"
|
||||
#include "nes-axrom.cpp"
|
||||
#include "nes-bnrom.cpp"
|
||||
#include "nes-cnrom.cpp"
|
||||
#include "nes-exrom.cpp"
|
||||
#include "nes-fxrom.cpp"
|
||||
#include "nes-gxrom.cpp"
|
||||
#include "nes-hkrom.cpp"
|
||||
#include "nes-nrom.cpp"
|
||||
#include "nes-pxrom.cpp"
|
||||
#include "nes-sxrom.cpp"
|
||||
#include "nes-txrom.cpp"
|
||||
#include "nes-uxrom.cpp"
|
||||
#include "sunsoft-5b.cpp"
|
||||
|
||||
uint8 Board::Memory::read(unsigned addr) const {
|
||||
return data[mirror(addr, size)];
|
||||
}
|
||||
|
||||
void Board::Memory::write(unsigned addr, uint8 byte) {
|
||||
if(writable) data[mirror(addr, size)] = byte;
|
||||
}
|
||||
|
||||
unsigned Board::mirror(unsigned addr, unsigned size) {
|
||||
unsigned base = 0;
|
||||
if(size) {
|
||||
unsigned mask = 1 << 23;
|
||||
while(addr >= size) {
|
||||
while(!(addr & mask)) mask >>= 1;
|
||||
addr -= mask;
|
||||
if(size > mask) {
|
||||
size -= mask;
|
||||
base += mask;
|
||||
}
|
||||
mask >>= 1;
|
||||
}
|
||||
base += addr;
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
void Board::main() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
cartridge.clock += 12 * 4095;
|
||||
tick();
|
||||
}
|
||||
}
|
||||
|
||||
void Board::tick() {
|
||||
cartridge.clock += 12;
|
||||
if(cartridge.clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||
}
|
||||
|
||||
uint8 Board::chr_read(unsigned addr) {
|
||||
if(chrram.size) return chrram.data[mirror(addr, chrram.size)];
|
||||
if(chrrom.size) return chrrom.data[mirror(addr, chrrom.size)];
|
||||
return 0u;
|
||||
}
|
||||
|
||||
void Board::chr_write(unsigned addr, uint8 data) {
|
||||
if(chrram.size) chrram.data[mirror(addr, chrram.size)] = data;
|
||||
}
|
||||
|
||||
void Board::power() {
|
||||
}
|
||||
|
||||
void Board::reset() {
|
||||
}
|
||||
|
||||
void Board::serialize(serializer &s) {
|
||||
if(prgram.size) s.array(prgram.data, prgram.size);
|
||||
if(chrram.size) s.array(chrram.data, chrram.size);
|
||||
}
|
||||
|
||||
Board::Board(XML::Document &document) {
|
||||
cartridge.board = this;
|
||||
auto &cartridge = document["cartridge"];
|
||||
|
||||
information.type = cartridge["board"]["type"].data;
|
||||
information.battery = cartridge["prg"]["ram"]["nonvolatile"].data == "true";
|
||||
|
||||
auto &prom = cartridge["prg"]["rom"];
|
||||
auto &pram = cartridge["prg"]["ram"];
|
||||
auto &crom = cartridge["chr"]["rom"];
|
||||
auto &cram = cartridge["chr"]["ram"];
|
||||
|
||||
prgrom.size = numeral(prom["size"].data);
|
||||
prgram.size = numeral(pram["size"].data);
|
||||
chrrom.size = numeral(crom["size"].data);
|
||||
chrram.size = numeral(cram["size"].data);
|
||||
|
||||
if(prgrom.size) prgrom.data = new uint8[prgrom.size]();
|
||||
if(prgram.size) prgram.data = new uint8[prgram.size]();
|
||||
if(chrrom.size) chrrom.data = new uint8[chrrom.size]();
|
||||
if(chrram.size) chrram.data = new uint8[chrram.size]();
|
||||
|
||||
if(prom["name"].data) interface->loadRequest(ID::ProgramROM, prom["name"].data);
|
||||
if(pram["name"].data) interface->loadRequest(ID::ProgramRAM, pram["name"].data);
|
||||
if(crom["name"].data) interface->loadRequest(ID::CharacterROM, crom["name"].data);
|
||||
if(cram["name"].data) interface->loadRequest(ID::CharacterRAM, cram["name"].data);
|
||||
|
||||
if(pram["name"].data) Famicom::cartridge.memory.append({ID::ProgramRAM, pram["name"].data});
|
||||
if(cram["name"].data) Famicom::cartridge.memory.append({ID::CharacterRAM, cram["name"].data});
|
||||
|
||||
prgram.writable = true;
|
||||
chrram.writable = true;
|
||||
}
|
||||
|
||||
Board::~Board() {
|
||||
}
|
||||
|
||||
Board* Board::load(const string &manifest) {
|
||||
XML::Document document(manifest);
|
||||
string type = document["cartridge"]["board"]["type"].data;
|
||||
|
||||
if(type == "BANDAI-FCG" ) return new BandaiFCG(document);
|
||||
|
||||
if(type == "KONAMI-VRC-1") return new KonamiVRC1(document);
|
||||
if(type == "KONAMI-VRC-2") return new KonamiVRC2(document);
|
||||
if(type == "KONAMI-VRC-3") return new KonamiVRC3(document);
|
||||
if(type == "KONAMI-VRC-4") return new KonamiVRC4(document);
|
||||
if(type == "KONAMI-VRC-6") return new KonamiVRC6(document);
|
||||
if(type == "KONAMI-VRC-7") return new KonamiVRC7(document);
|
||||
|
||||
if(type == "NES-AMROM" ) return new NES_AxROM(document);
|
||||
if(type == "NES-ANROM" ) return new NES_AxROM(document);
|
||||
if(type == "NES-AN1ROM" ) return new NES_AxROM(document);
|
||||
if(type == "NES-AOROM" ) return new NES_AxROM(document);
|
||||
|
||||
if(type == "NES-BNROM" ) return new NES_BNROM(document);
|
||||
|
||||
if(type == "NES-CNROM" ) return new NES_CNROM(document);
|
||||
|
||||
if(type == "NES-EKROM" ) return new NES_ExROM(document);
|
||||
if(type == "NES-ELROM" ) return new NES_ExROM(document);
|
||||
if(type == "NES-ETROM" ) return new NES_ExROM(document);
|
||||
if(type == "NES-EWROM" ) return new NES_ExROM(document);
|
||||
|
||||
if(type == "NES-FJROM" ) return new NES_FxROM(document);
|
||||
if(type == "NES-FKROM" ) return new NES_FxROM(document);
|
||||
|
||||
if(type == "NES-GNROM" ) return new NES_GxROM(document);
|
||||
if(type == "NES-MHROM" ) return new NES_GxROM(document);
|
||||
|
||||
if(type == "NES-HKROM" ) return new NES_HKROM(document);
|
||||
|
||||
if(type == "NES-NROM-128") return new NES_NROM(document);
|
||||
if(type == "NES-NROM-256") return new NES_NROM(document);
|
||||
|
||||
if(type == "NES-PEEOROM" ) return new NES_PxROM(document);
|
||||
if(type == "NES-PNROM" ) return new NES_PxROM(document);
|
||||
|
||||
if(type == "NES-SNROM" ) return new NES_SxROM(document);
|
||||
if(type == "NES-SXROM" ) return new NES_SxROM(document);
|
||||
|
||||
if(type == "NES-TLROM" ) return new NES_TxROM(document);
|
||||
|
||||
if(type == "NES-UNROM" ) return new NES_UxROM(document);
|
||||
if(type == "NES-UOROM" ) return new NES_UxROM(document);
|
||||
|
||||
if(type == "SUNSOFT-5B" ) return new Sunsoft5B(document);
|
||||
|
||||
return nullptr;
|
||||
}
|
6
bsnes/nes/cartridge/board/board.hpp → bsnes/fc/cartridge/board/board.hpp
Executable file → Normal file
6
bsnes/nes/cartridge/board/board.hpp → bsnes/fc/cartridge/board/board.hpp
Executable file → Normal file
@@ -25,16 +25,14 @@ struct Board {
|
||||
|
||||
virtual inline void scanline(unsigned y) {}
|
||||
|
||||
virtual Memory& memory();
|
||||
|
||||
virtual void power();
|
||||
virtual void reset();
|
||||
|
||||
virtual void serialize(serializer&);
|
||||
Board(BML::Node &board, const uint8_t *data, unsigned size);
|
||||
Board(XML::Document &document);
|
||||
virtual ~Board();
|
||||
|
||||
static Board* load(const string &markup, const uint8_t *data, unsigned size);
|
||||
static Board* load(const string &manifest);
|
||||
|
||||
struct Information {
|
||||
string type;
|
40
bsnes/fc/cartridge/board/konami-vrc1.cpp
Normal file
40
bsnes/fc/cartridge/board/konami-vrc1.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
struct KonamiVRC1 : Board {
|
||||
|
||||
VRC1 vrc1;
|
||||
|
||||
uint8 prg_read(unsigned addr) {
|
||||
if(addr & 0x8000) return prgrom.read(vrc1.prg_addr(addr));
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
void prg_write(unsigned addr, uint8 data) {
|
||||
if(addr & 0x8000) return vrc1.reg_write(addr, data);
|
||||
}
|
||||
|
||||
uint8 chr_read(unsigned addr) {
|
||||
if(addr & 0x2000) return ppu.ciram_read(vrc1.ciram_addr(addr));
|
||||
return Board::chr_read(vrc1.chr_addr(addr));
|
||||
}
|
||||
|
||||
void chr_write(unsigned addr, uint8 data) {
|
||||
if(addr & 0x2000) return ppu.ciram_write(vrc1.ciram_addr(addr), data);
|
||||
return Board::chr_write(vrc1.chr_addr(addr), data);
|
||||
}
|
||||
|
||||
void power() {
|
||||
vrc1.power();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
vrc1.reset();
|
||||
}
|
||||
|
||||
void serialize(serializer &s) {
|
||||
Board::serialize(s);
|
||||
vrc1.serialize(s);
|
||||
}
|
||||
|
||||
KonamiVRC1(XML::Document &document) : Board(document), vrc1(*this) {
|
||||
}
|
||||
|
||||
};
|
57
bsnes/fc/cartridge/board/konami-vrc2.cpp
Normal file
57
bsnes/fc/cartridge/board/konami-vrc2.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
struct KonamiVRC2 : Board {
|
||||
|
||||
struct Settings {
|
||||
struct Pinout {
|
||||
unsigned a0;
|
||||
unsigned a1;
|
||||
} pinout;
|
||||
} settings;
|
||||
|
||||
VRC2 vrc2;
|
||||
|
||||
uint8 prg_read(unsigned addr) {
|
||||
if(addr < 0x6000) return cpu.mdr();
|
||||
if(addr < 0x8000) return vrc2.ram_read(addr);
|
||||
return prgrom.read(vrc2.prg_addr(addr));
|
||||
}
|
||||
|
||||
void prg_write(unsigned addr, uint8 data) {
|
||||
if(addr < 0x6000) return;
|
||||
if(addr < 0x8000) return vrc2.ram_write(addr, data);
|
||||
|
||||
bool a0 = (addr & settings.pinout.a0);
|
||||
bool a1 = (addr & settings.pinout.a1);
|
||||
addr &= 0xfff0;
|
||||
addr |= (a0 << 0) | (a1 << 1);
|
||||
return vrc2.reg_write(addr, data);
|
||||
}
|
||||
|
||||
uint8 chr_read(unsigned addr) {
|
||||
if(addr & 0x2000) return ppu.ciram_read(vrc2.ciram_addr(addr));
|
||||
return Board::chr_read(vrc2.chr_addr(addr));
|
||||
}
|
||||
|
||||
void chr_write(unsigned addr, uint8 data) {
|
||||
if(addr & 0x2000) return ppu.ciram_write(vrc2.ciram_addr(addr), data);
|
||||
return Board::chr_write(vrc2.chr_addr(addr), data);
|
||||
}
|
||||
|
||||
void power() {
|
||||
vrc2.power();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
vrc2.reset();
|
||||
}
|
||||
|
||||
void serialize(serializer &s) {
|
||||
Board::serialize(s);
|
||||
vrc2.serialize(s);
|
||||
}
|
||||
|
||||
KonamiVRC2(XML::Document &document) : Board(document), vrc2(*this) {
|
||||
settings.pinout.a0 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a0"].data);
|
||||
settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
|
||||
}
|
||||
|
||||
};
|
57
bsnes/fc/cartridge/board/konami-vrc3.cpp
Normal file
57
bsnes/fc/cartridge/board/konami-vrc3.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
struct KonamiVRC3 : Board {
|
||||
|
||||
struct Settings {
|
||||
bool mirror; //0 = horizontal, 1 = vertical
|
||||
} settings;
|
||||
|
||||
VRC3 vrc3;
|
||||
|
||||
void main() {
|
||||
vrc3.main();
|
||||
}
|
||||
|
||||
uint8 prg_read(unsigned addr) {
|
||||
if((addr & 0xe000) == 0x6000) return prgram.read(addr & 0x1fff);
|
||||
if(addr & 0x8000) return prgrom.read(vrc3.prg_addr(addr));
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
void prg_write(unsigned addr, uint8 data) {
|
||||
if((addr & 0xe000) == 0x6000) return prgram.write(addr & 0x1fff, data);
|
||||
if(addr & 0x8000) return vrc3.reg_write(addr, data);
|
||||
}
|
||||
|
||||
uint8 chr_read(unsigned addr) {
|
||||
if(addr & 0x2000) {
|
||||
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.ciram_read(addr & 0x07ff);
|
||||
}
|
||||
return chrram.read(addr);
|
||||
}
|
||||
|
||||
void chr_write(unsigned addr, uint8 data) {
|
||||
if(addr & 0x2000) {
|
||||
if(settings.mirror == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
return ppu.ciram_write(addr & 0x07ff, data);
|
||||
}
|
||||
return chrram.write(addr, data);
|
||||
}
|
||||
|
||||
void power() {
|
||||
vrc3.power();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
vrc3.reset();
|
||||
}
|
||||
|
||||
void serialize(serializer &s) {
|
||||
Board::serialize(s);
|
||||
vrc3.serialize(s);
|
||||
}
|
||||
|
||||
KonamiVRC3(XML::Document &document) : Board(document), vrc3(*this) {
|
||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
};
|
6
bsnes/nes/cartridge/board/konami-vrc4.cpp → bsnes/fc/cartridge/board/konami-vrc4.cpp
Executable file → Normal file
6
bsnes/nes/cartridge/board/konami-vrc4.cpp → bsnes/fc/cartridge/board/konami-vrc4.cpp
Executable file → Normal file
@@ -53,9 +53,9 @@ void serialize(serializer &s) {
|
||||
vrc4.serialize(s);
|
||||
}
|
||||
|
||||
KonamiVRC4(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc4(*this) {
|
||||
settings.pinout.a0 = 1 << decimal(board["chip"]["pinout"]["a0"].value);
|
||||
settings.pinout.a1 = 1 << decimal(board["chip"]["pinout"]["a1"].value);
|
||||
KonamiVRC4(XML::Document &document) : Board(document), vrc4(*this) {
|
||||
settings.pinout.a0 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a0"].data);
|
||||
settings.pinout.a1 = 1 << decimal(document["cartridge"]["chip"]["pinout"]["a1"].data);
|
||||
}
|
||||
|
||||
};
|
2
bsnes/nes/cartridge/board/konami-vrc6.cpp → bsnes/fc/cartridge/board/konami-vrc6.cpp
Executable file → Normal file
2
bsnes/nes/cartridge/board/konami-vrc6.cpp → bsnes/fc/cartridge/board/konami-vrc6.cpp
Executable file → Normal file
@@ -36,7 +36,7 @@ void main() { vrc6.main(); }
|
||||
void power() { vrc6.power(); }
|
||||
void reset() { vrc6.reset(); }
|
||||
|
||||
KonamiVRC6(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc6(*this) {
|
||||
KonamiVRC6(XML::Document &document) : Board(document), vrc6(*this) {
|
||||
}
|
||||
|
||||
};
|
2
bsnes/nes/cartridge/board/konami-vrc7.cpp → bsnes/fc/cartridge/board/konami-vrc7.cpp
Executable file → Normal file
2
bsnes/nes/cartridge/board/konami-vrc7.cpp → bsnes/fc/cartridge/board/konami-vrc7.cpp
Executable file → Normal file
@@ -41,7 +41,7 @@ void serialize(serializer &s) {
|
||||
vrc7.serialize(s);
|
||||
}
|
||||
|
||||
KonamiVRC7(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc7(*this) {
|
||||
KonamiVRC7(XML::Document &document) : Board(document), vrc7(*this) {
|
||||
}
|
||||
|
||||
};
|
2
bsnes/nes/cartridge/board/nes-axrom.cpp → bsnes/fc/cartridge/board/nes-axrom.cpp
Executable file → Normal file
2
bsnes/nes/cartridge/board/nes-axrom.cpp → bsnes/fc/cartridge/board/nes-axrom.cpp
Executable file → Normal file
@@ -45,7 +45,7 @@ void serialize(serializer &s) {
|
||||
s.integer(mirror_select);
|
||||
}
|
||||
|
||||
NES_AxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||
NES_AxROM(XML::Document &document) : Board(document) {
|
||||
}
|
||||
|
||||
};
|
4
bsnes/nes/cartridge/board/nes-bnrom.cpp → bsnes/fc/cartridge/board/nes-bnrom.cpp
Executable file → Normal file
4
bsnes/nes/cartridge/board/nes-bnrom.cpp → bsnes/fc/cartridge/board/nes-bnrom.cpp
Executable file → Normal file
@@ -45,8 +45,8 @@ void serialize(serializer &s) {
|
||||
s.integer(prg_bank);
|
||||
}
|
||||
|
||||
NES_BNROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||
settings.mirror = board["mirror"].value == "vertical" ? 1 : 0;
|
||||
NES_BNROM(XML::Document &document) : Board(document) {
|
||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
};
|
4
bsnes/nes/cartridge/board/nes-cnrom.cpp → bsnes/fc/cartridge/board/nes-cnrom.cpp
Executable file → Normal file
4
bsnes/nes/cartridge/board/nes-cnrom.cpp → bsnes/fc/cartridge/board/nes-cnrom.cpp
Executable file → Normal file
@@ -47,8 +47,8 @@ void serialize(serializer &s) {
|
||||
s.integer(chr_bank);
|
||||
}
|
||||
|
||||
NES_CNROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||
settings.mirror = board["mirror"].value == "vertical" ? 1 : 0;
|
||||
NES_CNROM(XML::Document &document) : Board(document) {
|
||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
};
|
2
bsnes/nes/cartridge/board/nes-exrom.cpp → bsnes/fc/cartridge/board/nes-exrom.cpp
Executable file → Normal file
2
bsnes/nes/cartridge/board/nes-exrom.cpp → bsnes/fc/cartridge/board/nes-exrom.cpp
Executable file → Normal file
@@ -46,7 +46,7 @@ void serialize(serializer &s) {
|
||||
mmc5.serialize(s);
|
||||
}
|
||||
|
||||
NES_ExROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc5(*this) {
|
||||
NES_ExROM(XML::Document &document) : Board(document), mmc5(*this) {
|
||||
revision = Revision::ELROM;
|
||||
}
|
||||
|
2
bsnes/nes/cartridge/board/nes-fxrom.cpp → bsnes/fc/cartridge/board/nes-fxrom.cpp
Executable file → Normal file
2
bsnes/nes/cartridge/board/nes-fxrom.cpp → bsnes/fc/cartridge/board/nes-fxrom.cpp
Executable file → Normal file
@@ -84,7 +84,7 @@ void serialize(serializer &s) {
|
||||
s.array(latch);
|
||||
}
|
||||
|
||||
NES_FxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||
NES_FxROM(XML::Document &document) : Board(document) {
|
||||
revision = Revision::FKROM;
|
||||
}
|
||||
|
4
bsnes/nes/cartridge/board/nes-gxrom.cpp → bsnes/fc/cartridge/board/nes-gxrom.cpp
Executable file → Normal file
4
bsnes/nes/cartridge/board/nes-gxrom.cpp → bsnes/fc/cartridge/board/nes-gxrom.cpp
Executable file → Normal file
@@ -54,8 +54,8 @@ void serialize(serializer &s) {
|
||||
s.integer(chr_bank);
|
||||
}
|
||||
|
||||
NES_GxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||
settings.mirror = board["mirror"].value == "vertical" ? 1 : 0;
|
||||
NES_GxROM(XML::Document &document) : Board(document) {
|
||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
};
|
48
bsnes/fc/cartridge/board/nes-hkrom.cpp
Normal file
48
bsnes/fc/cartridge/board/nes-hkrom.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
struct NES_HKROM : Board {
|
||||
|
||||
MMC6 mmc6;
|
||||
|
||||
void main() {
|
||||
mmc6.main();
|
||||
}
|
||||
|
||||
uint8 prg_read(unsigned addr) {
|
||||
if((addr & 0xf000) == 0x7000) return mmc6.ram_read(addr);
|
||||
if(addr & 0x8000) return prgrom.read(mmc6.prg_addr(addr));
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
void prg_write(unsigned addr, uint8 data) {
|
||||
if((addr & 0xf000) == 0x7000) return mmc6.ram_write(addr, data);
|
||||
if(addr & 0x8000) return mmc6.reg_write(addr, data);
|
||||
}
|
||||
|
||||
uint8 chr_read(unsigned addr) {
|
||||
mmc6.irq_test(addr);
|
||||
if(addr & 0x2000) return ppu.ciram_read(mmc6.ciram_addr(addr));
|
||||
return Board::chr_read(mmc6.chr_addr(addr));
|
||||
}
|
||||
|
||||
void chr_write(unsigned addr, uint8 data) {
|
||||
mmc6.irq_test(addr);
|
||||
if(addr & 0x2000) return ppu.ciram_write(mmc6.ciram_addr(addr), data);
|
||||
return Board::chr_write(mmc6.chr_addr(addr), data);
|
||||
}
|
||||
|
||||
void power() {
|
||||
mmc6.power();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
mmc6.reset();
|
||||
}
|
||||
|
||||
void serialize(serializer &s) {
|
||||
Board::serialize(s);
|
||||
mmc6.serialize(s);
|
||||
}
|
||||
|
||||
NES_HKROM(XML::Document &document) : Board(document), mmc6(*this) {
|
||||
}
|
||||
|
||||
};
|
4
bsnes/nes/cartridge/board/nes-nrom.cpp → bsnes/fc/cartridge/board/nes-nrom.cpp
Executable file → Normal file
4
bsnes/nes/cartridge/board/nes-nrom.cpp → bsnes/fc/cartridge/board/nes-nrom.cpp
Executable file → Normal file
@@ -36,8 +36,8 @@ void serialize(serializer &s) {
|
||||
Board::serialize(s);
|
||||
}
|
||||
|
||||
NES_NROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||
settings.mirror = board["mirror"].value == "vertical" ? 1 : 0;
|
||||
NES_NROM(XML::Document &document) : Board(document) {
|
||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
};
|
2
bsnes/nes/cartridge/board/nes-pxrom.cpp → bsnes/fc/cartridge/board/nes-pxrom.cpp
Executable file → Normal file
2
bsnes/nes/cartridge/board/nes-pxrom.cpp → bsnes/fc/cartridge/board/nes-pxrom.cpp
Executable file → Normal file
@@ -90,7 +90,7 @@ void serialize(serializer &s) {
|
||||
s.array(latch);
|
||||
}
|
||||
|
||||
NES_PxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||
NES_PxROM(XML::Document &document) : Board(document) {
|
||||
revision = Revision::PNROM;
|
||||
}
|
||||
|
2
bsnes/nes/cartridge/board/nes-sxrom.cpp → bsnes/fc/cartridge/board/nes-sxrom.cpp
Executable file → Normal file
2
bsnes/nes/cartridge/board/nes-sxrom.cpp → bsnes/fc/cartridge/board/nes-sxrom.cpp
Executable file → Normal file
@@ -94,7 +94,7 @@ void serialize(serializer &s) {
|
||||
mmc1.serialize(s);
|
||||
}
|
||||
|
||||
NES_SxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc1(*this) {
|
||||
NES_SxROM(XML::Document &document) : Board(document), mmc1(*this) {
|
||||
revision = Revision::SXROM;
|
||||
}
|
||||
|
67
bsnes/fc/cartridge/board/nes-txrom.cpp
Normal file
67
bsnes/fc/cartridge/board/nes-txrom.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
struct NES_TxROM : Board {
|
||||
|
||||
enum class Revision : unsigned {
|
||||
TBROM,
|
||||
TEROM,
|
||||
TFROM,
|
||||
TGROM,
|
||||
TKROM,
|
||||
TKSROM,
|
||||
TLROM,
|
||||
TL1ROM,
|
||||
TL2ROM,
|
||||
TLSROM,
|
||||
TNROM,
|
||||
TQROM,
|
||||
TR1ROM,
|
||||
TSROM,
|
||||
TVROM,
|
||||
} revision;
|
||||
|
||||
MMC3 mmc3;
|
||||
|
||||
void main() {
|
||||
mmc3.main();
|
||||
}
|
||||
|
||||
uint8 prg_read(unsigned addr) {
|
||||
if((addr & 0xe000) == 0x6000) return mmc3.ram_read(addr);
|
||||
if(addr & 0x8000) return prgrom.read(mmc3.prg_addr(addr));
|
||||
return cpu.mdr();
|
||||
}
|
||||
|
||||
void prg_write(unsigned addr, uint8 data) {
|
||||
if((addr & 0xe000) == 0x6000) return mmc3.ram_write(addr, data);
|
||||
if(addr & 0x8000) return mmc3.reg_write(addr, data);
|
||||
}
|
||||
|
||||
uint8 chr_read(unsigned addr) {
|
||||
mmc3.irq_test(addr);
|
||||
if(addr & 0x2000) return ppu.ciram_read(mmc3.ciram_addr(addr));
|
||||
return Board::chr_read(mmc3.chr_addr(addr));
|
||||
}
|
||||
|
||||
void chr_write(unsigned addr, uint8 data) {
|
||||
mmc3.irq_test(addr);
|
||||
if(addr & 0x2000) return ppu.ciram_write(mmc3.ciram_addr(addr), data);
|
||||
return Board::chr_write(mmc3.chr_addr(addr), data);
|
||||
}
|
||||
|
||||
void power() {
|
||||
mmc3.power();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
mmc3.reset();
|
||||
}
|
||||
|
||||
void serialize(serializer &s) {
|
||||
Board::serialize(s);
|
||||
mmc3.serialize(s);
|
||||
}
|
||||
|
||||
NES_TxROM(XML::Document &document) : Board(document), mmc3(*this) {
|
||||
revision = Revision::TLROM;
|
||||
}
|
||||
|
||||
};
|
4
bsnes/nes/cartridge/board/nes-uxrom.cpp → bsnes/fc/cartridge/board/nes-uxrom.cpp
Executable file → Normal file
4
bsnes/nes/cartridge/board/nes-uxrom.cpp → bsnes/fc/cartridge/board/nes-uxrom.cpp
Executable file → Normal file
@@ -48,8 +48,8 @@ void serialize(serializer &s) {
|
||||
s.integer(prg_bank);
|
||||
}
|
||||
|
||||
NES_UxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||
settings.mirror = board["mirror"].value == "vertical" ? 1 : 0;
|
||||
NES_UxROM(XML::Document &document) : Board(document) {
|
||||
settings.mirror = document["cartridge"]["mirror"]["mode"].data == "vertical" ? 1 : 0;
|
||||
}
|
||||
|
||||
};
|
2
bsnes/nes/cartridge/board/sunsoft-5b.cpp → bsnes/fc/cartridge/board/sunsoft-5b.cpp
Executable file → Normal file
2
bsnes/nes/cartridge/board/sunsoft-5b.cpp → bsnes/fc/cartridge/board/sunsoft-5b.cpp
Executable file → Normal file
@@ -220,7 +220,7 @@ void serialize(serializer &s) {
|
||||
pulse[2].serialize(s);
|
||||
}
|
||||
|
||||
Sunsoft5B(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
|
||||
Sunsoft5B(XML::Document &document) : Board(document) {
|
||||
}
|
||||
|
||||
};
|
41
bsnes/nes/cartridge/cartridge.cpp → bsnes/fc/cartridge/cartridge.cpp
Executable file → Normal file
41
bsnes/nes/cartridge/cartridge.cpp → bsnes/fc/cartridge/cartridge.cpp
Executable file → Normal file
@@ -1,8 +1,7 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
#include "ines.cpp"
|
||||
#include "chip/chip.cpp"
|
||||
#include "board/board.cpp"
|
||||
Cartridge cartridge;
|
||||
@@ -15,18 +14,23 @@ void Cartridge::main() {
|
||||
board->main();
|
||||
}
|
||||
|
||||
void Cartridge::load(const string &markup, const uint8_t *data, unsigned size) {
|
||||
if((size & 0xff) == 0) {
|
||||
sha256 = nall::sha256(data, size);
|
||||
board = Board::load(markup, data, size);
|
||||
} else {
|
||||
//unsigned crc32 = crc32_calculate(data + 16, size - 16);
|
||||
//print(hex<8>(crc32), "\n");
|
||||
sha256 = nall::sha256(data + 16, size - 16);
|
||||
board = Board::load(markup != "" ? markup : iNES(data, size), data + 16, size - 16);
|
||||
}
|
||||
void Cartridge::load(const string &manifest) {
|
||||
information.markup = manifest;
|
||||
|
||||
Board::load(manifest); //this call will set Cartridge::board if successful
|
||||
if(board == nullptr) return;
|
||||
|
||||
sha256_ctx sha;
|
||||
uint8 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;
|
||||
}
|
||||
@@ -34,14 +38,7 @@ void Cartridge::load(const string &markup, const uint8_t *data, unsigned size) {
|
||||
void Cartridge::unload() {
|
||||
if(loaded == false) return;
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
unsigned Cartridge::ram_size() {
|
||||
return board->memory().size;
|
||||
}
|
||||
|
||||
uint8* Cartridge::ram_data() {
|
||||
return board->memory().data;
|
||||
memory.reset();
|
||||
}
|
||||
|
||||
void Cartridge::power() {
|
||||
@@ -78,7 +75,7 @@ void Cartridge::scanline(unsigned y) {
|
||||
}
|
||||
|
||||
void Cartridge::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
return board->serialize(s);
|
||||
}
|
||||
|
17
bsnes/nes/cartridge/cartridge.hpp → bsnes/fc/cartridge/cartridge.hpp
Executable file → Normal file
17
bsnes/nes/cartridge/cartridge.hpp → bsnes/fc/cartridge/cartridge.hpp
Executable file → Normal file
@@ -1,22 +1,29 @@
|
||||
#include "chip/chip.hpp"
|
||||
#include "board/board.hpp"
|
||||
|
||||
struct Cartridge : Processor, property<Cartridge> {
|
||||
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 &manifest);
|
||||
void unload();
|
||||
|
||||
unsigned ram_size();
|
||||
uint8* ram_data();
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
readonly<bool> loaded;
|
||||
readonly<string> sha256;
|
||||
|
||||
struct Information {
|
||||
string markup;
|
||||
} information;
|
||||
|
||||
struct Memory {
|
||||
unsigned id;
|
||||
string name;
|
||||
};
|
||||
vector<Memory> memory;
|
||||
|
||||
void serialize(serializer&);
|
||||
Cartridge();
|
||||
|
4
bsnes/nes/cartridge/chip/chip.cpp → bsnes/fc/cartridge/chip/chip.cpp
Executable file → Normal file
4
bsnes/nes/cartridge/chip/chip.cpp → bsnes/fc/cartridge/chip/chip.cpp
Executable file → Normal file
@@ -1,6 +1,10 @@
|
||||
#include "mmc1.cpp"
|
||||
#include "mmc3.cpp"
|
||||
#include "mmc5.cpp"
|
||||
#include "mmc6.cpp"
|
||||
#include "vrc1.cpp"
|
||||
#include "vrc2.cpp"
|
||||
#include "vrc3.cpp"
|
||||
#include "vrc4.cpp"
|
||||
#include "vrc6.cpp"
|
||||
#include "vrc7.cpp"
|
0
bsnes/nes/cartridge/chip/chip.hpp → bsnes/fc/cartridge/chip/chip.hpp
Executable file → Normal file
0
bsnes/nes/cartridge/chip/chip.hpp → bsnes/fc/cartridge/chip/chip.hpp
Executable file → Normal file
0
bsnes/nes/cartridge/chip/mmc1.cpp → bsnes/fc/cartridge/chip/mmc1.cpp
Executable file → Normal file
0
bsnes/nes/cartridge/chip/mmc1.cpp → bsnes/fc/cartridge/chip/mmc1.cpp
Executable file → Normal file
49
bsnes/nes/cartridge/chip/mmc3.cpp → bsnes/fc/cartridge/chip/mmc3.cpp
Executable file → Normal file
49
bsnes/nes/cartridge/chip/mmc3.cpp → bsnes/fc/cartridge/chip/mmc3.cpp
Executable file → Normal file
@@ -89,6 +89,55 @@ void ram_write(unsigned addr, uint8 data) {
|
||||
if(ram_enable && !ram_write_protect) board.prgram.data[addr & 0x1fff] = data;
|
||||
}
|
||||
|
||||
void reg_write(unsigned addr, uint8 data) {
|
||||
switch(addr & 0xe001) {
|
||||
case 0x8000:
|
||||
chr_mode = data & 0x80;
|
||||
prg_mode = data & 0x40;
|
||||
bank_select = data & 0x07;
|
||||
break;
|
||||
|
||||
case 0x8001:
|
||||
switch(bank_select) {
|
||||
case 0: chr_bank[0] = data & ~1; break;
|
||||
case 1: chr_bank[1] = data & ~1; break;
|
||||
case 2: chr_bank[2] = data; break;
|
||||
case 3: chr_bank[3] = data; break;
|
||||
case 4: chr_bank[4] = data; break;
|
||||
case 5: chr_bank[5] = data; break;
|
||||
case 6: prg_bank[0] = data & 0x3f; break;
|
||||
case 7: prg_bank[1] = data & 0x3f; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xa000:
|
||||
mirror = data & 0x01;
|
||||
break;
|
||||
|
||||
case 0xa001:
|
||||
ram_enable = data & 0x80;
|
||||
ram_write_protect = data & 0x40;
|
||||
break;
|
||||
|
||||
case 0xc000:
|
||||
irq_latch = data;
|
||||
break;
|
||||
|
||||
case 0xc001:
|
||||
irq_counter = 0;
|
||||
break;
|
||||
|
||||
case 0xe000:
|
||||
irq_enable = false;
|
||||
irq_line = 0;
|
||||
break;
|
||||
|
||||
case 0xe001:
|
||||
irq_enable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void power() {
|
||||
}
|
||||
|
97
bsnes/nes/cartridge/chip/mmc5.cpp → bsnes/fc/cartridge/chip/mmc5.cpp
Executable file → Normal file
97
bsnes/nes/cartridge/chip/mmc5.cpp → bsnes/fc/cartridge/chip/mmc5.cpp
Executable file → Normal file
@@ -17,7 +17,7 @@ uint2 prgram_write_protect[2]; //$5102,$5103
|
||||
uint2 exram_mode; //$5104
|
||||
uint2 nametable_mode[4]; //$5105
|
||||
uint8 fillmode_tile; //$5106
|
||||
uint2 fillmode_color; //$5107
|
||||
uint8 fillmode_color; //$5107
|
||||
|
||||
bool ram_select; //$5113
|
||||
uint2 ram_bank; //$5113
|
||||
@@ -54,6 +54,10 @@ bool sprite_8x16;
|
||||
uint8 exbank;
|
||||
uint8 exattr;
|
||||
|
||||
bool vs_fetch;
|
||||
uint8 vs_vpos;
|
||||
uint8 vs_hpos;
|
||||
|
||||
void main() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
@@ -188,6 +192,8 @@ void prg_write(unsigned addr, uint8 data) {
|
||||
|
||||
case 0x5107:
|
||||
fillmode_color = data & 3;
|
||||
fillmode_color |= fillmode_color << 2;
|
||||
fillmode_color |= fillmode_color << 4;
|
||||
break;
|
||||
|
||||
case 0x5113:
|
||||
@@ -251,69 +257,55 @@ void prg_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
|
||||
unsigned chr_sprite_addr(unsigned addr) {
|
||||
unsigned bank;
|
||||
|
||||
if(chr_mode == 0) {
|
||||
bank = chr_sprite_bank[7];
|
||||
auto bank = chr_sprite_bank[7];
|
||||
return (bank * 0x2000) + (addr & 0x1fff);
|
||||
}
|
||||
|
||||
if(chr_mode == 1) {
|
||||
bank = (addr < 0x1000) ? chr_sprite_bank[3]
|
||||
:/*addr < 0x2000 */ chr_sprite_bank[7];
|
||||
auto bank = chr_sprite_bank[(addr / 0x1000) * 4 + 3];
|
||||
return (bank * 0x1000) + (addr & 0x0fff);
|
||||
}
|
||||
|
||||
if(chr_mode == 2) {
|
||||
bank = (addr < 0x0800) ? chr_sprite_bank[1]
|
||||
: (addr < 0x1000) ? chr_sprite_bank[3]
|
||||
: (addr < 0x1800) ? chr_sprite_bank[5]
|
||||
:/*addr < 0x2000 */ chr_sprite_bank[7];
|
||||
auto bank = chr_sprite_bank[(addr / 0x0800) * 2 + 1];
|
||||
return (bank * 0x0800) + (addr & 0x07ff);
|
||||
}
|
||||
|
||||
if(chr_mode == 3) {
|
||||
bank = (addr < 0x0400) ? chr_sprite_bank[0]
|
||||
: (addr < 0x0800) ? chr_sprite_bank[1]
|
||||
: (addr < 0x0c00) ? chr_sprite_bank[2]
|
||||
: (addr < 0x1000) ? chr_sprite_bank[3]
|
||||
: (addr < 0x1400) ? chr_sprite_bank[4]
|
||||
: (addr < 0x1800) ? chr_sprite_bank[5]
|
||||
: (addr < 0x1c00) ? chr_sprite_bank[6]
|
||||
:/*addr < 0x2000 */ chr_sprite_bank[7];
|
||||
auto bank = chr_sprite_bank[(addr / 0x0400)];
|
||||
return (bank * 0x0400) + (addr & 0x03ff);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned chr_bg_addr(unsigned addr) {
|
||||
addr &= 0x0fff;
|
||||
unsigned bank;
|
||||
|
||||
if(chr_mode == 0) {
|
||||
bank = chr_bg_bank[3];
|
||||
auto bank = chr_bg_bank[3];
|
||||
return (bank * 0x2000) + (addr & 0x0fff);
|
||||
}
|
||||
|
||||
if(chr_mode == 1) {
|
||||
bank = chr_bg_bank[3];
|
||||
auto bank = chr_bg_bank[3];
|
||||
return (bank * 0x1000) + (addr & 0x0fff);
|
||||
}
|
||||
|
||||
if(chr_mode == 2) {
|
||||
bank = (addr < 0x0800) ? chr_bg_bank[1]
|
||||
:/*addr < 0x1000 */ chr_bg_bank[3];
|
||||
auto bank = chr_bg_bank[(addr / 0x0800) * 2 + 1];
|
||||
return (bank * 0x0800) + (addr & 0x07ff);
|
||||
}
|
||||
|
||||
if(chr_mode == 3) {
|
||||
bank = (addr < 0x0400) ? chr_bg_bank[0]
|
||||
: (addr < 0x0800) ? chr_bg_bank[1]
|
||||
: (addr < 0x0c00) ? chr_bg_bank[2]
|
||||
:/*addr < 0x1000 */ chr_bg_bank[3];
|
||||
auto bank = chr_bg_bank[(addr / 0x0400)];
|
||||
return (bank * 0x0400) + (addr & 0x03ff);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned chr_vs_addr(unsigned addr) {
|
||||
return (vs_bank * 0x1000) + (addr & 0x0ff8) + (vs_vpos & 7);
|
||||
}
|
||||
|
||||
void blank() {
|
||||
in_frame = false;
|
||||
}
|
||||
@@ -334,11 +326,14 @@ void scanline() {
|
||||
}
|
||||
|
||||
uint8 ciram_read(unsigned addr) {
|
||||
if(vs_fetch && (hcounter & 2) == 0) return exram[vs_vpos / 8 * 32 + vs_hpos / 8];
|
||||
if(vs_fetch && (hcounter & 2) != 0) return exram[vs_vpos / 32 * 8 + vs_hpos / 32 + 0x03c0];
|
||||
|
||||
switch(nametable_mode[(addr >> 10) & 3]) {
|
||||
case 0: return ppu.ciram_read(0x0000 | (addr & 0x03ff));
|
||||
case 1: return ppu.ciram_read(0x0400 | (addr & 0x03ff));
|
||||
case 2: return exram_mode < 2 ? exram[addr & 0x03ff] : 0x00;
|
||||
case 3: return (hcounter & 2) == 0 ? fillmode_tile : (uint8)fillmode_color;
|
||||
case 3: return (hcounter & 2) == 0 ? fillmode_tile : fillmode_color;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,14 +350,21 @@ uint8 chr_read(unsigned addr) {
|
||||
&& (chr_access[3] & 0x2000)) scanline();
|
||||
|
||||
if(in_frame == false) {
|
||||
vs_fetch = false;
|
||||
if(addr & 0x2000) return ciram_read(addr);
|
||||
return 0x00;
|
||||
return board.chrrom.read(chr_active ? chr_bg_addr(addr) : chr_sprite_addr(addr));
|
||||
}
|
||||
|
||||
unsigned mode = nametable_mode[(addr >> 10) & 3];
|
||||
bool bg_fetch = (hcounter < 256 || hcounter >= 320);
|
||||
uint8 result = 0x00;
|
||||
|
||||
if((hcounter & 7) == 0) {
|
||||
vs_hpos = hcounter >= 320 ? hcounter - 320 : hcounter + 16;
|
||||
vs_vpos = vcounter + vs_scroll;
|
||||
vs_fetch = vs_enable && bg_fetch && exram_mode < 2
|
||||
&& (vs_side ? vs_hpos / 8 >= vs_tile : vs_hpos / 8 < vs_tile);
|
||||
if(vs_vpos >= 240) vs_vpos -= 240;
|
||||
|
||||
result = ciram_read(addr);
|
||||
|
||||
exbank = (chr_bank_hi << 6) | (exram[addr & 0x03ff] & 0x3f);
|
||||
@@ -371,21 +373,12 @@ uint8 chr_read(unsigned addr) {
|
||||
exattr |= exattr << 4;
|
||||
} else if((hcounter & 7) == 2) {
|
||||
result = ciram_read(addr);
|
||||
|
||||
if((hcounter < 256 || hcounter >= 320) && exram_mode == 1) {
|
||||
result = exattr;
|
||||
}
|
||||
if(bg_fetch && exram_mode == 1) result = exattr;
|
||||
} else {
|
||||
if(sprite_8x16 == false) {
|
||||
result = board.chrrom.read(chr_active ? chr_bg_addr(addr) : chr_sprite_addr(addr));
|
||||
}
|
||||
else if(hcounter < 256) result = board.chrrom.read(chr_bg_addr(addr));
|
||||
else if(hcounter < 320) result = board.chrrom.read(chr_sprite_addr(addr));
|
||||
else /* hcounter < 340*/result = board.chrrom.read(chr_bg_addr(addr));
|
||||
|
||||
if((hcounter < 256 || hcounter >= 320) && exram_mode == 1) {
|
||||
result = board.chrrom.read(exbank * 0x1000 + addr);
|
||||
}
|
||||
if(vs_fetch) result = board.chrrom.read(chr_vs_addr(addr));
|
||||
else if(sprite_8x16 ? bg_fetch : chr_active) result = board.chrrom.read(chr_bg_addr(addr));
|
||||
else result = board.chrrom.read(chr_sprite_addr(addr));
|
||||
if(bg_fetch && exram_mode == 1) result = board.chrrom.read(exbank * 0x1000 + (addr & 0x0fff));
|
||||
}
|
||||
|
||||
hcounter += 2;
|
||||
@@ -394,9 +387,11 @@ uint8 chr_read(unsigned addr) {
|
||||
|
||||
void chr_write(unsigned addr, uint8 data) {
|
||||
if(addr & 0x2000) {
|
||||
unsigned mode = nametable_mode[(addr >> 10) & 3];
|
||||
if(mode == 0) ppu.ciram_write(0x0000 | (addr & 0x03ff), data);
|
||||
if(mode == 1) ppu.ciram_write(0x0400 | (addr & 0x03ff), data);
|
||||
switch(nametable_mode[(addr >> 10) & 3]) {
|
||||
case 0: return ppu.ciram_write(0x0000 | (addr & 0x03ff), data);
|
||||
case 1: return ppu.ciram_write(0x0400 | (addr & 0x03ff), data);
|
||||
case 2: exram[addr & 0x03ff] = data; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -444,6 +439,10 @@ void reset() {
|
||||
|
||||
exbank = 0;
|
||||
exattr = 0;
|
||||
|
||||
vs_fetch = 0;
|
||||
vs_vpos = 0;
|
||||
vs_hpos = 0;
|
||||
}
|
||||
|
||||
void serialize(serializer &s) {
|
||||
@@ -485,6 +484,10 @@ void serialize(serializer &s) {
|
||||
|
||||
s.integer(exbank);
|
||||
s.integer(exattr);
|
||||
|
||||
s.integer(vs_fetch);
|
||||
s.integer(vs_vpos);
|
||||
s.integer(vs_hpos);
|
||||
}
|
||||
|
||||
MMC5(Board &board) : Chip(board) {
|
200
bsnes/fc/cartridge/chip/mmc6.cpp
Normal file
200
bsnes/fc/cartridge/chip/mmc6.cpp
Normal file
@@ -0,0 +1,200 @@
|
||||
struct MMC6 : Chip {
|
||||
|
||||
bool chr_mode;
|
||||
bool prg_mode;
|
||||
bool ram_enable;
|
||||
uint3 bank_select;
|
||||
uint8 prg_bank[2];
|
||||
uint8 chr_bank[6];
|
||||
bool mirror;
|
||||
bool ram_readable[2];
|
||||
bool ram_writable[2];
|
||||
uint8 irq_latch;
|
||||
uint8 irq_counter;
|
||||
bool irq_enable;
|
||||
unsigned irq_delay;
|
||||
bool irq_line;
|
||||
|
||||
uint16 chr_abus;
|
||||
|
||||
void main() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
if(irq_delay) irq_delay--;
|
||||
cpu.set_irq_line(irq_line);
|
||||
tick();
|
||||
}
|
||||
}
|
||||
|
||||
void irq_test(unsigned addr) {
|
||||
if(!(chr_abus & 0x1000) && (addr & 0x1000)) {
|
||||
if(irq_delay == 0) {
|
||||
if(irq_counter == 0) {
|
||||
irq_counter = irq_latch;
|
||||
} else if(--irq_counter == 0) {
|
||||
if(irq_enable) irq_line = 1;
|
||||
}
|
||||
}
|
||||
irq_delay = 6;
|
||||
}
|
||||
chr_abus = addr;
|
||||
}
|
||||
|
||||
unsigned prg_addr(unsigned addr) const {
|
||||
switch((addr >> 13) & 3) {
|
||||
case 0:
|
||||
if(prg_mode == 1) return (0x3e << 13) | (addr & 0x1fff);
|
||||
return (prg_bank[0] << 13) | (addr & 0x1fff);
|
||||
case 1:
|
||||
return (prg_bank[1] << 13) | (addr & 0x1fff);
|
||||
case 2:
|
||||
if(prg_mode == 0) return (0x3e << 13) | (addr & 0x1fff);
|
||||
return (prg_bank[0] << 13) | (addr & 0x1fff);
|
||||
case 3:
|
||||
return (0x3f << 13) | (addr & 0x1fff);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned chr_addr(unsigned addr) const {
|
||||
if(chr_mode == 0) {
|
||||
if(addr <= 0x07ff) return (chr_bank[0] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x0fff) return (chr_bank[1] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x13ff) return (chr_bank[2] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x17ff) return (chr_bank[3] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x1bff) return (chr_bank[4] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x1fff) return (chr_bank[5] << 10) | (addr & 0x03ff);
|
||||
} else {
|
||||
if(addr <= 0x03ff) return (chr_bank[2] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x07ff) return (chr_bank[3] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x0bff) return (chr_bank[4] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x0fff) return (chr_bank[5] << 10) | (addr & 0x03ff);
|
||||
if(addr <= 0x17ff) return (chr_bank[0] << 10) | (addr & 0x07ff);
|
||||
if(addr <= 0x1fff) return (chr_bank[1] << 10) | (addr & 0x07ff);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned ciram_addr(unsigned addr) const {
|
||||
if(mirror == 0) return ((addr & 0x0400) >> 0) | (addr & 0x03ff);
|
||||
if(mirror == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff);
|
||||
}
|
||||
|
||||
uint8 ram_read(unsigned addr) {
|
||||
if(ram_enable == false) return cpu.mdr();
|
||||
if(ram_readable[0] == false && ram_readable[1] == false) return cpu.mdr();
|
||||
bool region = addr & 0x0200;
|
||||
if(ram_readable[region] == false) return 0x00;
|
||||
return board.prgram.read((region * 0x0200) + (addr & 0x01ff));
|
||||
}
|
||||
|
||||
void ram_write(unsigned addr, uint8 data) {
|
||||
if(ram_enable == false) return;
|
||||
bool region = addr & 0x0200;
|
||||
if(ram_writable[region] == false) return;
|
||||
return board.prgram.write((region * 0x0200) + (addr & 0x01ff), data);
|
||||
}
|
||||
|
||||
void reg_write(unsigned addr, uint8 data) {
|
||||
switch(addr & 0xe001) {
|
||||
case 0x8000:
|
||||
chr_mode = data & 0x80;
|
||||
prg_mode = data & 0x40;
|
||||
ram_enable = data & 0x20;
|
||||
bank_select = data & 0x07;
|
||||
if(ram_enable == false) {
|
||||
for(auto &n : ram_readable) n = false;
|
||||
for(auto &n : ram_writable) n = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x8001:
|
||||
switch(bank_select) {
|
||||
case 0: chr_bank[0] = data & ~1; break;
|
||||
case 1: chr_bank[1] = data & ~1; break;
|
||||
case 2: chr_bank[2] = data; break;
|
||||
case 3: chr_bank[3] = data; break;
|
||||
case 4: chr_bank[4] = data; break;
|
||||
case 5: chr_bank[5] = data; break;
|
||||
case 6: prg_bank[0] = data & 0x3f; break;
|
||||
case 7: prg_bank[1] = data & 0x3f; break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xa000:
|
||||
mirror = data & 0x01;
|
||||
break;
|
||||
|
||||
case 0xa001:
|
||||
if(ram_enable == false) break;
|
||||
ram_readable[1] = data & 0x80;
|
||||
ram_writable[1] = data & 0x40;
|
||||
ram_readable[0] = data & 0x20;
|
||||
ram_writable[0] = data & 0x10;
|
||||
break;
|
||||
|
||||
case 0xc000:
|
||||
irq_latch = data;
|
||||
break;
|
||||
|
||||
case 0xc001:
|
||||
irq_counter = 0;
|
||||
break;
|
||||
|
||||
case 0xe000:
|
||||
irq_enable = false;
|
||||
irq_line = 0;
|
||||
break;
|
||||
|
||||
case 0xe001:
|
||||
irq_enable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void power() {
|
||||
}
|
||||
|
||||
void reset() {
|
||||
chr_mode = 0;
|
||||
prg_mode = 0;
|
||||
ram_enable = 0;
|
||||
bank_select = 0;
|
||||
for(auto &n : prg_bank) n = 0;
|
||||
for(auto &n : chr_bank) n = 0;
|
||||
mirror = 0;
|
||||
for(auto &n : ram_readable) n = 0;
|
||||
for(auto &n : ram_writable) n = 0;
|
||||
irq_latch = 0;
|
||||
irq_counter = 0;
|
||||
irq_enable = 0;
|
||||
irq_delay = 0;
|
||||
irq_line = 0;
|
||||
|
||||
chr_abus = 0;
|
||||
}
|
||||
|
||||
void serialize(serializer &s) {
|
||||
s.integer(chr_mode);
|
||||
s.integer(prg_mode);
|
||||
s.integer(ram_enable);
|
||||
s.integer(bank_select);
|
||||
for(auto &n : prg_bank) s.integer(n);
|
||||
for(auto &n : chr_bank) s.integer(n);
|
||||
s.integer(mirror);
|
||||
for(auto &n : ram_readable) s.integer(n);
|
||||
for(auto &n : ram_writable) s.integer(n);
|
||||
s.integer(irq_latch);
|
||||
s.integer(irq_counter);
|
||||
s.integer(irq_enable);
|
||||
s.integer(irq_delay);
|
||||
s.integer(irq_line);
|
||||
|
||||
s.integer(chr_abus);
|
||||
}
|
||||
|
||||
MMC6(Board &board) : Chip(board) {
|
||||
}
|
||||
|
||||
};
|
80
bsnes/fc/cartridge/chip/vrc1.cpp
Normal file
80
bsnes/fc/cartridge/chip/vrc1.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
struct VRC1 : Chip {
|
||||
|
||||
uint4 prg_bank[3];
|
||||
uint4 chr_banklo[2];
|
||||
bool chr_bankhi[2];
|
||||
bool mirror;
|
||||
|
||||
unsigned prg_addr(unsigned addr) const {
|
||||
unsigned bank = 0x0f;
|
||||
if((addr & 0xe000) == 0x8000) bank = prg_bank[0];
|
||||
if((addr & 0xe000) == 0xa000) bank = prg_bank[1];
|
||||
if((addr & 0xe000) == 0xc000) bank = prg_bank[2];
|
||||
return (bank * 0x2000) + (addr & 0x1fff);
|
||||
}
|
||||
|
||||
unsigned chr_addr(unsigned addr) const {
|
||||
unsigned bank = chr_banklo[(bool)(addr & 0x1000)];
|
||||
bank |= chr_bankhi[(bool)(addr & 0x1000)] << 4;
|
||||
return (bank * 0x1000) + (addr & 0x0fff);
|
||||
}
|
||||
|
||||
unsigned ciram_addr(unsigned addr) const {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
void reg_write(unsigned addr, uint8 data) {
|
||||
switch(addr & 0xf000) {
|
||||
case 0x8000:
|
||||
prg_bank[0] = data & 0x0f;
|
||||
break;
|
||||
|
||||
case 0x9000:
|
||||
chr_bankhi[1] = data & 0x04;
|
||||
chr_bankhi[0] = data & 0x02;
|
||||
mirror = data & 0x01;
|
||||
break;
|
||||
|
||||
case 0xa000:
|
||||
prg_bank[1] = data & 0x0f;
|
||||
break;
|
||||
|
||||
case 0xc000:
|
||||
prg_bank[2] = data & 0x0f;
|
||||
break;
|
||||
|
||||
case 0xe000:
|
||||
chr_banklo[0] = data & 0x0f;
|
||||
break;
|
||||
|
||||
case 0xf000:
|
||||
chr_banklo[1] = data & 0x0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void power() {
|
||||
}
|
||||
|
||||
void reset() {
|
||||
for(auto &n : prg_bank) n = 0;
|
||||
for(auto &n : chr_banklo) n = 0;
|
||||
for(auto &n : chr_bankhi) n = 0;
|
||||
mirror = 0;
|
||||
}
|
||||
|
||||
void serialize(serializer &s) {
|
||||
for(auto &n : prg_bank) s.integer(n);
|
||||
for(auto &n : chr_banklo) s.integer(n);
|
||||
for(auto &n : chr_bankhi) s.integer(n);
|
||||
s.integer(mirror);
|
||||
}
|
||||
|
||||
VRC1(Board &board) : Chip(board) {
|
||||
}
|
||||
|
||||
};
|
110
bsnes/fc/cartridge/chip/vrc2.cpp
Normal file
110
bsnes/fc/cartridge/chip/vrc2.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
struct VRC2 : Chip {
|
||||
|
||||
uint5 prg_bank[2];
|
||||
uint8 chr_bank[8];
|
||||
uint2 mirror;
|
||||
bool latch;
|
||||
|
||||
unsigned prg_addr(unsigned addr) const {
|
||||
unsigned bank;
|
||||
switch(addr & 0xe000) {
|
||||
case 0x8000: bank = prg_bank[0]; break;
|
||||
case 0xa000: bank = prg_bank[1]; break;
|
||||
case 0xc000: bank = 0x1e; break;
|
||||
case 0xe000: bank = 0x1f; break;
|
||||
}
|
||||
return (bank * 0x2000) + (addr & 0x1fff);
|
||||
}
|
||||
|
||||
unsigned chr_addr(unsigned addr) const {
|
||||
unsigned bank = chr_bank[addr / 0x0400];
|
||||
return (bank * 0x0400) + (addr & 0x03ff);
|
||||
}
|
||||
|
||||
unsigned ciram_addr(unsigned addr) const {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
||||
case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first)
|
||||
case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second)
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
uint8 ram_read(unsigned addr) {
|
||||
if(board.prgram.size == 0) {
|
||||
if((addr & 0xf000) == 0x6000) return cpu.mdr() | latch;
|
||||
return cpu.mdr();
|
||||
}
|
||||
return board.prgram.read(addr & 0x1fff);
|
||||
}
|
||||
|
||||
void ram_write(unsigned addr, uint8 data) {
|
||||
if(board.prgram.size == 0) {
|
||||
if((addr & 0xf000) == 0x6000) latch = data & 0x01;
|
||||
return;
|
||||
}
|
||||
return board.prgram.write(addr & 0x1fff, data);
|
||||
}
|
||||
|
||||
void reg_write(unsigned addr, uint8 data) {
|
||||
switch(addr) {
|
||||
case 0x8000: case 0x8001: case 0x8002: case 0x8003:
|
||||
prg_bank[0] = data & 0x1f;
|
||||
break;
|
||||
|
||||
case 0x9000: case 0x9001: case 0x9002: case 0x9003:
|
||||
mirror = data & 0x03;
|
||||
break;
|
||||
|
||||
case 0xa000: case 0xa001: case 0xa002: case 0xa003:
|
||||
prg_bank[1] = data & 0x1f;
|
||||
break;
|
||||
|
||||
case 0xb000: chr_bank[0] = (chr_bank[0] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xb001: chr_bank[0] = (chr_bank[0] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xb002: chr_bank[1] = (chr_bank[1] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xb003: chr_bank[1] = (chr_bank[1] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xc000: chr_bank[2] = (chr_bank[2] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xc001: chr_bank[2] = (chr_bank[2] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xc002: chr_bank[3] = (chr_bank[3] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xc003: chr_bank[3] = (chr_bank[3] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xd000: chr_bank[4] = (chr_bank[4] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xd001: chr_bank[4] = (chr_bank[4] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xd002: chr_bank[5] = (chr_bank[5] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xd003: chr_bank[5] = (chr_bank[5] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xe000: chr_bank[6] = (chr_bank[6] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xe001: chr_bank[6] = (chr_bank[6] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
|
||||
case 0xe002: chr_bank[7] = (chr_bank[7] & 0xf0) | ((data & 0x0f) << 0); break;
|
||||
case 0xe003: chr_bank[7] = (chr_bank[7] & 0x0f) | ((data & 0x0f) << 4); break;
|
||||
}
|
||||
}
|
||||
|
||||
void power() {
|
||||
}
|
||||
|
||||
void reset() {
|
||||
for(auto &n : prg_bank) n = 0;
|
||||
for(auto &n : chr_bank) n = 0;
|
||||
mirror = 0;
|
||||
latch = 0;
|
||||
}
|
||||
|
||||
void serialize(serializer &s) {
|
||||
for(auto &n : prg_bank) s.integer(n);
|
||||
for(auto &n : chr_bank) s.integer(n);
|
||||
s.integer(mirror);
|
||||
s.integer(latch);
|
||||
}
|
||||
|
||||
VRC2(Board &board) : Chip(board) {
|
||||
}
|
||||
|
||||
};
|
100
bsnes/fc/cartridge/chip/vrc3.cpp
Normal file
100
bsnes/fc/cartridge/chip/vrc3.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
struct VRC3 : Chip {
|
||||
|
||||
uint4 prg_bank;
|
||||
bool irq_mode;
|
||||
bool irq_enable;
|
||||
bool irq_acknowledge;
|
||||
uint16 irq_latch;
|
||||
struct {
|
||||
union {
|
||||
uint16 w;
|
||||
struct { uint8 order_lsb2(l, h); };
|
||||
};
|
||||
} irq_counter;
|
||||
bool irq_line;
|
||||
|
||||
void main() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
if(irq_enable) {
|
||||
if(irq_mode == 0) { //16-bit
|
||||
if(++irq_counter.w == 0) {
|
||||
irq_line = 1;
|
||||
irq_enable = irq_acknowledge;
|
||||
irq_counter.w = irq_latch;
|
||||
}
|
||||
}
|
||||
if(irq_mode == 1) { //8-bit
|
||||
if(++irq_counter.l == 0) {
|
||||
irq_line = 1;
|
||||
irq_enable = irq_acknowledge;
|
||||
irq_counter.l = irq_latch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cpu.set_irq_line(irq_line);
|
||||
tick();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned prg_addr(unsigned addr) const {
|
||||
unsigned bank = (addr < 0xc000 ? (unsigned)prg_bank : 0x0f);
|
||||
return (bank * 0x4000) + (addr & 0x3fff);
|
||||
}
|
||||
|
||||
void reg_write(unsigned addr, uint8 data) {
|
||||
switch(addr & 0xf000) {
|
||||
case 0x8000: irq_latch = (irq_latch & 0xfff0) | ((data & 0x0f) << 0); break;
|
||||
case 0x9000: irq_latch = (irq_latch & 0xff0f) | ((data & 0x0f) << 4); break;
|
||||
case 0xa000: irq_latch = (irq_latch & 0xf0ff) | ((data & 0x0f) << 8); break;
|
||||
case 0xb000: irq_latch = (irq_latch & 0x0fff) | ((data & 0x0f) << 12); break;
|
||||
|
||||
case 0xc000:
|
||||
irq_mode = data & 0x04;
|
||||
irq_enable = data & 0x02;
|
||||
irq_acknowledge = data & 0x01;
|
||||
if(irq_enable) irq_counter.w = irq_latch;
|
||||
break;
|
||||
|
||||
case 0xd000:
|
||||
irq_line = 0;
|
||||
irq_enable = irq_acknowledge;
|
||||
break;
|
||||
|
||||
case 0xf000:
|
||||
prg_bank = data & 0x0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void power() {
|
||||
}
|
||||
|
||||
void reset() {
|
||||
prg_bank = 0;
|
||||
irq_mode = 0;
|
||||
irq_enable = 0;
|
||||
irq_acknowledge = 0;
|
||||
irq_latch = 0;
|
||||
irq_counter.w = 0;
|
||||
irq_line = 0;
|
||||
}
|
||||
|
||||
void serialize(serializer &s) {
|
||||
s.integer(prg_bank);
|
||||
s.integer(irq_mode);
|
||||
s.integer(irq_enable);
|
||||
s.integer(irq_acknowledge);
|
||||
s.integer(irq_latch);
|
||||
s.integer(irq_counter.w);
|
||||
s.integer(irq_line);
|
||||
}
|
||||
|
||||
VRC3(Board &board) : Chip(board) {
|
||||
}
|
||||
|
||||
};
|
51
bsnes/nes/cartridge/chip/vrc4.cpp → bsnes/fc/cartridge/chip/vrc4.cpp
Executable file → Normal file
51
bsnes/nes/cartridge/chip/vrc4.cpp → bsnes/fc/cartridge/chip/vrc4.cpp
Executable file → Normal file
@@ -49,6 +49,32 @@ void main() {
|
||||
}
|
||||
}
|
||||
|
||||
unsigned prg_addr(unsigned addr) const {
|
||||
unsigned bank = 0, banks = board.prgrom.size / 0x2000;
|
||||
switch(addr & 0xe000) {
|
||||
case 0x8000: bank = prg_mode == 0 ? (unsigned)prg_bank[0] : banks - 2; break;
|
||||
case 0xa000: bank = prg_bank[1]; break;
|
||||
case 0xc000: bank = prg_mode == 0 ? banks - 2 : (unsigned)prg_bank[0]; break;
|
||||
case 0xe000: bank = banks - 1; break;
|
||||
}
|
||||
return (bank * 0x2000) + (addr & 0x1fff);
|
||||
}
|
||||
|
||||
unsigned chr_addr(unsigned addr) const {
|
||||
unsigned bank = chr_bank[addr / 0x0400];
|
||||
return (bank * 0x0400) + (addr & 0x03ff);
|
||||
}
|
||||
|
||||
unsigned ciram_addr(unsigned addr) const {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
||||
case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first)
|
||||
case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second)
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
void reg_write(unsigned addr, uint8 data) {
|
||||
switch(addr) {
|
||||
case 0x8000: case 0x8001: case 0x8002: case 0x8003:
|
||||
@@ -117,31 +143,6 @@ void reg_write(unsigned addr, uint8 data) {
|
||||
}
|
||||
}
|
||||
|
||||
unsigned prg_addr(unsigned addr) const {
|
||||
unsigned bank = 0, banks = board.prgrom.size / 0x2000;
|
||||
switch((addr / 0x2000) & 3) {
|
||||
case 0: bank = prg_mode == 0 ? (unsigned)prg_bank[0] : banks - 2; break;
|
||||
case 1: bank = prg_bank[1]; break;
|
||||
case 2: bank = prg_mode == 0 ? banks - 2 : (unsigned)prg_bank[0]; break;
|
||||
case 3: bank = banks - 1; break;
|
||||
}
|
||||
return (bank * 0x2000) + (addr & 0x1fff);
|
||||
}
|
||||
|
||||
unsigned chr_addr(unsigned addr) const {
|
||||
unsigned bank = chr_bank[addr / 0x0400];
|
||||
return (bank * 0x0400) + (addr & 0x03ff);
|
||||
}
|
||||
|
||||
unsigned ciram_addr(unsigned addr) const {
|
||||
switch(mirror) {
|
||||
case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring
|
||||
case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring
|
||||
case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first)
|
||||
case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second)
|
||||
}
|
||||
}
|
||||
|
||||
void power() {
|
||||
}
|
||||
|
0
bsnes/nes/cartridge/chip/vrc6.cpp → bsnes/fc/cartridge/chip/vrc6.cpp
Executable file → Normal file
0
bsnes/nes/cartridge/chip/vrc6.cpp → bsnes/fc/cartridge/chip/vrc6.cpp
Executable file → Normal file
0
bsnes/nes/cartridge/chip/vrc7.cpp → bsnes/fc/cartridge/chip/vrc7.cpp
Executable file → Normal file
0
bsnes/nes/cartridge/chip/vrc7.cpp → bsnes/fc/cartridge/chip/vrc7.cpp
Executable file → Normal file
4
bsnes/nes/cheat/cheat.cpp → bsnes/fc/cheat/cheat.cpp
Executable file → Normal file
4
bsnes/nes/cheat/cheat.cpp → bsnes/fc/cheat/cheat.cpp
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
Cheat cheat;
|
||||
|
2
bsnes/nes/cheat/cheat.hpp → bsnes/fc/cheat/cheat.hpp
Executable file → Normal file
2
bsnes/nes/cheat/cheat.hpp → bsnes/fc/cheat/cheat.hpp
Executable file → Normal file
@@ -4,7 +4,7 @@ struct CheatCode {
|
||||
unsigned comp;
|
||||
};
|
||||
|
||||
struct Cheat : public linear_vector<CheatCode> {
|
||||
struct Cheat : public vector<CheatCode> {
|
||||
static bool decode(const string &code, unsigned &addr, unsigned &data, unsigned &comp);
|
||||
|
||||
void synchronize();
|
70
bsnes/nes/cpu/cpu.cpp → bsnes/fc/cpu/cpu.cpp
Executable file → Normal file
70
bsnes/nes/cpu/cpu.cpp → bsnes/fc/cpu/cpu.cpp
Executable file → Normal file
@@ -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() {
|
||||
Processor::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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
28
bsnes/nes/cpu/cpu.hpp → bsnes/fc/cpu/cpu.hpp
Executable file → Normal file
28
bsnes/nes/cpu/cpu.hpp → bsnes/fc/cpu/cpu.hpp
Executable file → Normal file
@@ -1,6 +1,4 @@
|
||||
struct CPU : Processor {
|
||||
#include "core/core.hpp"
|
||||
#include "memory/memory.hpp"
|
||||
struct CPU : Processor::R6502, Thread {
|
||||
uint8 ram[0x0800];
|
||||
|
||||
struct Status {
|
||||
@@ -21,16 +19,14 @@ struct CPU : Processor {
|
||||
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 : Processor {
|
||||
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;
|
22
bsnes/nes/cpu/serialization.cpp → bsnes/fc/cpu/serialization.cpp
Executable file → Normal file
22
bsnes/nes/cpu/serialization.cpp → bsnes/fc/cpu/serialization.cpp
Executable file → Normal file
@@ -1,27 +1,9 @@
|
||||
void CPU::serialize(serializer &s) {
|
||||
Processor::serialize(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
Normal file
63
bsnes/fc/cpu/timing.cpp
Normal 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;
|
||||
}
|
62
bsnes/fc/fc.hpp
Normal file
62
bsnes/fc/fc.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#ifndef FC_HPP
|
||||
#define FC_HPP
|
||||
|
||||
#include <emulator/emulator.hpp>
|
||||
#include <processor/r6502/r6502.hpp>
|
||||
|
||||
namespace Famicom {
|
||||
namespace Info {
|
||||
static const char Name[] = "bnes";
|
||||
static const unsigned SerializerVersion = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bnes - Famicom emulator
|
||||
authors: byuu, Ryphecha
|
||||
license: GPLv3
|
||||
project started: 2011-09-05
|
||||
*/
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
namespace Famicom {
|
||||
struct Thread {
|
||||
cothread_t thread;
|
||||
unsigned frequency;
|
||||
int64 clock;
|
||||
|
||||
inline void create(void (*entrypoint)(), unsigned frequency) {
|
||||
if(thread) co_delete(thread);
|
||||
thread = co_create(65536 * sizeof(void*), entrypoint);
|
||||
this->frequency = frequency;
|
||||
clock = 0;
|
||||
}
|
||||
|
||||
inline void serialize(serializer &s) {
|
||||
s.integer(frequency);
|
||||
s.integer(clock);
|
||||
}
|
||||
|
||||
inline Thread() : thread(nullptr) {
|
||||
}
|
||||
|
||||
inline ~Thread() {
|
||||
if(thread) co_delete(thread);
|
||||
}
|
||||
};
|
||||
|
||||
#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
|
5
bsnes/nes/input/input.cpp → bsnes/fc/input/input.cpp
Executable file → Normal file
5
bsnes/nes/input/input.cpp → bsnes/fc/input/input.cpp
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
#include "serialization.cpp"
|
||||
Input input;
|
||||
@@ -42,7 +42,6 @@ void Input::connect(bool port, Device device) {
|
||||
}
|
||||
|
||||
void Input::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void Input::reset() {
|
2
bsnes/nes/input/input.hpp → bsnes/fc/input/input.hpp
Executable file → Normal file
2
bsnes/nes/input/input.hpp → bsnes/fc/input/input.hpp
Executable file → Normal file
@@ -1,7 +1,7 @@
|
||||
struct Input {
|
||||
enum class Device : unsigned {
|
||||
None,
|
||||
Joypad,
|
||||
None,
|
||||
};
|
||||
|
||||
void latch(bool data);
|
0
bsnes/nes/input/serialization.cpp → bsnes/fc/input/serialization.cpp
Executable file → Normal file
0
bsnes/nes/input/serialization.cpp → bsnes/fc/input/serialization.cpp
Executable file → Normal file
155
bsnes/fc/interface/interface.cpp
Normal file
155
bsnes/fc/interface/interface.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
#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();
|
||||
}
|
||||
|
||||
unsigned Interface::group(unsigned id) {
|
||||
switch(id) {
|
||||
case ID::ProgramROM:
|
||||
case ID::ProgramRAM:
|
||||
case ID::CharacterROM:
|
||||
case ID::CharacterRAM:
|
||||
return 1;
|
||||
}
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
void Interface::load(unsigned id, const string &manifest) {
|
||||
cartridge.load(manifest);
|
||||
}
|
||||
|
||||
void Interface::save() {
|
||||
for(auto &memory : cartridge.memory) {
|
||||
saveRequest(memory.id, memory.name);
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::load(unsigned id, const stream &stream, const string &manifest) {
|
||||
if(id == ID::ProgramROM) {
|
||||
stream.read(cartridge.board->prgrom.data, min(cartridge.board->prgrom.size, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::ProgramRAM) {
|
||||
stream.read(cartridge.board->prgram.data, min(cartridge.board->prgram.size, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::CharacterROM) {
|
||||
stream.read(cartridge.board->chrrom.data, min(cartridge.board->chrrom.size, stream.size()));
|
||||
}
|
||||
|
||||
if(id == ID::CharacterRAM) {
|
||||
stream.read(cartridge.board->chrram.data, min(cartridge.board->chrram.size, stream.size()));
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::save(unsigned id, const stream &stream) {
|
||||
if(id == ID::ProgramRAM) {
|
||||
stream.write(cartridge.board->prgram.data, cartridge.board->prgram.size);
|
||||
}
|
||||
|
||||
if(id == ID::CharacterRAM) {
|
||||
stream.write(cartridge.board->chrram.data, cartridge.board->chrram.size);
|
||||
}
|
||||
}
|
||||
|
||||
void Interface::unload() {
|
||||
save();
|
||||
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::paletteUpdate() {
|
||||
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;
|
||||
information.capability.states = true;
|
||||
information.capability.cheats = true;
|
||||
|
||||
media.append({ID::Famicom, "Famicom", "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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
58
bsnes/fc/interface/interface.hpp
Normal file
58
bsnes/fc/interface/interface.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef FC_HPP
|
||||
namespace Famicom {
|
||||
#endif
|
||||
|
||||
struct ID {
|
||||
enum : unsigned {
|
||||
System,
|
||||
Famicom,
|
||||
};
|
||||
|
||||
enum : unsigned {
|
||||
ProgramROM,
|
||||
ProgramRAM,
|
||||
CharacterROM,
|
||||
CharacterRAM,
|
||||
};
|
||||
|
||||
enum : unsigned {
|
||||
Port1 = 1,
|
||||
Port2 = 2,
|
||||
};
|
||||
};
|
||||
|
||||
struct Interface : Emulator::Interface {
|
||||
double videoFrequency();
|
||||
double audioFrequency();
|
||||
|
||||
bool loaded();
|
||||
string sha256();
|
||||
unsigned group(unsigned id);
|
||||
void load(unsigned id, const string &manifest);
|
||||
void save();
|
||||
void load(unsigned id, const stream &stream, const string &manifest = "");
|
||||
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 paletteUpdate();
|
||||
|
||||
Interface();
|
||||
|
||||
private:
|
||||
vector<Device> device;
|
||||
};
|
||||
|
||||
extern Interface *interface;
|
||||
|
||||
#ifndef FC_HPP
|
||||
}
|
||||
#endif
|
4
bsnes/nes/memory/memory.cpp → bsnes/fc/memory/memory.cpp
Executable file → Normal file
4
bsnes/nes/memory/memory.cpp → bsnes/fc/memory/memory.cpp
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
Bus bus;
|
||||
|
0
bsnes/nes/memory/memory.hpp → bsnes/fc/memory/memory.hpp
Executable file → Normal file
0
bsnes/nes/memory/memory.hpp → bsnes/fc/memory/memory.hpp
Executable file → Normal file
106
bsnes/nes/ppu/ppu.cpp → bsnes/fc/ppu/ppu.cpp
Executable file → Normal file
106
bsnes/nes/ppu/ppu.cpp → bsnes/fc/ppu/ppu.cpp
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
#include "serialization.cpp"
|
||||
PPU ppu;
|
||||
@@ -20,25 +20,33 @@ void PPU::main() {
|
||||
}
|
||||
|
||||
void PPU::tick() {
|
||||
if(status.ly == 240 && status.lx == 340) status.nmi_hold = 1;
|
||||
if(status.ly == 241 && status.lx == 0) status.nmi_flag = status.nmi_hold;
|
||||
if(status.ly == 241 && status.lx == 2) cpu.set_nmi_line(status.nmi_enable && status.nmi_flag);
|
||||
|
||||
if(status.ly == 260 && status.lx == 340) status.sprite_zero_hit = 0, status.sprite_overflow = 0;
|
||||
|
||||
if(status.ly == 260 && status.lx == 340) status.nmi_hold = 0;
|
||||
if(status.ly == 261 && status.lx == 0) status.nmi_flag = status.nmi_hold;
|
||||
if(status.ly == 261 && status.lx == 2) cpu.set_nmi_line(status.nmi_enable && status.nmi_flag);
|
||||
|
||||
clock += 4;
|
||||
if(clock >= 0) co_switch(cpu.thread);
|
||||
|
||||
status.lx++;
|
||||
}
|
||||
|
||||
void PPU::scanline_edge() {
|
||||
if(status.ly == 241) {
|
||||
status.nmi = 1;
|
||||
if(status.nmi_enable) cpu.set_nmi_line(1);
|
||||
}
|
||||
if(status.ly == 261) {
|
||||
status.nmi = 0;
|
||||
cpu.set_nmi_line(0);
|
||||
status.sprite_zero_hit = 0;
|
||||
void PPU::scanline() {
|
||||
status.lx = 0;
|
||||
if(++status.ly == 262) {
|
||||
status.ly = 0;
|
||||
frame();
|
||||
}
|
||||
cartridge.scanline(status.ly);
|
||||
}
|
||||
|
||||
void PPU::frame_edge() {
|
||||
void PPU::frame() {
|
||||
status.field ^= 1;
|
||||
interface->videoRefresh(buffer);
|
||||
scheduler.exit(Scheduler::ExitReason::FrameEvent);
|
||||
}
|
||||
|
||||
@@ -58,6 +66,9 @@ void PPU::reset() {
|
||||
status.taddr = 0x0000;
|
||||
status.xaddr = 0x00;
|
||||
|
||||
status.nmi_hold = 0;
|
||||
status.nmi_flag = 0;
|
||||
|
||||
//$2000
|
||||
status.nmi_enable = false;
|
||||
status.master_select = 0;
|
||||
@@ -75,18 +86,16 @@ void PPU::reset() {
|
||||
status.grayscale = false;
|
||||
|
||||
//$2002
|
||||
status.nmi = false;
|
||||
status.sprite_zero_hit = false;
|
||||
status.sprite_overflow = false;
|
||||
|
||||
//$2003
|
||||
status.oam_addr = 0x00;
|
||||
|
||||
memset(buffer, 0, sizeof buffer);
|
||||
|
||||
memset(ciram, 0, sizeof ciram);
|
||||
memset(cgram, 0, sizeof cgram);
|
||||
memset(oam, 0, sizeof oam);
|
||||
for(auto &n : buffer) n = 0;
|
||||
for(auto &n : ciram ) n = 0;
|
||||
for(auto &n : cgram ) n = 0;
|
||||
for(auto &n : oam ) n = 0;
|
||||
}
|
||||
|
||||
uint8 PPU::read(uint16 addr) {
|
||||
@@ -94,13 +103,13 @@ uint8 PPU::read(uint16 addr) {
|
||||
|
||||
switch(addr & 7) {
|
||||
case 2: //PPUSTATUS
|
||||
result |= status.nmi << 7;
|
||||
result |= status.nmi_flag << 7;
|
||||
result |= status.sprite_zero_hit << 6;
|
||||
result |= status.sprite_overflow << 5;
|
||||
result |= status.mdr & 0x1f;
|
||||
status.nmi = 0;
|
||||
cpu.set_nmi_line(0);
|
||||
status.address_latch = 0;
|
||||
status.nmi_hold = 0;
|
||||
cpu.set_nmi_line(status.nmi_flag = 0);
|
||||
break;
|
||||
case 4: //OAMDATA
|
||||
result = oam[status.oam_addr];
|
||||
@@ -133,13 +142,13 @@ void PPU::write(uint16 addr, uint8 data) {
|
||||
switch(addr & 7) {
|
||||
case 0: //PPUCTRL
|
||||
status.nmi_enable = data & 0x80;
|
||||
cpu.set_nmi_line(status.nmi_enable && status.nmi);
|
||||
status.master_select = data & 0x40;
|
||||
status.sprite_size = data & 0x20;
|
||||
status.bg_addr = (data & 0x10) ? 0x1000 : 0x0000;
|
||||
status.sprite_addr = (data & 0x08) ? 0x1000 : 0x0000;
|
||||
status.vram_increment = (data & 0x04) ? 32 : 1;
|
||||
status.taddr = (status.taddr & 0x73ff) | ((data & 0x03) << 10);
|
||||
cpu.set_nmi_line(status.nmi_enable && status.nmi_hold && status.nmi_flag);
|
||||
return;
|
||||
case 1: //PPUMASK
|
||||
status.emphasis = data >> 5;
|
||||
@@ -249,15 +258,6 @@ uint8 PPU::chr_load(uint16 addr) {
|
||||
|
||||
//
|
||||
|
||||
void PPU::ly_increment() {
|
||||
if(++status.ly == 262) {
|
||||
status.ly = 0;
|
||||
frame_edge();
|
||||
}
|
||||
scanline_edge();
|
||||
cartridge.scanline(status.ly);
|
||||
}
|
||||
|
||||
void PPU::scrollx_increment() {
|
||||
if(raster_enable() == false) return;
|
||||
status.vaddr = (status.vaddr & 0x7fe0) | ((status.vaddr + 0x0001) & 0x001f);
|
||||
@@ -280,10 +280,10 @@ void PPU::scrolly_increment() {
|
||||
|
||||
//
|
||||
|
||||
void PPU::raster_pixel(unsigned x) {
|
||||
uint16 *output = buffer + status.ly * 256;
|
||||
void PPU::raster_pixel() {
|
||||
uint32 *output = buffer + status.ly * 256;
|
||||
|
||||
unsigned mask = 0x8000 >> (status.xaddr + x);
|
||||
unsigned mask = 0x8000 >> (status.xaddr + (status.lx & 7));
|
||||
unsigned palette = 0, object_palette = 0;
|
||||
bool object_priority = 0;
|
||||
palette |= (raster.tiledatalo & mask) ? 1 : 0;
|
||||
@@ -297,6 +297,7 @@ void PPU::raster_pixel(unsigned x) {
|
||||
if(status.bg_enable == false) palette = 0;
|
||||
if(status.bg_edge_enable == false && status.lx < 8) palette = 0;
|
||||
|
||||
if(status.sprite_enable == true)
|
||||
for(signed sprite = 7; sprite >= 0; sprite--) {
|
||||
if(status.sprite_edge_enable == false && status.lx < 8) continue;
|
||||
if(raster.oam[sprite].id == 64) continue;
|
||||
@@ -311,7 +312,7 @@ void PPU::raster_pixel(unsigned x) {
|
||||
sprite_palette |= (raster.oam[sprite].tiledatahi & mask) ? 2 : 0;
|
||||
if(sprite_palette == 0) continue;
|
||||
|
||||
if(raster.oam[sprite].id == 0 && palette) status.sprite_zero_hit = 1;
|
||||
if(raster.oam[sprite].id == 0 && palette && status.lx != 255) status.sprite_zero_hit = 1;
|
||||
sprite_palette |= (raster.oam[sprite].attr & 3) << 2;
|
||||
|
||||
object_priority = raster.oam[sprite].attr & 0x20;
|
||||
@@ -323,11 +324,11 @@ void PPU::raster_pixel(unsigned x) {
|
||||
}
|
||||
|
||||
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() {
|
||||
if(status.sprite_enable == false) return;
|
||||
if(raster_enable() == false) return;
|
||||
|
||||
unsigned n = raster.oam_iterator++;
|
||||
signed ly = (status.ly == 261 ? -1 : status.ly);
|
||||
@@ -349,14 +350,10 @@ void PPU::raster_sprite() {
|
||||
|
||||
void PPU::raster_scanline() {
|
||||
if((status.ly >= 240 && status.ly <= 260)) {
|
||||
for(unsigned x = 0; x < 340; x++) tick();
|
||||
if(raster_enable() == false || status.field != 1 || status.ly != 240) tick();
|
||||
return ly_increment();
|
||||
for(unsigned x = 0; x < 341; x++) tick();
|
||||
return scanline();
|
||||
}
|
||||
|
||||
signed lx = 0, ly = (status.ly == 261 ? -1 : status.ly);
|
||||
status.lx = 0;
|
||||
|
||||
raster.oam_iterator = 0;
|
||||
raster.oam_counter = 0;
|
||||
|
||||
@@ -373,36 +370,36 @@ void PPU::raster_scanline() {
|
||||
for(unsigned tile = 0; tile < 32; tile++) { // 0-255
|
||||
unsigned nametable = chr_load(0x2000 | (status.vaddr & 0x0fff));
|
||||
unsigned tileaddr = status.bg_addr + (nametable << 4) + (scrolly() & 7);
|
||||
raster_pixel(0);
|
||||
raster_pixel();
|
||||
tick();
|
||||
|
||||
raster_pixel(1);
|
||||
raster_pixel();
|
||||
tick();
|
||||
|
||||
unsigned attribute = chr_load(0x23c0 | (status.vaddr & 0x0fc0) | ((scrolly() >> 5) << 3) | (scrollx() >> 5));
|
||||
if(scrolly() & 16) attribute >>= 4;
|
||||
if(scrollx() & 16) attribute >>= 2;
|
||||
raster_pixel(2);
|
||||
raster_pixel();
|
||||
tick();
|
||||
|
||||
scrollx_increment();
|
||||
if(tile == 31) scrolly_increment();
|
||||
raster_pixel(3);
|
||||
raster_pixel();
|
||||
raster_sprite();
|
||||
tick();
|
||||
|
||||
unsigned tiledatalo = chr_load(tileaddr + 0);
|
||||
raster_pixel(4);
|
||||
raster_pixel();
|
||||
tick();
|
||||
|
||||
raster_pixel(5);
|
||||
raster_pixel();
|
||||
tick();
|
||||
|
||||
unsigned tiledatahi = chr_load(tileaddr + 8);
|
||||
raster_pixel(6);
|
||||
raster_pixel();
|
||||
tick();
|
||||
|
||||
raster_pixel(7);
|
||||
raster_pixel();
|
||||
raster_sprite();
|
||||
tick();
|
||||
|
||||
@@ -474,6 +471,7 @@ void PPU::raster_scanline() {
|
||||
//336-339
|
||||
chr_load(0x2000 | (status.vaddr & 0x0fff));
|
||||
tick();
|
||||
bool skip = (raster_enable() && status.field == 1 && status.ly == 261);
|
||||
tick();
|
||||
|
||||
chr_load(0x2000 | (status.vaddr & 0x0fff));
|
||||
@@ -481,9 +479,9 @@ void PPU::raster_scanline() {
|
||||
tick();
|
||||
|
||||
//340
|
||||
tick();
|
||||
if(skip == false) tick();
|
||||
|
||||
return ly_increment();
|
||||
return scanline();
|
||||
}
|
||||
|
||||
}
|
15
bsnes/nes/ppu/ppu.hpp → bsnes/fc/ppu/ppu.hpp
Executable file → Normal file
15
bsnes/nes/ppu/ppu.hpp → bsnes/fc/ppu/ppu.hpp
Executable file → Normal file
@@ -1,10 +1,10 @@
|
||||
struct PPU : Processor {
|
||||
struct PPU : Thread {
|
||||
static void Main();
|
||||
void main();
|
||||
void tick();
|
||||
|
||||
void scanline_edge();
|
||||
void frame_edge();
|
||||
void scanline();
|
||||
void frame();
|
||||
|
||||
void power();
|
||||
void reset();
|
||||
@@ -26,11 +26,10 @@ struct PPU : Processor {
|
||||
|
||||
uint8 chr_load(uint16 addr);
|
||||
|
||||
void ly_increment();
|
||||
void scrollx_increment();
|
||||
void scrolly_increment();
|
||||
|
||||
void raster_pixel(unsigned x);
|
||||
void raster_pixel();
|
||||
void raster_sprite();
|
||||
void raster_scanline();
|
||||
|
||||
@@ -51,6 +50,9 @@ struct PPU : Processor {
|
||||
uint15 taddr;
|
||||
uint8 xaddr;
|
||||
|
||||
bool nmi_hold;
|
||||
bool nmi_flag;
|
||||
|
||||
//$2000
|
||||
bool nmi_enable;
|
||||
bool master_select;
|
||||
@@ -68,7 +70,6 @@ struct PPU : Processor {
|
||||
bool grayscale;
|
||||
|
||||
//$2002
|
||||
bool nmi;
|
||||
bool sprite_zero_hit;
|
||||
bool sprite_overflow;
|
||||
|
||||
@@ -97,7 +98,7 @@ struct PPU : Processor {
|
||||
} oam[8], soam[8];
|
||||
} raster;
|
||||
|
||||
uint16 buffer[256 * 262];
|
||||
uint32 buffer[256 * 262];
|
||||
uint8 ciram[2048];
|
||||
uint8 cgram[32];
|
||||
uint8 oam[256];
|
6
bsnes/nes/ppu/serialization.cpp → bsnes/fc/ppu/serialization.cpp
Executable file → Normal file
6
bsnes/nes/ppu/serialization.cpp → bsnes/fc/ppu/serialization.cpp
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
void PPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.integer(status.mdr);
|
||||
|
||||
@@ -15,6 +15,9 @@ void PPU::serialize(serializer &s) {
|
||||
s.integer(status.taddr);
|
||||
s.integer(status.xaddr);
|
||||
|
||||
s.integer(status.nmi_hold);
|
||||
s.integer(status.nmi_flag);
|
||||
|
||||
s.integer(status.nmi_enable);
|
||||
s.integer(status.master_select);
|
||||
s.integer(status.sprite_size);
|
||||
@@ -29,7 +32,6 @@ void PPU::serialize(serializer &s) {
|
||||
s.integer(status.bg_edge_enable);
|
||||
s.integer(status.grayscale);
|
||||
|
||||
s.integer(status.nmi);
|
||||
s.integer(status.sprite_zero_hit);
|
||||
s.integer(status.sprite_overflow);
|
||||
|
5
bsnes/nes/scheduler/scheduler.cpp → bsnes/fc/scheduler/scheduler.cpp
Executable file → Normal file
5
bsnes/nes/scheduler/scheduler.cpp → bsnes/fc/scheduler/scheduler.cpp
Executable file → Normal file
@@ -1,6 +1,6 @@
|
||||
#include <nes/nes.hpp>
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
namespace NES {
|
||||
namespace Famicom {
|
||||
|
||||
Scheduler scheduler;
|
||||
|
||||
@@ -16,7 +16,6 @@ void Scheduler::exit(ExitReason reason) {
|
||||
}
|
||||
|
||||
void Scheduler::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void Scheduler::reset() {
|
0
bsnes/nes/scheduler/scheduler.hpp → bsnes/fc/scheduler/scheduler.hpp
Executable file → Normal file
0
bsnes/nes/scheduler/scheduler.hpp → bsnes/fc/scheduler/scheduler.hpp
Executable file → Normal file
22
bsnes/nes/system/serialization.cpp → bsnes/fc/system/serialization.cpp
Executable file → Normal file
22
bsnes/nes/system/serialization.cpp → bsnes/fc/system/serialization.cpp
Executable file → Normal file
@@ -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,19 +16,18 @@ 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;
|
||||
|
||||
reset();
|
||||
power();
|
||||
serialize_all(s);
|
||||
return true;
|
||||
}
|
||||
@@ -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);
|
11
bsnes/nes/system/system.cpp → bsnes/fc/system/system.cpp
Executable file → Normal file
11
bsnes/nes/system/system.cpp → bsnes/fc/system/system.cpp
Executable file → Normal file
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
0
bsnes/nes/system/system.hpp → bsnes/fc/system/system.hpp
Executable file → Normal file
0
bsnes/nes/system/system.hpp → bsnes/fc/system/system.hpp
Executable file → Normal file
68
bsnes/fc/video/video.cpp
Normal file
68
bsnes/fc/video/video.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include <fc/fc.hpp>
|
||||
|
||||
#define VIDEO_CPP
|
||||
namespace Famicom {
|
||||
|
||||
Video video;
|
||||
|
||||
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
|
||||
) {
|
||||
signed color = (n & 0x0f), level = color < 0xe ? (n >> 4) & 3 : 1;
|
||||
|
||||
static const double black = 0.518, white = 1.962, attenuation = 0.746;
|
||||
static const double levels[8] = {
|
||||
0.350, 0.518, 0.962, 1.550,
|
||||
1.094, 1.506, 1.962, 1.962,
|
||||
};
|
||||
|
||||
double lo_and_hi[2] = {
|
||||
levels[level + 4 * (color == 0x0)],
|
||||
levels[level + 4 * (color < 0xd)],
|
||||
};
|
||||
|
||||
double y = 0.0, i = 0.0, q = 0.0;
|
||||
auto wave = [](signed p, signed color) { return (color + p + 8) % 12 < 6; };
|
||||
for(signed p = 0; p < 12; p++) {
|
||||
double spot = lo_and_hi[wave(p, color)];
|
||||
|
||||
if(((n & 0x040) && wave(p, 12))
|
||||
|| ((n & 0x080) && wave(p, 4))
|
||||
|| ((n & 0x100) && wave(p, 8))
|
||||
) spot *= attenuation;
|
||||
|
||||
double v = (spot - black) / (white - black);
|
||||
|
||||
v = (v - 0.5) * contrast + 0.5;
|
||||
v *= brightness / 12.0;
|
||||
|
||||
y += v;
|
||||
i += v * std::cos((3.141592653 / 6.0) * (p + hue));
|
||||
q += v * std::sin((3.141592653 / 6.0) * (p + hue));
|
||||
}
|
||||
|
||||
i *= saturation;
|
||||
q *= saturation;
|
||||
|
||||
auto gammaAdjust = [=](double f) { return f < 0.0 ? 0.0 : std::pow(f, 2.2 / gamma); };
|
||||
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);
|
||||
|
||||
return interface->videoColor(n, uclamp<16>(r), uclamp<16>(g), uclamp<16>(b));
|
||||
}
|
||||
|
||||
}
|
12
bsnes/fc/video/video.hpp
Normal file
12
bsnes/fc/video/video.hpp
Normal 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,15 +0,0 @@
|
||||
gameboy_objects := gameboy-interface gameboy-system gameboy-scheduler
|
||||
gameboy_objects += gameboy-memory gameboy-cartridge
|
||||
gameboy_objects += gameboy-cpu gameboy-apu gameboy-lcd
|
||||
gameboy_objects += gameboy-cheat
|
||||
objects += $(gameboy_objects)
|
||||
|
||||
obj/gameboy-interface.o: $(gameboy)/interface/interface.cpp $(call rwildcard,$(gameboy)/interface/)
|
||||
obj/gameboy-system.o: $(gameboy)/system/system.cpp $(call rwildcard,$(gameboy)/system/)
|
||||
obj/gameboy-scheduler.o: $(gameboy)/scheduler/scheduler.cpp $(call rwildcard,$(gameboy)/scheduler/)
|
||||
obj/gameboy-cartridge.o: $(gameboy)/cartridge/cartridge.cpp $(call rwildcard,$(gameboy)/cartridge/)
|
||||
obj/gameboy-memory.o: $(gameboy)/memory/memory.cpp $(call rwildcard,$(gameboy)/memory/)
|
||||
obj/gameboy-cpu.o: $(gameboy)/cpu/cpu.cpp $(call rwildcard,$(gameboy)/cpu/)
|
||||
obj/gameboy-apu.o: $(gameboy)/apu/apu.cpp $(call rwildcard,$(gameboy)/apu/)
|
||||
obj/gameboy-lcd.o: $(gameboy)/lcd/lcd.cpp $(call rwildcard,$(gameboy)/lcd/)
|
||||
obj/gameboy-cheat.o: $(gameboy)/cheat/cheat.cpp $(call rwildcard,$(gameboy)/cheat/)
|
@@ -1,129 +0,0 @@
|
||||
#ifdef APU_CPP
|
||||
|
||||
void APU::Master::run() {
|
||||
static int16_t volume[] = {
|
||||
-16384, -14336, -12288, -10240, -8192, -6144, -4096, -2048,
|
||||
+2048, +4096, +6144, +8192, +10240, +12288, +14336, +16384,
|
||||
};
|
||||
|
||||
if(enable == false) {
|
||||
center = 0;
|
||||
left = 0;
|
||||
right = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
signed sample = 0, channels;
|
||||
sample += apu.square1.output;
|
||||
sample += apu.square2.output;
|
||||
sample += apu.wave.output;
|
||||
sample += apu.noise.output;
|
||||
sample >>= 2;
|
||||
center = volume[sample];
|
||||
|
||||
sample = 0;
|
||||
channels = 0;
|
||||
if(channel1_left_enable) { sample += apu.square1.output; channels++; }
|
||||
if(channel2_left_enable) { sample += apu.square2.output; channels++; }
|
||||
if(channel3_left_enable) { sample += apu.wave.output; channels++; }
|
||||
if(channel4_left_enable) { sample += apu.noise.output; channels++; }
|
||||
if(channels) sample /= channels;
|
||||
left = volume[sample];
|
||||
|
||||
switch(left_volume) {
|
||||
case 0: left >>= 3; break; // 12.5%
|
||||
case 1: left >>= 2; break; // 25.0%
|
||||
case 2: left = (left >> 2) + (left >> 3); break; // 37.5%
|
||||
case 3: left >>= 1; break; // 50.0%
|
||||
case 4: left = (left >> 1) + (left >> 3); break; // 62.5%
|
||||
case 5: left -= (left >> 2); break; // 75.0%
|
||||
case 6: left -= (left >> 3); break; // 87.5%
|
||||
//case 7: break; //100.0%
|
||||
}
|
||||
|
||||
sample = 0;
|
||||
channels = 0;
|
||||
if(channel1_right_enable) { sample += apu.square1.output; channels++; }
|
||||
if(channel2_right_enable) { sample += apu.square2.output; channels++; }
|
||||
if(channel3_right_enable) { sample += apu.wave.output; channels++; }
|
||||
if(channel4_right_enable) { sample += apu.noise.output; channels++; }
|
||||
if(channels) sample /= channels;
|
||||
right = volume[sample];
|
||||
|
||||
switch(right_volume) {
|
||||
case 0: right >>= 3; break; // 12.5%
|
||||
case 1: right >>= 2; break; // 25.0%
|
||||
case 2: right = (right >> 2) + (right >> 3); break; // 37.5%
|
||||
case 3: right >>= 1; break; // 50.0%
|
||||
case 4: right = (right >> 1) + (right >> 3); break; // 62.5%
|
||||
case 5: right -= (right >> 2); break; // 75.0%
|
||||
case 6: right -= (right >> 3); break; // 87.5%
|
||||
//case 7: break; //100.0%
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Master::write(unsigned r, uint8 data) {
|
||||
if(r == 0) { //$ff24 NR50
|
||||
left_in_enable = data & 0x80;
|
||||
left_volume = (data >> 4) & 7;
|
||||
right_in_enable = data & 0x08;
|
||||
right_volume = (data >> 0) & 7;
|
||||
}
|
||||
|
||||
if(r == 1) { //$ff25 NR51
|
||||
channel4_left_enable = data & 0x80;
|
||||
channel3_left_enable = data & 0x40;
|
||||
channel2_left_enable = data & 0x20;
|
||||
channel1_left_enable = data & 0x10;
|
||||
channel4_right_enable = data & 0x08;
|
||||
channel3_right_enable = data & 0x04;
|
||||
channel2_right_enable = data & 0x02;
|
||||
channel1_right_enable = data & 0x01;
|
||||
}
|
||||
|
||||
if(r == 2) { //$ff26 NR52
|
||||
enable = data & 0x80;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Master::power() {
|
||||
left_in_enable = 0;
|
||||
left_volume = 0;
|
||||
right_in_enable = 0;
|
||||
right_volume = 0;
|
||||
channel4_left_enable = 0;
|
||||
channel3_left_enable = 0;
|
||||
channel2_left_enable = 0;
|
||||
channel1_left_enable = 0;
|
||||
channel4_right_enable = 0;
|
||||
channel3_right_enable = 0;
|
||||
channel2_right_enable = 0;
|
||||
channel1_right_enable = 0;
|
||||
enable = 0;
|
||||
|
||||
center = 0;
|
||||
left = 0;
|
||||
right = 0;
|
||||
}
|
||||
|
||||
void APU::Master::serialize(serializer &s) {
|
||||
s.integer(left_in_enable);
|
||||
s.integer(left_volume);
|
||||
s.integer(right_in_enable);
|
||||
s.integer(right_volume);
|
||||
s.integer(channel4_left_enable);
|
||||
s.integer(channel3_left_enable);
|
||||
s.integer(channel2_left_enable);
|
||||
s.integer(channel1_left_enable);
|
||||
s.integer(channel4_right_enable);
|
||||
s.integer(channel3_right_enable);
|
||||
s.integer(channel2_right_enable);
|
||||
s.integer(channel1_right_enable);
|
||||
s.integer(enable);
|
||||
|
||||
s.integer(center);
|
||||
s.integer(left);
|
||||
s.integer(right);
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,140 +0,0 @@
|
||||
#include <gameboy/gameboy.hpp>
|
||||
|
||||
#include <nall/crc32.hpp>
|
||||
|
||||
#define CARTRIDGE_CPP
|
||||
namespace GameBoy {
|
||||
|
||||
#include "mbc0/mbc0.cpp"
|
||||
#include "mbc1/mbc1.cpp"
|
||||
#include "mbc2/mbc2.cpp"
|
||||
#include "mbc3/mbc3.cpp"
|
||||
#include "mbc5/mbc5.cpp"
|
||||
#include "mmm01/mmm01.cpp"
|
||||
#include "huc1/huc1.cpp"
|
||||
#include "huc3/huc3.cpp"
|
||||
#include "serialization.cpp"
|
||||
Cartridge cartridge;
|
||||
|
||||
void Cartridge::load(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);
|
||||
|
||||
//uint32_t crc = crc32_calculate(data, size);
|
||||
//print("CRC32 = ", hex<4>(crc), "\n");
|
||||
|
||||
info.mapper = Mapper::Unknown;
|
||||
info.ram = false;
|
||||
info.battery = false;
|
||||
info.rtc = false;
|
||||
info.rumble = false;
|
||||
|
||||
info.romsize = 0;
|
||||
info.ramsize = 0;
|
||||
|
||||
BML::Document document(markup);
|
||||
|
||||
auto &mapperid = document["cartridge"]["mapper"].value;
|
||||
if(mapperid == "none" ) info.mapper = Mapper::MBC0;
|
||||
if(mapperid == "MBC1" ) info.mapper = Mapper::MBC1;
|
||||
if(mapperid == "MBC2" ) info.mapper = Mapper::MBC2;
|
||||
if(mapperid == "MBC3" ) info.mapper = Mapper::MBC3;
|
||||
if(mapperid == "MBC5" ) info.mapper = Mapper::MBC5;
|
||||
if(mapperid == "MMM01") info.mapper = Mapper::MMM01;
|
||||
if(mapperid == "HuC1" ) info.mapper = Mapper::HuC1;
|
||||
if(mapperid == "HuC3" ) info.mapper = Mapper::HuC3;
|
||||
|
||||
info.rtc = document["cartridge"]["rtc"].exists();
|
||||
info.rumble = document["cartridge"]["rumble"].exists();
|
||||
|
||||
info.romsize = hex(document["cartridge"]["rom"]["size"].value);
|
||||
info.ramsize = hex(document["cartridge"]["ram"]["size"].value);
|
||||
info.battery = document["cartridge"]["ram"]["non-volatile"].exists();
|
||||
|
||||
switch(info.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;
|
||||
}
|
||||
|
||||
ramdata = new uint8_t[ramsize = info.ramsize]();
|
||||
system.load();
|
||||
|
||||
loaded = true;
|
||||
sha256 = nall::sha256(romdata, romsize);
|
||||
}
|
||||
|
||||
void Cartridge::unload() {
|
||||
if(loaded == false) return;
|
||||
|
||||
if(romdata) { delete[] romdata; romdata = 0; }
|
||||
if(ramdata) { delete[] ramdata; ramdata = 0; }
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
uint8 Cartridge::rom_read(unsigned addr) {
|
||||
if(addr >= romsize) addr %= romsize;
|
||||
return romdata[addr];
|
||||
}
|
||||
|
||||
void Cartridge::rom_write(unsigned addr, uint8 data) {
|
||||
if(addr >= romsize) addr %= romsize;
|
||||
romdata[addr] = data;
|
||||
}
|
||||
|
||||
uint8 Cartridge::ram_read(unsigned addr) {
|
||||
if(ramsize == 0) return 0x00;
|
||||
if(addr >= ramsize) addr %= ramsize;
|
||||
return ramdata[addr];
|
||||
}
|
||||
|
||||
void Cartridge::ram_write(unsigned addr, uint8 data) {
|
||||
if(ramsize == 0) return;
|
||||
if(addr >= ramsize) addr %= ramsize;
|
||||
ramdata[addr] = data;
|
||||
}
|
||||
|
||||
uint8 Cartridge::mmio_read(uint16 addr) {
|
||||
if(bootrom_enable && within<0x0000, 0x00ff>(addr)) return System::BootROM::sgb[addr];
|
||||
return mapper->mmio_read(addr);
|
||||
}
|
||||
|
||||
void Cartridge::mmio_write(uint16 addr, uint8 data) {
|
||||
if(bootrom_enable && addr == 0xff50) bootrom_enable = false;
|
||||
mapper->mmio_write(addr, data);
|
||||
}
|
||||
|
||||
void Cartridge::power() {
|
||||
bootrom_enable = true;
|
||||
|
||||
mbc0.power();
|
||||
mbc1.power();
|
||||
mbc2.power();
|
||||
mbc3.power();
|
||||
mbc5.power();
|
||||
mmm01.power();
|
||||
huc1.power();
|
||||
huc3.power();
|
||||
|
||||
for(unsigned n = 0x0000; n <= 0x7fff; n++) bus.mmio[n] = this;
|
||||
for(unsigned n = 0xa000; n <= 0xbfff; n++) bus.mmio[n] = this;
|
||||
bus.mmio[0xff50] = this;
|
||||
}
|
||||
|
||||
Cartridge::Cartridge() {
|
||||
loaded = false;
|
||||
romdata = 0;
|
||||
ramdata = 0;
|
||||
}
|
||||
|
||||
Cartridge::~Cartridge() {
|
||||
unload();
|
||||
}
|
||||
|
||||
}
|
@@ -1,53 +0,0 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
uint8 Cartridge::HuC1::mmio_read(uint16 addr) {
|
||||
if(within<0x0000, 0x3fff>(addr)) {
|
||||
return cartridge.rom_read(addr);
|
||||
}
|
||||
|
||||
if(within<0x4000, 0x7fff>(addr)) {
|
||||
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
|
||||
}
|
||||
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void Cartridge::HuC1::mmio_write(uint16 addr, uint8 data) {
|
||||
if(within<0x0000, 0x1fff>(addr)) {
|
||||
ram_enable = (data & 0x0f) == 0x0a;
|
||||
return;
|
||||
}
|
||||
|
||||
if(within<0x2000, 0x3fff>(addr)) {
|
||||
rom_select = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(within<0x4000, 0x5fff>(addr)) {
|
||||
ram_select = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(within<0x6000, 0x7fff>(addr)) {
|
||||
//unknown purpose
|
||||
return;
|
||||
}
|
||||
|
||||
if(within<0xa000, 0xbfff>(addr)) {
|
||||
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::HuC1::power() {
|
||||
ram_enable = false;
|
||||
rom_select = 0x01;
|
||||
ram_select = 0x00;
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,9 +0,0 @@
|
||||
struct HuC1 : MMIO {
|
||||
bool ram_enable; //0000-1fff
|
||||
uint8 rom_select; //2000-3fff
|
||||
uint8 ram_select; //4000-5fff
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
void power();
|
||||
} huc1;
|
@@ -1,10 +0,0 @@
|
||||
struct MBC1 : MMIO {
|
||||
bool ram_enable; //0000-1fff
|
||||
uint8 rom_select; //2000-3fff
|
||||
uint8 ram_select; //4000-5fff
|
||||
bool mode_select; //6000-7fff
|
||||
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
||||
void power();
|
||||
} mbc1;
|
@@ -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,144 +0,0 @@
|
||||
#ifdef CPU_CPP
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
status.joyp = 0x0f;
|
||||
if(status.p15 == 1 && status.p14 == 1) status.joyp -= status.mlt_req;
|
||||
if(status.p15 == 0) status.joyp &= button ^ 0x0f;
|
||||
if(status.p14 == 0) status.joyp &= dpad ^ 0x0f;
|
||||
if(status.joyp != 0x0f) interrupt_raise(Interrupt::Joypad);
|
||||
}
|
||||
|
||||
uint8 CPU::mmio_read(uint16 addr) {
|
||||
if(addr >= 0xc000 && addr <= 0xdfff) return wram[addr & 0x1fff];
|
||||
if(addr >= 0xe000 && addr <= 0xfdff) return wram[addr & 0x1fff];
|
||||
if(addr >= 0xff80 && addr <= 0xfffe) return hram[addr & 0x7f];
|
||||
|
||||
if(addr == 0xff00) { //JOYP
|
||||
return (status.p15 << 5)
|
||||
| (status.p14 << 4)
|
||||
| (status.joyp << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff01) { //SB
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
if(addr == 0xff02) { //SC
|
||||
return (status.serial_transfer << 7)
|
||||
| (status.serial_clock << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff04) { //DIV
|
||||
return status.div;
|
||||
}
|
||||
|
||||
if(addr == 0xff05) { //TIMA
|
||||
return status.tima;
|
||||
}
|
||||
|
||||
if(addr == 0xff06) { //TMA
|
||||
return status.tma;
|
||||
}
|
||||
|
||||
if(addr == 0xff07) { //TAC
|
||||
return (status.timer_enable << 2)
|
||||
| (status.timer_clock << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xff0f) { //IF
|
||||
return (status.interrupt_request_joypad << 4)
|
||||
| (status.interrupt_request_serial << 3)
|
||||
| (status.interrupt_request_timer << 2)
|
||||
| (status.interrupt_request_stat << 1)
|
||||
| (status.interrupt_request_vblank << 0);
|
||||
}
|
||||
|
||||
if(addr == 0xffff) { //IE
|
||||
return (status.interrupt_enable_joypad << 4)
|
||||
| (status.interrupt_enable_serial << 3)
|
||||
| (status.interrupt_enable_timer << 2)
|
||||
| (status.interrupt_enable_stat << 1)
|
||||
| (status.interrupt_enable_vblank << 0);
|
||||
}
|
||||
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
void CPU::mmio_write(uint16 addr, uint8 data) {
|
||||
if(addr >= 0xc000 && addr <= 0xdfff) { wram[addr & 0x1fff] = data; return; }
|
||||
if(addr >= 0xe000 && addr <= 0xfdff) { wram[addr & 0x1fff] = data; return; }
|
||||
if(addr >= 0xff80 && addr <= 0xfffe) { hram[addr & 0x7f] = data; return; }
|
||||
|
||||
if(addr == 0xff00) { //JOYP
|
||||
status.p15 = data & 0x20;
|
||||
status.p14 = data & 0x10;
|
||||
interface->joypWrite(status.p15, status.p14);
|
||||
mmio_joyp_poll();
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff01) { //SB
|
||||
status.serial_data = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff02) { //SC
|
||||
status.serial_transfer = data & 0x80;
|
||||
status.serial_clock = data & 0x01;
|
||||
if(status.serial_transfer) status.serial_bits = 8;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff04) { //DIV
|
||||
status.div = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff05) { //TIMA
|
||||
status.tima = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff06) { //TMA
|
||||
status.tma = data;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff07) { //TAC
|
||||
status.timer_enable = data & 0x04;
|
||||
status.timer_clock = data & 0x03;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xff0f) { //IF
|
||||
status.interrupt_request_joypad = data & 0x10;
|
||||
status.interrupt_request_serial = data & 0x08;
|
||||
status.interrupt_request_timer = data & 0x04;
|
||||
status.interrupt_request_stat = data & 0x02;
|
||||
status.interrupt_request_vblank = data & 0x01;
|
||||
return;
|
||||
}
|
||||
|
||||
if(addr == 0xffff) { //IE
|
||||
status.interrupt_enable_joypad = data & 0x10;
|
||||
status.interrupt_enable_serial = data & 0x08;
|
||||
status.interrupt_enable_timer = data & 0x04;
|
||||
status.interrupt_enable_stat = data & 0x02;
|
||||
status.interrupt_enable_vblank = data & 0x01;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@@ -1,3 +0,0 @@
|
||||
void mmio_joyp_poll();
|
||||
uint8 mmio_read(uint16 addr);
|
||||
void mmio_write(uint16 addr, uint8 data);
|
@@ -1,12 +0,0 @@
|
||||
void add_clocks(unsigned clocks);
|
||||
void timer_262144hz();
|
||||
void timer_65536hz();
|
||||
void timer_16384hz();
|
||||
void timer_8192hz();
|
||||
void timer_4096hz();
|
||||
|
||||
//opcode.cpp
|
||||
void op_io();
|
||||
uint8 op_read(uint16 addr);
|
||||
void op_write(uint16 addr, uint8 data);
|
||||
void cycle_edge();
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user