mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-17 21:02:04 +02:00
Compare commits
58 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
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 |
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
purify/*.o
|
||||
purify/purify
|
||||
purify/analyze-gba
|
@@ -1,19 +1,20 @@
|
||||
include nall/Makefile
|
||||
|
||||
nes := nes
|
||||
nes := nes
|
||||
snes := snes
|
||||
gameboy := gameboy
|
||||
gb := gb
|
||||
gba := gba
|
||||
|
||||
profile := accuracy
|
||||
ui := ui
|
||||
target := ui
|
||||
|
||||
# options += console
|
||||
# options += debugger
|
||||
|
||||
# compiler
|
||||
c := $(compiler) -std=gnu99
|
||||
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
|
||||
flags := -I. -O3 -fomit-frame-pointer
|
||||
link :=
|
||||
link := -s
|
||||
objects := libco
|
||||
|
||||
# profile-guided optimization mode
|
||||
@@ -29,17 +30,18 @@ endif
|
||||
|
||||
# platform
|
||||
ifeq ($(platform),x)
|
||||
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
|
||||
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 = \
|
||||
@@ -59,6 +61,7 @@ all: build;
|
||||
obj/libco.o: libco/libco.c libco/*
|
||||
|
||||
include $(ui)/Makefile
|
||||
flags := $(flags) $(foreach o,$(call strupper,$(options)),-D$o)
|
||||
|
||||
# targets
|
||||
clean:
|
||||
@@ -90,7 +93,8 @@ sync:
|
||||
rm -r phoenix/nall
|
||||
rm -r phoenix/test
|
||||
|
||||
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
|
||||
archive:
|
||||
if [ -f bsnes.tar.bz2 ]; then rm bsnes.tar.bz2; fi
|
||||
tar -cjf bsnes.tar.bz2 `ls`
|
||||
|
||||
help:;
|
||||
|
130
bsnes/base/base.hpp
Executable file
130
bsnes/base/base.hpp
Executable file
@@ -0,0 +1,130 @@
|
||||
#ifndef BASE_HPP
|
||||
#define BASE_HPP
|
||||
|
||||
static const char Version[] = "088";
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/algorithm.hpp>
|
||||
#include <nall/any.hpp>
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/bitarray.hpp>
|
||||
#include <nall/dl.hpp>
|
||||
#include <nall/dsp.hpp>
|
||||
#include <nall/endian.hpp>
|
||||
#include <nall/file.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/moduloarray.hpp>
|
||||
#include <nall/priorityqueue.hpp>
|
||||
#include <nall/property.hpp>
|
||||
#include <nall/random.hpp>
|
||||
#include <nall/serializer.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
#include <nall/varint.hpp>
|
||||
#include <nall/vector.hpp>
|
||||
using namespace nall;
|
||||
|
||||
//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
|
@@ -13304,7 +13304,7 @@
|
||||
<code>SZSGUGSA</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infintie time</description>
|
||||
<description>Infinite time</description>
|
||||
<code>SZSVGTVG</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
@@ -30509,6 +30509,10 @@
|
||||
<description>Infinite Super Bombs</description>
|
||||
<code>SZKTYPVG</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Walk through walls</description>
|
||||
<code>EONGELAP</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>5 Super Bombs on pick-up</description>
|
||||
<code>IAVTPSZA</code>
|
||||
@@ -44061,10 +44065,9 @@
|
||||
<description>Infinite lives</description>
|
||||
<code>DD67-4468</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>One hit kills</description>
|
||||
<code>DDB3-C764</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="One hit kills">
|
||||
<name>DDB3-C764</name>
|
||||
<cheat enable="false">
|
||||
<description>Small magic power-up adds 3 instead of 1</description>
|
||||
<code>D7C0-37A7</code>
|
||||
@@ -44639,6 +44642,37 @@
|
||||
<code>7EEA00:FF</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="0a8cd5101f849ccd4e40d55fdc4edce914b2825b69eb76ec31cf53b59719e79e">
|
||||
<name>Advanced Dungeons & Dragons - Eye of the Beholder (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite HP</description>
|
||||
<code>8285-6D2C</code>
|
||||
<code>82DE-049B</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>No waiting to hit again</description>
|
||||
<code>828D-A798</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>One hit kills (works for enemies also)</description>
|
||||
<code>CBAA-A726</code>
|
||||
<code>3CA2-AD96</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Pick a lawful, human male fighter and he will be at Level 8</description>
|
||||
<code>D68B-A474</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Pick a lawful, human male fighter and he will be at level 6</description>
|
||||
<code>D18B-A474</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>999,999 EXP 1st class</description>
|
||||
<code>7E0533:3F</code>
|
||||
<code>7E0534:42</code>
|
||||
<code>7E0535:0F</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="8083307f3f4b7df9e5bf53d5f25877c2e548f0f677540d4ee62d60ccca3098f8">
|
||||
<name>Adventures of Batman & Robin, The (USA)</name>
|
||||
<cheat enable="false">
|
||||
@@ -44922,10 +44956,6 @@
|
||||
<description>Infinite lives - both players</description>
|
||||
<code>8229-37A0</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Don't lose power-ups when you die - both players</description>
|
||||
<code>8229-37D0</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infinite Bombs for American F-18 - P1</description>
|
||||
<code>8237-47A1</code>
|
||||
@@ -44958,6 +44988,24 @@
|
||||
<description>Infinite Bombs for British IDS - P2</description>
|
||||
<code>823D-C769</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Don't lose power-ups when you die - both players</description>
|
||||
<code>8229-37D0</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Hit anywhere + one hit kills</description>
|
||||
<code>40CA-14DD</code>
|
||||
<code>40CA-17AD</code>
|
||||
<code>40C2-1FDD</code>
|
||||
<code>40C2-14DD</code>
|
||||
<code>40C2-17DD</code>
|
||||
<code>6DC5-1F0D</code>
|
||||
<code>6DCB-1DAD</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>One hit kills</description>
|
||||
<code>6DCB-1DAD</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infinite lives (alt)</description>
|
||||
<code>7FB78C:02</code>
|
||||
@@ -45946,7 +45994,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="05eb897d7696555790591c431c9d55a43ff9a1c12162443c17c5fcddfa5eb3c5">
|
||||
<name>Alien vs. Predator (USA)</name>
|
||||
<name>Alien vs Predator (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility</description>
|
||||
<code>1D3B-0FAD</code>
|
||||
@@ -51189,7 +51237,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="9a064b67f522b75b82d0857519c0e33b4dbbe494c2ef79a44fdc913d605d0b26">
|
||||
<name>Choplifter III - Rescue & Survive (USA)</name>
|
||||
<name>Choplifter III - Rescue-Survive (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Have all weapons and infinte ammo</description>
|
||||
<code>DD67-CDA7</code>
|
||||
@@ -52078,7 +52126,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="5536cea2da39f2572abe3b0fcf71f8fcd981376b470b174969772aae4a7a1845">
|
||||
<name>College Football USA '97 - The Road to New Orleans (USA)</name>
|
||||
<name>College Football USA 97 (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Always 1st down</description>
|
||||
<code>7E1836:05</code>
|
||||
@@ -55934,7 +55982,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="1a79d51a2ad7dd4848205a07ff8e5d873b155dc420de5e52158c9bab935e05c3">
|
||||
<name>Dream TV (USA)</name>
|
||||
<name>Dream T.V. (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Almost infinite health</description>
|
||||
<code>8FA6-3DA8</code>
|
||||
@@ -57016,37 +57064,6 @@
|
||||
<code>D461-D4A7</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="0a8cd5101f849ccd4e40d55fdc4edce914b2825b69eb76ec31cf53b59719e79e">
|
||||
<name>Eye of the Beholder (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite HP</description>
|
||||
<code>8285-6D2C</code>
|
||||
<code>82DE-049B</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>No waiting to hit again</description>
|
||||
<code>828D-A798</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>One hit kills (works for enemies also)</description>
|
||||
<code>CBAA-A726</code>
|
||||
<code>3CA2-AD96</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Pick a lawful, human male fighter and he will be at Level 8</description>
|
||||
<code>D68B-A474</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Pick a lawful, human male fighter and he will be at level 6</description>
|
||||
<code>D18B-A474</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>999,999 EXP 1st class</description>
|
||||
<code>7E0533:3F</code>
|
||||
<code>7E0534:42</code>
|
||||
<code>7E0535:0F</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="1d38e3af9e3a6409e93f4705b68c42558f558c68f3e83ef2a40e46cf560b26cc">
|
||||
<name>F1 ROC - Race of Champions (USA)</name>
|
||||
<cheat enable="false">
|
||||
@@ -62253,7 +62270,18 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="8796ca4de3aeffd3a494fe28e7d7e2aeb220ca652b43684f29e2cc94f02c20c4">
|
||||
<name>Gods (USA)</name>
|
||||
<name>Gods - The Bitmap Brothers (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility</description>
|
||||
<code>C268-3576</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Continually hit anywhere</description>
|
||||
<code>40A2-49E8</code>
|
||||
<code>40A3-4988</code>
|
||||
<code>40AF-1188</code>
|
||||
<code>6DAD-1988</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Shields last until at least end of the world (disable if you get stuck)</description>
|
||||
<code>1DE7-31E8</code>
|
||||
@@ -62605,7 +62633,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="f921297c361f16ad3f1257e91829638fc795f9323172015d7237ed648c8f7515">
|
||||
<name>GunForce - Battle Fire Engulfed Terror Island (USA)</name>
|
||||
<name>GunForce (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility</description>
|
||||
<code>69BD-A4A1</code>
|
||||
@@ -63215,7 +63243,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="48a3ac52e2c9128abc2dc60e07817a51898e8a93be0d51d6f541a8635263a089">
|
||||
<name>Home Improvement (USA)</name>
|
||||
<name>Home Improvement - Power Tool Pursuit! (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility</description>
|
||||
<code>6D62-4B82</code>
|
||||
@@ -66016,18 +66044,18 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="5eff7c27f69b3ebc1ec1294ffcd1debf3512bc3e6c1c75fbdc5e778dcaaba1c9">
|
||||
<name>Jurassic Park II - The Chaos Continues (USA) (En,Fr,De,It)</name>
|
||||
<name>Jurassic Park Part 2 - The Chaos Continues (USA) (En,Fr,De,It)</name>
|
||||
<cheat enable="false">
|
||||
<description>Almost invincible</description>
|
||||
<code>8BEB-C22D</code>
|
||||
<code>8B65-1C67</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Invincibiltiy after one hit until you enter a new screen</description>
|
||||
<description>Invincibility after one hit until you enter a new screen</description>
|
||||
<code>82B6-C704</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infintie health against some larger dinosaurs</description>
|
||||
<description>Infinite health against some larger dinosaurs</description>
|
||||
<code>6DED-3A9D</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
@@ -66144,7 +66172,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="05152bcf9bf086e7bcdbfa7dd8edfe2085f1339c4d7e193e0071c49a10471ef4">
|
||||
<name>Kablooey (USA)</name>
|
||||
<name>Ka-blooey (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite lives</description>
|
||||
<code>C261-0F0D</code>
|
||||
@@ -67515,7 +67543,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="6638b5541059814d4c34574e5e277ef613aebf81c91d3def557a7642fb5840e1">
|
||||
<name>King of Dragons, The (USA)</name>
|
||||
<name>King of Dragons (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility - both players</description>
|
||||
<code>ED76-E4AF</code>
|
||||
@@ -68864,6 +68892,15 @@
|
||||
<code>40C6-C469</code>
|
||||
<code>4081-1F69</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Hit anywhere</description>
|
||||
<code>40E4-37A0</code>
|
||||
<code>40ED-37D0</code>
|
||||
<code>40E0-3DD0</code>
|
||||
<code>40E0-3FA0</code>
|
||||
<code>6DED-3FD0</code>
|
||||
<code>6DEF-3DA0</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infinite health - P1</description>
|
||||
<code>7E130D:08</code>
|
||||
@@ -75159,7 +75196,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="49dd77b310b476c875633335243553be59ecfb0bffae62e46f2e53ff05c20fcd">
|
||||
<name>Marvel Super Heroes - War of the Gems (USA)</name>
|
||||
<name>Marvel Super Heroes in War of the Gems (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite health</description>
|
||||
<code>B9D9-74D4</code>
|
||||
@@ -78156,7 +78193,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="f292598ac462fdfcd32ad9b6b35ac01d4bab020391dff92bfe94780ec604289a">
|
||||
<name>Musya (USA)</name>
|
||||
<name>Musya - The Classic Japanese Tale of Horror (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility (blinking)</description>
|
||||
<code>7E103C:0A</code>
|
||||
@@ -79477,7 +79514,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="55f3432a130085c112d65aa6443c41eb7a8aeec59aad2c2b4b2ac536b604b449">
|
||||
<name>NHLPA Hockey '93 (USA)</name>
|
||||
<name>NHLPA Hockey 93 (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Period clock runs faster</description>
|
||||
<code>F160-4776</code>
|
||||
@@ -79942,7 +79979,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="3c109e50b91ec6df3bb8509778ae544c99433fb40dda9b801178dfe513053618">
|
||||
<name>Ninjawarriors, The (USA)</name>
|
||||
<name>Ninjawarriors (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility</description>
|
||||
<code>EDB0-D768</code>
|
||||
@@ -80450,7 +80487,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="190742792a950a112f893cba0e083eb787cf24293f698967defff929635ba0e7">
|
||||
<name>Operation Logic Bomb (USA)</name>
|
||||
<name>Operation Logic Bomb - The Ultimate Search & Destroy (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite health</description>
|
||||
<code>C2B5-4DD0</code>
|
||||
@@ -81407,7 +81444,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="14ad9d2fb8e6bb0f49bc9e53f3c472177653d1c24102169ade308a2fab8a8888">
|
||||
<name>Parodius da! - Shinwa kara Owarai e (Japan)</name>
|
||||
<name>Parodius Da! - Shinwa kara Owarai e (Japan)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite lives</description>
|
||||
<code>7E0098:03</code>
|
||||
@@ -81540,7 +81577,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="0663330bc061f4b768fa1806610878ef6e6cf546f36041ae087c8e55703693b8">
|
||||
<name>Phalanx - The Enforce Fighter A-144 (USA)</name>
|
||||
<name>Phalanx (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite health</description>
|
||||
<code>3C21-AD0F</code>
|
||||
@@ -82657,7 +82694,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="04ca1a481093c4a7e12f18b33697d6e05e50e30e0f5b1655aa265abd14719bba">
|
||||
<name>Prince of Persia 2 - The Shadow & The Flame (USA)</name>
|
||||
<name>Prince of Persia 2 (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite health</description>
|
||||
<code>7E0957:03</code>
|
||||
@@ -83724,7 +83761,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="4d6c7d6d2693d8d43bafaff7582f9a94885362dadd9ee4012bbbdce1ba10c30e">
|
||||
<name>R-Type III - The Third Lightning (USA)</name>
|
||||
<name>R-Type III (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility</description>
|
||||
<code>DD62-33DD</code>
|
||||
@@ -83747,7 +83784,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="edf990e502c646a2fe83fcd1d359ca0ed5003ace06cb4c3de5a51a0c56d6ec54">
|
||||
<name>R.P.M. Racing (USA)</name>
|
||||
<name>Radical Psycho Machine Racing (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Sturdy tires are free</description>
|
||||
<code>DDB8-0465</code>
|
||||
@@ -86788,7 +86825,22 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="c73757eea258e169e506eaef989227a59918060f94117917f338183db14c50b6">
|
||||
<name>Shaq Fu (USA)</name>
|
||||
<name>Shaq-Fu (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility - P1</description>
|
||||
<code>0D8B-8DDD</code>
|
||||
<code>2D8B-8D6D</code>
|
||||
<code>3D86-87AD</code>
|
||||
<code>4D8B-8D0D</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Hit anywhere - P1</description>
|
||||
<code>0D85-87DD</code>
|
||||
<code>3D85-84AD</code>
|
||||
<code>4D85-870D</code>
|
||||
<code>DD86-8D6D</code>
|
||||
<code>FA86-8D0D</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infinite continues - Duel Mode</description>
|
||||
<code>C269-EF0D</code>
|
||||
@@ -86994,7 +87046,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="c0bd1b378337c32047a6b7122a3813beb646e496fbdb1fa5c87ab9856271e4c5">
|
||||
<name>SimAnt (USA)</name>
|
||||
<name>SimAnt - The Electronic Ant Colony (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Always have maximum energy</description>
|
||||
<code>DD88-0D0A</code>
|
||||
@@ -87041,7 +87093,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="bf74c58e4190faca2f3a967dc190fe529d13887d1262b72e057b5353e43cf67f">
|
||||
<name>SimCity 2000 (USA)</name>
|
||||
<name>SimCity 2000 - The Ultimate City Simulator (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Start with $99,999,999 on all the maps except the Land Of Freedom</description>
|
||||
<code>EEF3-8700</code>
|
||||
@@ -88207,7 +88259,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="dc5353ddc350816619230f25f8c51bddabf7438e6dfba21662eb1c4794856735">
|
||||
<name>Space Invaders - The Original Game (USA)</name>
|
||||
<name>Space Invaders (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite lives</description>
|
||||
<code>CB6F-37A9</code>
|
||||
@@ -88482,7 +88534,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="32d0f1ca5b91fd9b2caf81422fb9e8fb30bc091f0b2a429b9269dd307fcba4fd">
|
||||
<name>Spawn (USA)</name>
|
||||
<name>Spawn - The Video Game (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility after one hit (invisible)</description>
|
||||
<code>C203-84D1</code>
|
||||
@@ -88495,10 +88547,9 @@
|
||||
<description>Infinite health</description>
|
||||
<code>C208-87D1</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Don't blink after getting hit</description>
|
||||
<code>FDDB-5FB9</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="Don't blink after getting hit">
|
||||
<name>FDDB-5FB9</name>
|
||||
<cheat enable="false">
|
||||
<description>Falling doesn't use life points</description>
|
||||
<code>C2F4-7FD1</code>
|
||||
@@ -88856,7 +88907,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="2701e94631ae1c43ca0ccef2b50bc0341a4111b31b885fa372ab5b4a49b06942">
|
||||
<name>SpellCraft (USA) (Proto)</name>
|
||||
<name>SpellCraft - Aspects of Valor (USA) (Proto)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite health</description>
|
||||
<code>7E018D:99</code>
|
||||
@@ -89240,6 +89291,33 @@
|
||||
<code>7E14D9:03</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="2c0bac12a7866fad1cb306da768a201c12f2520332df1ef51cba1576db21ff06">
|
||||
<name>Star Fox - Super Weekend (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite Shield</description>
|
||||
<code>7E0396:28</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infinite Bombs</description>
|
||||
<code>7E15AF:04</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infinite time (minutes)</description>
|
||||
<code>7EF0DA:09</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infinite time (seconds tens)</description>
|
||||
<code>7EF0DC:09</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infinite time (seconds ones)</description>
|
||||
<code>7EF0DB:09</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Have Double Blaster</description>
|
||||
<code>7E14D9:01</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="82e39dfbb3e4fe5c28044e80878392070c618b298dd5a267e5ea53c8f72cc548">
|
||||
<name>Star Fox (USA) (Rev 2)</name>
|
||||
<cheat enable="false">
|
||||
@@ -89267,33 +89345,6 @@
|
||||
<code>7E0396:35</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="2c0bac12a7866fad1cb306da768a201c12f2520332df1ef51cba1576db21ff06">
|
||||
<name>Star Fox (USA) (Super Weekend Competition)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite Shield</description>
|
||||
<code>7E0396:28</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infinite Bombs</description>
|
||||
<code>7E15AF:04</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infinite time (minutes)</description>
|
||||
<code>7EF0DA:09</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infinite time (seconds tens)</description>
|
||||
<code>7EF0DC:09</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infinite time (seconds ones)</description>
|
||||
<code>7EF0DB:09</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Have Double Blaster</description>
|
||||
<code>7E14D9:01</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="efae37be832d0ea1490784d57bef00761a8bf0b5bcef9c23f558e063441c3876">
|
||||
<name>Star Ocean (Japan)</name>
|
||||
<cheat enable="false">
|
||||
@@ -99206,7 +99257,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="4f500da19dbb1557a7bc0ce14437098c1402478d573fb569303b81c011f86fbf">
|
||||
<name>Tom & Jerry (USA)</name>
|
||||
<name>Tom and Jerry (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility</description>
|
||||
<code>7E14C8:33</code>
|
||||
@@ -99870,7 +99921,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="7a6e5da46b026900fba4584a32ad40d940b9ecf9fccfb11f96a205a914014784">
|
||||
<name>Toys (USA)</name>
|
||||
<name>Toys - Let the Toy Wars begin! (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite lives</description>
|
||||
<code>C261-3D7B</code>
|
||||
@@ -100419,7 +100470,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="11659bd8dd620d50400d16042aeb2d0ddb00c7183fc1ecb95b1a34f07db0431b">
|
||||
<name>Ultima VI - The False Prophet (USA)</name>
|
||||
<name>Ultima - The False Prophet (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite time</description>
|
||||
<code>89C8-D76D</code>
|
||||
@@ -100630,7 +100681,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="a31af0e39afb55bbc92a5543b504327fbe7e8cd0a5e08626976bed7b65376737">
|
||||
<name>Ultima VII - The Black Gate (USA)</name>
|
||||
<name>Ultima - The Black Gate (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite health</description>
|
||||
<code>7E1CFA:E4</code>
|
||||
@@ -100730,7 +100781,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="e9fae4c2e171a1fc4f2bd800abd9e42750aaf7a4db9e40c5b9142e15029500bd">
|
||||
<name>Ultraman - Towards the Future (USA)</name>
|
||||
<name>Ultraman (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite health</description>
|
||||
<code>4ABA-67DF</code>
|
||||
@@ -100840,7 +100891,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="64bc4707f422661a66618088887e2363a5f896ea683c58984fffd96dd21ab5f0">
|
||||
<name>Uncharted Waters - New Horizons (USA)</name>
|
||||
<name>New Horizons (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Joao starts with 156 Leadership instead of 78</description>
|
||||
<code>BA6D-873D</code>
|
||||
@@ -102087,6 +102138,19 @@
|
||||
</cartridge>
|
||||
<cartridge sha256="c8f159e2625ac8078535c06857ea28475706da45df494de8e46f50888272cf71">
|
||||
<name>Wild Guns (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility</description>
|
||||
<code>4061-DFAA</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Hit anywhere</description>
|
||||
<code>40B4-0DDF</code>
|
||||
<code>40B4-070F</code>
|
||||
<code>40B7-0FAF</code>
|
||||
<code>40BD-AD0A</code>
|
||||
<code>40BF-0F6F</code>
|
||||
<code>6DBE-DDDF</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Infinite specials</description>
|
||||
<code>7E1FA0:05</code>
|
||||
@@ -102284,7 +102348,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="9c2b458e8fda5cb437a4c6d28fb430e45c4cfef98420c40546b8e08563a4fc7d">
|
||||
<name>Wolfenstein 3D (USA)</name>
|
||||
<name>Wolfenstein 3-D (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Infinite health</description>
|
||||
<code>C2CC-5D64</code>
|
||||
@@ -102355,6 +102419,22 @@
|
||||
<description>No enemies</description>
|
||||
<code>69E9-3A1F</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Hit anywhere + one hit kills</description>
|
||||
<code>4060-340D</code>
|
||||
<code>4060-3D6D</code>
|
||||
<code>4061-37DD</code>
|
||||
<code>4061-3DDD</code>
|
||||
<code>4064-3D6D</code>
|
||||
<code>4064-376D</code>
|
||||
<code>4065-37AD</code>
|
||||
<code>4069-340D</code>
|
||||
<code>4069-3D6D</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>One hit kills</description>
|
||||
<code>4065-37AD</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility</description>
|
||||
<code>7E00B8:FF</code>
|
||||
@@ -102764,6 +102844,11 @@
|
||||
<description>Infinite lives - mission mode</description>
|
||||
<code>C2D7-5F64</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Hit anywhere</description>
|
||||
<code>40E3-5766</code>
|
||||
<code>6DEF-84D6</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Easy specials (press X)</description>
|
||||
<code>3344-E701</code>
|
||||
@@ -103210,7 +103295,7 @@
|
||||
<code>EE8E-00BE</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Invincibiltiy (alt)</description>
|
||||
<description>Invincibility (alt)</description>
|
||||
<code>7E1AFC:08</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
@@ -104426,6 +104511,14 @@
|
||||
<code>BE6-C4E-3BE</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="a52b036d637b59950749de679208785480b8ad2d5e95c0ea2a6f638750cc645e">
|
||||
<name>Amazing Spider-Man, The (USA, Europe)</name>
|
||||
<cheat enable="false">
|
||||
<description>Hit anywhere</description>
|
||||
<code>008-EAD-809</code>
|
||||
<code>008-8CD-7FF</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="3f0688ed9219c44ce133647f0668cde50fdcba7ed8f04c34c3a0fc5ce596bfe5">
|
||||
<name>Asteroids (USA, Europe)</name>
|
||||
<cheat enable="false">
|
||||
@@ -108178,7 +108271,7 @@
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="fedb0c8100987cb466c116a3ac3a6572675b6aa721a7a8930cec1ae39f677bc6">
|
||||
<name>Mickey's Chase (USA)</name>
|
||||
<name>Mickey's Dangerous Chase (USA)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility after first hit</description>
|
||||
<code>001-A8E-E6E</code>
|
||||
@@ -109521,6 +109614,13 @@
|
||||
<code>FA8-C1B-E61</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="2b059983d79efc5a4f77b41a4efbad68c65ae259715dc008f20a3c11226a943b">
|
||||
<name>R-Type II (Europe)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility</description>
|
||||
<code>C9F-3FE-081</code>
|
||||
</cheat>
|
||||
</cartridge>
|
||||
<cartridge sha256="e0a07f84198e062c9ba8d617ef15679ba044f96510e5c62309ea1f743499a2c9">
|
||||
<name>Samurai Shodown (USA, Europe) (SGB Enhanced)</name>
|
||||
<cheat enable="false">
|
||||
@@ -110642,6 +110742,44 @@
|
||||
</cartridge>
|
||||
<cartridge sha256="8730c69cb2aa82260ac07257e0e29d61f598de2f8fa3e65da1d694790fa5db16">
|
||||
<name>Street Fighter II (USA, Europe) (Rev A) (SGB Enhanced)</name>
|
||||
<cheat enable="false">
|
||||
<description>Invincibility</description>
|
||||
<code>18A-8ED-4CA</code>
|
||||
<code>18A-9FD-4CA</code>
|
||||
<code>18A-D2D-4CA</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Hit anywhere - P1</description>
|
||||
<code>00A-B1D-F7E</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Hit anywhere - P2</description>
|
||||
<code>00A-8FD-F7E</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Fireball kills</description>
|
||||
<code>885-838-B3E</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Nobody takes damage from anything but throws/grabs</description>
|
||||
<code>009-249-3B7</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Opponent can't win any normal rounds</description>
|
||||
<code>00B-938-E6D</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Allows you to select a higher skill level</description>
|
||||
<code>093-85A-F72</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Fireball doesn't do any damage</description>
|
||||
<code>005-838-B3E</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Fireball does more damage</description>
|
||||
<code>405-838-B3E</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Player one starts with very little energy</description>
|
||||
<code>013-F89-2AB</code>
|
||||
@@ -110686,30 +110824,6 @@
|
||||
<description>Start with seconds on the timer</description>
|
||||
<code>884-619-6E7</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Allows you to select a higher skill level</description>
|
||||
<code>093-85A-F72</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Opponent can't win any normal rounds</description>
|
||||
<code>00B-938-E6D</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Fireball doesn't do any damage</description>
|
||||
<code>005-838-B3E</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Fireball does more damage</description>
|
||||
<code>405-838-B3E</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Fireball kills</description>
|
||||
<code>885-838-B3E</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Nobody takes damage from anything but throws/grabs</description>
|
||||
<code>009-249-3B7</code>
|
||||
</cheat>
|
||||
<cheat enable="false">
|
||||
<description>Ryu - Foot sweep doesn't do any damage</description>
|
||||
<code>005-0B8-A2A</code>
|
||||
|
3812
bsnes/data/laevateinn.hpp
Executable file
3812
bsnes/data/laevateinn.hpp
Executable file
File diff suppressed because it is too large
Load Diff
@@ -1,16 +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 gameboy-video
|
||||
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/)
|
||||
obj/gameboy-video.o: $(gameboy)/video/video.cpp $(call rwildcard,$(gameboy)/video/)
|
@@ -1,108 +0,0 @@
|
||||
#ifndef GAMEBOY_HPP
|
||||
#define GAMEBOY_HPP
|
||||
|
||||
namespace GameBoy {
|
||||
namespace Info {
|
||||
static const char Name[] = "bgameboy";
|
||||
static const unsigned SerializerVersion = 3;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bgameboy - Game Boy, Super Game Boy, and Game Boy Color emulator
|
||||
author: byuu
|
||||
license: GPLv3
|
||||
project started: 2010-12-27
|
||||
*/
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
#include <nall/platform.hpp>
|
||||
#include <nall/property.hpp>
|
||||
#include <nall/random.hpp>
|
||||
#include <nall/serializer.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/varint.hpp>
|
||||
using namespace nall;
|
||||
|
||||
namespace GameBoy {
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
typedef uint_t< 1> uint1;
|
||||
typedef uint_t< 2> uint2;
|
||||
typedef uint_t< 3> uint3;
|
||||
typedef uint_t< 4> uint4;
|
||||
typedef uint_t< 5> uint5;
|
||||
typedef uint_t< 6> uint6;
|
||||
typedef uint_t< 7> uint7;
|
||||
|
||||
typedef uint_t< 9> uint9;
|
||||
typedef uint_t<10> uint10;
|
||||
typedef uint_t<11> uint11;
|
||||
typedef uint_t<12> uint12;
|
||||
typedef uint_t<13> uint13;
|
||||
typedef uint_t<14> uint14;
|
||||
typedef uint_t<15> uint15;
|
||||
|
||||
typedef uint_t<17> uint17;
|
||||
typedef uint_t<18> uint18;
|
||||
typedef uint_t<19> uint19;
|
||||
typedef uint_t<20> uint20;
|
||||
typedef uint_t<21> uint21;
|
||||
typedef uint_t<22> uint22;
|
||||
typedef uint_t<23> uint23;
|
||||
typedef uint_t<24> uint24;
|
||||
typedef uint_t<25> uint25;
|
||||
typedef uint_t<26> uint26;
|
||||
typedef uint_t<27> uint27;
|
||||
typedef uint_t<28> uint28;
|
||||
typedef uint_t<29> uint29;
|
||||
typedef uint_t<30> uint30;
|
||||
typedef uint_t<31> uint31;
|
||||
|
||||
struct Processor {
|
||||
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 Processor() : thread(nullptr) {
|
||||
}
|
||||
|
||||
inline ~Processor() {
|
||||
if(thread) co_delete(thread);
|
||||
}
|
||||
};
|
||||
|
||||
#include <gameboy/memory/memory.hpp>
|
||||
#include <gameboy/system/system.hpp>
|
||||
#include <gameboy/scheduler/scheduler.hpp>
|
||||
#include <gameboy/cartridge/cartridge.hpp>
|
||||
#include <gameboy/cpu/cpu.hpp>
|
||||
#include <gameboy/apu/apu.hpp>
|
||||
#include <gameboy/lcd/lcd.hpp>
|
||||
#include <gameboy/cheat/cheat.hpp>
|
||||
#include <gameboy/video/video.hpp>
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,135 +0,0 @@
|
||||
#ifdef SYSTEM_CPP
|
||||
|
||||
//SHA256 = 4bf5021be357ce523a59ac5f4efff5d6371ae50112a6db0adf4a75916ad760a9
|
||||
const uint8_t System::BootROM::cgb[2048] = {
|
||||
0x31,0xfe,0xff,0x3e,0x02,0xc3,0x7c,0x00,0xd3,0x00,0x98,0xa0,0x12,0xd3,0x00,0x80,
|
||||
0x00,0x40,0x1e,0x53,0xd0,0x00,0x1f,0x42,0x1c,0x00,0x14,0x2a,0x4d,0x19,0x8c,0x7e,
|
||||
0x00,0x7c,0x31,0x6e,0x4a,0x45,0x52,0x4a,0x00,0x00,0xff,0x53,0x1f,0x7c,0xff,0x03,
|
||||
0x1f,0x00,0xff,0x1f,0xa7,0x00,0xef,0x1b,0x1f,0x00,0xef,0x1b,0x00,0x7c,0x00,0x00,
|
||||
0xff,0x03,0xce,0xed,0x66,0x66,0xcc,0x0d,0x00,0x0b,0x03,0x73,0x00,0x83,0x00,0x0c,
|
||||
0x00,0x0d,0x00,0x08,0x11,0x1f,0x88,0x89,0x00,0x0e,0xdc,0xcc,0x6e,0xe6,0xdd,0xdd,
|
||||
0xd9,0x99,0xbb,0xbb,0x67,0x63,0x6e,0x0e,0xec,0xcc,0xdd,0xdc,0x99,0x9f,0xbb,0xb9,
|
||||
0x33,0x3e,0x3c,0x42,0xb9,0xa5,0xb9,0xa5,0x42,0x3c,0x58,0x43,0xe0,0x70,0x3e,0xfc,
|
||||
0xe0,0x47,0xcd,0x75,0x02,0xcd,0x00,0x02,0x26,0xd0,0xcd,0x03,0x02,0x21,0x00,0xfe,
|
||||
0x0e,0xa0,0xaf,0x22,0x0d,0x20,0xfc,0x11,0x04,0x01,0x21,0x10,0x80,0x4c,0x1a,0xe2,
|
||||
0x0c,0xcd,0xc6,0x03,0xcd,0xc7,0x03,0x13,0x7b,0xfe,0x34,0x20,0xf1,0x11,0x72,0x00,
|
||||
0x06,0x08,0x1a,0x13,0x22,0x23,0x05,0x20,0xf9,0xcd,0xf0,0x03,0x3e,0x01,0xe0,0x4f,
|
||||
0x3e,0x91,0xe0,0x40,0x21,0xb2,0x98,0x06,0x4e,0x0e,0x44,0xcd,0x91,0x02,0xaf,0xe0,
|
||||
0x4f,0x0e,0x80,0x21,0x42,0x00,0x06,0x18,0xf2,0x0c,0xbe,0x20,0xfe,0x23,0x05,0x20,
|
||||
0xf7,0x21,0x34,0x01,0x06,0x19,0x78,0x86,0x2c,0x05,0x20,0xfb,0x86,0x20,0xfe,0xcd,
|
||||
0x1c,0x03,0x18,0x02,0x00,0x00,0xcd,0xd0,0x05,0xaf,0xe0,0x70,0x3e,0x11,0xe0,0x50,
|
||||
0x21,0x00,0x80,0xaf,0x22,0xcb,0x6c,0x28,0xfb,0xc9,0x2a,0x12,0x13,0x0d,0x20,0xfa,
|
||||
0xc9,0xe5,0x21,0x0f,0xff,0xcb,0x86,0xcb,0x46,0x28,0xfc,0xe1,0xc9,0x11,0x00,0xff,
|
||||
0x21,0x03,0xd0,0x0e,0x0f,0x3e,0x30,0x12,0x3e,0x20,0x12,0x1a,0x2f,0xa1,0xcb,0x37,
|
||||
0x47,0x3e,0x10,0x12,0x1a,0x2f,0xa1,0xb0,0x4f,0x7e,0xa9,0xe6,0xf0,0x47,0x2a,0xa9,
|
||||
0xa1,0xb0,0x32,0x47,0x79,0x77,0x3e,0x30,0x12,0xc9,0x3e,0x80,0xe0,0x68,0xe0,0x6a,
|
||||
0x0e,0x6b,0x2a,0xe2,0x05,0x20,0xfb,0x4a,0x09,0x43,0x0e,0x69,0x2a,0xe2,0x05,0x20,
|
||||
0xfb,0xc9,0xc5,0xd5,0xe5,0x21,0x00,0xd8,0x06,0x01,0x16,0x3f,0x1e,0x40,0xcd,0x4a,
|
||||
0x02,0xe1,0xd1,0xc1,0xc9,0x3e,0x80,0xe0,0x26,0xe0,0x11,0x3e,0xf3,0xe0,0x12,0xe0,
|
||||
0x25,0x3e,0x77,0xe0,0x24,0x21,0x30,0xff,0xaf,0x0e,0x10,0x22,0x2f,0x0d,0x20,0xfb,
|
||||
0xc9,0xcd,0x11,0x02,0xcd,0x62,0x02,0x79,0xfe,0x38,0x20,0x14,0xe5,0xaf,0xe0,0x4f,
|
||||
0x21,0xa7,0x99,0x3e,0x38,0x22,0x3c,0xfe,0x3f,0x20,0xfa,0x3e,0x01,0xe0,0x4f,0xe1,
|
||||
0xc5,0xe5,0x21,0x43,0x01,0xcb,0x7e,0xcc,0x89,0x05,0xe1,0xc1,0xcd,0x11,0x02,0x79,
|
||||
0xd6,0x30,0xd2,0x06,0x03,0x79,0xfe,0x01,0xca,0x06,0x03,0x7d,0xfe,0xd1,0x28,0x21,
|
||||
0xc5,0x06,0x03,0x0e,0x01,0x16,0x03,0x7e,0xe6,0xf8,0xb1,0x22,0x15,0x20,0xf8,0x0c,
|
||||
0x79,0xfe,0x06,0x20,0xf0,0x11,0x11,0x00,0x19,0x05,0x20,0xe7,0x11,0xa1,0xff,0x19,
|
||||
0xc1,0x04,0x78,0x1e,0x83,0xfe,0x62,0x28,0x06,0x1e,0xc1,0xfe,0x64,0x20,0x07,0x7b,
|
||||
0xe0,0x13,0x3e,0x87,0xe0,0x14,0xfa,0x02,0xd0,0xfe,0x00,0x28,0x0a,0x3d,0xea,0x02,
|
||||
0xd0,0x79,0xfe,0x01,0xca,0x91,0x02,0x0d,0xc2,0x91,0x02,0xc9,0x0e,0x26,0xcd,0x4a,
|
||||
0x03,0xcd,0x11,0x02,0xcd,0x62,0x02,0x0d,0x20,0xf4,0xcd,0x11,0x02,0x3e,0x01,0xe0,
|
||||
0x4f,0xcd,0x3e,0x03,0xcd,0x41,0x03,0xaf,0xe0,0x4f,0xcd,0x3e,0x03,0xc9,0x21,0x08,
|
||||
0x00,0x11,0x51,0xff,0x0e,0x05,0xcd,0x0a,0x02,0xc9,0xc5,0xd5,0xe5,0x21,0x40,0xd8,
|
||||
0x0e,0x20,0x7e,0xe6,0x1f,0xfe,0x1f,0x28,0x01,0x3c,0x57,0x2a,0x07,0x07,0x07,0xe6,
|
||||
0x07,0x47,0x3a,0x07,0x07,0x07,0xe6,0x18,0xb0,0xfe,0x1f,0x28,0x01,0x3c,0x0f,0x0f,
|
||||
0x0f,0x47,0xe6,0xe0,0xb2,0x22,0x78,0xe6,0x03,0x5f,0x7e,0x0f,0x0f,0xe6,0x1f,0xfe,
|
||||
0x1f,0x28,0x01,0x3c,0x07,0x07,0xb3,0x22,0x0d,0x20,0xc7,0xe1,0xd1,0xc1,0xc9,0x0e,
|
||||
0x00,0x1a,0xe6,0xf0,0xcb,0x49,0x28,0x02,0xcb,0x37,0x47,0x23,0x7e,0xb0,0x22,0x1a,
|
||||
0xe6,0x0f,0xcb,0x49,0x20,0x02,0xcb,0x37,0x47,0x23,0x7e,0xb0,0x22,0x13,0xcb,0x41,
|
||||
0x28,0x0d,0xd5,0x11,0xf8,0xff,0xcb,0x49,0x28,0x03,0x11,0x08,0x00,0x19,0xd1,0x0c,
|
||||
0x79,0xfe,0x18,0x20,0xcc,0xc9,0x47,0xd5,0x16,0x04,0x58,0xcb,0x10,0x17,0xcb,0x13,
|
||||
0x17,0x15,0x20,0xf6,0xd1,0x22,0x23,0x22,0x23,0xc9,0x3e,0x19,0xea,0x10,0x99,0x21,
|
||||
0x2f,0x99,0x0e,0x0c,0x3d,0x28,0x08,0x32,0x0d,0x20,0xf9,0x2e,0x0f,0x18,0xf3,0xc9,
|
||||
0x3e,0x01,0xe0,0x4f,0xcd,0x00,0x02,0x11,0x07,0x06,0x21,0x80,0x80,0x0e,0xc0,0x1a,
|
||||
0x22,0x23,0x22,0x23,0x13,0x0d,0x20,0xf7,0x11,0x04,0x01,0xcd,0x8f,0x03,0x01,0xa8,
|
||||
0xff,0x09,0xcd,0x8f,0x03,0x01,0xf8,0xff,0x09,0x11,0x72,0x00,0x0e,0x08,0x23,0x1a,
|
||||
0x22,0x13,0x0d,0x20,0xf9,0x21,0xc2,0x98,0x06,0x08,0x3e,0x08,0x0e,0x10,0x22,0x0d,
|
||||
0x20,0xfc,0x11,0x10,0x00,0x19,0x05,0x20,0xf3,0xaf,0xe0,0x4f,0x21,0xc2,0x98,0x3e,
|
||||
0x08,0x22,0x3c,0xfe,0x18,0x20,0x02,0x2e,0xe2,0xfe,0x28,0x20,0x03,0x21,0x02,0x99,
|
||||
0xfe,0x38,0x20,0xed,0x21,0xd8,0x08,0x11,0x40,0xd8,0x06,0x08,0x3e,0xff,0x12,0x13,
|
||||
0x12,0x13,0x0e,0x02,0xcd,0x0a,0x02,0x3e,0x00,0x12,0x13,0x12,0x13,0x13,0x13,0x05,
|
||||
0x20,0xea,0xcd,0x62,0x02,0x21,0x4b,0x01,0x7e,0xfe,0x33,0x20,0x0b,0x2e,0x44,0x1e,
|
||||
0x30,0x2a,0xbb,0x20,0x49,0x1c,0x18,0x04,0x2e,0x4b,0x1e,0x01,0x2a,0xbb,0x20,0x3e,
|
||||
0x2e,0x34,0x01,0x10,0x00,0x2a,0x80,0x47,0x0d,0x20,0xfa,0xea,0x00,0xd0,0x21,0xc7,
|
||||
0x06,0x0e,0x00,0x2a,0xb8,0x28,0x08,0x0c,0x79,0xfe,0x4f,0x20,0xf6,0x18,0x1f,0x79,
|
||||
0xd6,0x41,0x38,0x1c,0x21,0x16,0x07,0x16,0x00,0x5f,0x19,0xfa,0x37,0x01,0x57,0x7e,
|
||||
0xba,0x28,0x0d,0x11,0x0e,0x00,0x19,0x79,0x83,0x4f,0xd6,0x5e,0x38,0xed,0x0e,0x00,
|
||||
0x21,0x33,0x07,0x06,0x00,0x09,0x7e,0xe6,0x1f,0xea,0x08,0xd0,0x7e,0xe6,0xe0,0x07,
|
||||
0x07,0x07,0xea,0x0b,0xd0,0xcd,0xe9,0x04,0xc9,0x11,0x91,0x07,0x21,0x00,0xd9,0xfa,
|
||||
0x0b,0xd0,0x47,0x0e,0x1e,0xcb,0x40,0x20,0x02,0x13,0x13,0x1a,0x22,0x20,0x02,0x1b,
|
||||
0x1b,0xcb,0x48,0x20,0x02,0x13,0x13,0x1a,0x22,0x13,0x13,0x20,0x02,0x1b,0x1b,0xcb,
|
||||
0x50,0x28,0x05,0x1b,0x2b,0x1a,0x22,0x13,0x1a,0x22,0x13,0x0d,0x20,0xd7,0x21,0x00,
|
||||
0xd9,0x11,0x00,0xda,0xcd,0x64,0x05,0xc9,0x21,0x12,0x00,0xfa,0x05,0xd0,0x07,0x07,
|
||||
0x06,0x00,0x4f,0x09,0x11,0x40,0xd8,0x06,0x08,0xe5,0x0e,0x02,0xcd,0x0a,0x02,0x13,
|
||||
0x13,0x13,0x13,0x13,0x13,0xe1,0x05,0x20,0xf0,0x11,0x42,0xd8,0x0e,0x02,0xcd,0x0a,
|
||||
0x02,0x11,0x4a,0xd8,0x0e,0x02,0xcd,0x0a,0x02,0x2b,0x2b,0x11,0x44,0xd8,0x0e,0x02,
|
||||
0xcd,0x0a,0x02,0xc9,0x0e,0x60,0x2a,0xe5,0xc5,0x21,0xe8,0x07,0x06,0x00,0x4f,0x09,
|
||||
0x0e,0x08,0xcd,0x0a,0x02,0xc1,0xe1,0x0d,0x20,0xec,0xc9,0xfa,0x08,0xd0,0x11,0x18,
|
||||
0x00,0x3c,0x3d,0x28,0x03,0x19,0x20,0xfa,0xc9,0xcd,0x1d,0x02,0x78,0xe6,0xff,0x28,
|
||||
0x0f,0x21,0xe4,0x08,0x06,0x00,0x2a,0xb9,0x28,0x08,0x04,0x78,0xfe,0x0c,0x20,0xf6,
|
||||
0x18,0x2d,0x78,0xea,0x05,0xd0,0x3e,0x1e,0xea,0x02,0xd0,0x11,0x0b,0x00,0x19,0x56,
|
||||
0x7a,0xe6,0x1f,0x5f,0x21,0x08,0xd0,0x3a,0x22,0x7b,0x77,0x7a,0xe6,0xe0,0x07,0x07,
|
||||
0x07,0x5f,0x21,0x0b,0xd0,0x3a,0x22,0x7b,0x77,0xcd,0xe9,0x04,0xcd,0x28,0x05,0xc9,
|
||||
0xcd,0x11,0x02,0xfa,0x43,0x01,0xcb,0x7f,0x28,0x04,0xe0,0x4c,0x18,0x28,0x3e,0x04,
|
||||
0xe0,0x4c,0x3e,0x01,0xe0,0x6c,0x21,0x00,0xda,0xcd,0x7b,0x05,0x06,0x10,0x16,0x00,
|
||||
0x1e,0x08,0xcd,0x4a,0x02,0x21,0x7a,0x00,0xfa,0x00,0xd0,0x47,0x0e,0x02,0x2a,0xb8,
|
||||
0xcc,0xda,0x03,0x0d,0x20,0xf8,0xc9,0x01,0x0f,0x3f,0x7e,0xff,0xff,0xc0,0x00,0xc0,
|
||||
0xf0,0xf1,0x03,0x7c,0xfc,0xfe,0xfe,0x03,0x07,0x07,0x0f,0xe0,0xe0,0xf0,0xf0,0x1e,
|
||||
0x3e,0x7e,0xfe,0x0f,0x0f,0x1f,0x1f,0xff,0xff,0x00,0x00,0x01,0x01,0x01,0x03,0xff,
|
||||
0xff,0xe1,0xe0,0xc0,0xf0,0xf9,0xfb,0x1f,0x7f,0xf8,0xe0,0xf3,0xfd,0x3e,0x1e,0xe0,
|
||||
0xf0,0xf9,0x7f,0x3e,0x7c,0xf8,0xe0,0xf8,0xf0,0xf0,0xf8,0x00,0x00,0x7f,0x7f,0x07,
|
||||
0x0f,0x9f,0xbf,0x9e,0x1f,0xff,0xff,0x0f,0x1e,0x3e,0x3c,0xf1,0xfb,0x7f,0x7f,0xfe,
|
||||
0xde,0xdf,0x9f,0x1f,0x3f,0x3e,0x3c,0xf8,0xf8,0x00,0x00,0x03,0x03,0x07,0x07,0xff,
|
||||
0xff,0xc1,0xc0,0xf3,0xe7,0xf7,0xf3,0xc0,0xc0,0xc0,0xc0,0x1f,0x1f,0x1e,0x3e,0x3f,
|
||||
0x1f,0x3e,0x3e,0x80,0x00,0x00,0x00,0x7c,0x1f,0x07,0x00,0x0f,0xff,0xfe,0x00,0x7c,
|
||||
0xf8,0xf0,0x00,0x1f,0x0f,0x0f,0x00,0x7c,0xf8,0xf8,0x00,0x3f,0x3e,0x1c,0x00,0x0f,
|
||||
0x0f,0x0f,0x00,0x7c,0xff,0xff,0x00,0x00,0xf8,0xf8,0x00,0x07,0x0f,0x0f,0x00,0x81,
|
||||
0xff,0xff,0x00,0xf3,0xe1,0x80,0x00,0xe0,0xff,0x7f,0x00,0xfc,0xf0,0xc0,0x00,0x3e,
|
||||
0x7c,0x7c,0x00,0x00,0x00,0x00,0x00,0x00,0x88,0x16,0x36,0xd1,0xdb,0xf2,0x3c,0x8c,
|
||||
0x92,0x3d,0x5c,0x58,0xc9,0x3e,0x70,0x1d,0x59,0x69,0x19,0x35,0xa8,0x14,0xaa,0x75,
|
||||
0x95,0x99,0x34,0x6f,0x15,0xff,0x97,0x4b,0x90,0x17,0x10,0x39,0xf7,0xf6,0xa2,0x49,
|
||||
0x4e,0x43,0x68,0xe0,0x8b,0xf0,0xce,0x0c,0x29,0xe8,0xb7,0x86,0x9a,0x52,0x01,0x9d,
|
||||
0x71,0x9c,0xbd,0x5d,0x6d,0x67,0x3f,0x6b,0xb3,0x46,0x28,0xa5,0xc6,0xd3,0x27,0x61,
|
||||
0x18,0x66,0x6a,0xbf,0x0d,0xf4,0x42,0x45,0x46,0x41,0x41,0x52,0x42,0x45,0x4b,0x45,
|
||||
0x4b,0x20,0x52,0x2d,0x55,0x52,0x41,0x52,0x20,0x49,0x4e,0x41,0x49,0x4c,0x49,0x43,
|
||||
0x45,0x20,0x52,0x7c,0x08,0x12,0xa3,0xa2,0x07,0x87,0x4b,0x20,0x12,0x65,0xa8,0x16,
|
||||
0xa9,0x86,0xb1,0x68,0xa0,0x87,0x66,0x12,0xa1,0x30,0x3c,0x12,0x85,0x12,0x64,0x1b,
|
||||
0x07,0x06,0x6f,0x6e,0x6e,0xae,0xaf,0x6f,0xb2,0xaf,0xb2,0xa8,0xab,0x6f,0xaf,0x86,
|
||||
0xae,0xa2,0xa2,0x12,0xaf,0x13,0x12,0xa1,0x6e,0xaf,0xaf,0xad,0x06,0x4c,0x6e,0xaf,
|
||||
0xaf,0x12,0x7c,0xac,0xa8,0x6a,0x6e,0x13,0xa0,0x2d,0xa8,0x2b,0xac,0x64,0xac,0x6d,
|
||||
0x87,0xbc,0x60,0xb4,0x13,0x72,0x7c,0xb5,0xae,0xae,0x7c,0x7c,0x65,0xa2,0x6c,0x64,
|
||||
0x85,0x80,0xb0,0x40,0x88,0x20,0x68,0xde,0x00,0x70,0xde,0x20,0x78,0x20,0x20,0x38,
|
||||
0x20,0xb0,0x90,0x20,0xb0,0xa0,0xe0,0xb0,0xc0,0x98,0xb6,0x48,0x80,0xe0,0x50,0x1e,
|
||||
0x1e,0x58,0x20,0xb8,0xe0,0x88,0xb0,0x10,0x20,0x00,0x10,0x20,0xe0,0x18,0xe0,0x18,
|
||||
0x00,0x18,0xe0,0x20,0xa8,0xe0,0x20,0x18,0xe0,0x00,0x20,0x18,0xd8,0xc8,0x18,0xe0,
|
||||
0x00,0xe0,0x40,0x28,0x28,0x28,0x18,0xe0,0x60,0x20,0x18,0xe0,0x00,0x00,0x08,0xe0,
|
||||
0x18,0x30,0xd0,0xd0,0xd0,0x20,0xe0,0xe8,0xff,0x7f,0xbf,0x32,0xd0,0x00,0x00,0x00,
|
||||
0x9f,0x63,0x79,0x42,0xb0,0x15,0xcb,0x04,0xff,0x7f,0x31,0x6e,0x4a,0x45,0x00,0x00,
|
||||
0xff,0x7f,0xef,0x1b,0x00,0x02,0x00,0x00,0xff,0x7f,0x1f,0x42,0xf2,0x1c,0x00,0x00,
|
||||
0xff,0x7f,0x94,0x52,0x4a,0x29,0x00,0x00,0xff,0x7f,0xff,0x03,0x2f,0x01,0x00,0x00,
|
||||
0xff,0x7f,0xef,0x03,0xd6,0x01,0x00,0x00,0xff,0x7f,0xb5,0x42,0xc8,0x3d,0x00,0x00,
|
||||
0x74,0x7e,0xff,0x03,0x80,0x01,0x00,0x00,0xff,0x67,0xac,0x77,0x13,0x1a,0x6b,0x2d,
|
||||
0xd6,0x7e,0xff,0x4b,0x75,0x21,0x00,0x00,0xff,0x53,0x5f,0x4a,0x52,0x7e,0x00,0x00,
|
||||
0xff,0x4f,0xd2,0x7e,0x4c,0x3a,0xe0,0x1c,0xed,0x03,0xff,0x7f,0x5f,0x25,0x00,0x00,
|
||||
0x6a,0x03,0x1f,0x02,0xff,0x03,0xff,0x7f,0xff,0x7f,0xdf,0x01,0x12,0x01,0x00,0x00,
|
||||
0x1f,0x23,0x5f,0x03,0xf2,0x00,0x09,0x00,0xff,0x7f,0xea,0x03,0x1f,0x01,0x00,0x00,
|
||||
0x9f,0x29,0x1a,0x00,0x0c,0x00,0x00,0x00,0xff,0x7f,0x7f,0x02,0x1f,0x00,0x00,0x00,
|
||||
0xff,0x7f,0xe0,0x03,0x06,0x02,0x20,0x01,0xff,0x7f,0xeb,0x7e,0x1f,0x00,0x00,0x7c,
|
||||
0xff,0x7f,0xff,0x3f,0x00,0x7e,0x1f,0x00,0xff,0x7f,0xff,0x03,0x1f,0x00,0x00,0x00,
|
||||
0xff,0x03,0x1f,0x00,0x0c,0x00,0x00,0x00,0xff,0x7f,0x3f,0x03,0x93,0x01,0x00,0x00,
|
||||
0x00,0x00,0x00,0x42,0x7f,0x03,0xff,0x7f,0xff,0x7f,0x8c,0x7e,0x00,0x7c,0x00,0x00,
|
||||
0xff,0x7f,0xef,0x1b,0x80,0x61,0x00,0x00,0xff,0x7f,0x00,0x7c,0xe0,0x03,0x1f,0x7c,
|
||||
0x1f,0x00,0xff,0x03,0x40,0x41,0x42,0x20,0x21,0x22,0x80,0x81,0x82,0x10,0x11,0x12,
|
||||
0x12,0xb0,0x79,0xb8,0xad,0x16,0x17,0x07,0xba,0x05,0x7c,0x13,0x00,0x00,0x00,0x00,
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,23 +0,0 @@
|
||||
#ifdef SYSTEM_CPP
|
||||
|
||||
//SHA256 = cf053eccb4ccafff9e67339d4e78e98dce7d1ed59be819d2a1ba2232c6fce1c7
|
||||
const uint8_t System::BootROM::dmg[256] = {
|
||||
0x31,0xfe,0xff,0xaf,0x21,0xff,0x9f,0x32,0xcb,0x7c,0x20,0xfb,0x21,0x26,0xff,0x0e,
|
||||
0x11,0x3e,0x80,0x32,0xe2,0x0c,0x3e,0xf3,0xe2,0x32,0x3e,0x77,0x77,0x3e,0xfc,0xe0,
|
||||
0x47,0x11,0x04,0x01,0x21,0x10,0x80,0x1a,0xcd,0x95,0x00,0xcd,0x96,0x00,0x13,0x7b,
|
||||
0xfe,0x34,0x20,0xf3,0x11,0xd8,0x00,0x06,0x08,0x1a,0x13,0x22,0x23,0x05,0x20,0xf9,
|
||||
0x3e,0x19,0xea,0x10,0x99,0x21,0x2f,0x99,0x0e,0x0c,0x3d,0x28,0x08,0x32,0x0d,0x20,
|
||||
0xf9,0x2e,0x0f,0x18,0xf3,0x67,0x3e,0x64,0x57,0xe0,0x42,0x3e,0x91,0xe0,0x40,0x04,
|
||||
0x1e,0x02,0x0e,0x0c,0xf0,0x44,0xfe,0x90,0x20,0xfa,0x0d,0x20,0xf7,0x1d,0x20,0xf2,
|
||||
0x0e,0x13,0x24,0x7c,0x1e,0x83,0xfe,0x62,0x28,0x06,0x1e,0xc1,0xfe,0x64,0x20,0x06,
|
||||
0x7b,0xe2,0x0c,0x3e,0x87,0xe2,0xf0,0x42,0x90,0xe0,0x42,0x15,0x20,0xd2,0x05,0x20,
|
||||
0x4f,0x16,0x20,0x18,0xcb,0x4f,0x06,0x04,0xc5,0xcb,0x11,0x17,0xc1,0xcb,0x11,0x17,
|
||||
0x05,0x20,0xf5,0x22,0x23,0x22,0x23,0xc9,0xce,0xed,0x66,0x66,0xcc,0x0d,0x00,0x0b,
|
||||
0x03,0x73,0x00,0x83,0x00,0x0c,0x00,0x0d,0x00,0x08,0x11,0x1f,0x88,0x89,0x00,0x0e,
|
||||
0xdc,0xcc,0x6e,0xe6,0xdd,0xdd,0xd9,0x99,0xbb,0xbb,0x67,0x63,0x6e,0x0e,0xec,0xcc,
|
||||
0xdd,0xdc,0x99,0x9f,0xbb,0xb9,0x33,0x3e,0x3c,0x42,0xb9,0xa5,0xb9,0xa5,0x42,0x3c,
|
||||
0x21,0x04,0x01,0x11,0xa8,0x00,0x1a,0x13,0xbe,0x20,0xfe,0x23,0x7d,0xfe,0x34,0x20,
|
||||
0xf5,0x06,0x19,0x78,0x86,0x23,0x05,0x20,0xfb,0x86,0x20,0xfe,0x3e,0x01,0xe0,0x50,
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,23 +0,0 @@
|
||||
#ifdef SYSTEM_CPP
|
||||
|
||||
//SHA256 = 0e4ddff32fc9d1eeaae812a157dd246459b00c9e14f2f61751f661f32361e360
|
||||
const uint8_t System::BootROM::sgb[256] = {
|
||||
0x31,0xfe,0xff,0x3e,0x30,0xe0,0x00,0xaf,0x21,0xff,0x9f,0x32,0xcb,0x7c,0x20,0xfb,
|
||||
0x21,0x26,0xff,0x0e,0x11,0x3e,0x80,0x32,0xe2,0x0c,0x3e,0xf3,0xe2,0x32,0x3e,0x77,
|
||||
0x77,0x3e,0xfc,0xe0,0x47,0x21,0x5f,0xc0,0x0e,0x08,0xaf,0x32,0x0d,0x20,0xfc,0x11,
|
||||
0x4f,0x01,0x3e,0xfb,0x0e,0x06,0xf5,0x06,0x00,0x1a,0x1b,0x32,0x80,0x47,0x0d,0x20,
|
||||
0xf8,0x32,0xf1,0x32,0x0e,0x0e,0xd6,0x02,0xfe,0xef,0x20,0xea,0x11,0x04,0x01,0x21,
|
||||
0x10,0x80,0x1a,0xcd,0xd3,0x00,0xcd,0xd4,0x00,0x13,0x7b,0xfe,0x34,0x20,0xf3,0x11,
|
||||
0xe6,0x00,0x06,0x08,0x1a,0x13,0x22,0x23,0x05,0x20,0xf9,0x3e,0x19,0xea,0x10,0x99,
|
||||
0x21,0x2f,0x99,0x0e,0x0c,0x3d,0x28,0x08,0x32,0x0d,0x20,0xf9,0x2e,0x0f,0x18,0xf3,
|
||||
0x3e,0x91,0xe0,0x40,0x21,0x00,0xc0,0x0e,0x00,0x3e,0x00,0xe2,0x3e,0x30,0xe2,0x06,
|
||||
0x10,0x1e,0x08,0x2a,0x57,0xcb,0x42,0x3e,0x10,0x20,0x02,0x3e,0x20,0xe2,0x3e,0x30,
|
||||
0xe2,0xcb,0x1a,0x1d,0x20,0xef,0x05,0x20,0xe8,0x3e,0x20,0xe2,0x3e,0x30,0xe2,0xcd,
|
||||
0xc2,0x00,0x7d,0xfe,0x60,0x20,0xd2,0x0e,0x13,0x3e,0xc1,0xe2,0x0c,0x3e,0x07,0xe2,
|
||||
0x18,0x3a,0x16,0x04,0xf0,0x44,0xfe,0x90,0x20,0xfa,0x1e,0x00,0x1d,0x20,0xfd,0x15,
|
||||
0x20,0xf2,0xc9,0x4f,0x06,0x04,0xc5,0xcb,0x11,0x17,0xc1,0xcb,0x11,0x17,0x05,0x20,
|
||||
0xf5,0x22,0x23,0x22,0x23,0xc9,0x3c,0x42,0xb9,0xa5,0xb9,0xa5,0x42,0x3c,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x01,0xe0,0x50,
|
||||
};
|
||||
|
||||
#endif
|
18
bsnes/gb/Makefile
Executable file
18
bsnes/gb/Makefile
Executable file
@@ -0,0 +1,18 @@
|
||||
options += gameboy
|
||||
|
||||
gb_objects := gb-interface gb-system gb-scheduler
|
||||
gb_objects += gb-memory gb-cartridge
|
||||
gb_objects += gb-cpu gb-apu gb-lcd
|
||||
gb_objects += gb-cheat gb-video
|
||||
objects += $(gb_objects)
|
||||
|
||||
obj/gb-interface.o: $(gb)/interface/interface.cpp $(call rwildcard,$(gb)/interface/)
|
||||
obj/gb-system.o: $(gb)/system/system.cpp $(call rwildcard,$(gb)/system/)
|
||||
obj/gb-scheduler.o: $(gb)/scheduler/scheduler.cpp $(call rwildcard,$(gb)/scheduler/)
|
||||
obj/gb-cartridge.o: $(gb)/cartridge/cartridge.cpp $(call rwildcard,$(gb)/cartridge/)
|
||||
obj/gb-memory.o: $(gb)/memory/memory.cpp $(call rwildcard,$(gb)/memory/)
|
||||
obj/gb-cpu.o: $(gb)/cpu/cpu.cpp $(call rwildcard,$(gb)/cpu/)
|
||||
obj/gb-apu.o: $(gb)/apu/apu.cpp $(call rwildcard,$(gb)/apu/)
|
||||
obj/gb-lcd.o: $(gb)/lcd/lcd.cpp $(call rwildcard,$(gb)/lcd/)
|
||||
obj/gb-cheat.o: $(gb)/cheat/cheat.cpp $(call rwildcard,$(gb)/cheat/)
|
||||
obj/gb-video.o: $(gb)/video/video.cpp $(call rwildcard,$(gb)/video/)
|
@@ -1,7 +1,7 @@
|
||||
#include <gameboy/gameboy.hpp>
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
#define APU_CPP
|
||||
namespace GameBoy {
|
||||
namespace GB {
|
||||
|
||||
#include "square1/square1.cpp"
|
||||
#include "square2/square2.cpp"
|
||||
@@ -49,7 +49,7 @@ void APU::main() {
|
||||
interface->audioSample(master.center, master.left, master.right);
|
||||
|
||||
clock += 1 * cpu.frequency;
|
||||
if(clock >= 0) co_switch(scheduler.active_thread = cpu.thread);
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(scheduler.active_thread = cpu.thread);
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
struct APU : Processor, MMIO {
|
||||
struct APU : Thread, MMIO {
|
||||
#include "square1/square1.hpp"
|
||||
#include "square2/square2.hpp"
|
||||
#include "wave/wave.hpp"
|
@@ -20,36 +20,18 @@ void APU::Master::run() {
|
||||
if(channel2_left_enable) sample += apu.square2.output;
|
||||
if(channel3_left_enable) sample += apu.wave.output;
|
||||
if(channel4_left_enable) sample += apu.noise.output;
|
||||
left = (sample * 512) - 16384;
|
||||
|
||||
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 = (sample * 512) - 16384;
|
||||
sample = (sample * (left_volume + 1)) / 8;
|
||||
left = sample;
|
||||
|
||||
sample = 0;
|
||||
if(channel1_right_enable) sample += apu.square1.output;
|
||||
if(channel2_right_enable) sample += apu.square2.output;
|
||||
if(channel3_right_enable) sample += apu.wave.output;
|
||||
if(channel4_right_enable) sample += apu.noise.output;
|
||||
right = (sample * 512) - 16384;
|
||||
|
||||
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%
|
||||
}
|
||||
sample = (sample * 512) - 16384;
|
||||
sample = (sample * (right_volume + 1)) / 8;
|
||||
right = sample;
|
||||
}
|
||||
|
||||
void APU::Master::write(unsigned r, uint8 data) {
|
@@ -20,8 +20,11 @@ void APU::Noise::run() {
|
||||
}
|
||||
|
||||
void APU::Noise::clock_length() {
|
||||
if(counter && length) {
|
||||
if(--length == 0) enable = false;
|
||||
//if(counter && length) {
|
||||
// if(--length == 0) enable = false;
|
||||
//}
|
||||
if(enable && counter) {
|
||||
if(++length == 0) enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +38,8 @@ void APU::Noise::clock_envelope() {
|
||||
|
||||
void APU::Noise::write(unsigned r, uint8 data) {
|
||||
if(r == 1) { //$ff20 NR41
|
||||
length = 64 - (data & 0x3f);
|
||||
//length = 64 - (data & 0x3f);
|
||||
length = data & 0x3f;
|
||||
}
|
||||
|
||||
if(r == 2) { //$ff21 NR42
|
||||
@@ -62,7 +66,7 @@ void APU::Noise::write(unsigned r, uint8 data) {
|
||||
lfsr = ~0U;
|
||||
envelope_period = envelope_frequency;
|
||||
volume = envelope_volume;
|
||||
if(length == 0) length = 64;
|
||||
//if(length == 0) length = 64;
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,7 +10,7 @@ struct Noise {
|
||||
bool counter;
|
||||
|
||||
int16 output;
|
||||
unsigned length;
|
||||
uint6 length;
|
||||
uint3 envelope_period;
|
||||
uint4 volume;
|
||||
unsigned period;
|
@@ -1,7 +1,7 @@
|
||||
#ifdef APU_CPP
|
||||
|
||||
void APU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(mmio_data);
|
||||
s.integer(sequencer_base);
|
@@ -39,8 +39,12 @@ void APU::Square1::sweep(bool update) {
|
||||
}
|
||||
|
||||
void APU::Square1::clock_length() {
|
||||
if(counter && length) {
|
||||
if(--length == 0) enable = false;
|
||||
//if(counter && length) {
|
||||
// if(--length == 0) enable = false;
|
||||
//}
|
||||
|
||||
if(counter && enable) {
|
||||
if(++length == 0) enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +74,8 @@ void APU::Square1::write(unsigned r, uint8 data) {
|
||||
|
||||
if(r == 1) { //$ff11 NR11
|
||||
duty = data >> 6;
|
||||
length = 64 - (data & 0x3f);
|
||||
//length = 64 - (data & 0x3f);
|
||||
length = data & 0x3f;
|
||||
}
|
||||
|
||||
if(r == 2) { //$ff12 NR12
|
||||
@@ -91,6 +96,7 @@ void APU::Square1::write(unsigned r, uint8 data) {
|
||||
|
||||
if(initialize) {
|
||||
enable = dac_enable();
|
||||
period = 4 * (2048 - frequency);
|
||||
envelope_period = envelope_frequency;
|
||||
volume = envelope_volume;
|
||||
frequency_shadow = frequency;
|
||||
@@ -98,11 +104,9 @@ void APU::Square1::write(unsigned r, uint8 data) {
|
||||
sweep_enable = sweep_period || sweep_shift;
|
||||
sweep_negate = false;
|
||||
if(sweep_shift) sweep(0);
|
||||
if(length == 0) length = 64;
|
||||
//if(length == 0) length = 64;
|
||||
}
|
||||
}
|
||||
|
||||
period = 4 * (2048 - frequency);
|
||||
}
|
||||
|
||||
void APU::Square1::power() {
|
@@ -6,7 +6,7 @@ struct Square1 {
|
||||
uint3 sweep_shift;
|
||||
bool sweep_negate;
|
||||
uint2 duty;
|
||||
unsigned length;
|
||||
uint6 length;
|
||||
uint4 envelope_volume;
|
||||
bool envelope_direction;
|
||||
uint3 envelope_frequency;
|
@@ -23,8 +23,12 @@ void APU::Square2::run() {
|
||||
}
|
||||
|
||||
void APU::Square2::clock_length() {
|
||||
if(counter && length) {
|
||||
if(--length == 0) enable = false;
|
||||
//if(counter && length) {
|
||||
// if(--length == 0) enable = false;
|
||||
//}
|
||||
|
||||
if(counter && enable) {
|
||||
if(++length == 0) enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +43,8 @@ void APU::Square2::clock_envelope() {
|
||||
void APU::Square2::write(unsigned r, uint8 data) {
|
||||
if(r == 1) { //$ff16 NR21
|
||||
duty = data >> 6;
|
||||
length = 64 - (data & 0x3f);
|
||||
//length = 64 - (data & 0x3f);
|
||||
length = (data & 0x3f);
|
||||
}
|
||||
|
||||
if(r == 2) { //$ff17 NR22
|
||||
@@ -60,13 +65,12 @@ void APU::Square2::write(unsigned r, uint8 data) {
|
||||
|
||||
if(initialize) {
|
||||
enable = dac_enable();
|
||||
period = 4 * (2048 - frequency);
|
||||
envelope_period = envelope_frequency;
|
||||
volume = envelope_volume;
|
||||
if(length == 0) length = 64;
|
||||
//if(length == 0) length = 64;
|
||||
}
|
||||
}
|
||||
|
||||
period = 4 * (2048 - frequency);
|
||||
}
|
||||
|
||||
void APU::Square2::power() {
|
@@ -2,7 +2,7 @@ struct Square2 {
|
||||
bool enable;
|
||||
|
||||
uint2 duty;
|
||||
unsigned length;
|
||||
uint6 length;
|
||||
uint4 envelope_volume;
|
||||
bool envelope_direction;
|
||||
uint3 envelope_frequency;
|
@@ -13,8 +13,11 @@ void APU::Wave::run() {
|
||||
}
|
||||
|
||||
void APU::Wave::clock_length() {
|
||||
if(counter && length) {
|
||||
if(--length == 0) enable = false;
|
||||
//if(counter && length) {
|
||||
// if(--length == 0) enable = false;
|
||||
//}
|
||||
if(enable && counter) {
|
||||
if(++length == 0) enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +28,8 @@ void APU::Wave::write(unsigned r, uint8 data) {
|
||||
}
|
||||
|
||||
if(r == 1) { //$ff1b NR31
|
||||
length = 256 - data;
|
||||
//length = 256 - data;
|
||||
length = data;
|
||||
}
|
||||
|
||||
if(r == 2) { //$ff1c NR32
|
||||
@@ -48,12 +52,11 @@ void APU::Wave::write(unsigned r, uint8 data) {
|
||||
|
||||
if(initialize) {
|
||||
enable = dac_enable;
|
||||
period = 2 * (2048 - frequency);
|
||||
pattern_offset = 0;
|
||||
if(length == 0) length = 256;
|
||||
//if(length == 0) length = 256;
|
||||
}
|
||||
}
|
||||
|
||||
period = 2 * (2048 - frequency);
|
||||
}
|
||||
|
||||
void APU::Wave::write_pattern(unsigned p, uint8 data) {
|
@@ -8,7 +8,7 @@ struct Wave {
|
||||
uint8 pattern[32];
|
||||
|
||||
int16 output;
|
||||
unsigned length;
|
||||
uint8 length;
|
||||
unsigned period;
|
||||
uint5 pattern_offset;
|
||||
uint4 pattern_sample;
|
@@ -1,9 +1,7 @@
|
||||
#include <gameboy/gameboy.hpp>
|
||||
|
||||
#include <nall/crc32.hpp>
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
#define CARTRIDGE_CPP
|
||||
namespace GameBoy {
|
||||
namespace GB {
|
||||
|
||||
#include "mbc0/mbc0.cpp"
|
||||
#include "mbc1/mbc1.cpp"
|
||||
@@ -21,35 +19,36 @@ void Cartridge::load(System::Revision revision, const string &markup, const uint
|
||||
romdata = allocate<uint8>(romsize = size, 0xff);
|
||||
if(data) memcpy(romdata, data, size);
|
||||
|
||||
info.mapper = Mapper::Unknown;
|
||||
info.ram = false;
|
||||
info.battery = false;
|
||||
info.rtc = false;
|
||||
info.rumble = false;
|
||||
information.markup = markup;
|
||||
information.mapper = Mapper::Unknown;
|
||||
information.ram = false;
|
||||
information.battery = false;
|
||||
information.rtc = false;
|
||||
information.rumble = false;
|
||||
|
||||
info.romsize = 0;
|
||||
info.ramsize = 0;
|
||||
information.romsize = 0;
|
||||
information.ramsize = 0;
|
||||
|
||||
XML::Document document(markup);
|
||||
|
||||
auto &mapperid = document["cartridge"]["mapper"].data;
|
||||
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;
|
||||
if(mapperid == "none" ) information.mapper = Mapper::MBC0;
|
||||
if(mapperid == "MBC1" ) information.mapper = Mapper::MBC1;
|
||||
if(mapperid == "MBC2" ) information.mapper = Mapper::MBC2;
|
||||
if(mapperid == "MBC3" ) information.mapper = Mapper::MBC3;
|
||||
if(mapperid == "MBC5" ) information.mapper = Mapper::MBC5;
|
||||
if(mapperid == "MMM01") information.mapper = Mapper::MMM01;
|
||||
if(mapperid == "HuC1" ) information.mapper = Mapper::HuC1;
|
||||
if(mapperid == "HuC3" ) information.mapper = Mapper::HuC3;
|
||||
|
||||
info.rtc = document["cartridge"]["rtc"].data == "true";
|
||||
info.rumble = document["cartridge"]["rumble"].data == "true";
|
||||
information.rtc = document["cartridge"]["rtc"].data == "true";
|
||||
information.rumble = document["cartridge"]["rumble"].data == "true";
|
||||
|
||||
info.romsize = hex(document["cartridge"]["rom"]["size"].data);
|
||||
info.ramsize = hex(document["cartridge"]["ram"]["size"].data);
|
||||
info.battery = document["cartridge"]["ram"]["battery"].data == "true";
|
||||
information.romsize = numeral(document["cartridge"]["rom"]["size"].data);
|
||||
information.ramsize = numeral(document["cartridge"]["ram"]["size"].data);
|
||||
information.battery = document["cartridge"]["ram"]["nonvolatile"].data == "true";
|
||||
|
||||
switch(info.mapper) { default:
|
||||
switch(information.mapper) { default:
|
||||
case Mapper::MBC0: mapper = &mbc0; break;
|
||||
case Mapper::MBC1: mapper = &mbc1; break;
|
||||
case Mapper::MBC2: mapper = &mbc2; break;
|
||||
@@ -60,7 +59,7 @@ void Cartridge::load(System::Revision revision, const string &markup, const uint
|
||||
case Mapper::HuC3: mapper = &huc3; break;
|
||||
}
|
||||
|
||||
ramdata = new uint8_t[ramsize = info.ramsize]();
|
||||
ramdata = new uint8_t[ramsize = information.ramsize]();
|
||||
system.load(revision);
|
||||
|
||||
loaded = true;
|
||||
@@ -103,9 +102,9 @@ uint8 Cartridge::mmio_read(uint16 addr) {
|
||||
if(bootrom_enable) {
|
||||
const uint8 *data = nullptr;
|
||||
switch(system.revision()) { default:
|
||||
case System::Revision::GameBoy: data = System::BootROM::dmg; break;
|
||||
case System::Revision::SuperGameBoy: data = System::BootROM::sgb; break;
|
||||
case System::Revision::GameBoyColor: data = System::BootROM::cgb; break;
|
||||
case System::Revision::GameBoy: data = system.bootROM.dmg; break;
|
||||
case System::Revision::SuperGameBoy: data = system.bootROM.sgb; break;
|
||||
case System::Revision::GameBoyColor: data = system.bootROM.cgb; break;
|
||||
}
|
||||
if(addr >= 0x0000 && addr <= 0x00ff) return data[addr];
|
||||
if(addr >= 0x0200 && addr <= 0x08ff && system.cgb()) return data[addr - 256];
|
@@ -21,7 +21,7 @@ struct Cartridge : MMIO, property<Cartridge> {
|
||||
};
|
||||
|
||||
struct Information {
|
||||
string xml;
|
||||
string markup;
|
||||
|
||||
Mapper mapper;
|
||||
bool ram;
|
||||
@@ -31,7 +31,7 @@ struct Cartridge : MMIO, property<Cartridge> {
|
||||
|
||||
unsigned romsize;
|
||||
unsigned ramsize;
|
||||
} info;
|
||||
} information;
|
||||
|
||||
readonly<bool> loaded;
|
||||
readonly<string> sha256;
|
@@ -1,7 +1,7 @@
|
||||
#ifdef CARTRIDGE_CPP
|
||||
|
||||
void Cartridge::serialize(serializer &s) {
|
||||
if(info.battery) s.array(ramdata, ramsize);
|
||||
if(information.battery) s.array(ramdata, ramsize);
|
||||
s.integer(bootrom_enable);
|
||||
|
||||
s.integer(mbc1.ram_enable);
|
@@ -1,6 +1,6 @@
|
||||
#include <gameboy/gameboy.hpp>
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
namespace GameBoy {
|
||||
namespace GB {
|
||||
|
||||
Cheat cheat;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#include <gameboy/gameboy.hpp>
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
#define CPU_CPP
|
||||
namespace GameBoy {
|
||||
namespace GB {
|
||||
|
||||
#include "core/core.cpp"
|
||||
#include "mmio/mmio.cpp"
|
@@ -1,4 +1,4 @@
|
||||
struct CPU : Processor, MMIO {
|
||||
struct CPU : Thread, MMIO {
|
||||
#include "core/core.hpp"
|
||||
#include "mmio/mmio.hpp"
|
||||
#include "timing/timing.hpp"
|
@@ -1,7 +1,7 @@
|
||||
#ifdef CPU_CPP
|
||||
|
||||
void CPU::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(wram);
|
||||
s.array(hram);
|
59
bsnes/gb/gb.hpp
Executable file
59
bsnes/gb/gb.hpp
Executable file
@@ -0,0 +1,59 @@
|
||||
#ifndef GB_HPP
|
||||
#define GB_HPP
|
||||
|
||||
#include <base/base.hpp>
|
||||
|
||||
namespace GB {
|
||||
namespace Info {
|
||||
static const char Name[] = "bgbc";
|
||||
static const unsigned SerializerVersion = 3;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bgbc - Game Boy, Super Game Boy, and Game Boy Color emulator
|
||||
author: byuu
|
||||
license: GPLv3
|
||||
project started: 2010-12-27
|
||||
*/
|
||||
|
||||
#include <libco/libco.h>
|
||||
|
||||
namespace GB {
|
||||
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 <gb/memory/memory.hpp>
|
||||
#include <gb/system/system.hpp>
|
||||
#include <gb/scheduler/scheduler.hpp>
|
||||
#include <gb/cartridge/cartridge.hpp>
|
||||
#include <gb/cpu/cpu.hpp>
|
||||
#include <gb/apu/apu.hpp>
|
||||
#include <gb/lcd/lcd.hpp>
|
||||
#include <gb/cheat/cheat.hpp>
|
||||
#include <gb/video/video.hpp>
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,6 +1,6 @@
|
||||
#include <gameboy/gameboy.hpp>
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
namespace GameBoy {
|
||||
namespace GB {
|
||||
|
||||
Interface *interface = nullptr;
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#include <gameboy/gameboy.hpp>
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
//LY = 0-153
|
||||
//Raster = 0-143
|
||||
@@ -7,7 +7,7 @@
|
||||
//LX = 0-455
|
||||
|
||||
#define LCD_CPP
|
||||
namespace GameBoy {
|
||||
namespace GB {
|
||||
|
||||
#include "dmg.cpp"
|
||||
#include "cgb.cpp"
|
@@ -1,4 +1,4 @@
|
||||
struct LCD : Processor, MMIO {
|
||||
struct LCD : Thread, MMIO {
|
||||
#include "mmio/mmio.hpp"
|
||||
|
||||
struct Status {
|
@@ -1,7 +1,7 @@
|
||||
#ifdef LCD_CPP
|
||||
|
||||
void LCD::serialize(serializer &s) {
|
||||
Processor::serialize(s);
|
||||
Thread::serialize(s);
|
||||
|
||||
s.array(screen);
|
||||
s.array(line);
|
@@ -1,7 +1,7 @@
|
||||
#include <gameboy/gameboy.hpp>
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
#define MEMORY_CPP
|
||||
namespace GameBoy {
|
||||
namespace GB {
|
||||
|
||||
Unmapped unmapped;
|
||||
Bus bus;
|
@@ -1,7 +1,7 @@
|
||||
#include <gameboy/gameboy.hpp>
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
#define SCHEDULER_CPP
|
||||
namespace GameBoy {
|
||||
namespace GB {
|
||||
|
||||
Scheduler scheduler;
|
||||
|
||||
@@ -16,11 +16,6 @@ void Scheduler::exit(ExitReason reason) {
|
||||
co_switch(host_thread);
|
||||
}
|
||||
|
||||
void Scheduler::swapto(Processor &p) {
|
||||
active_thread = p.thread;
|
||||
co_switch(active_thread);
|
||||
}
|
||||
|
||||
void Scheduler::init() {
|
||||
host_thread = co_active();
|
||||
active_thread = cpu.thread;
|
@@ -8,7 +8,6 @@ struct Scheduler : property<Scheduler> {
|
||||
|
||||
void enter();
|
||||
void exit(ExitReason);
|
||||
void swapto(Processor&);
|
||||
|
||||
void init();
|
||||
Scheduler();
|
@@ -1,11 +1,8 @@
|
||||
#include <gameboy/gameboy.hpp>
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
#define SYSTEM_CPP
|
||||
namespace GameBoy {
|
||||
namespace GB {
|
||||
|
||||
#include "bootrom-dmg.cpp"
|
||||
#include "bootrom-sgb.cpp"
|
||||
#include "bootrom-cgb.cpp"
|
||||
#include "serialization.cpp"
|
||||
System system;
|
||||
|
||||
@@ -21,8 +18,15 @@ void System::runtosave() {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::CPU;
|
||||
runthreadtosave();
|
||||
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.active_thread = lcd.thread;
|
||||
runthreadtosave();
|
||||
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.active_thread = apu.thread;
|
||||
runthreadtosave();
|
||||
|
||||
scheduler.sync = Scheduler::SynchronizeMode::None;
|
||||
}
|
||||
|
||||
void System::runthreadtosave() {
|
||||
@@ -35,6 +39,11 @@ void System::runthreadtosave() {
|
||||
}
|
||||
|
||||
void System::init() {
|
||||
file fp;
|
||||
fp.open("/home/byuu/Desktop/boot.rom", file::mode::write);
|
||||
fp.write(bootROM.sgb, 256);
|
||||
fp.close();
|
||||
|
||||
assert(interface != 0);
|
||||
}
|
||||
|
||||
@@ -54,4 +63,10 @@ void System::power() {
|
||||
clocks_executed = 0;
|
||||
}
|
||||
|
||||
System::System() {
|
||||
for(auto &byte : bootROM.dmg) byte = 0;
|
||||
for(auto &byte : bootROM.sgb) byte = 0;
|
||||
for(auto &byte : bootROM.cgb) byte = 0;
|
||||
}
|
||||
|
||||
}
|
@@ -16,9 +16,9 @@ struct System : property<System> {
|
||||
inline bool cgb() const { return revision == Revision::GameBoyColor; }
|
||||
|
||||
struct BootROM {
|
||||
static const uint8 dmg[ 256];
|
||||
static const uint8 sgb[ 256];
|
||||
static const uint8 cgb[2048];
|
||||
uint8 dmg[ 256];
|
||||
uint8 sgb[ 256];
|
||||
uint8 cgb[2048];
|
||||
} bootROM;
|
||||
|
||||
void run();
|
||||
@@ -40,8 +40,10 @@ struct System : property<System> {
|
||||
void serialize(serializer&);
|
||||
void serialize_all(serializer&);
|
||||
void serialize_init();
|
||||
|
||||
System();
|
||||
};
|
||||
|
||||
#include <gameboy/interface/interface.hpp>
|
||||
#include <gb/interface/interface.hpp>
|
||||
|
||||
extern System system;
|
@@ -1,7 +1,7 @@
|
||||
#include <gameboy/gameboy.hpp>
|
||||
#include <gb/gb.hpp>
|
||||
|
||||
#define VIDEO_CPP
|
||||
namespace GameBoy {
|
||||
namespace GB {
|
||||
|
||||
Video video;
|
||||
|
||||
@@ -65,7 +65,7 @@ void Video::generate(Format format) {
|
||||
}
|
||||
|
||||
Video::Video() {
|
||||
palette = new unsigned[1 << 15];
|
||||
palette = new unsigned[1 << 15]();
|
||||
}
|
||||
|
||||
Video::~Video() {
|
14
bsnes/gba/Makefile
Executable file
14
bsnes/gba/Makefile
Executable file
@@ -0,0 +1,14 @@
|
||||
gba_objects := gba-memory gba-interface gba-scheduler gba-system
|
||||
gba_objects += gba-video gba-cartridge
|
||||
gba_objects += gba-cpu gba-ppu gba-apu
|
||||
objects += $(gba_objects)
|
||||
|
||||
obj/gba-memory.o: $(gba)/memory/memory.cpp $(call rwildcard,$(gba)/memory)
|
||||
obj/gba-interface.o: $(gba)/interface/interface.cpp $(call rwildcard,$(gba)/interface)
|
||||
obj/gba-scheduler.o: $(gba)/scheduler/scheduler.cpp $(call rwildcard,$(gba)/scheduler)
|
||||
obj/gba-system.o: $(gba)/system/system.cpp $(call rwildcard,$(gba)/system)
|
||||
obj/gba-video.o: $(gba)/video/video.cpp $(call rwildcard,$(gba)/video)
|
||||
obj/gba-cartridge.o: $(gba)/cartridge/cartridge.cpp $(call rwildcard,$(gba)/cartridge)
|
||||
obj/gba-cpu.o: $(gba)/cpu/cpu.cpp $(call rwildcard,$(gba)/cpu)
|
||||
obj/gba-ppu.o: $(gba)/ppu/ppu.cpp $(call rwildcard,$(gba)/ppu)
|
||||
obj/gba-apu.o: $(gba)/apu/apu.cpp $(call rwildcard,$(gba)/apu)
|
98
bsnes/gba/apu/apu.cpp
Executable file
98
bsnes/gba/apu/apu.cpp
Executable file
@@ -0,0 +1,98 @@
|
||||
#include <gba/gba.hpp>
|
||||
|
||||
namespace GBA {
|
||||
|
||||
#include "registers.cpp"
|
||||
#include "mmio.cpp"
|
||||
#include "square.cpp"
|
||||
#include "square1.cpp"
|
||||
#include "square2.cpp"
|
||||
#include "wave.cpp"
|
||||
#include "noise.cpp"
|
||||
#include "sequencer.cpp"
|
||||
#include "fifo.cpp"
|
||||
#include "serialization.cpp"
|
||||
APU apu;
|
||||
|
||||
void APU::Enter() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::All) {
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
apu.main();
|
||||
}
|
||||
}
|
||||
|
||||
void APU::main() {
|
||||
for(unsigned n = 0; n < 128; n++) {
|
||||
runsequencer();
|
||||
}
|
||||
|
||||
signed lsample = regs.bias.level - 0x0200;
|
||||
signed rsample = regs.bias.level - 0x0200;
|
||||
|
||||
//(4-bit x 4 -> 6-bit) + 3-bit volume = 9-bit output
|
||||
if(sequencer.masterenable) {
|
||||
signed lsequence = 0;
|
||||
if(sequencer.lenable[0]) lsequence += square1.output;
|
||||
if(sequencer.lenable[1]) lsequence += square2.output;
|
||||
if(sequencer.lenable[2]) lsequence += wave.output;
|
||||
if(sequencer.lenable[3]) lsequence += noise.output;
|
||||
|
||||
signed rsequence = 0;
|
||||
if(sequencer.renable[0]) rsequence += square1.output;
|
||||
if(sequencer.renable[1]) rsequence += square2.output;
|
||||
if(sequencer.renable[2]) rsequence += wave.output;
|
||||
if(sequencer.renable[3]) rsequence += noise.output;
|
||||
|
||||
if(sequencer.volume < 3) {
|
||||
lsample += lsequence * (sequencer.lvolume + 1) >> (2 - sequencer.volume);
|
||||
rsample += rsequence * (sequencer.rvolume + 1) >> (2 - sequencer.volume);
|
||||
}
|
||||
}
|
||||
|
||||
//(8-bit x 2 -> 7-bit) + 1-bit volume = 10-bit output
|
||||
signed fifo0 = fifo[0].output + (1 << fifo[0].volume);
|
||||
signed fifo1 = fifo[1].output + (1 << fifo[1].volume);
|
||||
|
||||
if(fifo[0].lenable) lsample += fifo0;
|
||||
if(fifo[1].lenable) lsample += fifo1;
|
||||
|
||||
if(fifo[0].renable) rsample += fifo0;
|
||||
if(fifo[1].renable) rsample += fifo1;
|
||||
|
||||
lsample = sclamp<10>(lsample);
|
||||
rsample = sclamp<10>(rsample);
|
||||
|
||||
if(regs.bias.amplitude == 1) lsample &= ~3, rsample &= ~3;
|
||||
if(regs.bias.amplitude == 2) lsample &= ~7, rsample &= ~7;
|
||||
if(regs.bias.amplitude == 3) lsample &= ~15, rsample &= ~15;
|
||||
|
||||
if(cpu.regs.mode == CPU::Registers::Mode::Stop) lsample = 0, rsample = 0;
|
||||
interface->audioSample(sclamp<16>(lsample << 7), sclamp<16>(rsample << 7)); //should be <<5, use <<7 for added volume
|
||||
step(512);
|
||||
}
|
||||
|
||||
void APU::step(unsigned clocks) {
|
||||
clock += clocks;
|
||||
if(clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread);
|
||||
}
|
||||
|
||||
void APU::power() {
|
||||
create(APU::Enter, 16777216);
|
||||
|
||||
square1.power();
|
||||
square2.power();
|
||||
wave.power();
|
||||
noise.power();
|
||||
sequencer.power();
|
||||
fifo[0].power();
|
||||
fifo[1].power();
|
||||
|
||||
regs.bias = 0x0200;
|
||||
|
||||
for(unsigned n = 0x060; n <= 0x0a7; n++) bus.mmio[n] = this;
|
||||
}
|
||||
|
||||
}
|
17
bsnes/gba/apu/apu.hpp
Executable file
17
bsnes/gba/apu/apu.hpp
Executable file
@@ -0,0 +1,17 @@
|
||||
struct APU : Thread, MMIO {
|
||||
#include "registers.hpp"
|
||||
|
||||
static void Enter();
|
||||
void main();
|
||||
void step(unsigned clocks);
|
||||
|
||||
uint8 read(uint32 addr);
|
||||
void write(uint32 addr, uint8 byte);
|
||||
void power();
|
||||
|
||||
void runsequencer();
|
||||
|
||||
void serialize(serializer&);
|
||||
};
|
||||
|
||||
extern APU apu;
|
28
bsnes/gba/apu/fifo.cpp
Executable file
28
bsnes/gba/apu/fifo.cpp
Executable file
@@ -0,0 +1,28 @@
|
||||
void APU::FIFO::read() {
|
||||
if(size == 0) return;
|
||||
size--;
|
||||
output = sample[rdoffset++];
|
||||
}
|
||||
|
||||
void APU::FIFO::write(int8 byte) {
|
||||
if(size == 32) return;
|
||||
size++;
|
||||
sample[wroffset++] = byte;
|
||||
}
|
||||
|
||||
void APU::FIFO::reset() {
|
||||
for(auto &byte : sample) byte = 0;
|
||||
output = 0;
|
||||
|
||||
rdoffset = 0;
|
||||
wroffset = 0;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
void APU::FIFO::power() {
|
||||
reset();
|
||||
|
||||
lenable = 0;
|
||||
renable = 0;
|
||||
timer = 0;
|
||||
}
|
209
bsnes/gba/apu/mmio.cpp
Executable file
209
bsnes/gba/apu/mmio.cpp
Executable file
@@ -0,0 +1,209 @@
|
||||
uint8 APU::read(uint32 addr) {
|
||||
switch(addr) {
|
||||
|
||||
//NR10
|
||||
case 0x04000060: return square1.read(0);
|
||||
case 0x04000061: return 0u;
|
||||
|
||||
//NR11 + NR12
|
||||
case 0x04000062: return square1.read(1);
|
||||
case 0x04000063: return square1.read(2);
|
||||
|
||||
//NR13 + NR14
|
||||
case 0x04000064: return square1.read(3);
|
||||
case 0x04000065: return square1.read(4);
|
||||
|
||||
//NR21 + NR22
|
||||
case 0x04000068: return square2.read(1);
|
||||
case 0x04000069: return square2.read(2);
|
||||
|
||||
//NR23 + NR24
|
||||
case 0x0400006c: return square2.read(3);
|
||||
case 0x0400006d: return square2.read(4);
|
||||
|
||||
//NR30
|
||||
case 0x04000070: return wave.read(0);
|
||||
case 0x04000071: return 0u;
|
||||
|
||||
//NR31 + NR32
|
||||
case 0x04000072: return wave.read(1);
|
||||
case 0x04000073: return wave.read(2);
|
||||
|
||||
//NR33 + NR34
|
||||
case 0x04000074: return wave.read(3);
|
||||
case 0x04000075: return wave.read(4);
|
||||
|
||||
//NR41 + NR42
|
||||
case 0x04000078: return noise.read(1);
|
||||
case 0x04000079: return noise.read(2);
|
||||
|
||||
//NR43 + NR44
|
||||
case 0x0400007c: return noise.read(3);
|
||||
case 0x0400007d: return noise.read(4);
|
||||
|
||||
//NR50 + NR51
|
||||
case 0x04000080: return sequencer.read(0);
|
||||
case 0x04000081: return sequencer.read(1);
|
||||
|
||||
//NR52
|
||||
case 0x04000084: return sequencer.read(2);
|
||||
case 0x04000085: return 0u;
|
||||
|
||||
//SOUNDBIAS
|
||||
case 0x04000088: return regs.bias >> 0;
|
||||
case 0x04000089: return regs.bias >> 8;
|
||||
|
||||
//WAVE_RAM0_L
|
||||
case 0x04000090: return wave.readram( 0);
|
||||
case 0x04000091: return wave.readram( 1);
|
||||
|
||||
//WAVE_RAM0_H
|
||||
case 0x04000092: return wave.readram( 2);
|
||||
case 0x04000093: return wave.readram( 3);
|
||||
|
||||
//WAVE_RAM1_L
|
||||
case 0x04000094: return wave.readram( 4);
|
||||
case 0x04000095: return wave.readram( 5);
|
||||
|
||||
//WAVE_RAM1_H
|
||||
case 0x04000096: return wave.readram( 6);
|
||||
case 0x04000097: return wave.readram( 7);
|
||||
|
||||
//WAVE_RAM2_L
|
||||
case 0x04000098: return wave.readram( 8);
|
||||
case 0x04000099: return wave.readram( 9);
|
||||
|
||||
//WAVE_RAM2_H
|
||||
case 0x0400009a: return wave.readram(10);
|
||||
case 0x0400009b: return wave.readram(11);
|
||||
|
||||
//WAVE_RAM3_L
|
||||
case 0x0400009c: return wave.readram(12);
|
||||
case 0x0400009d: return wave.readram(13);
|
||||
|
||||
//WAVE_RAM3_H
|
||||
case 0x0400009e: return wave.readram(14);
|
||||
case 0x0400009f: return wave.readram(15);
|
||||
|
||||
}
|
||||
|
||||
return 0u;
|
||||
}
|
||||
|
||||
void APU::write(uint32 addr, uint8 byte) {
|
||||
switch(addr) {
|
||||
|
||||
//NR10
|
||||
case 0x04000060: return square1.write(0, byte);
|
||||
case 0x04000061: return;
|
||||
|
||||
//NR11 + NR12
|
||||
case 0x04000062: return square1.write(1, byte);
|
||||
case 0x04000063: return square1.write(2, byte);
|
||||
|
||||
//NR13 + NR14
|
||||
case 0x04000064: return square1.write(3, byte);
|
||||
case 0x04000065: return square1.write(4, byte);
|
||||
|
||||
//NR21 + NR22
|
||||
case 0x04000068: return square2.write(1, byte);
|
||||
case 0x04000069: return square2.write(2, byte);
|
||||
|
||||
//NR23 + NR24
|
||||
case 0x0400006c: return square2.write(3, byte);
|
||||
case 0x0400006d: return square2.write(4, byte);
|
||||
|
||||
//NR30
|
||||
case 0x04000070: return wave.write(0, byte);
|
||||
case 0x04000071: return;
|
||||
|
||||
//NR31 + NR32
|
||||
case 0x04000072: return wave.write(1, byte);
|
||||
case 0x04000073: return wave.write(2, byte);
|
||||
|
||||
//NR33 + NR34
|
||||
case 0x04000074: return wave.write(3, byte);
|
||||
case 0x04000075: return wave.write(4, byte);
|
||||
|
||||
//NR41 + NR42
|
||||
case 0x04000078: return noise.write(1, byte);
|
||||
case 0x04000079: return noise.write(2, byte);
|
||||
|
||||
//NR43 + NR44
|
||||
case 0x0400007c: return noise.write(3, byte);
|
||||
case 0x0400007d: return noise.write(4, byte);
|
||||
|
||||
//NR50 + NR51
|
||||
case 0x04000080: return sequencer.write(0, byte);
|
||||
case 0x04000081: return sequencer.write(1, byte);
|
||||
|
||||
//SOUND_CNT_H
|
||||
case 0x04000082:
|
||||
sequencer.volume = byte >> 0;
|
||||
fifo[0].volume = byte >> 2;
|
||||
fifo[1].volume = byte >> 3;
|
||||
return;
|
||||
case 0x04000083:
|
||||
fifo[0].renable = byte >> 0;
|
||||
fifo[0].lenable = byte >> 1;
|
||||
fifo[0].timer = byte >> 2;
|
||||
if(byte & 1 << 3) fifo[0].reset();
|
||||
fifo[1].renable = byte >> 4;
|
||||
fifo[1].lenable = byte >> 5;
|
||||
fifo[1].timer = byte >> 6;
|
||||
if(byte & 1 << 7) fifo[1].reset();
|
||||
return;
|
||||
|
||||
//NR52
|
||||
case 0x04000084: return sequencer.write(2, byte);
|
||||
case 0x04000085: return;
|
||||
|
||||
//SOUNDBIAS
|
||||
case 0x04000088: regs.bias = (regs.bias & 0xff00) | (byte << 0); return;
|
||||
case 0x04000089: regs.bias = (regs.bias & 0x00ff) | (byte << 8); return;
|
||||
|
||||
//WAVE_RAM0_L
|
||||
case 0x04000090: return wave.writeram( 0, byte);
|
||||
case 0x04000091: return wave.writeram( 1, byte);
|
||||
|
||||
//WAVE_RAM0_H
|
||||
case 0x04000092: return wave.writeram( 2, byte);
|
||||
case 0x04000093: return wave.writeram( 3, byte);
|
||||
|
||||
//WAVE_RAM1_L
|
||||
case 0x04000094: return wave.writeram( 4, byte);
|
||||
case 0x04000095: return wave.writeram( 5, byte);
|
||||
|
||||
//WAVE_RAM1_H
|
||||
case 0x04000096: return wave.writeram( 6, byte);
|
||||
case 0x04000097: return wave.writeram( 7, byte);
|
||||
|
||||
//WAVE_RAM2_L
|
||||
case 0x04000098: return wave.writeram( 8, byte);
|
||||
case 0x04000099: return wave.writeram( 9, byte);
|
||||
|
||||
//WAVE_RAM2_H
|
||||
case 0x0400009a: return wave.writeram(10, byte);
|
||||
case 0x0400009b: return wave.writeram(11, byte);
|
||||
|
||||
//WAVE_RAM3_L
|
||||
case 0x0400009c: return wave.writeram(12, byte);
|
||||
case 0x0400009d: return wave.writeram(13, byte);
|
||||
|
||||
//WAVE_RAM3_H
|
||||
case 0x0400009e: return wave.writeram(14, byte);
|
||||
case 0x0400009f: return wave.writeram(15, byte);
|
||||
|
||||
//FIFO_A_L
|
||||
//FIFO_A_H
|
||||
case 0x040000a0: case 0x040000a1:
|
||||
case 0x040000a2: case 0x040000a3:
|
||||
return fifo[0].write(byte);
|
||||
|
||||
//FIFO_B_L
|
||||
//FIFO_B_H
|
||||
case 0x040000a4: case 0x040000a5:
|
||||
case 0x040000a6: case 0x040000a7:
|
||||
return fifo[1].write(byte);
|
||||
}
|
||||
}
|
93
bsnes/gba/apu/noise.cpp
Executable file
93
bsnes/gba/apu/noise.cpp
Executable file
@@ -0,0 +1,93 @@
|
||||
unsigned APU::Noise::divider() const {
|
||||
if(divisor == 0) return 8;
|
||||
return divisor * 16;
|
||||
}
|
||||
|
||||
void APU::Noise::run() {
|
||||
if(period && --period == 0) {
|
||||
period = divider() << frequency;
|
||||
if(frequency < 14) {
|
||||
bool bit = (lfsr ^ (lfsr >> 1)) & 1;
|
||||
lfsr = (lfsr >> 1) ^ (bit << (narrowlfsr ? 6 : 14));
|
||||
}
|
||||
}
|
||||
|
||||
output = volume;
|
||||
if(enable == false || (lfsr & 1)) output = 0;
|
||||
}
|
||||
|
||||
void APU::Noise::clocklength() {
|
||||
if(enable && counter) {
|
||||
if(++length == 0) enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Noise::clockenvelope() {
|
||||
if(enable && envelope.frequency && --envelope.period == 0) {
|
||||
envelope.period = envelope.frequency;
|
||||
if(envelope.direction == 0 && volume > 0) volume--;
|
||||
if(envelope.direction == 1 && volume < 15) volume++;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 APU::Noise::read(unsigned addr) const {
|
||||
switch(addr) {
|
||||
case 1: return (length << 0);
|
||||
case 2: return (envelope.frequency << 0) | (envelope.direction << 3) | (envelope.volume << 4);
|
||||
case 3: return (divisor << 0) | (narrowlfsr << 3) | (frequency << 4);
|
||||
case 4: return (counter << 6) | (initialize << 7);
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Noise::write(unsigned addr, uint8 byte) {
|
||||
switch(addr) {
|
||||
case 1: //NR41
|
||||
length = byte >> 0;
|
||||
break;
|
||||
|
||||
case 2: //NR42
|
||||
envelope.frequency = byte >> 0;
|
||||
envelope.direction = byte >> 3;
|
||||
envelope.volume = byte >> 4;
|
||||
if(envelope.dacenable() == false) enable = false;
|
||||
break;
|
||||
|
||||
case 3: //NR43
|
||||
divisor = byte >> 0;
|
||||
narrowlfsr = byte >> 3;
|
||||
frequency = byte >> 4;
|
||||
period = divider() << frequency;
|
||||
break;
|
||||
|
||||
case 4: //NR44
|
||||
counter = byte >> 6;
|
||||
initialize = byte >> 7;
|
||||
|
||||
if(initialize) {
|
||||
enable = envelope.dacenable();
|
||||
lfsr = ~0u;
|
||||
envelope.period = envelope.frequency;
|
||||
volume = envelope.volume;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Noise::power() {
|
||||
envelope.frequency = 0;
|
||||
envelope.direction = 0;
|
||||
envelope.volume = 0;
|
||||
envelope.period = 0;
|
||||
length = 0;
|
||||
divisor = 0;
|
||||
narrowlfsr = 0;
|
||||
frequency = 0;
|
||||
counter = 0;
|
||||
initialize = 0;
|
||||
enable = 0;
|
||||
lfsr = 0;
|
||||
output = 0;
|
||||
period = 0;
|
||||
volume = 0;
|
||||
}
|
12
bsnes/gba/apu/registers.cpp
Executable file
12
bsnes/gba/apu/registers.cpp
Executable file
@@ -0,0 +1,12 @@
|
||||
APU::Registers::SoundBias::operator uint16() const {
|
||||
return (
|
||||
(level << 0)
|
||||
| (amplitude << 14)
|
||||
);
|
||||
}
|
||||
|
||||
uint16 APU::Registers::SoundBias::operator=(uint16 source) {
|
||||
level = (source >> 0) & 1023;
|
||||
amplitude = (source >> 14) & 3;
|
||||
return operator uint16();
|
||||
}
|
158
bsnes/gba/apu/registers.hpp
Executable file
158
bsnes/gba/apu/registers.hpp
Executable file
@@ -0,0 +1,158 @@
|
||||
struct Registers {
|
||||
struct SoundBias {
|
||||
uint10 level;
|
||||
uint2 amplitude;
|
||||
|
||||
operator uint16() const;
|
||||
uint16 operator=(uint16 source);
|
||||
SoundBias& operator=(const SoundBias&) = delete;
|
||||
} bias;
|
||||
|
||||
unsigned clock;
|
||||
} regs;
|
||||
|
||||
struct Sweep {
|
||||
uint3 shift;
|
||||
uint1 direction;
|
||||
uint3 frequency;
|
||||
|
||||
uint1 enable;
|
||||
uint1 negate;
|
||||
uint3 period;
|
||||
};
|
||||
|
||||
struct Envelope {
|
||||
uint3 frequency;
|
||||
uint1 direction;
|
||||
uint4 volume;
|
||||
|
||||
uint3 period;
|
||||
|
||||
inline bool dacenable() const { return volume || direction; }
|
||||
};
|
||||
|
||||
struct Square {
|
||||
Envelope envelope;
|
||||
uint1 enable;
|
||||
uint6 length;
|
||||
uint2 duty;
|
||||
uint11 frequency;
|
||||
uint1 counter;
|
||||
uint1 initialize;
|
||||
|
||||
signed shadowfrequency;
|
||||
uint1 signal;
|
||||
uint4 output;
|
||||
unsigned period;
|
||||
uint3 phase;
|
||||
uint4 volume;
|
||||
|
||||
void run();
|
||||
void clocklength();
|
||||
void clockenvelope();
|
||||
};
|
||||
|
||||
struct Square1 : Square {
|
||||
Sweep sweep;
|
||||
|
||||
void runsweep(bool update);
|
||||
void clocksweep();
|
||||
uint8 read(unsigned addr) const;
|
||||
void write(unsigned addr, uint8 byte);
|
||||
void power();
|
||||
} square1;
|
||||
|
||||
struct Square2 : Square {
|
||||
uint8 read(unsigned addr) const;
|
||||
void write(unsigned addr, uint8 byte);
|
||||
void power();
|
||||
} square2;
|
||||
|
||||
struct Wave {
|
||||
uint1 mode;
|
||||
uint1 bank;
|
||||
uint1 dacenable;
|
||||
uint8 length;
|
||||
uint3 volume;
|
||||
uint11 frequency;
|
||||
uint1 counter;
|
||||
uint1 initialize;
|
||||
uint4 pattern[32];
|
||||
|
||||
uint1 enable;
|
||||
uint4 output;
|
||||
uint4 patternaddr;
|
||||
uint1 patternbank;
|
||||
uint4 patternsample;
|
||||
unsigned period;
|
||||
|
||||
void run();
|
||||
void clocklength();
|
||||
uint8 read(unsigned addr) const;
|
||||
void write(unsigned addr, uint8 byte);
|
||||
uint8 readram(unsigned addr) const;
|
||||
void writeram(unsigned addr, uint8 byte);
|
||||
void power();
|
||||
} wave;
|
||||
|
||||
struct Noise {
|
||||
Envelope envelope;
|
||||
uint6 length;
|
||||
uint3 divisor;
|
||||
uint1 narrowlfsr;
|
||||
uint4 frequency;
|
||||
uint1 counter;
|
||||
uint1 initialize;
|
||||
|
||||
uint1 enable;
|
||||
uint15 lfsr;
|
||||
uint4 output;
|
||||
unsigned period;
|
||||
uint4 volume;
|
||||
|
||||
unsigned divider() const;
|
||||
void run();
|
||||
void clocklength();
|
||||
void clockenvelope();
|
||||
uint8 read(unsigned addr) const;
|
||||
void write(unsigned addr, uint8 byte);
|
||||
void power();
|
||||
} noise;
|
||||
|
||||
struct Sequencer {
|
||||
uint2 volume;
|
||||
uint3 lvolume;
|
||||
uint3 rvolume;
|
||||
uint1 lenable[4];
|
||||
uint1 renable[4];
|
||||
uint1 enable[4];
|
||||
uint1 masterenable;
|
||||
|
||||
uint13 base;
|
||||
uint3 step;
|
||||
int16 lsample;
|
||||
int16 rsample;
|
||||
|
||||
uint8 read(unsigned addr) const;
|
||||
void write(unsigned addr, uint8 byte);
|
||||
void power();
|
||||
} sequencer;
|
||||
|
||||
struct FIFO {
|
||||
int8 sample[32];
|
||||
int8 output;
|
||||
|
||||
uint5 rdoffset;
|
||||
uint5 wroffset;
|
||||
uint6 size;
|
||||
|
||||
uint1 volume; //0 = 50%, 1 = 100%
|
||||
uint1 lenable;
|
||||
uint1 renable;
|
||||
uint1 timer;
|
||||
|
||||
void read();
|
||||
void write(int8 byte);
|
||||
void reset();
|
||||
void power();
|
||||
} fifo[2];
|
91
bsnes/gba/apu/sequencer.cpp
Executable file
91
bsnes/gba/apu/sequencer.cpp
Executable file
@@ -0,0 +1,91 @@
|
||||
void APU::runsequencer() {
|
||||
auto &r = sequencer;
|
||||
|
||||
if(r.base == 0) { //512hz
|
||||
if(r.step == 0 || r.step == 2 || r.step == 4 || r.step == 6) { //256hz
|
||||
square1.clocklength();
|
||||
square2.clocklength();
|
||||
wave.clocklength();
|
||||
noise.clocklength();
|
||||
}
|
||||
if(r.step == 2 || r.step == 6) { //128hz
|
||||
square1.clocksweep();
|
||||
}
|
||||
if(r.step == 7) { //64hz
|
||||
square1.clockenvelope();
|
||||
square2.clockenvelope();
|
||||
noise.clockenvelope();
|
||||
}
|
||||
r.step++;
|
||||
}
|
||||
r.base++;
|
||||
|
||||
if(r.enable[0]) square1.run();
|
||||
if(r.enable[1]) square2.run();
|
||||
if(r.enable[2]) wave.run();
|
||||
if(r.enable[3]) noise.run();
|
||||
}
|
||||
|
||||
uint8 APU::Sequencer::read(unsigned addr) const {
|
||||
switch(addr) {
|
||||
case 0: return (rvolume << 0) | (lvolume << 4);
|
||||
case 1: return (
|
||||
(renable[0] << 0)
|
||||
| (renable[1] << 1)
|
||||
| (renable[2] << 2)
|
||||
| (renable[3] << 3)
|
||||
| (lenable[0] << 4)
|
||||
| (lenable[1] << 5)
|
||||
| (lenable[2] << 6)
|
||||
| (lenable[3] << 7)
|
||||
);
|
||||
case 2: return (
|
||||
(enable[0] << 0)
|
||||
| (enable[1] << 1)
|
||||
| (enable[2] << 2)
|
||||
| (enable[3] << 3)
|
||||
| (masterenable << 7)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Sequencer::write(unsigned addr, uint8 byte) {
|
||||
switch(addr) {
|
||||
case 0: //NR50
|
||||
rvolume = byte >> 0;
|
||||
lvolume = byte >> 4;
|
||||
break;
|
||||
|
||||
case 1: //NR51
|
||||
renable[0] = byte >> 0;
|
||||
renable[1] = byte >> 1;
|
||||
renable[2] = byte >> 2;
|
||||
renable[3] = byte >> 3;
|
||||
lenable[0] = byte >> 4;
|
||||
lenable[1] = byte >> 5;
|
||||
lenable[2] = byte >> 6;
|
||||
lenable[3] = byte >> 7;
|
||||
break;
|
||||
|
||||
case 2: //NR52
|
||||
enable[0] = byte >> 0;
|
||||
enable[1] = byte >> 1;
|
||||
enable[2] = byte >> 2;
|
||||
enable[3] = byte >> 3;
|
||||
masterenable = byte >> 7;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Sequencer::power() {
|
||||
lvolume = 0;
|
||||
rvolume = 0;
|
||||
for(auto &n : lenable) n = 0;
|
||||
for(auto &n : renable) n = 0;
|
||||
for(auto &n : enable) n = 0;
|
||||
masterenable = 0;
|
||||
base = 0;
|
||||
step = 0;
|
||||
lsample = 0;
|
||||
rsample = 0;
|
||||
}
|
107
bsnes/gba/apu/serialization.cpp
Executable file
107
bsnes/gba/apu/serialization.cpp
Executable file
@@ -0,0 +1,107 @@
|
||||
void APU::serialize(serializer &s) {
|
||||
Thread::serialize(s);
|
||||
|
||||
s.integer(regs.bias.level);
|
||||
s.integer(regs.bias.amplitude);
|
||||
s.integer(regs.clock);
|
||||
|
||||
s.integer(square1.sweep.shift);
|
||||
s.integer(square1.sweep.direction);
|
||||
s.integer(square1.sweep.frequency);
|
||||
s.integer(square1.sweep.enable);
|
||||
s.integer(square1.sweep.negate);
|
||||
s.integer(square1.sweep.period);
|
||||
|
||||
s.integer(square1.envelope.frequency);
|
||||
s.integer(square1.envelope.direction);
|
||||
s.integer(square1.envelope.volume);
|
||||
s.integer(square1.envelope.period);
|
||||
|
||||
s.integer(square1.enable);
|
||||
s.integer(square1.length);
|
||||
s.integer(square1.duty);
|
||||
s.integer(square1.frequency);
|
||||
s.integer(square1.counter);
|
||||
s.integer(square1.initialize);
|
||||
s.integer(square1.shadowfrequency);
|
||||
s.integer(square1.signal);
|
||||
s.integer(square1.output);
|
||||
s.integer(square1.period);
|
||||
s.integer(square1.phase);
|
||||
s.integer(square1.volume);
|
||||
|
||||
s.integer(square2.envelope.frequency);
|
||||
s.integer(square2.envelope.direction);
|
||||
s.integer(square2.envelope.volume);
|
||||
s.integer(square2.envelope.period);
|
||||
|
||||
s.integer(square2.enable);
|
||||
s.integer(square2.length);
|
||||
s.integer(square2.duty);
|
||||
s.integer(square2.frequency);
|
||||
s.integer(square2.counter);
|
||||
s.integer(square2.initialize);
|
||||
s.integer(square2.shadowfrequency);
|
||||
s.integer(square2.signal);
|
||||
s.integer(square2.output);
|
||||
s.integer(square2.period);
|
||||
s.integer(square2.phase);
|
||||
s.integer(square2.volume);
|
||||
|
||||
s.integer(wave.mode);
|
||||
s.integer(wave.bank);
|
||||
s.integer(wave.dacenable);
|
||||
s.integer(wave.length);
|
||||
s.integer(wave.volume);
|
||||
s.integer(wave.frequency);
|
||||
s.integer(wave.counter);
|
||||
s.integer(wave.initialize);
|
||||
for(auto &value : wave.pattern) s.integer(value);
|
||||
s.integer(wave.enable);
|
||||
s.integer(wave.output);
|
||||
s.integer(wave.patternaddr);
|
||||
s.integer(wave.patternbank);
|
||||
s.integer(wave.patternsample);
|
||||
s.integer(wave.period);
|
||||
|
||||
s.integer(noise.envelope.frequency);
|
||||
s.integer(noise.envelope.direction);
|
||||
s.integer(noise.envelope.volume);
|
||||
s.integer(noise.envelope.period);
|
||||
|
||||
s.integer(noise.length);
|
||||
s.integer(noise.divisor);
|
||||
s.integer(noise.narrowlfsr);
|
||||
s.integer(noise.frequency);
|
||||
s.integer(noise.counter);
|
||||
s.integer(noise.initialize);
|
||||
s.integer(noise.enable);
|
||||
s.integer(noise.lfsr);
|
||||
s.integer(noise.output);
|
||||
s.integer(noise.period);
|
||||
s.integer(noise.volume);
|
||||
|
||||
s.integer(sequencer.volume);
|
||||
s.integer(sequencer.lvolume);
|
||||
s.integer(sequencer.rvolume);
|
||||
for(auto &flag : sequencer.lenable) s.integer(flag);
|
||||
for(auto &flag : sequencer.renable) s.integer(flag);
|
||||
for(auto &flag : sequencer.enable) s.integer(flag);
|
||||
s.integer(sequencer.masterenable);
|
||||
s.integer(sequencer.base);
|
||||
s.integer(sequencer.step);
|
||||
s.integer(sequencer.lsample);
|
||||
s.integer(sequencer.rsample);
|
||||
|
||||
for(auto &f : fifo) {
|
||||
for(auto &value : f.sample) s.integer(value);
|
||||
s.integer(f.output);
|
||||
s.integer(f.rdoffset);
|
||||
s.integer(f.wroffset);
|
||||
s.integer(f.size);
|
||||
s.integer(f.volume);
|
||||
s.integer(f.lenable);
|
||||
s.integer(f.renable);
|
||||
s.integer(f.timer);
|
||||
}
|
||||
}
|
30
bsnes/gba/apu/square.cpp
Executable file
30
bsnes/gba/apu/square.cpp
Executable file
@@ -0,0 +1,30 @@
|
||||
void APU::Square::run() {
|
||||
if(period && --period == 0) {
|
||||
period = 4 * (2048 - frequency);
|
||||
phase++;
|
||||
switch(duty) {
|
||||
case 0: signal = (phase == 6); break; //_____-_
|
||||
case 1: signal = (phase >= 6); break; //______--
|
||||
case 2: signal = (phase >= 4); break; //____----
|
||||
case 3: signal = (phase <= 5); break; //------__
|
||||
}
|
||||
}
|
||||
|
||||
uint4 sample = volume;
|
||||
if(enable == false || signal == false) sample = 0;
|
||||
output = sample;
|
||||
}
|
||||
|
||||
void APU::Square::clocklength() {
|
||||
if(enable && counter) {
|
||||
if(++length == 0) enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square::clockenvelope() {
|
||||
if(enable && envelope.frequency && --envelope.period == 0) {
|
||||
envelope.period = envelope.frequency;
|
||||
if(envelope.direction == 0 && volume > 0) volume--;
|
||||
if(envelope.direction == 1 && volume < 15) volume++;
|
||||
}
|
||||
}
|
104
bsnes/gba/apu/square1.cpp
Executable file
104
bsnes/gba/apu/square1.cpp
Executable file
@@ -0,0 +1,104 @@
|
||||
void APU::Square1::runsweep(bool update) {
|
||||
if(sweep.enable == false) return;
|
||||
|
||||
sweep.negate = sweep.direction;
|
||||
unsigned delta = shadowfrequency >> sweep.shift;
|
||||
signed updatefrequency = shadowfrequency + (sweep.negate ? -delta : delta);
|
||||
|
||||
if(updatefrequency > 2047) {
|
||||
enable = false;
|
||||
} else if(sweep.shift && update) {
|
||||
shadowfrequency = updatefrequency;
|
||||
frequency = updatefrequency;
|
||||
period = 4 * (2048 - frequency);
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square1::clocksweep() {
|
||||
if(enable && sweep.frequency && --sweep.period == 0) {
|
||||
sweep.period = sweep.frequency;
|
||||
runsweep(1);
|
||||
runsweep(0);
|
||||
}
|
||||
}
|
||||
|
||||
uint8 APU::Square1::read(unsigned addr) const {
|
||||
switch(addr) {
|
||||
case 0: return (sweep.shift << 0) | (sweep.direction << 3) | (sweep.frequency << 4);
|
||||
case 1: return (length << 0) | (duty << 6);
|
||||
case 2: return (envelope.frequency << 0) | (envelope.direction << 3) | (envelope.volume << 4);
|
||||
case 3: return (frequency << 0);
|
||||
case 4: return (frequency >> 8) | (counter << 6) | (initialize << 7);
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square1::write(unsigned addr, uint8 byte) {
|
||||
switch(addr) {
|
||||
case 0: //NR10
|
||||
if(sweep.negate && sweep.direction && !(byte & 0x08)) enable = false;
|
||||
sweep.shift = byte >> 0;
|
||||
sweep.direction = byte >> 3;
|
||||
sweep.frequency = byte >> 4;
|
||||
break;
|
||||
|
||||
case 1: //NR11
|
||||
length = byte >> 0;
|
||||
duty = byte >> 6;
|
||||
break;
|
||||
|
||||
case 2: //NR12
|
||||
envelope.frequency = byte >> 0;
|
||||
envelope.direction = byte >> 3;
|
||||
envelope.volume = byte >> 4;
|
||||
if(envelope.dacenable() == false) enable = false;
|
||||
break;
|
||||
|
||||
case 3: //NR13
|
||||
frequency = (frequency & 0xff00) | (byte << 0);
|
||||
break;
|
||||
|
||||
case 4: //NR14
|
||||
frequency = (frequency & 0x00ff) | (byte << 8);
|
||||
counter = byte >> 6;
|
||||
initialize = byte >> 7;
|
||||
|
||||
if(initialize) {
|
||||
enable = envelope.dacenable();
|
||||
period = 4 * (2048 - frequency);
|
||||
envelope.period = envelope.frequency;
|
||||
volume = envelope.volume;
|
||||
shadowfrequency = frequency;
|
||||
sweep.period = sweep.frequency;
|
||||
sweep.enable = sweep.period || sweep.shift;
|
||||
sweep.negate = false;
|
||||
if(sweep.shift) runsweep(0);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square1::power() {
|
||||
envelope.frequency = 0;
|
||||
envelope.direction = 0;
|
||||
envelope.direction = 0;
|
||||
envelope.period = 0;
|
||||
sweep.shift = 0;
|
||||
sweep.direction = 0;
|
||||
sweep.frequency = 0;
|
||||
sweep.enable = 0;
|
||||
sweep.negate = 0;
|
||||
sweep.period = 0;
|
||||
enable = 0;
|
||||
length = 0;
|
||||
duty = 0;
|
||||
frequency = 0;
|
||||
counter = 0;
|
||||
initialize = 0;
|
||||
shadowfrequency = 0;
|
||||
signal = 0;
|
||||
output = 0;
|
||||
period = 0;
|
||||
phase = 0;
|
||||
volume = 0;
|
||||
}
|
61
bsnes/gba/apu/square2.cpp
Executable file
61
bsnes/gba/apu/square2.cpp
Executable file
@@ -0,0 +1,61 @@
|
||||
uint8 APU::Square2::read(unsigned addr) const {
|
||||
switch(addr) {
|
||||
case 1: return (length << 0) | (duty << 6);
|
||||
case 2: return (envelope.frequency << 0) | (envelope.direction << 3) | (envelope.volume << 4);
|
||||
case 3: return (frequency >> 0);
|
||||
case 4: return (frequency >> 8) | (counter << 6) | (initialize << 7);
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square2::write(unsigned addr, uint8 byte) {
|
||||
switch(addr) {
|
||||
case 1: //NR21
|
||||
length = byte >> 0;
|
||||
duty = byte >> 6;
|
||||
break;
|
||||
|
||||
case 2: //NR22
|
||||
envelope.frequency = byte >> 0;
|
||||
envelope.direction = byte >> 3;
|
||||
envelope.volume = byte >> 4;
|
||||
if(envelope.dacenable() == false) enable = false;
|
||||
break;
|
||||
|
||||
case 3: //NR23
|
||||
frequency = (frequency & 0xff00) | (byte << 0);
|
||||
break;
|
||||
|
||||
case 4: //NR24
|
||||
frequency = (frequency & 0x00ff) | (byte << 8);
|
||||
counter = byte >> 6;
|
||||
initialize = byte >> 7;
|
||||
|
||||
if(initialize) {
|
||||
enable = envelope.dacenable();
|
||||
period = 4 * (2048 - frequency);
|
||||
envelope.period = envelope.frequency;
|
||||
volume = envelope.volume;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Square2::power() {
|
||||
envelope.frequency = 0;
|
||||
envelope.direction = 0;
|
||||
envelope.direction = 0;
|
||||
envelope.period = 0;
|
||||
enable = 0;
|
||||
length = 0;
|
||||
duty = 0;
|
||||
frequency = 0;
|
||||
counter = 0;
|
||||
initialize = 0;
|
||||
shadowfrequency = 0;
|
||||
signal = 0;
|
||||
output = 0;
|
||||
period = 0;
|
||||
phase = 0;
|
||||
volume = 0;
|
||||
}
|
95
bsnes/gba/apu/wave.cpp
Executable file
95
bsnes/gba/apu/wave.cpp
Executable file
@@ -0,0 +1,95 @@
|
||||
void APU::Wave::run() {
|
||||
if(period && --period == 0) {
|
||||
period = 2 * (2048 - frequency);
|
||||
patternsample = pattern[patternbank * 16 + patternaddr++];
|
||||
if(patternaddr == 0) patternbank ^= mode;
|
||||
}
|
||||
|
||||
output = patternsample;
|
||||
static unsigned multiplier[] = { 0, 4, 2, 1, 3, 3, 3, 3};
|
||||
output = (output * multiplier[volume]) / 4;
|
||||
if(enable == false) output = 0;
|
||||
}
|
||||
|
||||
void APU::Wave::clocklength() {
|
||||
if(enable && counter) {
|
||||
if(++length == 0) enable = false;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 APU::Wave::read(unsigned addr) const {
|
||||
switch(addr) {
|
||||
case 0: return (mode << 5) | (bank << 6) | (dacenable << 7);
|
||||
case 1: return (length << 0);
|
||||
case 2: return (volume << 5);
|
||||
case 3: return (frequency >> 0);
|
||||
case 4: return (frequency >> 8) | (counter << 6) | (initialize << 7);
|
||||
}
|
||||
}
|
||||
|
||||
void APU::Wave::write(unsigned addr, uint8 byte) {
|
||||
switch(addr) {
|
||||
case 0: //NR30
|
||||
mode = byte >> 5;
|
||||
bank = byte >> 6;
|
||||
dacenable = byte >> 7;
|
||||
if(dacenable == false) enable = false;
|
||||
break;
|
||||
|
||||
case 1: //NR31
|
||||
length = byte >> 0;
|
||||
break;
|
||||
|
||||
case 2: //NR32
|
||||
volume = byte >> 5;
|
||||
break;
|
||||
|
||||
case 3: //NR33
|
||||
frequency = (frequency & 0xff00) | (byte << 0);
|
||||
break;
|
||||
|
||||
case 4: //NR34
|
||||
frequency = (frequency & 0x00ff) | (byte << 8);
|
||||
counter = byte >> 6;
|
||||
initialize = byte >> 7;
|
||||
|
||||
if(initialize) {
|
||||
enable = dacenable;
|
||||
period = 2 * (2048 - frequency);
|
||||
patternaddr = 0;
|
||||
patternbank = mode ? (uint1)0 : bank;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 APU::Wave::readram(unsigned addr) const {
|
||||
uint8 byte = 0;
|
||||
byte |= pattern[addr * 2 + 0] << 0;
|
||||
byte |= pattern[addr * 2 + 1] << 4;
|
||||
return byte;
|
||||
}
|
||||
|
||||
void APU::Wave::writeram(unsigned addr, uint8 byte) {
|
||||
pattern[addr * 2 + 0] = byte >> 0;
|
||||
pattern[addr * 2 + 1] = byte >> 4;
|
||||
}
|
||||
|
||||
void APU::Wave::power() {
|
||||
mode = 0;
|
||||
bank = 0;
|
||||
dacenable = 0;
|
||||
length = 0;
|
||||
volume = 0;
|
||||
frequency = 0;
|
||||
counter = 0;
|
||||
initialize = 0;
|
||||
for(auto &sample : pattern) sample = 0;
|
||||
enable = 0;
|
||||
output = 0;
|
||||
patternaddr = 0;
|
||||
patternbank = 0;
|
||||
patternsample = 0;
|
||||
period = 0;
|
||||
}
|
130
bsnes/gba/cartridge/cartridge.cpp
Executable file
130
bsnes/gba/cartridge/cartridge.cpp
Executable file
@@ -0,0 +1,130 @@
|
||||
#include <gba/gba.hpp>
|
||||
|
||||
namespace GBA {
|
||||
|
||||
#include "eeprom.cpp"
|
||||
#include "flashrom.cpp"
|
||||
#include "serialization.cpp"
|
||||
Cartridge cartridge;
|
||||
|
||||
bool Cartridge::load(const string &markup, const uint8_t *data, unsigned size) {
|
||||
information.markup = markup;
|
||||
XML::Document document(markup);
|
||||
|
||||
for(unsigned addr = 0; addr < rom.size; addr++) {
|
||||
rom.data[addr] = data[Bus::mirror(addr, size)];
|
||||
}
|
||||
|
||||
has_sram = false;
|
||||
has_eeprom = false;
|
||||
has_flashrom = false;
|
||||
|
||||
if(document["cartridge"]["ram"].exists()) {
|
||||
auto &info = document["cartridge"]["ram"];
|
||||
|
||||
if(info["type"].data == "SRAM" || info["type"].data == "FRAM") {
|
||||
has_sram = true;
|
||||
ram.size = numeral(info["size"].data);
|
||||
ram.mask = ram.size - 1;
|
||||
for(unsigned n = 0; n < ram.size; n++) ram.data[n] = 0xff;
|
||||
}
|
||||
|
||||
if(info["type"].data == "EEPROM") {
|
||||
has_eeprom = true;
|
||||
eeprom.size = numeral(info["size"].data);
|
||||
eeprom.bits = eeprom.size <= 512 ? 6 : 14;
|
||||
if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size
|
||||
eeprom.mask = size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000;
|
||||
eeprom.test = size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000;
|
||||
for(unsigned n = 0; n < eeprom.size; n++) eeprom.data[n] = 0xff;
|
||||
}
|
||||
|
||||
if(info["type"].data == "FlashROM") {
|
||||
has_flashrom = true;
|
||||
flashrom.id = numeral(info["id"].data);
|
||||
flashrom.size = numeral(info["size"].data);
|
||||
for(unsigned n = 0; n < flashrom.size; n++) flashrom.data[n] = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
sha256 = nall::sha256(rom.data, rom.size);
|
||||
|
||||
system.load();
|
||||
return loaded = true;
|
||||
}
|
||||
|
||||
void Cartridge::unload() {
|
||||
if(loaded == false) return;
|
||||
loaded = false;
|
||||
}
|
||||
|
||||
void Cartridge::power() {
|
||||
eeprom.power();
|
||||
flashrom.power();
|
||||
}
|
||||
|
||||
uint8* Cartridge::ram_data() {
|
||||
if(has_sram) return ram.data;
|
||||
if(has_eeprom) return eeprom.data;
|
||||
if(has_flashrom) return flashrom.data;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned Cartridge::ram_size() {
|
||||
if(has_sram) return ram.size;
|
||||
if(has_eeprom) return eeprom.size;
|
||||
if(has_flashrom) return flashrom.size;
|
||||
return 0u;
|
||||
}
|
||||
|
||||
uint32 Cartridge::read(uint8 *data, uint32 addr, uint32 size) {
|
||||
if(size == Word) addr &= ~3;
|
||||
if(size == Half) addr &= ~1;
|
||||
data += addr;
|
||||
if(size == Word) return data[0] << 0 | data[1] << 8 | data[2] << 16 | data[3] << 24;
|
||||
if(size == Half) return data[0] << 0 | data[1] << 8;
|
||||
return data[0];
|
||||
}
|
||||
|
||||
void Cartridge::write(uint8 *data, uint32 addr, uint32 size, uint32 word) {
|
||||
if(size == Word) addr &= ~3;
|
||||
if(size == Half) addr &= ~1;
|
||||
data += addr;
|
||||
switch(size) {
|
||||
case Word: data[3] = word >> 24;
|
||||
data[2] = word >> 16;
|
||||
case Half: data[1] = word >> 8;
|
||||
case Byte: data[0] = word >> 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 Cartridge::read(uint32 addr, uint32 size) {
|
||||
if(has_sram && (addr & 0x0e000000 ) == 0x0e000000 ) return read(ram.data, addr & ram.mask, size);
|
||||
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.read();
|
||||
if(has_flashrom && (addr & 0x0f000000 ) == 0x0e000000 ) return flashrom.read(addr);
|
||||
if(addr < 0x0e000000) return read(rom.data, addr & 0x01ffffff, size);
|
||||
return cpu.pipeline.fetch.instruction;
|
||||
}
|
||||
|
||||
void Cartridge::write(uint32 addr, uint32 size, uint32 word) {
|
||||
if(has_sram && (addr & 0x0e000000 ) == 0x0e000000 ) return write(ram.data, addr & ram.mask, size, word);
|
||||
if(has_eeprom && (addr & eeprom.mask) == eeprom.test) return eeprom.write(word & 1);
|
||||
if(has_flashrom && (addr & 0x0f000000 ) == 0x0e000000 ) return flashrom.write(addr, word);
|
||||
}
|
||||
|
||||
Cartridge::Cartridge() {
|
||||
loaded = false;
|
||||
rom.data = new uint8[rom.size = 32 * 1024 * 1024];
|
||||
ram.data = new uint8[ram.size = 32 * 1024];
|
||||
eeprom.data = new uint8[eeprom.size = 8 * 1024];
|
||||
flashrom.data = new uint8[flashrom.size = 128 * 1024];
|
||||
}
|
||||
|
||||
Cartridge::~Cartridge() {
|
||||
delete[] rom.data;
|
||||
delete[] ram.data;
|
||||
delete[] eeprom.data;
|
||||
delete[] flashrom.data;
|
||||
}
|
||||
|
||||
}
|
33
bsnes/gba/cartridge/cartridge.hpp
Executable file
33
bsnes/gba/cartridge/cartridge.hpp
Executable file
@@ -0,0 +1,33 @@
|
||||
struct Cartridge : property<Cartridge> {
|
||||
#include "memory.hpp"
|
||||
|
||||
readonly<bool> loaded;
|
||||
readonly<string> sha256;
|
||||
|
||||
readonly<bool> has_sram;
|
||||
readonly<bool> has_eeprom;
|
||||
readonly<bool> has_flashrom;
|
||||
|
||||
struct Information {
|
||||
string markup;
|
||||
} information;
|
||||
|
||||
bool load(const string &markup, const uint8_t *data, unsigned size);
|
||||
void unload();
|
||||
void power();
|
||||
|
||||
uint8* ram_data();
|
||||
unsigned ram_size();
|
||||
|
||||
uint32 read(uint8 *data, uint32 addr, uint32 size);
|
||||
void write(uint8 *data, uint32 addr, uint32 size, uint32 word);
|
||||
|
||||
uint32 read(uint32 addr, uint32 size);
|
||||
void write(uint32 addr, uint32 size, uint32 word);
|
||||
|
||||
void serialize(serializer&);
|
||||
Cartridge();
|
||||
~Cartridge();
|
||||
};
|
||||
|
||||
extern Cartridge cartridge;
|
94
bsnes/gba/cartridge/eeprom.cpp
Executable file
94
bsnes/gba/cartridge/eeprom.cpp
Executable file
@@ -0,0 +1,94 @@
|
||||
bool Cartridge::EEPROM::read(unsigned addr) {
|
||||
return data[addr >> 3] & 0x80 >> (addr & 7);
|
||||
}
|
||||
|
||||
void Cartridge::EEPROM::write(unsigned addr, bool bit) {
|
||||
if(bit == 0) data[addr >> 3] &=~ (0x80 >> (addr & 7));
|
||||
if(bit == 1) data[addr >> 3] |= (0x80 >> (addr & 7));
|
||||
}
|
||||
|
||||
bool Cartridge::EEPROM::read() {
|
||||
bool bit = 1;
|
||||
|
||||
//EEPROM size auto-detection
|
||||
if(bits == 0 && mode == Mode::ReadAddress) {
|
||||
print("EEPROM address bits: ", --addressbits, "\n");
|
||||
bits = addressbits == 6 ? 6 : 14;
|
||||
size = 8192;
|
||||
mode = Mode::ReadData;
|
||||
offset = 0;
|
||||
//fallthrough
|
||||
}
|
||||
|
||||
if(mode == Mode::ReadData) {
|
||||
if(offset >= 4) bit = read(address * 64 + (offset - 4));
|
||||
if(++offset == 68) mode = Mode::Wait;
|
||||
}
|
||||
|
||||
return bit;
|
||||
}
|
||||
|
||||
void Cartridge::EEPROM::write(bool bit) {
|
||||
if(mode == Mode::Wait) {
|
||||
if(bit == 1) mode = Mode::Command;
|
||||
}
|
||||
|
||||
else if(mode == Mode::Command) {
|
||||
if(bit == 0) mode = Mode::WriteAddress;
|
||||
if(bit == 1) mode = Mode::ReadAddress;
|
||||
offset = 0;
|
||||
address = 0;
|
||||
addressbits = 0;
|
||||
}
|
||||
|
||||
else if(mode == Mode::ReadAddress) {
|
||||
address = (address << 1) | bit;
|
||||
addressbits++;
|
||||
if(++offset == bits) {
|
||||
mode = Mode::ReadValidate;
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
else if(mode == Mode::ReadValidate) {
|
||||
if(bit == 1); //invalid
|
||||
mode = Mode::ReadData;
|
||||
}
|
||||
|
||||
else if(mode == Mode::WriteAddress) {
|
||||
address = (address << 1) | bit;
|
||||
if(++offset == bits) {
|
||||
mode = Mode::WriteData;
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
else if(mode == Mode::WriteData) {
|
||||
write(address * 64 + offset, bit);
|
||||
if(++offset == 64) {
|
||||
mode = Mode::WriteValidate;
|
||||
}
|
||||
}
|
||||
|
||||
else if(mode == Mode::WriteValidate) {
|
||||
if(bit == 1); //invalid
|
||||
mode = Mode::Wait;
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::EEPROM::power() {
|
||||
mode = Mode::Wait;
|
||||
offset = 0;
|
||||
address = 0;
|
||||
}
|
||||
|
||||
void Cartridge::EEPROM::serialize(serializer &s) {
|
||||
s.array(data, size);
|
||||
s.integer(size);
|
||||
s.integer(mask);
|
||||
s.integer(test);
|
||||
s.integer(bits);
|
||||
s.integer((unsigned&)mode);
|
||||
s.integer(offset);
|
||||
s.integer(address);
|
||||
}
|
100
bsnes/gba/cartridge/flashrom.cpp
Executable file
100
bsnes/gba/cartridge/flashrom.cpp
Executable file
@@ -0,0 +1,100 @@
|
||||
//Dev.ID Size Blocks Manufacturer
|
||||
//====== ===== ======== ============
|
||||
//0xd4bf 64KB 16x4096 SST
|
||||
//0x1cc2 64KB 16x4096 Macronix
|
||||
//0x1b32 64KB 16x4096 Panasonic
|
||||
//0x3d1f 64KB 512x 128 Atmel
|
||||
//0x1362 128KB 32x4096 Sanyo
|
||||
//0x09c2 128KB 32x4096 Macronix
|
||||
|
||||
uint8 Cartridge::FlashROM::read(uint16 addr) {
|
||||
if(idmode) {
|
||||
if(addr == 0x0000) return id >> 0;
|
||||
if(addr == 0x0001) return id >> 8;
|
||||
return 0u;
|
||||
}
|
||||
|
||||
return data[bank << 16 | addr];
|
||||
}
|
||||
|
||||
void Cartridge::FlashROM::write(uint16 addr, uint8 byte) {
|
||||
if(bankselect) {
|
||||
bankselect = false;
|
||||
//bank select is only applicable on 128KB chips
|
||||
if(addr == 0x0000) bank = byte & (size > 64 * 1024);
|
||||
return;
|
||||
}
|
||||
|
||||
if(writeselect) {
|
||||
//Atmel writes 128 bytes per command; all others write 1 byte per command
|
||||
if(id != 0x3d1f || (addr & 0x007f) == 0x007f) writeselect = false;
|
||||
data[bank << 16 | addr] = byte;
|
||||
return;
|
||||
}
|
||||
|
||||
if(byte == 0xaa && addr == 0x5555) { unlockhi = true; return; }
|
||||
if(byte == 0x55 && addr == 0x2aaa) { unlocklo = true; return; }
|
||||
|
||||
if(unlockhi && unlocklo) {
|
||||
unlockhi = false;
|
||||
unlocklo = false;
|
||||
|
||||
if(byte == 0x10 && addr == 0x5555) {
|
||||
if(erasemode) {
|
||||
erasemode = false;
|
||||
for(unsigned n = 0; n < size; n++) data[n] = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
if(byte == 0x30 && (addr & 0x0fff) == 0x0000) {
|
||||
//command only valid for non-Atmel chips
|
||||
if(erasemode && id != 0x3d1f) {
|
||||
erasemode = false;
|
||||
unsigned offset = bank << 16 | (addr & ~4095);
|
||||
for(unsigned n = 0; n < 4096; n++) data[offset++] = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
if(byte == 0x80 && addr == 0x5555) {
|
||||
erasemode = true;
|
||||
}
|
||||
|
||||
if(byte == 0x90 && addr == 0x5555) {
|
||||
idmode = true;
|
||||
}
|
||||
|
||||
if(byte == 0xa0 && addr == 0x5555) {
|
||||
writeselect = true;
|
||||
}
|
||||
|
||||
if(byte == 0xb0 && addr == 0x5555) {
|
||||
bankselect = true;
|
||||
}
|
||||
|
||||
if(byte == 0xf0 && addr == 0x5555) {
|
||||
idmode = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Cartridge::FlashROM::power() {
|
||||
unlockhi = false;
|
||||
unlocklo = false;
|
||||
idmode = false;
|
||||
bankselect = false;
|
||||
writeselect = false;
|
||||
bank = 0;
|
||||
}
|
||||
|
||||
void Cartridge::FlashROM::serialize(serializer &s) {
|
||||
s.array(data, size);
|
||||
s.integer(size);
|
||||
s.integer(id);
|
||||
s.integer(unlockhi);
|
||||
s.integer(unlocklo);
|
||||
s.integer(idmode);
|
||||
s.integer(erasemode);
|
||||
s.integer(bankselect);
|
||||
s.integer(writeselect);
|
||||
s.integer(bank);
|
||||
}
|
45
bsnes/gba/cartridge/memory.hpp
Executable file
45
bsnes/gba/cartridge/memory.hpp
Executable file
@@ -0,0 +1,45 @@
|
||||
struct Memory {
|
||||
uint8 *data;
|
||||
unsigned size;
|
||||
unsigned mask;
|
||||
} rom, ram;
|
||||
|
||||
struct EEPROM {
|
||||
uint8 *data;
|
||||
unsigned size;
|
||||
unsigned mask;
|
||||
unsigned test;
|
||||
unsigned bits;
|
||||
|
||||
enum class Mode : unsigned { Wait, Command, ReadAddress, ReadValidate, ReadData, WriteAddress, WriteData, WriteValidate } mode;
|
||||
unsigned offset;
|
||||
unsigned address;
|
||||
unsigned addressbits;
|
||||
|
||||
bool read(unsigned addr);
|
||||
void write(unsigned addr, bool bit);
|
||||
|
||||
bool read();
|
||||
void write(bool bit);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
} eeprom;
|
||||
|
||||
struct FlashROM {
|
||||
uint8 *data;
|
||||
unsigned size;
|
||||
uint16 id;
|
||||
|
||||
bool unlockhi;
|
||||
bool unlocklo;
|
||||
bool idmode;
|
||||
bool erasemode;
|
||||
bool bankselect;
|
||||
bool writeselect;
|
||||
bool bank;
|
||||
|
||||
uint8 read(uint16 addr);
|
||||
void write(uint16 addr, uint8 byte);
|
||||
void power();
|
||||
void serialize(serializer&);
|
||||
} flashrom;
|
5
bsnes/gba/cartridge/serialization.cpp
Executable file
5
bsnes/gba/cartridge/serialization.cpp
Executable file
@@ -0,0 +1,5 @@
|
||||
void Cartridge::serialize(serializer &s) {
|
||||
if(has_sram) s.array(ram.data, ram.size);
|
||||
if(has_eeprom) eeprom.serialize(s);
|
||||
if(has_flashrom) flashrom.serialize(s);
|
||||
}
|
173
bsnes/gba/cpu/cpu.cpp
Executable file
173
bsnes/gba/cpu/cpu.cpp
Executable file
@@ -0,0 +1,173 @@
|
||||
#include <gba/gba.hpp>
|
||||
|
||||
namespace GBA {
|
||||
|
||||
#include "registers.cpp"
|
||||
#include "mmio.cpp"
|
||||
#include "memory.cpp"
|
||||
#include "dma.cpp"
|
||||
#include "timer.cpp"
|
||||
#include "serialization.cpp"
|
||||
CPU cpu;
|
||||
|
||||
void CPU::Enter() {
|
||||
while(true) {
|
||||
if(scheduler.sync == Scheduler::SynchronizeMode::CPU) {
|
||||
scheduler.sync = Scheduler::SynchronizeMode::All;
|
||||
scheduler.exit(Scheduler::ExitReason::SynchronizeEvent);
|
||||
}
|
||||
|
||||
cpu.main();
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::main() {
|
||||
#if defined(DEBUG)
|
||||
if(crash) {
|
||||
print(cpsr().t ? disassemble_thumb_instruction(pipeline.execute.address)
|
||||
: disassemble_arm_instruction(pipeline.execute.address), "\n");
|
||||
print(disassemble_registers(), "\n");
|
||||
print("Executed: ", instructions, "\n");
|
||||
while(true) step(frequency);
|
||||
}
|
||||
#endif
|
||||
|
||||
processor.irqline = regs.ime && (regs.irq.enable & regs.irq.flag);
|
||||
|
||||
if(regs.mode == Registers::Mode::Stop) {
|
||||
if((regs.irq.enable.keypad & regs.irq.flag.keypad) == 0) {
|
||||
sync_step(16); //STOP does not advance timers
|
||||
} else {
|
||||
regs.mode = Registers::Mode::Normal;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
dma_run();
|
||||
|
||||
if(regs.mode == Registers::Mode::Halt) {
|
||||
if((regs.irq.enable & regs.irq.flag) == 0) {
|
||||
step(16);
|
||||
} else {
|
||||
regs.mode = Registers::Mode::Normal;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
exec();
|
||||
}
|
||||
|
||||
void CPU::step(unsigned clocks) {
|
||||
timer_step(clocks);
|
||||
sync_step(clocks);
|
||||
}
|
||||
|
||||
void CPU::sync_step(unsigned clocks) {
|
||||
ppu.clock -= clocks;
|
||||
if(ppu.clock < 0) co_switch(ppu.thread);
|
||||
|
||||
apu.clock -= clocks;
|
||||
if(apu.clock < 0) co_switch(apu.thread);
|
||||
}
|
||||
|
||||
void CPU::bus_idle(uint32 addr) {
|
||||
step(1);
|
||||
return bus.idle(addr);
|
||||
}
|
||||
|
||||
uint32 CPU::bus_read(uint32 addr, uint32 size) {
|
||||
step(bus.speed(addr, size));
|
||||
return bus.read(addr, size);
|
||||
}
|
||||
|
||||
void CPU::bus_write(uint32 addr, uint32 size, uint32 word) {
|
||||
step(bus.speed(addr, size));
|
||||
return bus.write(addr, size, word);
|
||||
}
|
||||
|
||||
void CPU::keypad_run() {
|
||||
if(regs.keypad.control.enable == false) return;
|
||||
|
||||
bool test = regs.keypad.control.condition; //0 = OR, 1 = AND
|
||||
for(unsigned n = 0; n < 10; n++) {
|
||||
if(regs.keypad.control.flag[n] == false) continue;
|
||||
bool input = interface->inputPoll(n);
|
||||
if(regs.keypad.control.condition == 0) test |= input;
|
||||
if(regs.keypad.control.condition == 1) test &= input;
|
||||
}
|
||||
if(test) regs.irq.flag.keypad = true;
|
||||
}
|
||||
|
||||
void CPU::power() {
|
||||
create(CPU::Enter, 16777216);
|
||||
|
||||
ARM::power();
|
||||
for(unsigned n = 0; n < 32 * 1024; n++) iwram[n] = 0;
|
||||
for(unsigned n = 0; n < 256 * 1024; n++) ewram[n] = 0;
|
||||
|
||||
for(auto &dma : regs.dma) {
|
||||
dma.source = 0;
|
||||
dma.target = 0;
|
||||
dma.length = 0;
|
||||
dma.control = 0;
|
||||
dma.pending = 0;
|
||||
dma.run.target = 0;
|
||||
dma.run.source = 0;
|
||||
dma.run.length = 0;
|
||||
}
|
||||
for(auto &timer : regs.timer) {
|
||||
timer.period = 0;
|
||||
timer.reload = 0;
|
||||
timer.control = 0;
|
||||
}
|
||||
regs.keypad.control = 0;
|
||||
regs.ime = 0;
|
||||
regs.irq.enable = 0;
|
||||
regs.irq.flag = 0;
|
||||
regs.wait.control = 0;
|
||||
regs.postboot = 0;
|
||||
regs.mode = Registers::Mode::Normal;
|
||||
regs.clock = 0;
|
||||
regs.memory.control = 0x0d000020;
|
||||
|
||||
pending.dma.vblank = 0;
|
||||
pending.dma.hblank = 0;
|
||||
pending.dma.hdma = 0;
|
||||
|
||||
for(unsigned n = 0x0b0; n <= 0x0df; n++) bus.mmio[n] = this; //DMA
|
||||
for(unsigned n = 0x100; n <= 0x10f; n++) bus.mmio[n] = this; //Timers
|
||||
for(unsigned n = 0x120; n <= 0x12b; n++) bus.mmio[n] = this; //Serial
|
||||
for(unsigned n = 0x130; n <= 0x133; n++) bus.mmio[n] = this; //Keypad
|
||||
for(unsigned n = 0x134; n <= 0x159; n++) bus.mmio[n] = this; //Serial
|
||||
for(unsigned n = 0x200; n <= 0x209; n++) bus.mmio[n] = this; //System
|
||||
for(unsigned n = 0x300; n <= 0x301; n++) bus.mmio[n] = this; //System
|
||||
//0x080-0x083 mirrored via gba/memory/memory.cpp //System
|
||||
}
|
||||
|
||||
CPU::CPU() {
|
||||
iwram = new uint8[ 32 * 1024];
|
||||
ewram = new uint8[256 * 1024];
|
||||
|
||||
regs.dma[0].source.bits(27); regs.dma[0].run.source.bits(27);
|
||||
regs.dma[0].target.bits(27); regs.dma[0].run.target.bits(27);
|
||||
regs.dma[0].length.bits(14); regs.dma[0].run.length.bits(14);
|
||||
|
||||
regs.dma[1].source.bits(28); regs.dma[1].run.source.bits(28);
|
||||
regs.dma[1].target.bits(27); regs.dma[1].run.target.bits(27);
|
||||
regs.dma[1].length.bits(14); regs.dma[1].run.length.bits(14);
|
||||
|
||||
regs.dma[2].source.bits(28); regs.dma[2].run.source.bits(28);
|
||||
regs.dma[2].target.bits(27); regs.dma[2].run.target.bits(27);
|
||||
regs.dma[2].length.bits(14); regs.dma[2].run.length.bits(14);
|
||||
|
||||
regs.dma[3].source.bits(28); regs.dma[3].run.source.bits(28);
|
||||
regs.dma[3].target.bits(28); regs.dma[3].run.target.bits(28);
|
||||
regs.dma[3].length.bits(16); regs.dma[3].run.length.bits(16);
|
||||
}
|
||||
|
||||
CPU::~CPU() {
|
||||
delete[] iwram;
|
||||
delete[] ewram;
|
||||
}
|
||||
|
||||
}
|
43
bsnes/gba/cpu/cpu.hpp
Executable file
43
bsnes/gba/cpu/cpu.hpp
Executable file
@@ -0,0 +1,43 @@
|
||||
struct CPU : Processor::ARM, Thread, MMIO {
|
||||
uint8 *iwram;
|
||||
uint8 *ewram;
|
||||
#include "registers.hpp"
|
||||
#include "state.hpp"
|
||||
|
||||
static void Enter();
|
||||
void main();
|
||||
void step(unsigned clocks);
|
||||
void sync_step(unsigned clocks);
|
||||
|
||||
void bus_idle(uint32 addr);
|
||||
uint32 bus_read(uint32 addr, uint32 size);
|
||||
void bus_write(uint32 addr, uint32 size, uint32 word);
|
||||
|
||||
void keypad_run();
|
||||
void power();
|
||||
|
||||
uint8 read(uint32 addr);
|
||||
void write(uint32 addr, uint8 byte);
|
||||
|
||||
uint32 iwram_read(uint32 addr, uint32 size);
|
||||
void iwram_write(uint32 addr, uint32 size, uint32 word);
|
||||
|
||||
uint32 ewram_read(uint32 addr, uint32 size);
|
||||
void ewram_write(uint32 addr, uint32 size, uint32 word);
|
||||
|
||||
void dma_run();
|
||||
void dma_transfer(Registers::DMA &dma);
|
||||
void dma_vblank();
|
||||
void dma_hblank();
|
||||
void dma_hdma();
|
||||
|
||||
void timer_step(unsigned clocks);
|
||||
void timer_increment(unsigned n);
|
||||
void timer_fifo_run(unsigned n);
|
||||
|
||||
void serialize(serializer&);
|
||||
CPU();
|
||||
~CPU();
|
||||
};
|
||||
|
||||
extern CPU cpu;
|
60
bsnes/gba/cpu/dma.cpp
Executable file
60
bsnes/gba/cpu/dma.cpp
Executable file
@@ -0,0 +1,60 @@
|
||||
void CPU::dma_run() {
|
||||
for(unsigned n = 0; n < 4; n++) {
|
||||
auto &dma = regs.dma[n];
|
||||
if(dma.pending) {
|
||||
dma.pending = false;
|
||||
dma_transfer(dma);
|
||||
if(dma.control.irq) regs.irq.flag.dma[n] = 1;
|
||||
if(dma.control.drq && n == 3) regs.irq.flag.cartridge = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::dma_transfer(Registers::DMA &dma) {
|
||||
unsigned size = dma.control.size ? Word : Half;
|
||||
unsigned seek = dma.control.size ? 4 : 2;
|
||||
|
||||
sequential() = false;
|
||||
do {
|
||||
step(bus.speed(dma.run.source, size));
|
||||
uint32 word = bus.read(dma.run.source, size);
|
||||
|
||||
step(bus.speed(dma.run.target, size));
|
||||
bus.write(dma.run.target, size, word);
|
||||
|
||||
sequential() = true;
|
||||
|
||||
switch(dma.control.sourcemode) {
|
||||
case 0: dma.run.source += seek; break;
|
||||
case 1: dma.run.source -= seek; break;
|
||||
}
|
||||
|
||||
switch(dma.control.targetmode) {
|
||||
case 0: dma.run.target += seek; break;
|
||||
case 1: dma.run.target -= seek; break;
|
||||
case 3: dma.run.target += seek; break;
|
||||
}
|
||||
} while(--dma.run.length);
|
||||
sequential() = false;
|
||||
|
||||
if(dma.control.targetmode == 3) dma.run.target = dma.target;
|
||||
if(dma.control.repeat == 1) dma.run.length = dma.length;
|
||||
if(dma.control.repeat == 0) dma.control.enable = false;
|
||||
}
|
||||
|
||||
void CPU::dma_vblank() {
|
||||
for(auto &dma : regs.dma) {
|
||||
if(dma.control.enable && dma.control.timingmode == 1) dma.pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::dma_hblank() {
|
||||
for(auto &dma : regs.dma) {
|
||||
if(dma.control.enable && dma.control.timingmode == 2) dma.pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CPU::dma_hdma() {
|
||||
auto &dma = regs.dma[3];
|
||||
if(dma.control.enable && dma.control.timingmode == 3) dma.pending = true;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user