Compare commits

..

1 commit

Author SHA1 Message Date
Ilari Liusvaara
3a80e18300 Reload mode for movies 2013-03-20 01:24:11 +02:00
683 changed files with 47117 additions and 131815 deletions

8
.gitignore vendored
View file

@ -3,9 +3,7 @@
*.lib
*.obj
*.exe
*.dep
*.ldflags
*.files
docs
rom
lsnes
@ -15,9 +13,3 @@ lsnes
/gambatte
src/fonts/font.cpp
src/core/version.cpp
src/cmdhelp/*.cpp
include/cmdhelp/*.hpp
src/emulation/make-ports
src/cmdhelp/mkstubs
src/cmdhelp/mkstubsi
buildaux/mkdeps

6
.gitmodules vendored
View file

@ -1,6 +0,0 @@
[submodule "bsnes"]
path = bsnes
url = .
[submodule "gambatte"]
path = gambatte
url = .

2190
CHANGELOG

File diff suppressed because it is too large Load diff

117
Makefile
View file

@ -1,27 +1,62 @@
OPTIONS=options.build
include $(OPTIONS)
ifndef LUA
LUA=lua
endif
#Compilers.
REALCC = $(CROSS_PREFIX)$(CC)
REALLD = $(CROSS_PREFIX)$(LD)
REALRANLIB = $(CROSS_PREFIX)$(RANLIB)
#Flags.
HOSTCCFLAGS = -std=gnu++0x
CFLAGS += -std=gnu++0x -pthread $(USER_CFLAGS)
ifdef BOOST_NEEDS_MT
BOOST_LIB_POSTFIX=-mt
ifeq ($(CORE_TYPE), BSNES)
CORE_PATH=$(shell pwd)/bsnes
CORE_SUBDIR=bsnes
CORE_OBJECT=bsnes/out/libsnes.$(ARCHIVE_SUFFIX)
CORE_DEFINE=-DCORETYPE_BSNES=1
ifdef BSNES_IS_COMPAT
CFLAGS += -DBSNES_IS_COMPAT
BSNES_PROFILE_STRING=profile=compatibility
else
BSNES_PROFILE_STRING=profile=accuracy
endif
ifeq ($(BSNES_VERSION), 084)
BSNES_PROFILE_STRING+=options=debugger
CFLAGS += -DBSNES_HAS_DEBUGGER
else
ifeq ($(BSNES_VERSION), 085)
BSNES_PROFILE_STRING+=options=debugger
CFLAGS += -DBSNES_HAS_DEBUGGER
endif
ifdef HOST_BOOST_NEEDS_MT
HOST_BOOST_POSTFIX=-mt
endif
LDFLAGS = -pthread -lboost_iostreams$(BOOST_LIB_POSTFIX) -lboost_filesystem$(BOOST_LIB_POSTFIX) -lboost_system$(BOOST_LIB_POSTFIX) -lz $(USER_LDFLAGS)
HOSTHELPER_LDFLAGS =
ifeq ($(BSNES_VERSION), 087)
BSNES_TARGET_STRING=target=libsnes
else
BSNES_TARGET_STRING=ui=ui-libsnes
endif
CFLAGS += -DBSNES_V${BSNES_VERSION}
else
ifeq ($(CORE_TYPE), GAMBATTE)
CORE_PATH=$(shell pwd)/gambatte
CORE_SUBDIR=gambatte
CORE_OBJECT=gambatte/libgambatte/libgambatte.$(ARCHIVE_SUFFIX)
CORE_DEFINE=-DCORETYPE_GAMBATTE=1
BSNES_PROFILE_STRING=
BSNES_TARGET_STRING=
else
$(error "Bad value for CORETYPE (expected BSNES or GAMBATTE)")
endif
endif
#Flags.
HOSTCCFLAGS = -std=gnu++0x
CFLAGS += -I$(CORE_PATH) $(CORE_DEFINE) -std=gnu++0x $(USER_CFLAGS)
ifdef BOOST_NEEDS_MT
BOOST_LIB_POSTFIX=-mt
else
BOOST_LIB_POSTFIX=
endif
LDFLAGS = -lboost_iostreams$(BOOST_LIB_POSTFIX) -lboost_filesystem$(BOOST_LIB_POSTFIX) -lboost_system$(BOOST_LIB_POSTFIX) -lboost_regex$(BOOST_LIB_POSTFIX) -lz $(USER_LDFLAGS)
ifeq ($(THREADS), NATIVE)
CFLAGS += -DNATIVE_THREADS
@ -34,73 +69,35 @@ $(error "Bad value for THREADS (expected NATIVE or BOOST)")
endif
endif
ifeq ($(REGEX), BOOST)
CFLAGS += -DUSE_BOOST_REGEX
LDFLAGS += -lboost_regex$(BOOST_LIB_POSTFIX)
HOSTHELPER_LDFLAGS += -lboost_regex$(HOST_BOOST_POSTFIX)
endif
HOSTHELPER_LDFLAGS += -lboost_system$(HOST_BOOST_POSTFIX)
ifdef NEED_LIBICONV
LDFLAGS += -liconv
endif
ifdef USE_LIBGCRYPT
CFLAGS += -DUSE_LIBGCRYPT_SHA256
LDFLAGS += -lgcrypt -lgpg-error
endif
ifdef USE_LIBLZMA
CFLAGS += -DLIBLZMA_AVAILABLE
LDFLAGS += -llzma
endif
ifeq ($(ARCHITECTURE), I386)
CFLAGS += -DARCH_IS_I386
else
endif
export
all: src/__all_files__
CFLAGS += $(shell $(CROSS_PREFIX)pkg-config $(LUA) --cflags)
LDFLAGS += $(shell $(CROSS_PREFIX)pkg-config $(LUA) --libs)
CFLAGS += $(shell $(CROSS_PREFIX)curl-config --cflags)
LDFLAGS += $(shell $(CROSS_PREFIX)curl-config --libs)
compiler=$(subst ++,cc,$(REALCC))
gambatte_compiler=$(REALCC)
bsnes/out/libsnes.$(ARCHIVE_SUFFIX): forcelook
$(MAKE) -C bsnes $(BSNES_PROFILE_STRING) $(BSNES_TARGET_STRING)
$(REALRANLIB) bsnes/out/libsnes.$(ARCHIVE_SUFFIX)
$(CORE_OBJECT): forcelook
$(MAKE) -C $(CORE_SUBDIR) $(BSNES_PROFILE_STRING) $(BSNES_TARGET_STRING)
$(REALRANLIB) $@
src/__all_files__: src/core/version.cpp buildaux/mkdeps$(DOT_EXECUTABLE_SUFFIX) buildaux/txt2cstr$(DOT_EXECUTABLE_SUFFIX) forcelook
src/__all_files__: src/core/version.cpp forcelook $(CORE_OBJECT)
$(MAKE) -C src precheck
$(MAKE) -C src
cp src/lsnes$(DOT_EXECUTABLE_SUFFIX) .
buildaux/txt2cstr$(DOT_EXECUTABLE_SUFFIX): buildaux/txt2cstr.cpp
buildaux/version.exe: buildaux/version.cpp VERSION
$(HOSTCC) $(HOSTCCFLAGS) -o $@ $<
buildaux/version$(DOT_EXECUTABLE_SUFFIX): buildaux/version.cpp VERSION
$(HOSTCC) $(HOSTCCFLAGS) -o $@ $<
buildaux/mkdeps$(DOT_EXECUTABLE_SUFFIX): buildaux/mkdeps.cpp VERSION
$(HOSTCC) $(HOSTCCFLAGS) -o $@ $< -lboost_filesystem$(HOST_BOOST_POSTFIX) -lboost_system$(HOST_BOOST_POSTFIX)
src/core/version.cpp: buildaux/version$(DOT_EXECUTABLE_SUFFIX) forcelook
buildaux/version$(DOT_EXECUTABLE_SUFFIX) >$@
src/core/version.cpp: buildaux/version.exe forcelook
buildaux/version.exe >$@
platclean:
$(MAKE) -C src platclean
clean:
-$(MAKE) -C bsnes clean
-$(MAKE) -C gambatte clean
$(MAKE) -C src clean
rm -f buildaux/version$(DOT_EXECUTABLE_SUFFIX)
rm -f buildaux/mkdeps$(DOT_EXECUTABLE_SUFFIX)
rm -f buildaux/txt2cstr$(DOT_EXECUTABLE_SUFFIX)
forcelook:
@true

3
TODO
View file

@ -1,3 +0,0 @@
- Memory Tracking: Track dynamic state.
- Fix paths and filenames containing non-ASCII on Win32.
- Win64 build.

View file

@ -1 +1 @@
2-β24
1-Δ17ε1

1
bsnes

@ -1 +0,0 @@
Subproject commit 4cfbbeadc3abe3e3911f7f59ce57b715edc76563

View file

@ -1,13 +1,13 @@
From 831e9614a7babbacf59935960fbaa6cfc8d49c08 Mon Sep 17 00:00:00 2001
From df75db4512ef7e6ad70f8cee8c7d7071132168f0 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 9 Nov 2011 00:30:36 +0200
Subject: [PATCH 01/10] Make libsnes compile
Subject: [PATCH 1/7] Make libsnes compile
Changes between v083 and v084 had broken libsnes. Fix it so it at least
compiles.
---
ui-libsnes/libsnes.cpp | 37 +++++++++++++++++++++++++++++++++++--
1 file changed, 35 insertions(+), 2 deletions(-)
ui-libsnes/libsnes.cpp | 37 +++++++++++++++++++++++++++++++++++--
1 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/ui-libsnes/libsnes.cpp b/ui-libsnes/libsnes.cpp
index fbb4482..5f5ded6 100755
@ -78,5 +78,5 @@ index fbb4482..5f5ded6 100755
}
SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, xmlrom);
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,12 +1,11 @@
From df7851648e41ae6b6efd1a54cdcd32ac55a90131 Mon Sep 17 00:00:00 2001
From 637952f6b97bef882ca3870be8d434c31aeacf77 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 9 Nov 2011 00:31:59 +0200
Subject: [PATCH 02/10] Fix bsnes version number in libsnes to be v084, not
v083
Subject: [PATCH 2/7] Fix bsnes version number in libsnes to be v084, not v083
---
ui-libsnes/libsnes.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
ui-libsnes/libsnes.cpp | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/ui-libsnes/libsnes.cpp b/ui-libsnes/libsnes.cpp
index 5f5ded6..6b4ef12 100755
@ -22,5 +21,5 @@ index 5f5ded6..6b4ef12 100755
unsigned snes_library_revision_major(void) {
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,17 +1,17 @@
From b481e3d161d924cc5a4449329393c8d9f23b27ec Mon Sep 17 00:00:00 2001
From 308ba2d96d3dc0e49821c9db9902882e3919e372 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 9 Nov 2011 00:37:44 +0200
Subject: [PATCH 03/10] Don't use time() in emulating chips
Subject: [PATCH 3/7] Don't use time() in emulating chips
Instead of using time() in chip emulation, create new interface method
currentTime(), defaulting to time(0). This way frontend can cleanly
override the current time bsnes is using.
---
snes/chip/bsx/satellaview/satellaview.cpp | 2 +-
snes/chip/spc7110/spc7110.cpp | 2 +-
snes/chip/srtc/srtc.cpp | 2 +-
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
snes/chip/bsx/satellaview/satellaview.cpp | 2 +-
snes/chip/spc7110/spc7110.cpp | 2 +-
snes/chip/srtc/srtc.cpp | 2 +-
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
5 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/snes/chip/bsx/satellaview/satellaview.cpp b/snes/chip/bsx/satellaview/satellaview.cpp
@ -80,5 +80,5 @@ index f1a48c0..df975e8 100755
extern Interface *interface;
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,26 +1,26 @@
From af7fdd9f73a3eb5e9266c59bfb4dd676679b2f7d Mon Sep 17 00:00:00 2001
From 8d990991d97eb7742c4daa461b158d1aa9f6dce4 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 9 Nov 2011 01:52:08 +0200
Subject: [PATCH 04/10] Save controller state when savestating
Subject: [PATCH 4/7] Save controller state when savestating
When savestating, save the controller state and restore it upon loadstate.
Prevents libsnes from mixing up buttons.
---
snes/controller/controller.cpp | 8 +++++++
snes/controller/controller.hpp | 2 ++
snes/controller/gamepad/gamepad.cpp | 13 +++++++++++
snes/controller/gamepad/gamepad.hpp | 2 +-
snes/controller/justifier/justifier.cpp | 36 +++++++++++++++++++++++++++++++
snes/controller/justifier/justifier.hpp | 1 +
snes/controller/mouse/mouse.cpp | 13 +++++++++++
snes/controller/mouse/mouse.hpp | 2 +-
snes/controller/multitap/multitap.cpp | 16 ++++++++++++++
snes/controller/multitap/multitap.hpp | 2 +-
snes/controller/superscope/superscope.cpp | 31 ++++++++++++++++++++++++++
snes/controller/superscope/superscope.hpp | 1 +
snes/input/input.cpp | 15 +++++++++++++
snes/input/input.hpp | 1 +
snes/system/serialization.cpp | 1 +
snes/controller/controller.cpp | 8 ++++++
snes/controller/controller.hpp | 2 +
snes/controller/gamepad/gamepad.cpp | 13 ++++++++++
snes/controller/gamepad/gamepad.hpp | 2 +-
snes/controller/justifier/justifier.cpp | 36 +++++++++++++++++++++++++++++
snes/controller/justifier/justifier.hpp | 1 +
snes/controller/mouse/mouse.cpp | 13 ++++++++++
snes/controller/mouse/mouse.hpp | 2 +-
snes/controller/multitap/multitap.cpp | 16 +++++++++++++
snes/controller/multitap/multitap.hpp | 2 +-
snes/controller/superscope/superscope.cpp | 31 +++++++++++++++++++++++++
snes/controller/superscope/superscope.hpp | 1 +
snes/input/input.cpp | 15 ++++++++++++
snes/input/input.hpp | 1 +
snes/system/serialization.cpp | 1 +
15 files changed, 141 insertions(+), 3 deletions(-)
diff --git a/snes/controller/controller.cpp b/snes/controller/controller.cpp
@ -341,5 +341,5 @@ index f7d6f3b..08e7051 100755
if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.serialize(s);
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.serialize(s);
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,11 +1,11 @@
From aa1352516e38ff64f304d8831b357841c4795e43 Mon Sep 17 00:00:00 2001
From 0520c04455b9e96e6caa54009d4ef7c300146c67 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Fri, 11 Nov 2011 03:05:48 +0200
Subject: [PATCH 05/10] Fix unserialization of 64-bit signed integers
Subject: [PATCH 5/7] Fix unserialization of 64-bit signed integers
---
nall/serializer.hpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
nall/serializer.hpp | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/nall/serializer.hpp b/nall/serializer.hpp
index ff2337a..e6bc8fa 100755
@ -21,5 +21,5 @@ index ff2337a..e6bc8fa 100755
isize += size;
}
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,13 +1,13 @@
From 794d83cb28a93d9ae1e613598d3c7cf09090d6a3 Mon Sep 17 00:00:00 2001
From 723b5884d53db9d5e24b8cd300e97b1bb12fba29 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Fri, 11 Nov 2011 19:49:46 +0200
Subject: [PATCH 06/10] Allow frontend to control random number seed
Subject: [PATCH 6/7] Allow frontend to control random number seed
---
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
snes/system/system.cpp | 2 +-
3 files changed, 7 insertions(+), 1 deletion(-)
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
snes/system/system.cpp | 2 +-
3 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp
index b3017c9..0a21a13 100755
@ -49,5 +49,5 @@ index 6881810..8583595 100755
region = config.region;
expansion = config.expansion_port;
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,63 +1,60 @@
From 4f6981592e29038ad9f818399c0d5a48750cf28a Mon Sep 17 00:00:00 2001
From eea50468e8d7e7a034b05c819aef11a032f972eb Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 7 Mar 2012 16:57:18 +0200
Subject: [PATCH 07/10] Fix mouse polling
Subject: [PATCH 7/7] Fix mouse polling
Don't poll for mouse motion excessive number of times (no need to poll it for
each bit!)
---
snes/controller/mouse/mouse.cpp | 14 ++++++++++++--
snes/controller/mouse/mouse.hpp | 2 ++
2 files changed, 14 insertions(+), 2 deletions(-)
snes/controller/mouse/mouse.cpp | 12 ++++++++++--
snes/controller/mouse/mouse.hpp | 2 ++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp
index 6b26fae..1a066b9 100755
index 6b26fae..824ecd3 100755
--- a/snes/controller/mouse/mouse.cpp
+++ b/snes/controller/mouse/mouse.cpp
@@ -3,9 +3,13 @@
@@ -3,8 +3,10 @@
uint2 Mouse::data() {
if(counter >= 32) return 1;
- int position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
- int position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
+ if(counter == 0) {
+ _position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
+ _position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
+ position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
+ position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
+ }
+ int position_x = _position_x;
+ int position_y = _position_y;
bool direction_x = position_x < 0; //0 = right, 1 = left
bool direction_y = position_y < 0; //0 = down, 1 = up
@@ -67,10 +71,16 @@ void Mouse::serialize(serializer& s) {
@@ -67,10 +69,16 @@ void Mouse::serialize(serializer& s) {
unsigned char block[Controller::SaveSize] = {0};
block[0] = latched ? 1 : 0;
block[1] = counter;
+ block[2] = (unsigned short)_position_x >> 8;
+ block[3] = (unsigned short)_position_x;
+ block[4] = (unsigned short)_position_y >> 8;
+ block[5] = (unsigned short)_position_y;
+ block[2] = (unsigned short)position_x >> 8;
+ block[3] = (unsigned short)position_x;
+ block[4] = (unsigned short)position_y >> 8;
+ block[5] = (unsigned short)position_y;
s.array(block, Controller::SaveSize);
if(s.mode() == nall::serializer::Load) {
latched = (block[0] != 0);
counter = block[1];
+ _position_x = (short)(((unsigned short)block[2] << 8) | (unsigned short)block[3]);
+ _position_y = (short)(((unsigned short)block[4] << 8) | (unsigned short)block[5]);
+ position_x = (short)(((unsigned short)block[2] << 8) | (unsigned short)block[3]);
+ position_y = (short)(((unsigned short)block[4] << 8) | (unsigned short)block[5]);
}
}
diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp
index b66ea51..b07c8ab 100755
index b66ea51..6074f34 100755
--- a/snes/controller/mouse/mouse.hpp
+++ b/snes/controller/mouse/mouse.hpp
@@ -6,4 +6,6 @@ struct Mouse : Controller {
private:
bool latched;
unsigned counter;
+ int _position_x;
+ int _position_y;
+ int position_x;
+ int position_y;
};
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,12 +1,12 @@
From 7b09063fbcaf50c56b476a744f9f3d9634777740 Mon Sep 17 00:00:00 2001
From 170490ff3a98a4d4c923fb3fe48014359d4b5f6f Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Mon, 24 Sep 2012 21:46:09 +0300
Subject: [PATCH 08/10] Add needed support for detecting true polls as opposed
to just autopolling
Subject: [PATCH] Add needed support for detecting true polls as opposed to
just autopolling
---
snes/cpu/cpu.hpp | 1 +
snes/cpu/mmio/mmio.cpp | 18 ++++++++++--------
snes/cpu/cpu.hpp | 1 +
snes/cpu/mmio/mmio.cpp | 18 ++++++++++--------
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/snes/cpu/cpu.hpp b/snes/cpu/cpu.hpp
@ -65,5 +65,5 @@ index 8b6aaa6..c5ee930 100755
//DMAPx
uint8 CPU::mmio_r43x0(uint8 i) {
--
1.8.4.4
1.7.10.4

View file

@ -1,65 +0,0 @@
From 62f8a07104b57b75071318098145d99012dbc908 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sun, 27 Oct 2013 10:52:45 +0200
Subject: [PATCH 09/10] Support notifying latches
---
snes/cpu/mmio/mmio.cpp | 1 +
snes/cpu/timing/joypad.cpp | 1 +
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
4 files changed, 8 insertions(+)
diff --git a/snes/cpu/mmio/mmio.cpp b/snes/cpu/mmio/mmio.cpp
index c5ee930..b7afff0 100755
--- a/snes/cpu/mmio/mmio.cpp
+++ b/snes/cpu/mmio/mmio.cpp
@@ -33,6 +33,7 @@ void CPU::mmio_w2183(uint8 data) {
//strobing $4016.d0 affects both controller port latches.
//$4017 bit 0 writes are ignored.
void CPU::mmio_w4016(uint8 data) {
+ if(data&1) interface->notifyLatched();
input.port1->latch(data & 1);
input.port2->latch(data & 1);
}
diff --git a/snes/cpu/timing/joypad.cpp b/snes/cpu/timing/joypad.cpp
index 6e15346..c69b708 100755
--- a/snes/cpu/timing/joypad.cpp
+++ b/snes/cpu/timing/joypad.cpp
@@ -7,6 +7,7 @@ void CPU::step_auto_joypad_poll() {
if(status.auto_joypad_active && status.auto_joypad_poll) {
if(status.auto_joypad_counter == 0) {
+ interface->notifyLatched();
input.port1->latch(1);
input.port2->latch(1);
input.port1->latch(0);
diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp
index 0a21a13..6685556 100755
--- a/snes/interface/interface.cpp
+++ b/snes/interface/interface.cpp
@@ -28,4 +28,9 @@ time_t Interface::randomSeed()
return time(0);
}
+void Interface::notifyLatched()
+{
+ //Nothing.
+}
+
}
diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp
index 30ee7fd..203f7b0 100755
--- a/snes/interface/interface.hpp
+++ b/snes/interface/interface.hpp
@@ -7,6 +7,7 @@ struct Interface {
virtual void message(const string &text);
virtual time_t currentTime();
virtual time_t randomSeed();
+ virtual void notifyLatched();
};
extern Interface *interface;
--
1.8.4.4

View file

@ -1,22 +0,0 @@
From 242efcc9cf10fa58c8e06f154c41db21e6aa2688 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sat, 30 Nov 2013 10:26:59 +0200
Subject: [PATCH 10/10] Add support for auto-detecting bsnes version
---
bsnes.mk | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 bsnes.mk
diff --git a/bsnes.mk b/bsnes.mk
new file mode 100644
index 0000000..11300e2
--- /dev/null
+++ b/bsnes.mk
@@ -0,0 +1,3 @@
+BSNES_SUPPORTS_DEBUGGER=yes
+LIBSNES_DIR=ui-libsnes
+BSNES_VERSION=084
--
1.8.4.4

View file

@ -1,16 +1,16 @@
From b19b3b2d1d7a522af695f4482abb28e52804326b Mon Sep 17 00:00:00 2001
From 7c8d537a7be0f9c5883393e0d4a0df76d69bf19c Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 9 Nov 2011 00:30:36 +0200
Subject: [PATCH 01/27] Make libsnes compile
Subject: [PATCH 1/7] Make libsnes compile
Changes between v083 and v084 had broken libsnes. Fix it so it at least
compiles.
---
ui-libsnes/libsnes.cpp | 37 +++++++++++++++++++++++++++++++++++--
1 file changed, 35 insertions(+), 2 deletions(-)
ui-libsnes/libsnes.cpp | 37 +++++++++++++++++++++++++++++++++++--
1 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/ui-libsnes/libsnes.cpp b/ui-libsnes/libsnes.cpp
index fbb4482c..5f5ded69 100755
index fbb4482..5f5ded6 100755
--- a/ui-libsnes/libsnes.cpp
+++ b/ui-libsnes/libsnes.cpp
@@ -1,5 +1,6 @@
@ -78,5 +78,5 @@ index fbb4482c..5f5ded69 100755
}
SNES::cartridge.load(SNES::Cartridge::Mode::SuperGameBoy, xmlrom);
--
2.15.0.rc1
1.7.9.48.g85da4d

View file

@ -1,15 +1,14 @@
From bb2fed04fbfe62a89e4bcfe90f44b4738f7c7c1a Mon Sep 17 00:00:00 2001
From 5f9f74b1334cb05d8636d71c2cfc0a48685a7347 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 9 Nov 2011 00:31:59 +0200
Subject: [PATCH 02/27] Fix bsnes version number in libsnes to be v085, not
v083
Subject: [PATCH 2/7] Fix bsnes version number in libsnes to be v085, not v083
---
ui-libsnes/libsnes.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
ui-libsnes/libsnes.cpp | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/ui-libsnes/libsnes.cpp b/ui-libsnes/libsnes.cpp
index 5f5ded69..0e63075e 100755
index 5f5ded6..0e63075 100755
--- a/ui-libsnes/libsnes.cpp
+++ b/ui-libsnes/libsnes.cpp
@@ -112,7 +112,7 @@ struct Interface : public SNES::Interface {
@ -22,5 +21,5 @@ index 5f5ded69..0e63075e 100755
unsigned snes_library_revision_major(void) {
--
2.15.0.rc1
1.7.9.48.g85da4d

View file

@ -1,21 +1,21 @@
From 7379b4570e5755a5a1da25181ba4f5d1ca461a98 Mon Sep 17 00:00:00 2001
From 773d0a3f71fca2df375a8e75c081d1f28c3b817b Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 9 Nov 2011 00:37:44 +0200
Subject: [PATCH 03/27] Don't use time() in emulating chips
Subject: [PATCH 3/7] Don't use time() in emulating chips
Instead of using time() in chip emulation, create new interface method
currentTime(), defaulting to time(0). This way frontend can cleanly
override the current time bsnes is using.
---
snes/chip/bsx/satellaview/satellaview.cpp | 2 +-
snes/chip/spc7110/spc7110.cpp | 2 +-
snes/chip/srtc/srtc.cpp | 2 +-
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
snes/chip/bsx/satellaview/satellaview.cpp | 2 +-
snes/chip/spc7110/spc7110.cpp | 2 +-
snes/chip/srtc/srtc.cpp | 2 +-
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
5 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/snes/chip/bsx/satellaview/satellaview.cpp b/snes/chip/bsx/satellaview/satellaview.cpp
index 386fb628..3c980195 100755
index 386fb62..3c98019 100755
--- a/snes/chip/bsx/satellaview/satellaview.cpp
+++ b/snes/chip/bsx/satellaview/satellaview.cpp
@@ -38,7 +38,7 @@ uint8 BSXSatellaview::mmio_read(unsigned addr) {
@ -28,7 +28,7 @@ index 386fb628..3c980195 100755
regs.r2192_hour = t->tm_hour;
diff --git a/snes/chip/spc7110/spc7110.cpp b/snes/chip/spc7110/spc7110.cpp
index d2dc640b..74a817a6 100755
index d2dc640..74a817a 100755
--- a/snes/chip/spc7110/spc7110.cpp
+++ b/snes/chip/spc7110/spc7110.cpp
@@ -101,7 +101,7 @@ void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8;
@ -41,7 +41,7 @@ index d2dc640b..74a817a6 100755
//sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic.
//yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by
diff --git a/snes/chip/srtc/srtc.cpp b/snes/chip/srtc/srtc.cpp
index 1b2fd2aa..78fc4c1f 100755
index 1b2fd2a..78fc4c1 100755
--- a/snes/chip/srtc/srtc.cpp
+++ b/snes/chip/srtc/srtc.cpp
@@ -31,7 +31,7 @@ void SRTC::reset() {
@ -54,7 +54,7 @@ index 1b2fd2aa..78fc4c1f 100755
//sizeof(time_t) is platform-dependent; though rtc[] needs to be platform-agnostic.
//yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by
diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp
index a0e3a81b..b3017c90 100755
index a0e3a81..b3017c9 100755
--- a/snes/interface/interface.cpp
+++ b/snes/interface/interface.cpp
@@ -18,4 +18,9 @@ void Interface::message(const string &text) {
@ -68,7 +68,7 @@ index a0e3a81b..b3017c90 100755
+
}
diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp
index f1a48c0f..df975e83 100755
index f1a48c0..df975e8 100755
--- a/snes/interface/interface.hpp
+++ b/snes/interface/interface.hpp
@@ -5,6 +5,7 @@ struct Interface {
@ -80,5 +80,5 @@ index f1a48c0f..df975e83 100755
extern Interface *interface;
--
2.15.0.rc1
1.7.9.48.g85da4d

View file

@ -1,30 +1,30 @@
From efe1b5884c316ce070953edd87c6c9aeffffaa94 Mon Sep 17 00:00:00 2001
From c7bf497a7016c9be3a1e2fff46973a555f9ad555 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 9 Nov 2011 01:52:08 +0200
Subject: [PATCH 04/27] Save controller state when savestating
Subject: [PATCH 4/7] Save controller state when savestating
When savestating, save the controller state and restore it upon loadstate.
Prevents libsnes from mixing up buttons.
---
snes/controller/controller.cpp | 8 +++++++
snes/controller/controller.hpp | 2 ++
snes/controller/gamepad/gamepad.cpp | 13 +++++++++++
snes/controller/gamepad/gamepad.hpp | 2 +-
snes/controller/justifier/justifier.cpp | 36 +++++++++++++++++++++++++++++++
snes/controller/justifier/justifier.hpp | 1 +
snes/controller/mouse/mouse.cpp | 13 +++++++++++
snes/controller/mouse/mouse.hpp | 2 +-
snes/controller/multitap/multitap.cpp | 16 ++++++++++++++
snes/controller/multitap/multitap.hpp | 2 +-
snes/controller/superscope/superscope.cpp | 31 ++++++++++++++++++++++++++
snes/controller/superscope/superscope.hpp | 1 +
snes/system/input.cpp | 16 ++++++++++++++
snes/system/input.hpp | 1 +
snes/system/serialization.cpp | 1 +
snes/controller/controller.cpp | 8 ++++++
snes/controller/controller.hpp | 2 +
snes/controller/gamepad/gamepad.cpp | 13 ++++++++++
snes/controller/gamepad/gamepad.hpp | 2 +-
snes/controller/justifier/justifier.cpp | 36 +++++++++++++++++++++++++++++
snes/controller/justifier/justifier.hpp | 1 +
snes/controller/mouse/mouse.cpp | 13 ++++++++++
snes/controller/mouse/mouse.hpp | 2 +-
snes/controller/multitap/multitap.cpp | 16 +++++++++++++
snes/controller/multitap/multitap.hpp | 2 +-
snes/controller/superscope/superscope.cpp | 31 +++++++++++++++++++++++++
snes/controller/superscope/superscope.hpp | 1 +
snes/system/input.cpp | 16 +++++++++++++
snes/system/input.hpp | 1 +
snes/system/serialization.cpp | 1 +
15 files changed, 142 insertions(+), 3 deletions(-)
diff --git a/snes/controller/controller.cpp b/snes/controller/controller.cpp
index 9091b21b..f254bedb 100755
index 9091b21..f254bed 100755
--- a/snes/controller/controller.cpp
+++ b/snes/controller/controller.cpp
@@ -46,8 +46,16 @@ void Controller::iobit(bool data) {
@ -45,7 +45,7 @@ index 9091b21b..f254bedb 100755
+
}
diff --git a/snes/controller/controller.hpp b/snes/controller/controller.hpp
index 73327129..827b2eb4 100755
index 7332712..827b2eb 100755
--- a/snes/controller/controller.hpp
+++ b/snes/controller/controller.hpp
@@ -13,12 +13,14 @@
@ -64,7 +64,7 @@ index 73327129..827b2eb4 100755
bool iobit();
void iobit(bool data);
diff --git a/snes/controller/gamepad/gamepad.cpp b/snes/controller/gamepad/gamepad.cpp
index 594020d2..4fa1c99e 100755
index 594020d..4fa1c99 100755
--- a/snes/controller/gamepad/gamepad.cpp
+++ b/snes/controller/gamepad/gamepad.cpp
@@ -13,6 +13,19 @@ void Gamepad::latch(bool data) {
@ -88,7 +88,7 @@ index 594020d2..4fa1c99e 100755
latched = 0;
counter = 0;
diff --git a/snes/controller/gamepad/gamepad.hpp b/snes/controller/gamepad/gamepad.hpp
index c5ca69ca..a2392d1e 100755
index c5ca69c..a2392d1 100755
--- a/snes/controller/gamepad/gamepad.hpp
+++ b/snes/controller/gamepad/gamepad.hpp
@@ -2,7 +2,7 @@ struct Gamepad : Controller {
@ -101,7 +101,7 @@ index c5ca69ca..a2392d1e 100755
bool latched;
unsigned counter;
diff --git a/snes/controller/justifier/justifier.cpp b/snes/controller/justifier/justifier.cpp
index 62079166..ad13a9bd 100755
index 6207916..ad13a9b 100755
--- a/snes/controller/justifier/justifier.cpp
+++ b/snes/controller/justifier/justifier.cpp
@@ -100,6 +100,42 @@ void Justifier::latch(bool data) {
@ -148,7 +148,7 @@ index 62079166..ad13a9bd 100755
create(Controller::Enter, 21477272);
latched = 0;
diff --git a/snes/controller/justifier/justifier.hpp b/snes/controller/justifier/justifier.hpp
index f927acf6..6b7bba07 100755
index f927acf..6b7bba0 100755
--- a/snes/controller/justifier/justifier.hpp
+++ b/snes/controller/justifier/justifier.hpp
@@ -2,6 +2,7 @@ struct Justifier : Controller {
@ -160,7 +160,7 @@ index f927acf6..6b7bba07 100755
//private:
diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp
index c9f5d16b..6b26fae5 100755
index c9f5d16..6b26fae 100755
--- a/snes/controller/mouse/mouse.cpp
+++ b/snes/controller/mouse/mouse.cpp
@@ -61,6 +61,19 @@ void Mouse::latch(bool data) {
@ -184,7 +184,7 @@ index c9f5d16b..6b26fae5 100755
latched = 0;
counter = 0;
diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp
index 95e24b65..b66ea513 100755
index 95e24b6..b66ea51 100755
--- a/snes/controller/mouse/mouse.hpp
+++ b/snes/controller/mouse/mouse.hpp
@@ -2,7 +2,7 @@ struct Mouse : Controller {
@ -197,7 +197,7 @@ index 95e24b65..b66ea513 100755
bool latched;
unsigned counter;
diff --git a/snes/controller/multitap/multitap.cpp b/snes/controller/multitap/multitap.cpp
index 3a6eb720..146c41d4 100755
index 3a6eb72..146c41d 100755
--- a/snes/controller/multitap/multitap.cpp
+++ b/snes/controller/multitap/multitap.cpp
@@ -30,6 +30,22 @@ void Multitap::latch(bool data) {
@ -224,7 +224,7 @@ index 3a6eb720..146c41d4 100755
latched = 0;
counter1 = 0;
diff --git a/snes/controller/multitap/multitap.hpp b/snes/controller/multitap/multitap.hpp
index 0540af71..e6324ac5 100755
index 0540af7..e6324ac 100755
--- a/snes/controller/multitap/multitap.hpp
+++ b/snes/controller/multitap/multitap.hpp
@@ -2,7 +2,7 @@ struct Multitap : Controller {
@ -237,7 +237,7 @@ index 0540af71..e6324ac5 100755
bool latched;
unsigned counter1;
diff --git a/snes/controller/superscope/superscope.cpp b/snes/controller/superscope/superscope.cpp
index 12068f05..1a1dfbff 100755
index 12068f0..1a1dfbf 100755
--- a/snes/controller/superscope/superscope.cpp
+++ b/snes/controller/superscope/superscope.cpp
@@ -100,6 +100,37 @@ void SuperScope::latch(bool data) {
@ -279,7 +279,7 @@ index 12068f05..1a1dfbff 100755
create(Controller::Enter, 21477272);
latched = 0;
diff --git a/snes/controller/superscope/superscope.hpp b/snes/controller/superscope/superscope.hpp
index a7a90b71..93509d79 100755
index a7a90b7..93509d7 100755
--- a/snes/controller/superscope/superscope.hpp
+++ b/snes/controller/superscope/superscope.hpp
@@ -2,6 +2,7 @@ struct SuperScope : Controller {
@ -291,7 +291,7 @@ index a7a90b71..93509d79 100755
//private:
diff --git a/snes/system/input.cpp b/snes/system/input.cpp
index 90503106..ec5559dc 100755
index 9050310..ec5559d 100755
--- a/snes/system/input.cpp
+++ b/snes/system/input.cpp
@@ -26,6 +26,22 @@ void Input::connect(bool port, Input::Device id) {
@ -318,7 +318,7 @@ index 90503106..ec5559dc 100755
connect(Controller::Port1, Input::Device::Joypad);
connect(Controller::Port2, Input::Device::Joypad);
diff --git a/snes/system/input.hpp b/snes/system/input.hpp
index 13ef46e1..6832e823 100755
index 13ef46e..6832e82 100755
--- a/snes/system/input.hpp
+++ b/snes/system/input.hpp
@@ -31,6 +31,7 @@ struct Input {
@ -330,7 +330,7 @@ index 13ef46e1..6832e823 100755
Input();
~Input();
diff --git a/snes/system/serialization.cpp b/snes/system/serialization.cpp
index f7d6f3b1..08e70510 100755
index f7d6f3b..08e7051 100755
--- a/snes/system/serialization.cpp
+++ b/snes/system/serialization.cpp
@@ -56,6 +56,7 @@ void System::serialize_all(serializer &s) {
@ -342,5 +342,5 @@ index f7d6f3b1..08e70510 100755
if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.serialize(s);
if(cartridge.mode() == Cartridge::Mode::SuperGameBoy) icd2.serialize(s);
--
2.15.0.rc1
1.7.9.48.g85da4d

View file

@ -1,14 +1,14 @@
From cdf2f46490f128308eb7f399d03530936ebeda0a Mon Sep 17 00:00:00 2001
From 18812e5cc5bd4cdc7cc7ef87a18bce78adbb4b13 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Fri, 11 Nov 2011 03:05:48 +0200
Subject: [PATCH 05/27] Fix unserialization of 64-bit signed integers
Subject: [PATCH 5/7] Fix unserialization of 64-bit signed integers
---
nall/serializer.hpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
nall/serializer.hpp | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/nall/serializer.hpp b/nall/serializer.hpp
index ff2337ab..e6bc8fad 100755
index ff2337a..e6bc8fa 100755
--- a/nall/serializer.hpp
+++ b/nall/serializer.hpp
@@ -58,7 +58,7 @@ namespace nall {
@ -21,5 +21,5 @@ index ff2337ab..e6bc8fad 100755
isize += size;
}
--
2.15.0.rc1
1.7.9.48.g85da4d

View file

@ -1,16 +1,16 @@
From 4dc46334ec175e26277632fee4aea80768749af9 Mon Sep 17 00:00:00 2001
From efe643e986ac15028ac7c7842532d8a8fb33963b Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Fri, 11 Nov 2011 19:49:46 +0200
Subject: [PATCH 06/27] Allow frontend to control random number seed
Subject: [PATCH 6/7] Allow frontend to control random number seed
---
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
snes/system/system.cpp | 2 +-
3 files changed, 7 insertions(+), 1 deletion(-)
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
snes/system/system.cpp | 2 +-
3 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp
index b3017c90..0a21a132 100755
index b3017c9..0a21a13 100755
--- a/snes/interface/interface.cpp
+++ b/snes/interface/interface.cpp
@@ -23,4 +23,9 @@ time_t Interface::currentTime()
@ -24,7 +24,7 @@ index b3017c90..0a21a132 100755
+
}
diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp
index df975e83..30ee7fde 100755
index df975e8..30ee7fd 100755
--- a/snes/interface/interface.hpp
+++ b/snes/interface/interface.hpp
@@ -6,6 +6,7 @@ struct Interface {
@ -36,7 +36,7 @@ index df975e83..30ee7fde 100755
extern Interface *interface;
diff --git a/snes/system/system.cpp b/snes/system/system.cpp
index c19a7c51..dbd912d8 100755
index c19a7c5..dbd912d 100755
--- a/snes/system/system.cpp
+++ b/snes/system/system.cpp
@@ -146,7 +146,7 @@ void System::unload() {
@ -49,5 +49,5 @@ index c19a7c51..dbd912d8 100755
region = config.region;
expansion = config.expansion_port;
--
2.15.0.rc1
1.7.9.48.g85da4d

View file

@ -1,63 +1,60 @@
From eeaf6dc52d39ca9c150ff61864c11297d200d968 Mon Sep 17 00:00:00 2001
From ce95700dc34ffdc5370aa699992bd8275e21c5c2 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 7 Mar 2012 16:57:18 +0200
Subject: [PATCH 07/27] Fix mouse polling
Subject: [PATCH 7/7] Fix mouse polling
Don't poll for mouse motion excessive number of times (no need to poll it for
each bit!)
---
snes/controller/mouse/mouse.cpp | 14 ++++++++++++--
snes/controller/mouse/mouse.hpp | 2 ++
2 files changed, 14 insertions(+), 2 deletions(-)
snes/controller/mouse/mouse.cpp | 12 ++++++++++--
snes/controller/mouse/mouse.hpp | 2 ++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp
index 6b26fae5..1a066b98 100755
index 6b26fae..824ecd3 100755
--- a/snes/controller/mouse/mouse.cpp
+++ b/snes/controller/mouse/mouse.cpp
@@ -3,9 +3,13 @@
@@ -3,8 +3,10 @@
uint2 Mouse::data() {
if(counter >= 32) return 1;
- int position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
- int position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
+ if(counter == 0) {
+ _position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
+ _position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
+ position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
+ position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
+ }
+ int position_x = _position_x;
+ int position_y = _position_y;
bool direction_x = position_x < 0; //0 = right, 1 = left
bool direction_y = position_y < 0; //0 = down, 1 = up
@@ -67,10 +71,16 @@ void Mouse::serialize(serializer& s) {
@@ -67,10 +69,16 @@ void Mouse::serialize(serializer& s) {
unsigned char block[Controller::SaveSize] = {0};
block[0] = latched ? 1 : 0;
block[1] = counter;
+ block[2] = (unsigned short)_position_x >> 8;
+ block[3] = (unsigned short)_position_x;
+ block[4] = (unsigned short)_position_y >> 8;
+ block[5] = (unsigned short)_position_y;
+ block[2] = (unsigned short)position_x >> 8;
+ block[3] = (unsigned short)position_x;
+ block[4] = (unsigned short)position_y >> 8;
+ block[5] = (unsigned short)position_y;
s.array(block, Controller::SaveSize);
if(s.mode() == nall::serializer::Load) {
latched = (block[0] != 0);
counter = block[1];
+ _position_x = (short)(((unsigned short)block[2] << 8) | (unsigned short)block[3]);
+ _position_y = (short)(((unsigned short)block[4] << 8) | (unsigned short)block[5]);
+ position_x = (short)(((unsigned short)block[2] << 8) | (unsigned short)block[3]);
+ position_y = (short)(((unsigned short)block[4] << 8) | (unsigned short)block[5]);
}
}
diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp
index b66ea513..b07c8ab7 100755
index b66ea51..6074f34 100755
--- a/snes/controller/mouse/mouse.hpp
+++ b/snes/controller/mouse/mouse.hpp
@@ -6,4 +6,6 @@ struct Mouse : Controller {
private:
bool latched;
unsigned counter;
+ int _position_x;
+ int _position_y;
+ int position_x;
+ int position_y;
};
--
2.15.0.rc1
1.7.9.48.g85da4d

View file

@ -1,22 +1,22 @@
From 7018377c93553071fc404db872b2746d40ac3bce Mon Sep 17 00:00:00 2001
From 3761a50c0faed2d9252781c5508bf91cc84ad493 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sat, 1 Sep 2012 11:23:34 +0300
Subject: [PATCH 08/27] Fix uninitialized variables
Subject: [PATCH] Fix uninitialized variables
These uninitialized variables cause a lot of desyncs in Shadowrun.
---
snes/alt/dsp/dsp.cpp | 2 ++
snes/alt/ppu-compatibility/ppu.cpp | 11 +++++++++++
snes/cpu/core/core.cpp | 8 ++++++++
snes/cpu/core/core.hpp | 2 ++
snes/cpu/cpu.cpp | 1 +
snes/smp/core/core.cpp | 11 +++++++++++
snes/smp/core/core.hpp | 2 ++
snes/smp/smp.cpp | 1 +
8 files changed, 38 insertions(+)
snes/alt/dsp/dsp.cpp | 2 ++
snes/alt/ppu-compatibility/ppu.cpp | 11 +++++++++++
snes/cpu/core/core.cpp | 8 ++++++++
snes/cpu/core/core.hpp | 2 ++
snes/cpu/cpu.cpp | 1 +
snes/smp/core/core.cpp | 11 +++++++++++
snes/smp/core/core.hpp | 2 ++
snes/smp/smp.cpp | 1 +
8 files changed, 38 insertions(+), 0 deletions(-)
diff --git a/snes/alt/dsp/dsp.cpp b/snes/alt/dsp/dsp.cpp
index d0c9e077..c6809f73 100755
index d0c9e07..c6809f7 100755
--- a/snes/alt/dsp/dsp.cpp
+++ b/snes/alt/dsp/dsp.cpp
@@ -40,6 +40,8 @@ void DSP::write(uint8 addr, uint8 data) {
@ -29,7 +29,7 @@ index d0c9e077..c6809f73 100755
spc_dsp.reset();
spc_dsp.set_output(samplebuffer, 8192);
diff --git a/snes/alt/ppu-compatibility/ppu.cpp b/snes/alt/ppu-compatibility/ppu.cpp
index 1a3835b3..a21e5e31 100755
index 1a3835b..a21e5e3 100755
--- a/snes/alt/ppu-compatibility/ppu.cpp
+++ b/snes/alt/ppu-compatibility/ppu.cpp
@@ -345,6 +345,17 @@ void PPU::power() {
@ -51,7 +51,7 @@ index 1a3835b3..a21e5e31 100755
}
diff --git a/snes/cpu/core/core.cpp b/snes/cpu/core/core.cpp
index 427176b0..a5b809b9 100755
index 427176b..a5b809b 100755
--- a/snes/cpu/core/core.cpp
+++ b/snes/cpu/core/core.cpp
@@ -86,4 +86,12 @@ CPUcore::CPUcore() {
@ -68,7 +68,7 @@ index 427176b0..a5b809b9 100755
+
}
diff --git a/snes/cpu/core/core.hpp b/snes/cpu/core/core.hpp
index 964bd128..7a685a8d 100755
index 964bd12..7a685a8 100755
--- a/snes/cpu/core/core.hpp
+++ b/snes/cpu/core/core.hpp
@@ -7,6 +7,8 @@ struct CPUcore {
@ -81,7 +81,7 @@ index 964bd128..7a685a8d 100755
virtual uint8_t op_read(uint32_t addr) = 0;
virtual void op_write(uint32_t addr, uint8_t data) = 0;
diff --git a/snes/cpu/cpu.cpp b/snes/cpu/cpu.cpp
index f6ae9754..2d7d3432 100755
index f6ae975..2d7d343 100755
--- a/snes/cpu/cpu.cpp
+++ b/snes/cpu/cpu.cpp
@@ -125,6 +125,7 @@ void CPU::power() {
@ -93,7 +93,7 @@ index f6ae9754..2d7d3432 100755
void CPU::reset() {
diff --git a/snes/smp/core/core.cpp b/snes/smp/core/core.cpp
index 9c94d00a..2fc29be1 100755
index 9c94d00..2fc29be 100755
--- a/snes/smp/core/core.cpp
+++ b/snes/smp/core/core.cpp
@@ -269,4 +269,15 @@ void SMPcore::op_step() {
@ -113,7 +113,7 @@ index 9c94d00a..2fc29be1 100755
+
}
diff --git a/snes/smp/core/core.hpp b/snes/smp/core/core.hpp
index 6adf6f6b..1489fcef 100755
index 6adf6f6..1489fce 100755
--- a/snes/smp/core/core.hpp
+++ b/snes/smp/core/core.hpp
@@ -11,6 +11,8 @@ struct SMPcore {
@ -126,7 +126,7 @@ index 6adf6f6b..1489fcef 100755
string disassemble_opcode(uint16 addr);
diff --git a/snes/smp/smp.cpp b/snes/smp/smp.cpp
index 90806245..d4ccf425 100755
index 9080624..d4ccf42 100755
--- a/snes/smp/smp.cpp
+++ b/snes/smp/smp.cpp
@@ -53,6 +53,7 @@ void SMP::power() {
@ -138,5 +138,5 @@ index 90806245..d4ccf425 100755
void SMP::reset() {
--
2.15.0.rc1
1.7.9.48.g85da4d

View file

@ -1,16 +1,16 @@
From 6e0364c9a86caa71623a188a720b2d68b304b89b Mon Sep 17 00:00:00 2001
From 03f134f4db8d179cf95f6017dffd893cd3801e82 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Mon, 24 Sep 2012 21:46:09 +0300
Subject: [PATCH 09/27] Add needed support for detecting true polls as opposed
to just autopolling
Subject: [PATCH] Add needed support for detecting true polls as opposed to
just autopolling
---
snes/cpu/cpu.hpp | 1 +
snes/cpu/mmio/mmio.cpp | 18 ++++++++++--------
snes/cpu/cpu.hpp | 1 +
snes/cpu/mmio/mmio.cpp | 18 ++++++++++--------
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/snes/cpu/cpu.hpp b/snes/cpu/cpu.hpp
index 3da865e2..49445773 100755
index 3da865e..4944577 100755
--- a/snes/cpu/cpu.hpp
+++ b/snes/cpu/cpu.hpp
@@ -25,6 +25,7 @@ struct CPU : public Processor, public CPUcore, public PPUcounter {
@ -22,7 +22,7 @@ index 3da865e2..49445773 100755
#include "dma/dma.hpp"
#include "memory/memory.hpp"
diff --git a/snes/cpu/mmio/mmio.cpp b/snes/cpu/mmio/mmio.cpp
index 8b6aaa6a..c5ee930f 100755
index 8b6aaa6..c5ee930 100755
--- a/snes/cpu/mmio/mmio.cpp
+++ b/snes/cpu/mmio/mmio.cpp
@@ -42,6 +42,7 @@ void CPU::mmio_w4016(uint8 data) {
@ -65,5 +65,5 @@ index 8b6aaa6a..c5ee930f 100755
//DMAPx
uint8 CPU::mmio_r43x0(uint8 i) {
--
2.15.0.rc1
1.7.10.4

View file

@ -1,14 +1,14 @@
From e397bd46f17d6ea00c8c96d5a8e0c5f5b4a6f642 Mon Sep 17 00:00:00 2001
From 36777ec11c093a1cc902b8b72188e06f49a4d0f2 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sun, 14 Oct 2012 23:31:36 +0300
Subject: [PATCH 10/27] Fix compiling on GCC 4.7
Subject: [PATCH] Fix compiling on GCC 4.7
---
nall/string.hpp | 2 +-
nall/string.hpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/nall/string.hpp b/nall/string.hpp
index 1b255ce2..07a64dfc 100755
index 1b255ce..07a64df 100755
--- a/nall/string.hpp
+++ b/nall/string.hpp
@@ -25,8 +25,8 @@
@ -22,5 +22,5 @@ index 1b255ce2..07a64dfc 100755
#include <nall/string/convert.hpp>
#include <nall/string/cstring.hpp>
--
2.15.0.rc1
1.7.10.4

View file

@ -1,65 +0,0 @@
From e047aa8eb9883f60e4141effba8128a4a555d8be Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sun, 27 Oct 2013 10:52:45 +0200
Subject: [PATCH 11/27] Support notifying latches
---
snes/cpu/mmio/mmio.cpp | 1 +
snes/cpu/timing/joypad.cpp | 1 +
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
4 files changed, 8 insertions(+)
diff --git a/snes/cpu/mmio/mmio.cpp b/snes/cpu/mmio/mmio.cpp
index c5ee930f..b7afff00 100755
--- a/snes/cpu/mmio/mmio.cpp
+++ b/snes/cpu/mmio/mmio.cpp
@@ -33,6 +33,7 @@ void CPU::mmio_w2183(uint8 data) {
//strobing $4016.d0 affects both controller port latches.
//$4017 bit 0 writes are ignored.
void CPU::mmio_w4016(uint8 data) {
+ if(data&1) interface->notifyLatched();
input.port1->latch(data & 1);
input.port2->latch(data & 1);
}
diff --git a/snes/cpu/timing/joypad.cpp b/snes/cpu/timing/joypad.cpp
index 179df27d..6a98de00 100755
--- a/snes/cpu/timing/joypad.cpp
+++ b/snes/cpu/timing/joypad.cpp
@@ -9,6 +9,7 @@ void CPU::step_auto_joypad_poll() {
if(status.auto_joypad_active && status.auto_joypad_latch) {
if(status.auto_joypad_counter == 0) {
+ interface->notifyLatched();
input.port1->latch(1);
input.port2->latch(1);
input.port1->latch(0);
diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp
index 0a21a132..6685556c 100755
--- a/snes/interface/interface.cpp
+++ b/snes/interface/interface.cpp
@@ -28,4 +28,9 @@ time_t Interface::randomSeed()
return time(0);
}
+void Interface::notifyLatched()
+{
+ //Nothing.
+}
+
}
diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp
index 30ee7fde..203f7b0c 100755
--- a/snes/interface/interface.hpp
+++ b/snes/interface/interface.hpp
@@ -7,6 +7,7 @@ struct Interface {
virtual void message(const string &text);
virtual time_t currentTime();
virtual time_t randomSeed();
+ virtual void notifyLatched();
};
extern Interface *interface;
--
2.15.0.rc1

View file

@ -1,799 +0,0 @@
From a5b380757b086e3a00b47fe14e2a63c74683e8da Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Thu, 28 Nov 2013 22:36:29 +0200
Subject: [PATCH 12/27] Support unlimited number of breakpoints
---
snes/alt/cpu/cpu.cpp | 22 +++++++-------
snes/alt/ppu-compatibility/ppu.cpp | 4 +--
snes/alt/ppu-parallel/ppu.cpp | 4 +--
snes/alt/ppu-performance/ppu.cpp | 4 +--
snes/cartridge/cartridge.hpp | 17 +++++++++++
snes/cartridge/markup.cpp | 11 +++++++
snes/cheat/cheat.cpp | 11 ++++---
snes/cheat/cheat.hpp | 1 +
snes/chip/bsx/satellaview/satellaview.cpp | 4 +--
snes/chip/hitachidsp/hitachidsp.cpp | 2 +-
snes/chip/hitachidsp/memory.cpp | 2 +-
snes/chip/nss/nss.cpp | 4 +--
snes/chip/sa1/memory/memory.cpp | 2 +-
snes/chip/sa1/memory/memory.hpp | 2 +-
snes/chip/sa1/sa1.cpp | 2 +-
snes/chip/sdd1/sdd1.cpp | 4 +--
snes/cpu/core/core.hpp | 2 +-
snes/cpu/core/disassembler/disassembler.cpp | 2 +-
snes/cpu/core/memory.hpp | 2 +-
snes/cpu/cpu.cpp | 26 ++++++++--------
snes/cpu/debugger/debugger.cpp | 4 +--
snes/cpu/debugger/debugger.hpp | 2 +-
snes/cpu/dma/dma.cpp | 4 +--
snes/cpu/memory/memory.cpp | 4 +--
snes/cpu/memory/memory.hpp | 2 +-
snes/cpu/mmio/mmio.cpp | 2 +-
snes/debugger/debugger.cpp | 2 +-
snes/memory/memory-inline.hpp | 21 +++++++++++--
snes/memory/memory.cpp | 47 ++++++++++++++++++++++++++---
snes/memory/memory.hpp | 13 +++++++-
snes/ppu/ppu.cpp | 4 +--
snes/smp/core/core.hpp | 2 +-
snes/snes.hpp | 1 +
33 files changed, 166 insertions(+), 70 deletions(-)
diff --git a/snes/alt/cpu/cpu.cpp b/snes/alt/cpu/cpu.cpp
index 814908d0..dcbb92d3 100755
--- a/snes/alt/cpu/cpu.cpp
+++ b/snes/alt/cpu/cpu.cpp
@@ -89,24 +89,24 @@ void CPU::enable() {
function<uint8 (unsigned)> read = { &CPU::mmio_read, (CPU*)&cpu };
function<void (unsigned, uint8)> write = { &CPU::mmio_write, (CPU*)&cpu };
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, read, write);
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, read, write);
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, 0, read, write);
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, 0, read, write);
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, read, write);
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, read, write);
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, 0, read, write);
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, 0, read, write);
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, read, write);
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, read, write);
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, 0, read, write);
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, 0, read, write);
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, read, write);
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, read, write);
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, 0, read, write);
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, 0, read, write);
read = [](unsigned addr) { return cpu.wram[addr]; };
write = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
- bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
- bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
- bus.map(Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, read, write);
+ bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, 3, read, write, 0x000000, 0x002000);
+ bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, 3, read, write, 0x000000, 0x002000);
+ bus.map(Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, 3, read, write);
}
void CPU::power() {
diff --git a/snes/alt/ppu-compatibility/ppu.cpp b/snes/alt/ppu-compatibility/ppu.cpp
index a21e5e31..122b1430 100755
--- a/snes/alt/ppu-compatibility/ppu.cpp
+++ b/snes/alt/ppu-compatibility/ppu.cpp
@@ -126,8 +126,8 @@ void PPU::enable() {
function<uint8 (unsigned)> read = { &PPU::mmio_read, (PPU*)&ppu };
function<void (unsigned, uint8)> write = { &PPU::mmio_write, (PPU*)&ppu };
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write);
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write);
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, 0, read, write);
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, 0, read, write);
}
void PPU::power() {
diff --git a/snes/alt/ppu-parallel/ppu.cpp b/snes/alt/ppu-parallel/ppu.cpp
index 1c3dcb70..8dd118b2 100755
--- a/snes/alt/ppu-parallel/ppu.cpp
+++ b/snes/alt/ppu-parallel/ppu.cpp
@@ -36,8 +36,8 @@ void PPU::frame() {
}
void PPU::enable() {
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, { &PPU::mmio_read, this }, { &PPU::mmio_write, this });
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, { &PPU::mmio_read, this }, { &PPU::mmio_write, this });
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, 0, { &PPU::mmio_read, this }, { &PPU::mmio_write, this });
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, 0, { &PPU::mmio_read, this }, { &PPU::mmio_write, this });
}
void PPU::power() {
diff --git a/snes/alt/ppu-performance/ppu.cpp b/snes/alt/ppu-performance/ppu.cpp
index 7c231bc0..4b2b2948 100755
--- a/snes/alt/ppu-performance/ppu.cpp
+++ b/snes/alt/ppu-performance/ppu.cpp
@@ -90,8 +90,8 @@ void PPU::enable() {
function<uint8 (unsigned)> read = { &PPU::mmio_read, (PPU*)&ppu };
function<void (unsigned, uint8)> write = { &PPU::mmio_write, (PPU*)&ppu };
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write);
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write);
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, 0, read, write);
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, 0, read, write);
}
void PPU::power() {
diff --git a/snes/cartridge/cartridge.hpp b/snes/cartridge/cartridge.hpp
index 37555bc0..82e73c4c 100755
--- a/snes/cartridge/cartridge.hpp
+++ b/snes/cartridge/cartridge.hpp
@@ -12,6 +12,22 @@ struct Cartridge : property<Cartridge> {
PAL,
};
+ enum class MemoryClass : unsigned {
+ MISC = 0,
+ ROM = 1,
+ SRAM = 2,
+ WRAM = 3,
+ SUPERFXROM = 4,
+ SUPERFXRAM = 5,
+ SA1IRAM = 6,
+ SA1BWRAM = 7,
+ SUFAMITURBO_ROMA = 8,
+ SUFAMITURBO_ROMB = 9,
+ SUFAMITURBO_RAMA = 10,
+ SUFAMITURBO_RAMB = 11,
+ BSXFLASH = 12,
+ };
+
enum class Slot : unsigned {
Base,
Bsx,
@@ -68,6 +84,7 @@ struct Cartridge : property<Cartridge> {
unsigned addrhi;
unsigned offset;
unsigned size;
+ MemoryClass clazz;
Mapping();
Mapping(const function<uint8 (unsigned)>&, const function<void (unsigned, uint8)>&);
diff --git a/snes/cartridge/markup.cpp b/snes/cartridge/markup.cpp
index e639fe52..2dd0d646 100755
--- a/snes/cartridge/markup.cpp
+++ b/snes/cartridge/markup.cpp
@@ -74,6 +74,7 @@ void Cartridge::parse_markup_rom(XML::Node &root) {
for(auto &node : root) {
if(node.name != "map") continue;
Mapping m(rom);
+ m.clazz = MemoryClass::ROM;
parse_markup_map(m, node);
if(m.size == 0) m.size = rom.size();
mapping.append(m);
@@ -85,6 +86,7 @@ void Cartridge::parse_markup_ram(XML::Node &root) {
ram_size = parse_markup_integer(root["size"].data);
for(auto &node : root) {
Mapping m(ram);
+ m.clazz = MemoryClass::SRAM;
parse_markup_map(m, node);
if(m.size == 0) m.size = ram_size;
mapping.append(m);
@@ -133,6 +135,7 @@ void Cartridge::parse_markup_superfx(XML::Node &root) {
for(auto &leaf : node) {
if(leaf.name != "map") continue;
Mapping m(superfx.rom);
+ //m.clazz = MemoryClass::SUPERFXROM; -- Aliases ROM.
parse_markup_map(m, leaf);
mapping.append(m);
}
@@ -145,6 +148,7 @@ void Cartridge::parse_markup_superfx(XML::Node &root) {
}
if(leaf.name != "map") continue;
Mapping m(superfx.ram);
+ //m.clazz = MemoryClass::SUPERFXRAM; -- Aliases SRAM.
parse_markup_map(m, leaf);
if(m.size == 0) m.size = ram_size;
mapping.append(m);
@@ -188,6 +192,7 @@ void Cartridge::parse_markup_sa1(XML::Node &root) {
for(auto &node : iram) {
if(node.name != "map") continue;
Mapping m(sa1.cpuiram);
+ m.clazz = MemoryClass::SA1IRAM;
parse_markup_map(m, node);
if(m.size == 0) m.size = 2048;
mapping.append(m);
@@ -197,6 +202,7 @@ void Cartridge::parse_markup_sa1(XML::Node &root) {
for(auto &node : bwram) {
if(node.name != "map") continue;
Mapping m(sa1.cpubwram);
+ //m.clazz = MemoryClass::SA1BWRAM; -- Aliases SRAM
parse_markup_map(m, node);
if(m.size == 0) m.size = ram_size;
mapping.append(m);
@@ -341,6 +347,7 @@ void Cartridge::parse_markup_bsx(XML::Node &root) {
for(auto &node : root["slot"]) {
if(node.name != "map") continue;
Mapping m(bsxflash.memory);
+ m.clazz = MemoryClass::BSXFLASH;
parse_markup_map(m, node);
mapping.append(m);
}
@@ -373,6 +380,7 @@ void Cartridge::parse_markup_sufamiturbo(XML::Node &root) {
if(leaf.name != "map") continue;
Memory &memory = slotid == 0 ? sufamiturbo.slotA.rom : sufamiturbo.slotB.rom;
Mapping m(memory);
+ m.clazz = slotid ? MemoryClass::SUFAMITURBO_ROMB : MemoryClass::SUFAMITURBO_ROMA;
parse_markup_map(m, leaf);
if(m.size == 0) m.size = memory.size();
if(m.size) mapping.append(m);
@@ -384,6 +392,7 @@ void Cartridge::parse_markup_sufamiturbo(XML::Node &root) {
if(leaf.name != "map") continue;
Memory &memory = slotid == 0 ? sufamiturbo.slotA.ram : sufamiturbo.slotB.ram;
Mapping m(memory);
+ m.clazz = slotid ? MemoryClass::SUFAMITURBO_RAMB : MemoryClass::SUFAMITURBO_RAMA;
parse_markup_map(m, leaf);
if(m.size == 0) m.size = ram_size;
if(m.size) mapping.append(m);
@@ -536,11 +545,13 @@ void Cartridge::parse_markup_link(XML::Node &root) {
}
Cartridge::Mapping::Mapping() {
+ clazz = MemoryClass::MISC;
mode = Bus::MapMode::Direct;
banklo = bankhi = addrlo = addrhi = offset = size = 0;
}
Cartridge::Mapping::Mapping(Memory &memory) {
+ clazz = MemoryClass::MISC;
read = { &Memory::read, &memory };
write = { &Memory::write, &memory };
mode = Bus::MapMode::Direct;
diff --git a/snes/cheat/cheat.cpp b/snes/cheat/cheat.cpp
index 46c42d1c..3a269cc5 100755
--- a/snes/cheat/cheat.cpp
+++ b/snes/cheat/cheat.cpp
@@ -21,9 +21,9 @@ void Cheat::synchronize() {
for(unsigned i = 0; i < size(); i++) {
const CheatCode &code = operator[](i);
- unsigned addr = mirror(code.addr);
+ unsigned addr = code.nomirror ? code.addr : mirror(code.addr);
override[addr] = true;
- if((addr & 0xffe000) == 0x7e0000) {
+ if(!code.nomirror && (addr & 0xffe000) == 0x7e0000) {
//mirror $7e:0000-1fff to $00-3f|80-bf:0000-1fff
unsigned mirroraddr;
for(unsigned x = 0; x <= 0x3f; x++) {
@@ -40,11 +40,14 @@ void Cheat::synchronize() {
}
uint8 Cheat::read(unsigned addr) const {
- addr = mirror(addr);
+ unsigned raddr = mirror(addr);
for(unsigned i = 0; i < size(); i++) {
const CheatCode &code = operator[](i);
- if(addr == mirror(code.addr)) {
+ if(!code.nomirror && addr == mirror(code.addr)) {
+ return code.data;
+ }
+ if(code.nomirror && raddr == code.addr) {
return code.data;
}
}
diff --git a/snes/cheat/cheat.hpp b/snes/cheat/cheat.hpp
index 306b99b1..b4d2a42e 100755
--- a/snes/cheat/cheat.hpp
+++ b/snes/cheat/cheat.hpp
@@ -1,6 +1,7 @@
struct CheatCode {
unsigned addr;
unsigned data;
+ bool nomirror;
};
struct Cheat : public linear_vector<CheatCode> {
diff --git a/snes/chip/bsx/satellaview/satellaview.cpp b/snes/chip/bsx/satellaview/satellaview.cpp
index 3c980195..25af8e56 100755
--- a/snes/chip/bsx/satellaview/satellaview.cpp
+++ b/snes/chip/bsx/satellaview/satellaview.cpp
@@ -6,8 +6,8 @@ void BSXSatellaview::init() {
}
void BSXSatellaview::load() {
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2188, 0x219f, { &BSXSatellaview::mmio_read, &bsxsatellaview }, { &BSXSatellaview::mmio_write, &bsxsatellaview });
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2188, 0x219f, { &BSXSatellaview::mmio_read, &bsxsatellaview }, { &BSXSatellaview::mmio_write, &bsxsatellaview });
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2188, 0x219f, 0, { &BSXSatellaview::mmio_read, &bsxsatellaview }, { &BSXSatellaview::mmio_write, &bsxsatellaview });
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2188, 0x219f, 0, { &BSXSatellaview::mmio_read, &bsxsatellaview }, { &BSXSatellaview::mmio_write, &bsxsatellaview });
}
void BSXSatellaview::unload() {
diff --git a/snes/chip/hitachidsp/hitachidsp.cpp b/snes/chip/hitachidsp/hitachidsp.cpp
index 1042267e..3e5c5bdb 100755
--- a/snes/chip/hitachidsp/hitachidsp.cpp
+++ b/snes/chip/hitachidsp/hitachidsp.cpp
@@ -23,7 +23,7 @@ void HitachiDSP::enter() {
break;
case State::DMA:
for(unsigned n = 0; n < regs.dma_length; n++) {
- bus.write(regs.dma_target + n, bus.read(regs.dma_source + n));
+ bus.write(regs.dma_target + n, bus.read(regs.dma_source + n, false));
step(2);
}
state = State::Idle;
diff --git a/snes/chip/hitachidsp/memory.cpp b/snes/chip/hitachidsp/memory.cpp
index 3c9c3af1..36868e88 100755
--- a/snes/chip/hitachidsp/memory.cpp
+++ b/snes/chip/hitachidsp/memory.cpp
@@ -1,7 +1,7 @@
#ifdef HITACHIDSP_CPP
uint8 HitachiDSP::bus_read(unsigned addr) {
- if((addr & 0x408000) == 0x008000) return bus.read(addr);
+ if((addr & 0x408000) == 0x008000) return bus.read(addr, false);
return 0x00;
}
diff --git a/snes/chip/nss/nss.cpp b/snes/chip/nss/nss.cpp
index 964973d0..5946af3b 100755
--- a/snes/chip/nss/nss.cpp
+++ b/snes/chip/nss/nss.cpp
@@ -10,8 +10,8 @@ void NSS::init() {
void NSS::load() {
dip = 0x0000;
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4100, 0x4101, { &NSS::read, this }, { &NSS::write, this });
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4100, 0x4101, { &NSS::read, this }, { &NSS::write, this });
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4100, 0x4101, 0, { &NSS::read, this }, { &NSS::write, this });
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4100, 0x4101, 0, { &NSS::read, this }, { &NSS::write, this });
}
void NSS::unload() {
diff --git a/snes/chip/sa1/memory/memory.cpp b/snes/chip/sa1/memory/memory.cpp
index d13ac929..9bb4ff20 100755
--- a/snes/chip/sa1/memory/memory.cpp
+++ b/snes/chip/sa1/memory/memory.cpp
@@ -107,7 +107,7 @@ void SA1::op_io() {
tick();
}
-uint8 SA1::op_read(unsigned addr) {
+uint8 SA1::op_read(unsigned addr, bool exec) {
tick();
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
return bus_read(addr);
diff --git a/snes/chip/sa1/memory/memory.hpp b/snes/chip/sa1/memory/memory.hpp
index ffb9e9f6..ab8e1edd 100755
--- a/snes/chip/sa1/memory/memory.hpp
+++ b/snes/chip/sa1/memory/memory.hpp
@@ -3,7 +3,7 @@ void bus_write(unsigned addr, uint8 data);
uint8 vbr_read(unsigned addr);
alwaysinline void op_io();
-alwaysinline uint8 op_read(unsigned addr);
+alwaysinline uint8 op_read(unsigned addr, bool exec);
alwaysinline void op_write(unsigned addr, uint8 data);
uint8 mmc_read(unsigned addr);
diff --git a/snes/chip/sa1/sa1.cpp b/snes/chip/sa1/sa1.cpp
index 71c6310a..30e00809 100755
--- a/snes/chip/sa1/sa1.cpp
+++ b/snes/chip/sa1/sa1.cpp
@@ -37,7 +37,7 @@ void SA1::enter() {
}
void SA1::op_irq() {
- op_read(regs.pc.d);
+ op_read(regs.pc.d, false);
op_io();
if(!regs.e) op_writestack(regs.pc.b);
op_writestack(regs.pc.h);
diff --git a/snes/chip/sdd1/sdd1.cpp b/snes/chip/sdd1/sdd1.cpp
index c9b8b1c4..5d6cc55f 100755
--- a/snes/chip/sdd1/sdd1.cpp
+++ b/snes/chip/sdd1/sdd1.cpp
@@ -14,8 +14,8 @@ void SDD1::init() {
void SDD1::load() {
//hook S-CPU DMA MMIO registers to gather information for struct dma[];
//buffer address and transfer size information for use in SDD1::mcu_read()
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, 0, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, 0, { &SDD1::mmio_read, &sdd1 }, { &SDD1::mmio_write, &sdd1 });
}
void SDD1::unload() {
diff --git a/snes/cpu/core/core.hpp b/snes/cpu/core/core.hpp
index 7a685a8d..9d77f3c5 100755
--- a/snes/cpu/core/core.hpp
+++ b/snes/cpu/core/core.hpp
@@ -10,7 +10,7 @@ struct CPUcore {
void powercycle();
virtual void op_io() = 0;
- virtual uint8_t op_read(uint32_t addr) = 0;
+ virtual uint8_t op_read(uint32_t addr, bool exec = false) = 0;
virtual void op_write(uint32_t addr, uint8_t data) = 0;
virtual void last_cycle() = 0;
virtual bool interrupt_pending() = 0;
diff --git a/snes/cpu/core/disassembler/disassembler.cpp b/snes/cpu/core/disassembler/disassembler.cpp
index 030b3ab5..ab8dde24 100755
--- a/snes/cpu/core/disassembler/disassembler.cpp
+++ b/snes/cpu/core/disassembler/disassembler.cpp
@@ -6,7 +6,7 @@ uint8 CPUcore::dreadb(uint32 addr) {
//do not read MMIO registers within debugger
return 0x00;
}
- return bus.read(addr);
+ return bus.read(addr, false);
}
uint16 CPUcore::dreadw(uint32 addr) {
diff --git a/snes/cpu/core/memory.hpp b/snes/cpu/core/memory.hpp
index 49926578..132501c1 100755
--- a/snes/cpu/core/memory.hpp
+++ b/snes/cpu/core/memory.hpp
@@ -1,5 +1,5 @@
alwaysinline uint8_t op_readpc() {
- return op_read((regs.pc.b << 16) + regs.pc.w++);
+ return op_read((regs.pc.b << 16) + regs.pc.w++, true);
}
alwaysinline uint8_t op_readstack() {
diff --git a/snes/cpu/cpu.cpp b/snes/cpu/cpu.cpp
index 2d7d3432..39da6b16 100755
--- a/snes/cpu/cpu.cpp
+++ b/snes/cpu/cpu.cpp
@@ -78,8 +78,8 @@ void CPU::enter() {
} else if(status.reset_pending) {
status.reset_pending = false;
add_clocks(186);
- regs.pc.l = bus.read(0xfffc);
- regs.pc.h = bus.read(0xfffd);
+ regs.pc.l = bus.read(0xfffc, false);
+ regs.pc.h = bus.read(0xfffd, false);
}
}
@@ -95,24 +95,24 @@ void CPU::enable() {
function<uint8 (unsigned)> read = { &CPU::mmio_read, (CPU*)&cpu };
function<void (unsigned, uint8)> write = { &CPU::mmio_write, (CPU*)&cpu };
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, read, write);
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, read, write);
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2140, 0x2183, 0, read, write);
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2140, 0x2183, 0, read, write);
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, read, write);
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, read, write);
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4016, 0x4017, 0, read, write);
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4016, 0x4017, 0, read, write);
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, read, write);
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, read, write);
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4200, 0x421f, 0, read, write);
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4200, 0x421f, 0, read, write);
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, read, write);
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, read, write);
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x4300, 0x437f, 0, read, write);
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x4300, 0x437f, 0, read, write);
read = [](unsigned addr) { return cpu.wram[addr]; };
write = [](unsigned addr, uint8 data) { cpu.wram[addr] = data; };
- bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
- bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, read, write, 0x000000, 0x002000);
- bus.map(Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, read, write);
+ bus.map(Bus::MapMode::Linear, 0x00, 0x3f, 0x0000, 0x1fff, 3, read, write, 0x000000, 0x002000);
+ bus.map(Bus::MapMode::Linear, 0x80, 0xbf, 0x0000, 0x1fff, 3, read, write, 0x000000, 0x002000);
+ bus.map(Bus::MapMode::Linear, 0x7e, 0x7f, 0x0000, 0xffff, 3, read, write);
}
void CPU::power() {
diff --git a/snes/cpu/debugger/debugger.cpp b/snes/cpu/debugger/debugger.cpp
index a33518ed..8301bdb6 100755
--- a/snes/cpu/debugger/debugger.cpp
+++ b/snes/cpu/debugger/debugger.cpp
@@ -19,8 +19,8 @@ void CPUDebugger::op_step() {
synchronize_smp();
}
-uint8 CPUDebugger::op_read(uint32 addr) {
- uint8 data = CPU::op_read(addr);
+uint8 CPUDebugger::op_read(uint32 addr, bool exec) {
+ uint8 data = CPU::op_read(addr, exec);
usage[addr] |= UsageRead;
debugger.breakpoint_test(Debugger::Breakpoint::Source::CPUBus, Debugger::Breakpoint::Mode::Read, addr, data);
return data;
diff --git a/snes/cpu/debugger/debugger.hpp b/snes/cpu/debugger/debugger.hpp
index 579f6f03..c3d66db5 100755
--- a/snes/cpu/debugger/debugger.hpp
+++ b/snes/cpu/debugger/debugger.hpp
@@ -16,7 +16,7 @@ public:
bool opcode_edge; //true right before an opcode execues, used to skip over opcodes
void op_step();
- uint8 op_read(uint32 addr);
+ uint8 op_read(uint32 addr, bool exec = false);
void op_write(uint32 addr, uint8 data);
CPUDebugger();
diff --git a/snes/cpu/dma/dma.cpp b/snes/cpu/dma/dma.cpp
index e8cdb3ec..0a00bfea 100755
--- a/snes/cpu/dma/dma.cpp
+++ b/snes/cpu/dma/dma.cpp
@@ -26,7 +26,7 @@ bool CPU::dma_addr_valid(uint32 abus) {
uint8 CPU::dma_read(uint32 abus) {
if(dma_addr_valid(abus) == false) return 0x00;
- return bus.read(abus);
+ return bus.read(abus, false);
}
//simulate two-stage pipeline for DMA transfers; example:
@@ -49,7 +49,7 @@ void CPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) {
dma_write(dma_transfer_valid(bbus, abus), 0x2100 | bbus, regs.mdr);
} else {
dma_add_clocks(4);
- regs.mdr = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus) : 0x00;
+ regs.mdr = dma_transfer_valid(bbus, abus) ? bus.read(0x2100 | bbus, false) : 0x00;
dma_add_clocks(4);
dma_write(dma_addr_valid(abus), abus, regs.mdr);
}
diff --git a/snes/cpu/memory/memory.cpp b/snes/cpu/memory/memory.cpp
index c2c8f1fa..31f82c31 100755
--- a/snes/cpu/memory/memory.cpp
+++ b/snes/cpu/memory/memory.cpp
@@ -10,11 +10,11 @@ void CPU::op_io() {
alu_edge();
}
-uint8 CPU::op_read(uint32 addr) {
+uint8 CPU::op_read(uint32 addr, bool exec) {
status.clock_count = speed(addr);
dma_edge();
add_clocks(status.clock_count - 4);
- regs.mdr = bus.read(addr);
+ regs.mdr = bus.read(addr, exec);
add_clocks(4);
alu_edge();
return regs.mdr;
diff --git a/snes/cpu/memory/memory.hpp b/snes/cpu/memory/memory.hpp
index d33861d4..fd64ba8b 100755
--- a/snes/cpu/memory/memory.hpp
+++ b/snes/cpu/memory/memory.hpp
@@ -1,4 +1,4 @@
void op_io();
-debugvirtual uint8 op_read(uint32 addr);
+debugvirtual uint8 op_read(uint32 addr, bool exec);
debugvirtual void op_write(uint32 addr, uint8 data);
alwaysinline unsigned speed(unsigned addr) const;
diff --git a/snes/cpu/mmio/mmio.cpp b/snes/cpu/mmio/mmio.cpp
index b7afff00..30048c19 100755
--- a/snes/cpu/mmio/mmio.cpp
+++ b/snes/cpu/mmio/mmio.cpp
@@ -5,7 +5,7 @@ bool CPU::joylatch() { return status.joypad_strobe_latch; }
//WMDATA
uint8 CPU::mmio_r2180() {
- return bus.read(0x7e0000 | status.wram_addr++);
+ return bus.read(0x7e0000 | status.wram_addr++, false);
}
//WMDATA
diff --git a/snes/debugger/debugger.cpp b/snes/debugger/debugger.cpp
index b1312339..e8d0f5af 100755
--- a/snes/debugger/debugger.cpp
+++ b/snes/debugger/debugger.cpp
@@ -33,7 +33,7 @@ uint8 Debugger::read(Debugger::MemorySource source, unsigned addr) {
case MemorySource::CPUBus: {
//do not read from memory-mapped registers that could affect program behavior
if(((addr - 0x2000) & 0x40c000) == 0x000000) break; //$00-3f:2000-5fff MMIO
- return bus.read(addr & 0xffffff);
+ return bus.read(addr & 0xffffff, false);
} break;
case MemorySource::APUBus: {
diff --git a/snes/memory/memory-inline.hpp b/snes/memory/memory-inline.hpp
index 70503bea..45f150c9 100755
--- a/snes/memory/memory-inline.hpp
+++ b/snes/memory/memory-inline.hpp
@@ -51,11 +51,26 @@ MappedRAM::MappedRAM() : data_(0), size_(0), write_protect_(false) {}
//Bus
-uint8 Bus::read(unsigned addr) {
- if(cheat.override[addr]) return cheat.read(addr);
- return reader[lookup[addr]](target[addr]);
+uint8 Bus::read(unsigned addr, bool exec) {
+ uint8 emask = exec ? 0x24 : 0x09;
+ uint8 val;
+ if(__builtin_expect(cheat.override[addr], 0))
+ val = cheat.read(addr);
+ else
+ val = reader[lookup[addr]](target[addr]);
+ if(__builtin_expect((u_debugflags | debugflags[addr]) & emask, 0)) {
+ unsigned daddr = target[addr];
+ uint8 mclass = classmap[addr];
+ debug_read(mclass, daddr, addr, val, exec);
+ }
+ return val;
}
void Bus::write(unsigned addr, uint8 data) {
+ if(__builtin_expect((u_debugflags | debugflags[addr]) & 0x12, 0)) {
+ unsigned daddr = target[addr];
+ uint8 mclass = classmap[addr];
+ debug_write(mclass, daddr, addr, data);
+ }
return writer[lookup[addr]](target[addr], data);
}
diff --git a/snes/memory/memory.cpp b/snes/memory/memory.cpp
index ede9cbd0..a9a484a0 100755
--- a/snes/memory/memory.cpp
+++ b/snes/memory/memory.cpp
@@ -27,6 +27,7 @@ void Bus::map(
MapMode mode,
unsigned bank_lo, unsigned bank_hi,
unsigned addr_lo, unsigned addr_hi,
+ unsigned mclass,
const function<uint8 (unsigned)> &rd,
const function<void (unsigned, uint8)> &wr,
unsigned base, unsigned length
@@ -48,6 +49,7 @@ void Bus::map(
if(mode == MapMode::Shadow) destaddr = mirror(base + destaddr, length);
lookup[(bank << 16) | addr] = id;
target[(bank << 16) | addr] = destaddr;
+ if(mclass) classmap[(bank << 16) | addr] = mclass;
}
}
}
@@ -57,23 +59,58 @@ void Bus::map_reset() {
function<void (unsigned, uint8)> writer = [](unsigned, uint8) {};
idcount = 0;
- map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, reader, writer);
+ map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, 0xFF, reader, writer);
}
void Bus::map_xml() {
for(auto &m : cartridge.mapping) {
- map(m.mode, m.banklo, m.bankhi, m.addrlo, m.addrhi, m.read, m.write, m.offset, m.size);
+ map(m.mode, m.banklo, m.bankhi, m.addrlo, m.addrhi, (unsigned)m.clazz, m.read, m.write, m.offset, m.size);
}
}
+unsigned Bus::enumerateMirrors(uint8 clazz, uint32 offset, unsigned start)
+{
+ unsigned i;
+ for(i = start; i < 0x1000000; i++)
+ if((classmap[i] == clazz && target[i] == offset) || (i == offset && clazz == 255))
+ return i;
+ return i;
+}
+
+void Bus::clearDebugFlags()
+{
+ u_debugflags = 0;
+ memset(debugflags, 0, 0x1000000);
+}
+
+void Bus::debugFlags(uint8 setf, uint8 clrf)
+{
+ u_debugflags = (u_debugflags | setf) & ~clrf;
+}
+
+void Bus::debugFlags(uint8 setf, uint8 clrf, uint8 clazz, uint32 offset)
+{
+ if(clazz == 255) {
+ setf <<= 3;
+ clrf <<= 3;
+ debugflags[offset] = (debugflags[offset] | setf) & ~clrf;
+ } else
+ for(unsigned i = 0; i < 0x1000000; i++)
+ if(classmap[i] == clazz && target[i] == offset)
+ debugflags[i] = (debugflags[i] | setf) & ~clrf;
+}
+
Bus::Bus() {
- lookup = new uint8 [16 * 1024 * 1024];
- target = new uint32[16 * 1024 * 1024];
+ u_debugflags = 0;
+ lookup = new uint8 [112 * 1024 * 1024];
+ target = (uint32*)(lookup + 0x3000000);
+ classmap = lookup + 0x1000000;
+ debugflags = lookup + 0x2000000;
+ memset(debugflags, 0, 0x1000000);
}
Bus::~Bus() {
delete[] lookup;
- delete[] target;
}
}
diff --git a/snes/memory/memory.hpp b/snes/memory/memory.hpp
index 634e0717..c20e14db 100755
--- a/snes/memory/memory.hpp
+++ b/snes/memory/memory.hpp
@@ -44,10 +44,13 @@ private:
struct Bus {
unsigned mirror(unsigned addr, unsigned size);
- alwaysinline uint8 read(unsigned addr);
+ alwaysinline uint8 read(unsigned addr, bool exec);
alwaysinline void write(unsigned addr, uint8 data);
uint8 *lookup;
+ uint8 *classmap;
+ uint8 *debugflags;
+ uint8 u_debugflags;
uint32 *target;
unsigned idcount;
@@ -59,6 +62,7 @@ struct Bus {
MapMode mode,
unsigned bank_lo, unsigned bank_hi,
unsigned addr_lo, unsigned addr_hi,
+ unsigned mclass,
const function<uint8 (unsigned)> &read,
const function<void (unsigned, uint8)> &write,
unsigned base = 0, unsigned length = 0
@@ -67,6 +71,13 @@ struct Bus {
void map_reset();
void map_xml();
+ void clearDebugFlags();
+ void debugFlags(uint8 setf, uint8 clrf);
+ void debugFlags(uint8 setf, uint8 clrf, uint8 clazz, uint32 offset);
+ unsigned enumerateMirrors(uint8 clazz, uint32 offset, unsigned start);
+ function<void (uint8, unsigned, unsigned, uint8, bool)> debug_read;
+ function<void (uint8, unsigned, unsigned, uint8)> debug_write;
+
Bus();
~Bus();
};
diff --git a/snes/ppu/ppu.cpp b/snes/ppu/ppu.cpp
index 8545175f..13e231cf 100755
--- a/snes/ppu/ppu.cpp
+++ b/snes/ppu/ppu.cpp
@@ -87,8 +87,8 @@ void PPU::enable() {
function<uint8 (unsigned)> read = { &PPU::mmio_read, (PPU*)&ppu };
function<void (unsigned, uint8)> write = { &PPU::mmio_write, (PPU*)&ppu };
- bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, read, write);
- bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, read, write);
+ bus.map(Bus::MapMode::Direct, 0x00, 0x3f, 0x2100, 0x213f, 0, read, write);
+ bus.map(Bus::MapMode::Direct, 0x80, 0xbf, 0x2100, 0x213f, 0, read, write);
}
void PPU::power() {
diff --git a/snes/smp/core/core.hpp b/snes/smp/core/core.hpp
index 1489fcef..13d69364 100755
--- a/snes/smp/core/core.hpp
+++ b/snes/smp/core/core.hpp
@@ -2,7 +2,7 @@ struct SMPcore {
virtual void op_io() = 0;
virtual uint8 op_read(uint16 addr) = 0;
virtual void op_write(uint16 addr, uint8 data) = 0;
- void op_step();
+ virtual void op_step();
#include "registers.hpp"
#include "memory.hpp"
diff --git a/snes/snes.hpp b/snes/snes.hpp
index dffeeee3..37ed1feb 100755
--- a/snes/snes.hpp
+++ b/snes/snes.hpp
@@ -1,5 +1,6 @@
#ifndef SNES_HPP
#define SNES_HPP
+#define BSNES_SUPPORTS_ADV_BREAKPOINTS
namespace SNES {
namespace Info {
--
2.15.0.rc1

View file

@ -1,22 +0,0 @@
From 8bc6bb381e680616dcc843c99889799aedd43163 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sat, 30 Nov 2013 10:27:37 +0200
Subject: [PATCH 13/27] Support auto-detecting bsnes version
---
bsnes.mk | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 bsnes.mk
diff --git a/bsnes.mk b/bsnes.mk
new file mode 100644
index 00000000..20f22f61
--- /dev/null
+++ b/bsnes.mk
@@ -0,0 +1,3 @@
+BSNES_SUPPORTS_DEBUGGER=yes
+LIBSNES_DIR=ui-libsnes
+BSNES_VERSION=085
--
2.15.0.rc1

View file

@ -1,138 +0,0 @@
From 40c456dadd79cb2c94379fda8b41a4d0ba051ad1 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sat, 7 Dec 2013 23:32:44 +0200
Subject: [PATCH 14/27] Support alternate (more accurate) poll timings
---
snes/config/config.cpp | 1 +
snes/config/config.hpp | 1 +
snes/cpu/timing/joypad.cpp | 40 ++++++++++++++++++++++++++++++++++++++++
snes/cpu/timing/timing.cpp | 16 ++++++++++++----
snes/cpu/timing/timing.hpp | 1 +
snes/snes.hpp | 1 +
6 files changed, 56 insertions(+), 4 deletions(-)
diff --git a/snes/config/config.cpp b/snes/config/config.cpp
index 701af94c..206daae0 100755
--- a/snes/config/config.cpp
+++ b/snes/config/config.cpp
@@ -13,6 +13,7 @@ Configuration::Configuration() {
cpu.ntsc_frequency = 21477272; //315 / 88 * 6000000
cpu.pal_frequency = 21281370;
cpu.wram_init_value = 0x55;
+ cpu.alt_poll_timings = false;
smp.ntsc_frequency = 24607104; //32040.5 * 768
smp.pal_frequency = 24607104;
diff --git a/snes/config/config.hpp b/snes/config/config.hpp
index 1f4d037c..dabde597 100755
--- a/snes/config/config.hpp
+++ b/snes/config/config.hpp
@@ -10,6 +10,7 @@ struct Configuration {
unsigned ntsc_frequency;
unsigned pal_frequency;
unsigned wram_init_value;
+ bool alt_poll_timings;
} cpu;
struct SMP {
diff --git a/snes/cpu/timing/joypad.cpp b/snes/cpu/timing/joypad.cpp
index 6a98de00..ae8e94f8 100755
--- a/snes/cpu/timing/joypad.cpp
+++ b/snes/cpu/timing/joypad.cpp
@@ -29,4 +29,44 @@ void CPU::step_auto_joypad_poll() {
}
}
+//called every 128 clocks; see CPU::add_clocks()
+void CPU::step_auto_joypad_poll_NEW(bool polarity) {
+ if(status.auto_joypad_counter > 0 && status.auto_joypad_counter <= 34) {
+ if(!status.auto_joypad_latch) {
+ //FIXME: Is this right, busy flag goes on even if not enabled???
+ if(status.auto_joypad_counter == 1)
+ status.auto_joypad_active = true;
+ if(status.auto_joypad_counter == 34)
+ status.auto_joypad_active = false;
+ } else {
+ if(status.auto_joypad_counter == 1) {
+ status.auto_joypad_active = true;
+ input.port1->latch(1);
+ input.port2->latch(1);
+ }
+ if(status.auto_joypad_counter == 3) {
+ input.port1->latch(0);
+ input.port2->latch(0);
+ }
+ if((status.auto_joypad_counter & 1) != 0 && status.auto_joypad_counter != 1) {
+ uint2 port0 = input.port1->data();
+ uint2 port1 = input.port2->data();
+
+ status.joy1 = (status.joy1 << 1) | (bool)(port0 & 1);
+ status.joy2 = (status.joy2 << 1) | (bool)(port1 & 1);
+ status.joy3 = (status.joy3 << 1) | (bool)(port0 & 2);
+ status.joy4 = (status.joy4 << 1) | (bool)(port1 & 2);
+ }
+ if(status.auto_joypad_counter == 34)
+ status.auto_joypad_active = false;
+ }
+ status.auto_joypad_counter++;
+ }
+ if(vcounter() >= (ppu.overscan() == false ? 225 : 240) && status.auto_joypad_counter == 0 && !polarity) {
+ status.auto_joypad_latch = status.auto_joypad_poll;
+ status.auto_joypad_counter = 1;
+ }
+}
+
+
#endif
diff --git a/snes/cpu/timing/timing.cpp b/snes/cpu/timing/timing.cpp
index f1378f0c..d7cf24f3 100755
--- a/snes/cpu/timing/timing.cpp
+++ b/snes/cpu/timing/timing.cpp
@@ -17,10 +17,18 @@ void CPU::add_clocks(unsigned clocks) {
step(clocks);
- status.auto_joypad_clock += clocks;
- if(status.auto_joypad_clock >= 256) {
- status.auto_joypad_clock -= 256;
- step_auto_joypad_poll();
+ if(config.cpu.alt_poll_timings) {
+ bool opolarity = (status.auto_joypad_clock & 128);
+ status.auto_joypad_clock = (status.auto_joypad_clock + clocks) & 0xFF;
+ bool npolarity = (status.auto_joypad_clock & 128);
+ if(opolarity != npolarity)
+ step_auto_joypad_poll_NEW(opolarity);
+ } else {
+ status.auto_joypad_clock += clocks;
+ if(status.auto_joypad_clock >= 256) {
+ status.auto_joypad_clock -= 256;
+ step_auto_joypad_poll();
+ }
}
if(status.dram_refreshed == false && hcounter() >= status.dram_refresh_position) {
diff --git a/snes/cpu/timing/timing.hpp b/snes/cpu/timing/timing.hpp
index 6c225dab..bf15a727 100755
--- a/snes/cpu/timing/timing.hpp
+++ b/snes/cpu/timing/timing.hpp
@@ -22,3 +22,4 @@ alwaysinline bool irq_test();
//joypad.cpp
void step_auto_joypad_poll();
+void step_auto_joypad_poll_NEW(bool polarity);
diff --git a/snes/snes.hpp b/snes/snes.hpp
index 37ed1feb..4e3ba64c 100755
--- a/snes/snes.hpp
+++ b/snes/snes.hpp
@@ -1,6 +1,7 @@
#ifndef SNES_HPP
#define SNES_HPP
#define BSNES_SUPPORTS_ADV_BREAKPOINTS
+#define BSNES_SUPPORTS_ALT_TIMINGS
namespace SNES {
namespace Info {
--
2.15.0.rc1

View file

@ -1,103 +0,0 @@
From 863bde899b53ae31e854096ac5258208c848a293 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Thu, 6 Mar 2014 21:07:54 +0200
Subject: [PATCH 15/27] Fix mouse speed support
---
snes/config/config.cpp | 1 +
snes/config/config.hpp | 3 +++
snes/controller/mouse/mouse.cpp | 11 +++++++++--
snes/controller/mouse/mouse.hpp | 1 +
4 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/snes/config/config.cpp b/snes/config/config.cpp
index 206daae0..19831370 100755
--- a/snes/config/config.cpp
+++ b/snes/config/config.cpp
@@ -8,6 +8,7 @@ Configuration::Configuration() {
expansion_port = System::ExpansionPortDevice::BSX;
region = System::Region::Autodetect;
random = true;
+ mouse_speed_fix = false;
cpu.version = 2;
cpu.ntsc_frequency = 21477272; //315 / 88 * 6000000
diff --git a/snes/config/config.hpp b/snes/config/config.hpp
index dabde597..68fe0bde 100755
--- a/snes/config/config.hpp
+++ b/snes/config/config.hpp
@@ -1,9 +1,12 @@
+#define BSNES_SUPPORTS_MOUSE_SPEED_FIX
+
struct Configuration {
Input::Device controller_port1;
Input::Device controller_port2;
System::ExpansionPortDevice expansion_port;
System::Region region;
bool random;
+ bool mouse_speed_fix;
struct CPU {
unsigned version;
diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp
index 1a066b98..caa7a358 100755
--- a/snes/controller/mouse/mouse.cpp
+++ b/snes/controller/mouse/mouse.cpp
@@ -1,6 +1,10 @@
#ifdef CONTROLLER_CPP
uint2 Mouse::data() {
+ if(config.mouse_speed_fix && latched) {
+ speed = (speed + 1) % 3;
+ return 0;
+ }
if(counter >= 32) return 1;
if(counter == 0) {
@@ -31,8 +35,8 @@ uint2 Mouse::data() {
case 8: return interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Right);
case 9: return interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Left);
- case 10: return 0; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused)
- case 11: return 0; // ||
+ case 10: return speed >> 1; //speed (0 = slow, 1 = normal, 2 = fast, 3 = unused)
+ case 11: return speed & 1; // ||
case 12: return 0; //signature
case 13: return 0; // ||
@@ -75,10 +79,12 @@ void Mouse::serialize(serializer& s) {
block[3] = (unsigned short)_position_x;
block[4] = (unsigned short)_position_y >> 8;
block[5] = (unsigned short)_position_y;
+ block[6] = speed;
s.array(block, Controller::SaveSize);
if(s.mode() == nall::serializer::Load) {
latched = (block[0] != 0);
counter = block[1];
+ speed = block[6];
_position_x = (short)(((unsigned short)block[2] << 8) | (unsigned short)block[3]);
_position_y = (short)(((unsigned short)block[4] << 8) | (unsigned short)block[5]);
}
@@ -87,6 +93,7 @@ void Mouse::serialize(serializer& s) {
Mouse::Mouse(bool port) : Controller(port) {
latched = 0;
counter = 0;
+ speed = 0;
}
#endif
diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp
index b07c8ab7..13a9313e 100755
--- a/snes/controller/mouse/mouse.hpp
+++ b/snes/controller/mouse/mouse.hpp
@@ -6,6 +6,7 @@ struct Mouse : Controller {
private:
bool latched;
unsigned counter;
+ unsigned speed;
int _position_x;
int _position_y;
};
--
2.15.0.rc1

View file

@ -1,25 +0,0 @@
From 60267d1f22fd2ff3197c6c829640f66304c89283 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sun, 16 Mar 2014 16:40:55 +0200
Subject: [PATCH 16/27] Fix tracelog of controller registers
---
snes/cpu/core/disassembler/disassembler.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/snes/cpu/core/disassembler/disassembler.cpp b/snes/cpu/core/disassembler/disassembler.cpp
index ab8dde24..624a80ce 100755
--- a/snes/cpu/core/disassembler/disassembler.cpp
+++ b/snes/cpu/core/disassembler/disassembler.cpp
@@ -1,6 +1,8 @@
#ifdef CPUCORE_CPP
uint8 CPUcore::dreadb(uint32 addr) {
+ if((addr & 0x40fff8) == 0x4218)
+ return bus.read(addr, false); //Controller registers are safe to read.
if((addr & 0x40ffff) >= 0x2000 && (addr & 0x40ffff) <= 0x5fff) {
//$[00-3f|80-bf]:[2000-5fff]
//do not read MMIO registers within debugger
--
2.15.0.rc1

View file

@ -1,105 +0,0 @@
From de71f12eb59a41899a5c77d797e144e6f0919777 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Mon, 17 Mar 2014 14:22:58 +0200
Subject: [PATCH 17/27] Fix performance problem with non-bus breakpoints
---
snes/memory/memory.cpp | 35 ++++++++++++++++++++++++++---------
snes/memory/memory.hpp | 1 +
snes/snes.hpp | 1 +
3 files changed, 28 insertions(+), 9 deletions(-)
diff --git a/snes/memory/memory.cpp b/snes/memory/memory.cpp
index a9a484a0..d22e3137 100755
--- a/snes/memory/memory.cpp
+++ b/snes/memory/memory.cpp
@@ -43,6 +43,7 @@ void Bus::map(
unsigned offset = 0;
for(unsigned bank = bank_lo; bank <= bank_hi; bank++) {
+ region_start.insert((bank << 16) | addr_lo);
for(unsigned addr = addr_lo; addr <= addr_hi; addr++) {
unsigned destaddr = (bank << 16) | addr;
if(mode == MapMode::Linear) destaddr = mirror(base + offset++, length);
@@ -60,6 +61,7 @@ void Bus::map_reset() {
idcount = 0;
map(MapMode::Direct, 0x00, 0xff, 0x0000, 0xffff, 0xFF, reader, writer);
+ region_start.clear();
}
void Bus::map_xml() {
@@ -70,11 +72,21 @@ void Bus::map_xml() {
unsigned Bus::enumerateMirrors(uint8 clazz, uint32 offset, unsigned start)
{
- unsigned i;
- for(i = start; i < 0x1000000; i++)
- if((classmap[i] == clazz && target[i] == offset) || (i == offset && clazz == 255))
- return i;
- return i;
+ if(clazz == 255) {
+ if(start > offset)
+ return 0x1000000;
+ else
+ return start;
+ }
+ //Given region can not contain the same address twice.
+ for(std::set<uint32>::iterator i = region_start.lower_bound(start); i != region_start.end(); i++) {
+ if(classmap[*i] != clazz) continue;
+ if(target[*i] > offset) continue;
+ uint32 wouldbe = offset - target[*i] + *i;
+ if(wouldbe > 0xFFFFFF) continue;
+ if(classmap[wouldbe] == clazz && target[wouldbe] == offset) return wouldbe;
+ }
+ return 0x1000000;
}
void Bus::clearDebugFlags()
@@ -94,10 +106,15 @@ void Bus::debugFlags(uint8 setf, uint8 clrf, uint8 clazz, uint32 offset)
setf <<= 3;
clrf <<= 3;
debugflags[offset] = (debugflags[offset] | setf) & ~clrf;
- } else
- for(unsigned i = 0; i < 0x1000000; i++)
- if(classmap[i] == clazz && target[i] == offset)
- debugflags[i] = (debugflags[i] | setf) & ~clrf;
+ } else {
+ uint32 i = 0;
+ while(true) {
+ i = enumerateMirrors(clazz, offset, i);
+ if(i >= 0x1000000) break;
+ debugflags[i] = (debugflags[i] | setf) & ~clrf;
+ i++;
+ }
+ }
}
Bus::Bus() {
diff --git a/snes/memory/memory.hpp b/snes/memory/memory.hpp
index c20e14db..ee0c0a9e 100755
--- a/snes/memory/memory.hpp
+++ b/snes/memory/memory.hpp
@@ -52,6 +52,7 @@ struct Bus {
uint8 *debugflags;
uint8 u_debugflags;
uint32 *target;
+ std::set<uint32> region_start;
unsigned idcount;
function<uint8 (unsigned)> reader[256];
diff --git a/snes/snes.hpp b/snes/snes.hpp
index 4e3ba64c..9589db9b 100755
--- a/snes/snes.hpp
+++ b/snes/snes.hpp
@@ -38,6 +38,7 @@ namespace SNES {
#include <nall/varint.hpp>
#include <nall/vector.hpp>
#include <nall/gameboy/cartridge.hpp>
+#include <set>
using namespace nall;
#include <gameboy/gameboy.hpp>
--
2.15.0.rc1

View file

@ -1,537 +0,0 @@
From 6bd069191d29ad70d38c82d59dd72cd0996fc45c Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Mon, 31 Mar 2014 20:17:46 +0300
Subject: [PATCH 18/27] Support VRAM, OAM, CGRAM and APURAM breakpoints
---
snes/alt/ppu-compatibility/memory/memory.cpp | 44 +++++++++++++++++++++--
snes/alt/ppu-compatibility/ppu.hpp | 6 ++++
snes/cartridge/cartridge.hpp | 4 +++
snes/smp/core/core.hpp | 2 +-
snes/smp/core/memory.hpp | 6 ++--
snes/smp/core/opcodes.cpp | 36 +++++++++----------
snes/smp/debugger/debugger.cpp | 4 +--
snes/smp/debugger/debugger.hpp | 2 +-
snes/smp/memory/memory.cpp | 54 +++++++++++++++++++---------
snes/smp/memory/memory.hpp | 4 +--
snes/smp/smp.hpp | 4 +++
snes/snes.hpp | 1 +
12 files changed, 122 insertions(+), 45 deletions(-)
diff --git a/snes/alt/ppu-compatibility/memory/memory.cpp b/snes/alt/ppu-compatibility/memory/memory.cpp
index 3f120d84..e47cf201 100755
--- a/snes/alt/ppu-compatibility/memory/memory.cpp
+++ b/snes/alt/ppu-compatibility/memory/memory.cpp
@@ -47,20 +47,31 @@ uint8 PPU::vram_mmio_read(uint16 addr) {
data = vram[addr];
}
}
-
+ if(__builtin_expect(vram_debugflags[addr] & 0x1, 0)) {
+ debug_read(13, addr, data);
+ }
return data;
}
void PPU::vram_mmio_write(uint16 addr, uint8 data) {
if(regs.display_disabled == true) {
+ if(__builtin_expect(vram_debugflags[addr] & 0x2, 0)) {
+ debug_write(13, addr, data);
+ }
vram[addr] = data;
} else {
uint16 v = cpu.vcounter();
uint16 h = cpu.hcounter();
if(v == 0) {
if(h <= 4) {
+ if(__builtin_expect(vram_debugflags[addr] & 0x2, 0)) {
+ debug_write(13, addr, data);
+ }
vram[addr] = data;
} else if(h == 6) {
+ if(__builtin_expect(vram_debugflags[addr] & 0x2, 0)) {
+ debug_write(13, addr, cpu.regs.mdr);
+ }
vram[addr] = cpu.regs.mdr;
} else {
//no write
@@ -71,9 +82,15 @@ void PPU::vram_mmio_write(uint16 addr, uint8 data) {
if(h <= 4) {
//no write
} else {
+ if(__builtin_expect(vram_debugflags[addr] & 0x2, 0)) {
+ debug_write(13, addr, data);
+ }
vram[addr] = data;
}
} else {
+ if(__builtin_expect(vram_debugflags[addr] & 0x2, 0)) {
+ debug_write(13, addr, data);
+ }
vram[addr] = data;
}
}
@@ -93,7 +110,9 @@ uint8 PPU::oam_mmio_read(uint16 addr) {
data = oam[addr];
}
}
-
+ if(__builtin_expect(oam_debugflags[addr] & 0x1, 0)) {
+ debug_read(14, addr, data);
+ }
return data;
}
@@ -104,13 +123,22 @@ void PPU::oam_mmio_write(uint16 addr, uint8 data) {
sprite_list_valid = false;
if(regs.display_disabled == true) {
+ if(__builtin_expect(oam_debugflags[addr] & 0x2, 0)) {
+ debug_write(14, addr, data);
+ }
oam[addr] = data;
update_sprite_list(addr, data);
} else {
if(cpu.vcounter() < (!overscan() ? 225 : 240)) {
+ if(__builtin_expect(oam_debugflags[regs.ioamaddr] & 0x2, 0)) {
+ debug_write(14, regs.ioamaddr, data);
+ }
oam[regs.ioamaddr] = data;
update_sprite_list(regs.ioamaddr, data);
} else {
+ if(__builtin_expect(oam_debugflags[addr] & 0x2, 0)) {
+ debug_write(14, addr, data);
+ }
oam[addr] = data;
update_sprite_list(addr, data);
}
@@ -134,6 +162,9 @@ uint8 PPU::cgram_mmio_read(uint16 addr) {
}
if(addr & 1) data &= 0x7f;
+ if(__builtin_expect(cgram_debugflags[addr] & 0x1, 0)) {
+ debug_read(15, addr, data);
+ }
return data;
}
@@ -142,13 +173,22 @@ void PPU::cgram_mmio_write(uint16 addr, uint8 data) {
if(addr & 1) data &= 0x7f;
if(1 || regs.display_disabled == true) {
+ if(__builtin_expect(cgram_debugflags[addr] & 0x2, 0)) {
+ debug_write(15, addr, data);
+ }
cgram[addr] = data;
} else {
uint16 v = cpu.vcounter();
uint16 h = cpu.hcounter();
if(v < (!overscan() ? 225 : 240) && h >= 128 && h < 1096) {
+ if(__builtin_expect(cgram_debugflags[regs.icgramaddr] & 0x2, 0)) {
+ debug_write(15, regs.icgramaddr, data & 0x7f);
+ }
cgram[regs.icgramaddr] = data & 0x7f;
} else {
+ if(__builtin_expect(cgram_debugflags[addr] & 0x2, 0)) {
+ debug_write(15, addr, data);
+ }
cgram[addr] = data;
}
}
diff --git a/snes/alt/ppu-compatibility/ppu.hpp b/snes/alt/ppu-compatibility/ppu.hpp
index cccaabba..4adac4c4 100755
--- a/snes/alt/ppu-compatibility/ppu.hpp
+++ b/snes/alt/ppu-compatibility/ppu.hpp
@@ -3,6 +3,12 @@ public:
uint8 vram[128 * 1024];
uint8 oam[544];
uint8 cgram[512];
+ //4 is read, 2 is write.
+ uint8 vram_debugflags[128 * 1024];
+ uint8 oam_debugflags[544];
+ uint8 cgram_debugflags[512];
+ function<void (uint8, unsigned, uint8)> debug_read;
+ function<void (uint8, unsigned, uint8)> debug_write;
enum : bool { Threaded = true };
alwaysinline void step(unsigned clocks);
diff --git a/snes/cartridge/cartridge.hpp b/snes/cartridge/cartridge.hpp
index 82e73c4c..2358c088 100755
--- a/snes/cartridge/cartridge.hpp
+++ b/snes/cartridge/cartridge.hpp
@@ -26,6 +26,10 @@ struct Cartridge : property<Cartridge> {
SUFAMITURBO_RAMA = 10,
SUFAMITURBO_RAMB = 11,
BSXFLASH = 12,
+ VRAM = 13,
+ OAM = 14,
+ CGRAM = 15,
+ APURAM = 16,
};
enum class Slot : unsigned {
diff --git a/snes/smp/core/core.hpp b/snes/smp/core/core.hpp
index 13d69364..03f9ac66 100755
--- a/snes/smp/core/core.hpp
+++ b/snes/smp/core/core.hpp
@@ -1,6 +1,6 @@
struct SMPcore {
virtual void op_io() = 0;
- virtual uint8 op_read(uint16 addr) = 0;
+ virtual uint8 op_read(uint16 addr, bool exec) = 0;
virtual void op_write(uint16 addr, uint8 data) = 0;
virtual void op_step();
diff --git a/snes/smp/core/memory.hpp b/snes/smp/core/memory.hpp
index c4b6d99f..c297962f 100755
--- a/snes/smp/core/memory.hpp
+++ b/snes/smp/core/memory.hpp
@@ -1,9 +1,9 @@
alwaysinline uint8 op_readpc() {
- return op_read(regs.pc++);
+ return op_read(regs.pc++, true);
}
alwaysinline uint8 op_readsp() {
- return op_read(0x0100 | ++regs.s);
+ return op_read(0x0100 | ++regs.s, false);
}
alwaysinline void op_writesp(uint8 data) {
@@ -11,7 +11,7 @@ alwaysinline void op_writesp(uint8 data) {
}
alwaysinline uint8 op_readdp(uint8 addr) {
- return op_read((regs.p.p << 8) + addr);
+ return op_read((regs.p.p << 8) + addr, false);
}
alwaysinline void op_writedp(uint8 addr, uint8 data) {
diff --git a/snes/smp/core/opcodes.cpp b/snes/smp/core/opcodes.cpp
index 95b9844f..43db081d 100755
--- a/snes/smp/core/opcodes.cpp
+++ b/snes/smp/core/opcodes.cpp
@@ -11,7 +11,7 @@ template<uint8 (SMPcore::*op)(uint8)>
void SMPcore::op_adjust_addr() {
dp.l = op_readpc();
dp.h = op_readpc();
- rd = op_read(dp);
+ rd = op_read(dp, false);
rd = call(rd);
op_write(dp, rd);
}
@@ -78,7 +78,7 @@ template<uint8 (SMPcore::*op)(uint8, uint8)>
void SMPcore::op_read_addr(uint8 &r) {
dp.l = op_readpc();
dp.h = op_readpc();
- rd = op_read(dp);
+ rd = op_read(dp, false);
r = call(r, rd);
}
@@ -87,7 +87,7 @@ void SMPcore::op_read_addri(uint8 &r) {
dp.l = op_readpc();
dp.h = op_readpc();
op_io();
- rd = op_read(dp + r);
+ rd = op_read(dp + r, false);
regs.a = call(regs.a, rd);
}
@@ -127,7 +127,7 @@ void SMPcore::op_read_idpx() {
op_io();
sp.l = op_readdp(dp++);
sp.h = op_readdp(dp++);
- rd = op_read(sp);
+ rd = op_read(sp, false);
regs.a = call(regs.a, rd);
}
@@ -137,7 +137,7 @@ void SMPcore::op_read_idpy() {
op_io();
sp.l = op_readdp(dp++);
sp.h = op_readdp(dp++);
- rd = op_read(sp + regs.y);
+ rd = op_read(sp + regs.y, false);
regs.a = call(regs.a, rd);
}
@@ -153,7 +153,7 @@ void SMPcore::op_set_addr_bit() {
dp.h = op_readpc();
bit = dp >> 13;
dp &= 0x1fff;
- rd = op_read(dp);
+ rd = op_read(dp, false);
switch(opcode >> 5) {
case 0: //orc addr:bit
case 1: //orc !addr:bit
@@ -198,10 +198,10 @@ void SMPcore::op_set_flag(bool &flag, bool data) {
void SMPcore::op_test_addr(bool set) {
dp.l = op_readpc();
dp.h = op_readpc();
- rd = op_read(dp);
+ rd = op_read(dp, false);
regs.p.n = (regs.a - rd) & 0x80;
regs.p.z = (regs.a - rd) == 0;
- op_read(dp);
+ op_read(dp, false);
op_write(dp, set ? rd | regs.a : rd & ~regs.a);
}
@@ -216,7 +216,7 @@ void SMPcore::op_transfer(uint8 &from, uint8 &to) {
void SMPcore::op_write_addr(uint8 &r) {
dp.l = op_readpc();
dp.h = op_readpc();
- op_read(dp);
+ op_read(dp, false);
op_write(dp, r);
}
@@ -225,7 +225,7 @@ void SMPcore::op_write_addri(uint8 &i) {
dp.h = op_readpc();
op_io();
dp += i;
- op_read(dp);
+ op_read(dp, false);
op_write(dp, regs.a);
}
@@ -317,8 +317,8 @@ void SMPcore::op_bne_ydec() {
}
void SMPcore::op_brk() {
- rd.l = op_read(0xffde);
- rd.h = op_read(0xffdf);
+ rd.l = op_read(0xffde, false);
+ rd.h = op_read(0xffdf, false);
op_io();
op_io();
op_writesp(regs.pc.h);
@@ -411,8 +411,8 @@ void SMPcore::op_jmp_iaddrx() {
dp.h = op_readpc();
op_io();
dp += regs.x;
- rd.l = op_read(dp++);
- rd.h = op_read(dp++);
+ rd.l = op_read(dp++, false);
+ rd.h = op_read(dp++, false);
regs.pc = rd;
}
@@ -438,8 +438,8 @@ void SMPcore::op_jsr_addr() {
void SMPcore::op_jst() {
dp = 0xffde - ((opcode >> 4) << 1);
- rd.l = op_read(dp++);
- rd.h = op_read(dp++);
+ rd.l = op_read(dp++, false);
+ rd.h = op_read(dp++, false);
op_io();
op_io();
op_io();
@@ -505,7 +505,7 @@ void SMPcore::op_sta_idpx() {
op_io();
dp.l = op_readdp(sp++);
dp.h = op_readdp(sp++);
- op_read(dp);
+ op_read(dp, false);
op_write(dp, regs.a);
}
@@ -515,7 +515,7 @@ void SMPcore::op_sta_idpy() {
dp.h = op_readdp(sp++);
op_io();
dp += regs.y;
- op_read(dp);
+ op_read(dp, false);
op_write(dp, regs.a);
}
diff --git a/snes/smp/debugger/debugger.cpp b/snes/smp/debugger/debugger.cpp
index 9546c118..894fdac9 100755
--- a/snes/smp/debugger/debugger.cpp
+++ b/snes/smp/debugger/debugger.cpp
@@ -18,8 +18,8 @@ void SMPDebugger::op_step() {
synchronize_cpu();
}
-uint8 SMPDebugger::op_read(uint16 addr) {
- uint8 data = SMP::op_read(addr);
+uint8 SMPDebugger::op_read(uint16 addr, bool exec) {
+ uint8 data = SMP::op_read(addr, exec);
usage[addr] |= UsageRead;
debugger.breakpoint_test(Debugger::Breakpoint::Source::APURAM, Debugger::Breakpoint::Mode::Read, addr, data);
return data;
diff --git a/snes/smp/debugger/debugger.hpp b/snes/smp/debugger/debugger.hpp
index d5d28e53..26bc7af9 100755
--- a/snes/smp/debugger/debugger.hpp
+++ b/snes/smp/debugger/debugger.hpp
@@ -14,7 +14,7 @@ public:
bool opcode_edge;
void op_step();
- uint8 op_read(uint16 addr);
+ uint8 op_read(uint16 addr, bool exec);
void op_write(uint16 addr, uint8 data);
SMPDebugger();
diff --git a/snes/smp/memory/memory.cpp b/snes/smp/memory/memory.cpp
index 391324c4..58c11915 100755
--- a/snes/smp/memory/memory.cpp
+++ b/snes/smp/memory/memory.cpp
@@ -19,61 +19,83 @@ void SMP::port_write(uint2 port, uint8 data) {
apuram[0xf4 + port] = data;
}
-alwaysinline uint8 SMP::op_busread(uint16 addr) {
+alwaysinline uint8 SMP::op_busread(uint16 addr, bool exec) {
unsigned result;
+ uint8 data;
switch(addr) {
case 0xf0: //TEST -- write-only register
- return 0x00;
+ data = 0x00;
+ break;
case 0xf1: //CONTROL -- write-only register
- return 0x00;
+ data = 0x00;
+ break;
case 0xf2: //DSPADDR
- return status.dsp_addr;
+ data = status.dsp_addr;
+ break;
case 0xf3: //DSPDATA
//0x80-0xff are read-only mirrors of 0x00-0x7f
- return dsp.read(status.dsp_addr & 0x7f);
+ data = dsp.read(status.dsp_addr & 0x7f);
+ break;
case 0xf4: //CPUIO0
case 0xf5: //CPUIO1
case 0xf6: //CPUIO2
case 0xf7: //CPUIO3
synchronize_cpu();
- return cpu.port_read(addr);
+ data = cpu.port_read(addr);
+ break;
case 0xf8: //RAM0
- return status.ram00f8;
+ data = status.ram00f8;
+ break;
case 0xf9: //RAM1
- return status.ram00f9;
+ data = status.ram00f9;
+ break;
case 0xfa: //T0TARGET
case 0xfb: //T1TARGET
case 0xfc: //T2TARGET -- write-only registers
- return 0x00;
+ data = 0x00;
+ break;
case 0xfd: //T0OUT -- 4-bit counter value
result = timer0.stage3_ticks;
timer0.stage3_ticks = 0;
- return result;
+ data = result;
+ break;
case 0xfe: //T1OUT -- 4-bit counter value
result = timer1.stage3_ticks;
timer1.stage3_ticks = 0;
- return result;
+ data = result;
+ break;
case 0xff: //T2OUT -- 4-bit counter value
result = timer2.stage3_ticks;
timer2.stage3_ticks = 0;
- return result;
+ data = result;
+ break;
+ default:
+ data = ram_read(addr);
+ break;
}
-
- return ram_read(addr);
+ uint8 flag = exec ? 0x04 : 0x01;
+ if(__builtin_expect(debugflags[addr] & flag, 0)) {
+ debug_read(16, addr, data, exec);
+ }
+ return data;
}
alwaysinline void SMP::op_buswrite(uint16 addr, uint8 data) {
+ if(__builtin_expect(debugflags[addr] & 0x2, 0)) {
+ debug_write(16, addr, data);
+ }
+
switch(addr) {
case 0xf0: //TEST
if(regs.p.p) break; //writes only valid when P flag is clear
@@ -180,9 +202,9 @@ void SMP::op_io() {
cycle_edge();
}
-uint8 SMP::op_read(uint16 addr) {
+uint8 SMP::op_read(uint16 addr, bool exec) {
add_clocks(12);
- uint8 r = op_busread(addr);
+ uint8 r = op_busread(addr, exec);
add_clocks(12);
cycle_edge();
return r;
diff --git a/snes/smp/memory/memory.hpp b/snes/smp/memory/memory.hpp
index 1a07445d..faa28daa 100755
--- a/snes/smp/memory/memory.hpp
+++ b/snes/smp/memory/memory.hpp
@@ -1,9 +1,9 @@
uint8 ram_read(uint16 addr);
void ram_write(uint16 addr, uint8 data);
-uint8 op_busread(uint16 addr);
+uint8 op_busread(uint16 addr, bool exec);
void op_buswrite(uint16 addr, uint8 data);
void op_io();
-debugvirtual uint8 op_read(uint16 addr);
+debugvirtual uint8 op_read(uint16 addr, bool exec);
debugvirtual void op_write(uint16 addr, uint8 data);
diff --git a/snes/smp/smp.hpp b/snes/smp/smp.hpp
index 6b387cba..6b6ae837 100755
--- a/snes/smp/smp.hpp
+++ b/snes/smp/smp.hpp
@@ -1,6 +1,10 @@
struct SMP : public Processor, public SMPcore {
static const uint8 iplrom[64];
uint8 apuram[64 * 1024];
+ uint8 debugflags[64 * 1024];
+
+ function<void (uint8, unsigned, uint8, bool)> debug_read;
+ function<void (uint8, unsigned, uint8)> debug_write;
enum : bool { Threaded = true };
alwaysinline void step(unsigned clocks);
diff --git a/snes/snes.hpp b/snes/snes.hpp
index 9589db9b..27632bff 100755
--- a/snes/snes.hpp
+++ b/snes/snes.hpp
@@ -1,6 +1,7 @@
#ifndef SNES_HPP
#define SNES_HPP
#define BSNES_SUPPORTS_ADV_BREAKPOINTS
+#define BSNES_SUPPORTS_ADV_BREAKPOINTS_PPU
#define BSNES_SUPPORTS_ALT_TIMINGS
namespace SNES {
--
2.15.0.rc1

View file

@ -1,53 +0,0 @@
From f1106d3dffd27dab526a703aa434512495fbacea Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Mon, 14 Apr 2014 21:21:36 +0300
Subject: [PATCH 19/27] SA1 trace hook support
---
snes/chip/sa1/sa1.cpp | 2 ++
snes/chip/sa1/sa1.hpp | 3 +++
snes/snes.hpp | 1 +
3 files changed, 6 insertions(+)
diff --git a/snes/chip/sa1/sa1.cpp b/snes/chip/sa1/sa1.cpp
index 30e00809..fdec362c 100755
--- a/snes/chip/sa1/sa1.cpp
+++ b/snes/chip/sa1/sa1.cpp
@@ -32,6 +32,8 @@ void SA1::enter() {
continue;
}
+ if(__builtin_expect(trace_enabled ? 1 : 0, 0))
+ step_event();
(this->*opcode_table[op_readpc()])();
}
}
diff --git a/snes/chip/sa1/sa1.hpp b/snes/chip/sa1/sa1.hpp
index 732b2a85..efd36376 100755
--- a/snes/chip/sa1/sa1.hpp
+++ b/snes/chip/sa1/sa1.hpp
@@ -15,6 +15,9 @@ public:
uint16 hcounter;
} status;
+ bool trace_enabled;
+ nall::function<void()> step_event;
+
static void Enter();
void enter();
void tick();
diff --git a/snes/snes.hpp b/snes/snes.hpp
index 27632bff..3bdca7e5 100755
--- a/snes/snes.hpp
+++ b/snes/snes.hpp
@@ -3,6 +3,7 @@
#define BSNES_SUPPORTS_ADV_BREAKPOINTS
#define BSNES_SUPPORTS_ADV_BREAKPOINTS_PPU
#define BSNES_SUPPORTS_ALT_TIMINGS
+#define BSNES_SUPPORTS_TRACE_SA1
namespace SNES {
namespace Info {
--
2.15.0.rc1

View file

@ -1,78 +0,0 @@
From cf662a12578778cb50c25d5275ce58deabd7eabe Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 30 Apr 2014 00:18:58 +0300
Subject: [PATCH 20/27] Fixes to SA1 open bus emulation
---
snes/chip/sa1/memory/memory.cpp | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/snes/chip/sa1/memory/memory.cpp b/snes/chip/sa1/memory/memory.cpp
index 9bb4ff20..614dfb0c 100755
--- a/snes/chip/sa1/memory/memory.cpp
+++ b/snes/chip/sa1/memory/memory.cpp
@@ -36,6 +36,7 @@ uint8 SA1::bus_read(unsigned addr) {
synchronize_cpu();
return bitmap_read(addr & 0x0fffff);
}
+ return regs.mdr;
}
void SA1::bus_write(unsigned addr, uint8 data) {
@@ -73,29 +74,31 @@ void SA1::bus_write(unsigned addr, uint8 data) {
//to avoid syncing the S-CPU and SA-1*; as both chips are able to access
//these ports.
uint8 SA1::vbr_read(unsigned addr) {
+ //Let's share the bus state with main SA1 bus (is this correct?)
if((addr & 0x408000) == 0x008000) { //$00-3f|80-bf:8000-ffff
- return mmc_read(addr);
+ return regs.mdr = mmc_read(addr);
}
if((addr & 0xc00000) == 0xc00000) { //$c0-ff:0000-ffff
- return mmc_read(addr);
+ return regs.mdr = mmc_read(addr);
}
if((addr & 0x40e000) == 0x006000) { //$00-3f|80-bf:6000-7fff
- return cartridge.ram.read(addr & (cartridge.ram.size() - 1));
+ return regs.mdr = cartridge.ram.read(addr & (cartridge.ram.size() - 1));
}
if((addr & 0xf00000) == 0x400000) { //$40-4f:0000-ffff
- return cartridge.ram.read(addr & (cartridge.ram.size() - 1));
+ return regs.mdr = cartridge.ram.read(addr & (cartridge.ram.size() - 1));
}
if((addr & 0x40f800) == 0x000000) { //$00-3f|80-bf:0000-07ff
- return iram.read(addr & 2047);
+ return regs.mdr = iram.read(addr & 2047);
}
if((addr & 0x40f800) == 0x003000) { //$00-3f|80-bf:3000-37ff
- return iram.read(addr & 0x2047);
+ return regs.mdr = iram.read(addr & 0x2047);
}
+ return regs.mdr;
}
//ROM, I-RAM and MMIO registers are accessed at ~10.74MHz (2 clock ticks)
@@ -110,13 +113,13 @@ void SA1::op_io() {
uint8 SA1::op_read(unsigned addr, bool exec) {
tick();
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
- return bus_read(addr);
+ return regs.mdr = bus_read(addr);
}
void SA1::op_write(unsigned addr, uint8 data) {
tick();
if(((addr & 0x40e000) == 0x006000) || ((addr & 0xd00000) == 0x400000)) tick();
- bus_write(addr, data);
+ bus_write(addr, regs.mdr = data);
}
uint8 SA1::mmc_read(unsigned addr) {
--
2.15.0.rc1

View file

@ -1,25 +0,0 @@
From 63fc77b07d517c2f9a0fd6ca3fa94f30fb0f5ec2 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sun, 15 Jun 2014 22:01:26 +0300
Subject: [PATCH 21/27] Call notify latch function on alternate timings mode
too
---
snes/cpu/timing/joypad.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/snes/cpu/timing/joypad.cpp b/snes/cpu/timing/joypad.cpp
index ae8e94f8..3fd4d23e 100755
--- a/snes/cpu/timing/joypad.cpp
+++ b/snes/cpu/timing/joypad.cpp
@@ -41,6 +41,7 @@ void CPU::step_auto_joypad_poll_NEW(bool polarity) {
} else {
if(status.auto_joypad_counter == 1) {
status.auto_joypad_active = true;
+ interface->notifyLatched();
input.port1->latch(1);
input.port2->latch(1);
}
--
2.15.0.rc1

View file

@ -1,288 +0,0 @@
From 5bc96b8aeea26729ef4399c2d8d5e562894616e1 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Tue, 20 Jan 2015 10:04:58 +0200
Subject: [PATCH 22/27] Support DMA tracing
---
snes/alt/ppu-compatibility/mmio/mmio.cpp | 18 +++++++
snes/alt/ppu-compatibility/ppu.cpp | 1 +
snes/alt/ppu-compatibility/ppu.hpp | 4 ++
snes/cpu/cpu.cpp | 1 +
snes/cpu/cpu.hpp | 1 +
snes/cpu/dma/dma.cpp | 84 ++++++++++++++++++++++++++++++++
snes/cpu/dma/dma.hpp | 5 ++
snes/ppu/mmio/mmio.cpp | 18 +++++++
snes/ppu/ppu.cpp | 1 +
snes/ppu/ppu.hpp | 3 ++
snes/snes.hpp | 1 +
11 files changed, 137 insertions(+)
diff --git a/snes/alt/ppu-compatibility/mmio/mmio.cpp b/snes/alt/ppu-compatibility/mmio/mmio.cpp
index aedb67c1..0a269cc0 100755
--- a/snes/alt/ppu-compatibility/mmio/mmio.cpp
+++ b/snes/alt/ppu-compatibility/mmio/mmio.cpp
@@ -1,5 +1,23 @@
#ifdef PPU_CPP
+size_t PPU::get_dma_oam_subaddr(char* buf)
+{
+ return sprintf(buf, "[%03x]", regs.oam_addr);
+}
+
+size_t PPU::get_dma_cgram_subaddr(char* buf)
+{
+ return sprintf(buf, "[%02x%c]", regs.cgram_addr >> 1, (regs.cgram_addr & 1) ?
+ 'H' : 'L');
+}
+
+size_t PPU::get_dma_vram_subaddr(char* buf)
+{
+ return sprintf(buf, "[%04x map%d inc %d on %s]", regs.vram_addr << 1,
+ regs.vram_mapping, 2 * regs.vram_incsize, regs.vram_incmode ? "high" :
+ "low");
+}
+
//INIDISP
void PPU::mmio_w2100(uint8 value) {
if(regs.display_disabled == true && cpu.vcounter() == (!overscan() ? 225 : 240)) {
diff --git a/snes/alt/ppu-compatibility/ppu.cpp b/snes/alt/ppu-compatibility/ppu.cpp
index 122b1430..ac886edc 100755
--- a/snes/alt/ppu-compatibility/ppu.cpp
+++ b/snes/alt/ppu-compatibility/ppu.cpp
@@ -1,4 +1,5 @@
#include <snes/snes.hpp>
+#include <cstdio>
#define PPU_CPP
namespace SNES {
diff --git a/snes/alt/ppu-compatibility/ppu.hpp b/snes/alt/ppu-compatibility/ppu.hpp
index 4adac4c4..b0eabf7c 100755
--- a/snes/alt/ppu-compatibility/ppu.hpp
+++ b/snes/alt/ppu-compatibility/ppu.hpp
@@ -14,6 +14,10 @@ public:
alwaysinline void step(unsigned clocks);
alwaysinline void synchronize_cpu();
+ size_t get_dma_oam_subaddr(char* buf);
+ size_t get_dma_cgram_subaddr(char* buf);
+ size_t get_dma_vram_subaddr(char* buf);
+
#include "memory/memory.hpp"
#include "mmio/mmio.hpp"
#include "render/render.hpp"
diff --git a/snes/cpu/cpu.cpp b/snes/cpu/cpu.cpp
index 39da6b16..ce112afa 100755
--- a/snes/cpu/cpu.cpp
+++ b/snes/cpu/cpu.cpp
@@ -1,4 +1,5 @@
#include <snes/snes.hpp>
+#include <cstdio>
#define CPU_CPP
namespace SNES {
diff --git a/snes/cpu/cpu.hpp b/snes/cpu/cpu.hpp
index 49445773..fd665b1f 100755
--- a/snes/cpu/cpu.hpp
+++ b/snes/cpu/cpu.hpp
@@ -26,6 +26,7 @@ struct CPU : public Processor, public CPUcore, public PPUcounter {
~CPU();
bool controller_flag;
+ function<void(const char*)> dma_trace_fn;
private:
#include "dma/dma.hpp"
#include "memory/memory.hpp"
diff --git a/snes/cpu/dma/dma.cpp b/snes/cpu/dma/dma.cpp
index 0a00bfea..8f7be263 100755
--- a/snes/cpu/dma/dma.cpp
+++ b/snes/cpu/dma/dma.cpp
@@ -144,6 +144,7 @@ void CPU::dma_run() {
for(unsigned i = 0; i < 8; i++) {
if(channel[i].dma_enabled == false) continue;
+ dma_trace_start(i);
unsigned index = 0;
do {
@@ -155,6 +156,7 @@ void CPU::dma_run() {
dma_write(false);
dma_edge();
+ dma_trace_end(i);
channel[i].dma_enabled = false;
}
@@ -202,6 +204,7 @@ void CPU::hdma_run() {
channel[i].dma_enabled = false; //HDMA run during DMA will stop DMA mid-transfer
if(channel[i].hdma_do_transfer) {
+ dma_trace_hdma(i);
static const unsigned transfer_length[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
unsigned length = transfer_length[channel[i].transfer_mode];
for(unsigned index = 0; index < length; index++) {
@@ -286,4 +289,85 @@ void CPU::dma_reset() {
pipe.data = 0;
}
+size_t CPU::dma_trace_subaddr(char* buf, uint8 b_addr)
+{
+ if(b_addr == 0x04 || b_addr == 0x38) {
+ return ppu.get_dma_oam_subaddr(buf);
+ }
+ if(b_addr == 0x22 || b_addr == 0x3B) {
+ return ppu.get_dma_cgram_subaddr(buf);
+ }
+ if(b_addr == 0x18 || b_addr == 0x19 || b_addr == 0x39 || b_addr == 0x3A) {
+ return ppu.get_dma_vram_subaddr(buf);
+ }
+ if(b_addr == 0x80) {
+ return sprintf(buf, "[%06x]", 0x7e0000 | status.wram_addr);
+ }
+ return 0;
+}
+
+void CPU::dma_trace_start(unsigned i)
+{
+ if(!dma_trace_fn) return;
+ char buf[512];
+ size_t ptr = 0;
+ unsigned bytes = channel[i].transfer_size;
+ if(!bytes) bytes = 0x10000;
+ ptr += sprintf(buf + ptr, "-- DMA%i %d(%x) bytes ", i, bytes, bytes);
+ if(channel[i].direction) {
+ //B->A
+ ptr += sprintf(buf + ptr, "%02x", channel[i].dest_addr);
+ ptr += dma_trace_subaddr(buf + ptr, channel[i].dest_addr);
+ ptr += sprintf(buf + ptr, "-> %02x%04x", channel[i].source_bank,
+ channel[i].source_addr);
+ } else {
+ //A->B
+ ptr += sprintf(buf + ptr, "%02x%04x -> %02x", channel[i].source_bank,
+ channel[i].source_addr, channel[i].dest_addr);
+ ptr += dma_trace_subaddr(buf + ptr, channel[i].dest_addr);
+ }
+ if(channel[i].fixed_transfer)
+ ptr += sprintf(buf + ptr, " fixed");
+ else if(channel[i].reverse_transfer)
+ ptr += sprintf(buf + ptr, " decrement");
+ else
+ ptr += sprintf(buf + ptr, " incrment");
+ ptr += sprintf(buf + ptr, " mode%d --", channel[i].transfer_mode);
+ dma_trace_fn(buf);
+}
+
+void CPU::dma_trace_end(unsigned i)
+{
+ if(!dma_trace_fn) return;
+ if(!channel[i].transfer_size) return; //No message for complete DMA.
+ char buf[512];
+ size_t ptr = 0;
+ sprintf(buf, "-- DMA%i aborted with %d(0x%x) bytes remaining --", i,
+ (int)channel[i].transfer_size, (unsigned)channel[i].transfer_size);
+ dma_trace_fn(buf);
+}
+
+void CPU::dma_trace_hdma(unsigned i)
+{
+ if(!dma_trace_fn) return;
+ char buf[512];
+ size_t ptr = 0;
+ unsigned addr = channel[i].indirect ?
+ (channel[i].indirect_bank << 16) | (channel[i].indirect_addr) :
+ (channel[i].source_bank << 16) | (channel[i].hdma_addr);
+ ptr += sprintf(buf + ptr, "-- HDMA%i %06x -> %02x", i, addr,
+ channel[i].dest_addr);
+ ptr += dma_trace_subaddr(buf + ptr, channel[i].dest_addr);
+ if(channel[i].indirect)
+ ptr += sprintf(buf + ptr, " indirect");
+ if(channel[i].fixed_transfer)
+ ptr += sprintf(buf + ptr, " fixed");
+ else if(channel[i].reverse_transfer)
+ ptr += sprintf(buf + ptr, " decrement");
+ else
+ ptr += sprintf(buf + ptr, " incrment");
+ ptr += sprintf(buf + ptr, " mode%d --", channel[i].transfer_mode);
+ dma_trace_fn(buf);
+}
+
#endif
diff --git a/snes/cpu/dma/dma.hpp b/snes/cpu/dma/dma.hpp
index 33755bde..8740bb3a 100755
--- a/snes/cpu/dma/dma.hpp
+++ b/snes/cpu/dma/dma.hpp
@@ -77,3 +77,8 @@ void hdma_init();
void dma_power();
void dma_reset();
+
+size_t dma_trace_subaddr(char* buf, uint8 b_addr);
+void dma_trace_start(unsigned i);
+void dma_trace_end(unsigned i);
+void dma_trace_hdma(unsigned i);
diff --git a/snes/ppu/mmio/mmio.cpp b/snes/ppu/mmio/mmio.cpp
index 302f74f8..4a4fb9ce 100755
--- a/snes/ppu/mmio/mmio.cpp
+++ b/snes/ppu/mmio/mmio.cpp
@@ -1,5 +1,23 @@
#ifdef PPU_CPP
+size_t PPU::get_dma_oam_subaddr(char* buf)
+{
+ return sprintf(buf, "[%03x]", regs.oam_addr);
+}
+
+size_t PPU::get_dma_cgram_subaddr(char* buf)
+{
+ return sprintf(buf, "[%02x%c]", regs.cgram_addr >> 1, (regs.cgram_addr & 1) ?
+ 'H' : 'L');
+}
+
+size_t PPU::get_dma_vram_subaddr(char* buf)
+{
+ return sprintf(buf, "[%04x map%d inc %d on %s]", regs.vram_addr << 1,
+ regs.vram_mapping, 2 * regs.vram_incsize, regs.vram_incmode ? "high" :
+ "low");
+}
+
bool PPU::interlace() const {
return display.interlace;
}
diff --git a/snes/ppu/ppu.cpp b/snes/ppu/ppu.cpp
index 13e231cf..58742098 100755
--- a/snes/ppu/ppu.cpp
+++ b/snes/ppu/ppu.cpp
@@ -1,4 +1,5 @@
#include <snes/snes.hpp>
+#include <cstdio>
#define PPU_CPP
namespace SNES {
diff --git a/snes/ppu/ppu.hpp b/snes/ppu/ppu.hpp
index fdba113c..0addb775 100755
--- a/snes/ppu/ppu.hpp
+++ b/snes/ppu/ppu.hpp
@@ -21,6 +21,9 @@ struct PPU : public Processor, public PPUcounter {
PPU();
~PPU();
+ size_t get_dma_oam_subaddr(char* buf);
+ size_t get_dma_cgram_subaddr(char* buf);
+ size_t get_dma_vram_subaddr(char* buf);
private:
uint32 *surface;
uint32 *output;
diff --git a/snes/snes.hpp b/snes/snes.hpp
index 3bdca7e5..7c48ebb3 100755
--- a/snes/snes.hpp
+++ b/snes/snes.hpp
@@ -4,6 +4,7 @@
#define BSNES_SUPPORTS_ADV_BREAKPOINTS_PPU
#define BSNES_SUPPORTS_ALT_TIMINGS
#define BSNES_SUPPORTS_TRACE_SA1
+#define BSNES_SUPPORTS_DMA_TRACE
namespace SNES {
namespace Info {
--
2.15.0.rc1

View file

@ -1,86 +0,0 @@
From 9682df9e33c366dfe047a99c8bcefc2c8ab29620 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sat, 24 Jan 2015 16:46:18 +0200
Subject: [PATCH 23/27] Add autopoller and IRQ/NMI tracing
---
snes/cpu/cpu.cpp | 3 +++
snes/cpu/timing/joypad.cpp | 16 ++++++++++++++--
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/snes/cpu/cpu.cpp b/snes/cpu/cpu.cpp
index ce112afa..e11fc882 100755
--- a/snes/cpu/cpu.cpp
+++ b/snes/cpu/cpu.cpp
@@ -69,14 +69,17 @@ void CPU::enter() {
if(status.interrupt_pending) {
status.interrupt_pending = false;
if(status.nmi_pending) {
+ if(dma_trace_fn) dma_trace_fn("-- NMI occured --");
status.nmi_pending = false;
regs.vector = (regs.e == false ? 0xffea : 0xfffa);
op_irq();
} else if(status.irq_pending) {
+ if(dma_trace_fn) dma_trace_fn("-- IRQ occured --");
status.irq_pending = false;
regs.vector = (regs.e == false ? 0xffee : 0xfffe);
op_irq();
} else if(status.reset_pending) {
+ if(dma_trace_fn) dma_trace_fn("-- RESET occured --");
status.reset_pending = false;
add_clocks(186);
regs.pc.l = bus.read(0xfffc, false);
diff --git a/snes/cpu/timing/joypad.cpp b/snes/cpu/timing/joypad.cpp
index 3fd4d23e..afca7504 100755
--- a/snes/cpu/timing/joypad.cpp
+++ b/snes/cpu/timing/joypad.cpp
@@ -6,9 +6,9 @@ void CPU::step_auto_joypad_poll() {
//cache enable state at first iteration
if(status.auto_joypad_counter == 0) status.auto_joypad_latch = status.auto_joypad_poll;
status.auto_joypad_active = status.auto_joypad_counter <= 15;
-
if(status.auto_joypad_active && status.auto_joypad_latch) {
if(status.auto_joypad_counter == 0) {
+ if(dma_trace_fn) dma_trace_fn("-- Start automatic polling --");
interface->notifyLatched();
input.port1->latch(1);
input.port2->latch(1);
@@ -23,6 +23,12 @@ void CPU::step_auto_joypad_poll() {
status.joy2 = (status.joy2 << 1) | (bool)(port1 & 1);
status.joy3 = (status.joy3 << 1) | (bool)(port0 & 2);
status.joy4 = (status.joy4 << 1) | (bool)(port1 & 2);
+ if(status.auto_joypad_counter == 15) {
+ char buf[512];
+ sprintf(buf, "-- End automatic polling [%04x %04x %04x %04x] --",
+ status.joy1, status.joy2, status.joy3, status.joy4);
+ if(dma_trace_fn) dma_trace_fn(buf);
+ }
}
status.auto_joypad_counter++;
@@ -40,6 +46,7 @@ void CPU::step_auto_joypad_poll_NEW(bool polarity) {
status.auto_joypad_active = false;
} else {
if(status.auto_joypad_counter == 1) {
+ if(dma_trace_fn) dma_trace_fn("-- Start automatic polling --");
status.auto_joypad_active = true;
interface->notifyLatched();
input.port1->latch(1);
@@ -58,8 +65,13 @@ void CPU::step_auto_joypad_poll_NEW(bool polarity) {
status.joy3 = (status.joy3 << 1) | (bool)(port0 & 2);
status.joy4 = (status.joy4 << 1) | (bool)(port1 & 2);
}
- if(status.auto_joypad_counter == 34)
+ if(status.auto_joypad_counter == 34) {
status.auto_joypad_active = false;
+ char buf[512];
+ sprintf(buf, "-- End automatic polling [%04x %04x %04x %04x] --",
+ status.joy1, status.joy2, status.joy3, status.joy4);
+ if(dma_trace_fn) dma_trace_fn(buf);
+ }
}
status.auto_joypad_counter++;
}
--
2.15.0.rc1

View file

@ -1,50 +0,0 @@
From f2bbef8a4e12e05190a68dfe410cff3e4b1eb13f Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sat, 8 Aug 2015 11:09:41 +0300
Subject: [PATCH 24/27] Build fixes for GCC 5.X
---
nall/bit.hpp | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
diff --git a/nall/bit.hpp b/nall/bit.hpp
index 67a35ad6..11d9d8de 100755
--- a/nall/bit.hpp
+++ b/nall/bit.hpp
@@ -8,18 +8,27 @@ namespace nall {
}
template<int bits> constexpr inline unsigned uclip(const unsigned x) {
- enum { m = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1) };
- return (x & m);
+ return x & ((1U << (bits - 1)) + ((1U << (bits - 1)) - 1));
+ }
+
+ template<int bits> constexpr inline signed sclamp_b() {
+ return 1U << (bits - 1);
+ }
+
+ template<int bits> constexpr inline signed sclamp_m() {
+ return (1U << (bits - 1)) - 1;
}
template<int bits> constexpr inline signed sclamp(const signed x) {
- enum { b = 1U << (bits - 1), m = (1U << (bits - 1)) - 1 };
- return (x > m) ? m : (x < -b) ? -b : x;
+ return (x > sclamp_m<bits>()) ? sclamp_m<bits>() : (x < -sclamp_b<bits>()) ? -sclamp_b<bits>() : x;
+ }
+
+ template<int bits> constexpr inline signed sclip_m() {
+ return (1U << (bits)) - 1;
}
template<int bits> constexpr inline signed sclip(const signed x) {
- enum { b = 1U << (bits - 1), m = (1U << bits) - 1 };
- return ((x & m) ^ b) - b;
+ return ((x & sclip_m<bits>()) ^ sclamp_b<bits>()) - sclamp_b<bits>();
}
namespace bit {
--
2.15.0.rc1

View file

@ -1,26 +0,0 @@
From d39571de650d49636778a73c66414aff372c08af Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Mon, 7 Sep 2015 20:48:14 +0300
Subject: [PATCH 25/27] Fix MSU-1 bug where write to MSU1BASE+4 is mirred to
MSUBASE+5
---
snes/chip/msu1/msu1.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/snes/chip/msu1/msu1.cpp b/snes/chip/msu1/msu1.cpp
index 71700e60..ec1cf46a 100755
--- a/snes/chip/msu1/msu1.cpp
+++ b/snes/chip/msu1/msu1.cpp
@@ -107,7 +107,7 @@ void MSU1::mmio_write(unsigned addr, uint8 data) {
if(datafile.open()) datafile.seek(mmio.data_offset);
mmio.data_busy = false;
break;
- case 4: mmio.audio_track = (mmio.audio_track & 0xff00) | (data << 0);
+ case 4: mmio.audio_track = (mmio.audio_track & 0xff00) | (data << 0); break;
case 5: mmio.audio_track = (mmio.audio_track & 0x00ff) | (data << 8);
if(audiofile.open()) audiofile.close();
if(audiofile.open(interface->path(Cartridge::Slot::Base, { "-", (unsigned)mmio.audio_track, ".pcm" }), file::mode::read)) {
--
2.15.0.rc1

View file

@ -1,25 +0,0 @@
From c0a2270cfd5f56e8a311b36011e1f15fac6c54ca Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilariliusvaara@welho.com>
Date: Tue, 9 Aug 2016 18:54:57 +0300
Subject: [PATCH 26/27] Add <vector> to avoid compile error due to missing
std::vector
---
snes/snes.hpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/snes/snes.hpp b/snes/snes.hpp
index 7c48ebb3..3a65e360 100755
--- a/snes/snes.hpp
+++ b/snes/snes.hpp
@@ -22,6 +22,7 @@ namespace SNES {
#include <libco/libco.h>
+#include <vector>
#include <nall/platform.hpp>
#include <nall/algorithm.hpp>
#include <nall/any.hpp>
--
2.15.0.rc1

View file

@ -1,377 +0,0 @@
From 4cfbbeadc3abe3e3911f7f59ce57b715edc76563 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilariliusvaara@welho.com>
Date: Wed, 25 Oct 2017 14:18:34 +0300
Subject: [PATCH 27/27] Bus fixes: Do not update MDR on read from CPU MMIO
space
Also, updates the controller read timings to be more accurate.
---
snes/config/config.cpp | 1 +
snes/config/config.hpp | 1 +
snes/cpu/cpu.cpp | 2 +
snes/cpu/memory/memory.cpp | 26 ++++++++-
snes/cpu/mmio/mmio.cpp | 14 +++--
snes/cpu/timing/joypad.cpp | 132 +++++++++++++++++++++++++++++++++++++++------
snes/cpu/timing/timing.cpp | 11 ++--
snes/cpu/timing/timing.hpp | 3 +-
snes/snes.hpp | 1 +
9 files changed, 166 insertions(+), 25 deletions(-)
diff --git a/snes/config/config.cpp b/snes/config/config.cpp
index 19831370..8dcfd7e8 100755
--- a/snes/config/config.cpp
+++ b/snes/config/config.cpp
@@ -15,6 +15,7 @@ Configuration::Configuration() {
cpu.pal_frequency = 21281370;
cpu.wram_init_value = 0x55;
cpu.alt_poll_timings = false;
+ cpu.bus_fixes = false;
smp.ntsc_frequency = 24607104; //32040.5 * 768
smp.pal_frequency = 24607104;
diff --git a/snes/config/config.hpp b/snes/config/config.hpp
index 68fe0bde..d8577e39 100755
--- a/snes/config/config.hpp
+++ b/snes/config/config.hpp
@@ -14,6 +14,7 @@ struct Configuration {
unsigned pal_frequency;
unsigned wram_init_value;
bool alt_poll_timings;
+ bool bus_fixes;
} cpu;
struct SMP {
diff --git a/snes/cpu/cpu.cpp b/snes/cpu/cpu.cpp
index e11fc882..5e8e3137 100755
--- a/snes/cpu/cpu.cpp
+++ b/snes/cpu/cpu.cpp
@@ -1,5 +1,7 @@
#include <snes/snes.hpp>
#include <cstdio>
+#include <iostream>
+#include <cassert>
#define CPU_CPP
namespace SNES {
diff --git a/snes/cpu/memory/memory.cpp b/snes/cpu/memory/memory.cpp
index 31f82c31..df439c22 100755
--- a/snes/cpu/memory/memory.cpp
+++ b/snes/cpu/memory/memory.cpp
@@ -14,10 +14,32 @@ uint8 CPU::op_read(uint32 addr, bool exec) {
status.clock_count = speed(addr);
dma_edge();
add_clocks(status.clock_count - 4);
- regs.mdr = bus.read(addr, exec);
+ //MDR presents the state held by parasitic capacitance of the external bus.
+ //This bus is not affected by reads from CPU-internal registers, only if
+ //some external device responds. SDD1 does hook some of these addresses, but
+ //passes read straight through, as expected (as the CPU probably won't
+ //monitor if external device responds, even if it broadcasts a read).
+ //
+ //We use 4000-43FF as CPU register range, and not 4000-437F it likely is
+ //for quickness of checking. This will only affect things if some device
+ //tries to map the 4380-43FF range (that device will still work correctly,
+ //but openbus in that range won't).
+ //
+ //This was discovered while investigating why one Super Metroid glitch
+ //worked on emulator but crashed on real console.
+ //
+ //a word fetch from 2f4017 AND 0xfffc results in 2f3c and a word fetch from
+ //2f4210 AND 0x7f7f results in 2f22. This also extends to long fetches
+ //by arguments. E.g. long argument fetch from 94420F with 2F already on
+ //the bus AND 0x7f7fff results in 2f222f.
+ //
+ //The reason for masking some bits in above explanation was to ignore some
+ //known bits in those registers (bits 7 of 4210 and 4211, bits 0&1 of 4017).
+ uint8_t tmp = bus.read(addr, exec);
+ if(!config.cpu.bus_fixes || (addr & 0x40FC00) != 0x004000) regs.mdr = tmp;
add_clocks(4);
alu_edge();
- return regs.mdr;
+ return tmp;
}
void CPU::op_write(uint32 addr, uint8 data) {
diff --git a/snes/cpu/mmio/mmio.cpp b/snes/cpu/mmio/mmio.cpp
index 30048c19..be2990a3 100755
--- a/snes/cpu/mmio/mmio.cpp
+++ b/snes/cpu/mmio/mmio.cpp
@@ -33,9 +33,17 @@ void CPU::mmio_w2183(uint8 data) {
//strobing $4016.d0 affects both controller port latches.
//$4017 bit 0 writes are ignored.
void CPU::mmio_w4016(uint8 data) {
- if(data&1) interface->notifyLatched();
- input.port1->latch(data & 1);
- input.port2->latch(data & 1);
+ //Only consider autoassert if both busfix and auto flags are set.
+ auto auto_asserted = (status.auto_joypad_counter & 384) == 384;
+ //Bit 6 of status.auto_joypad_counter follows "manual" latch.
+ auto oldstatus = auto_asserted || (status.auto_joypad_counter & 64) != 0;
+ status.auto_joypad_counter &= ~64;
+ status.auto_joypad_counter |= (data & 1) << 6;
+ auto newstatus = auto_asserted || (status.auto_joypad_counter & 64) != 0;
+ //If !oldstatus and newstatus, signal latch.
+ if(!oldstatus && newstatus) interface->notifyLatched();
+ input.port1->latch(newstatus);
+ input.port2->latch(newstatus);
}
//JOYSER0
diff --git a/snes/cpu/timing/joypad.cpp b/snes/cpu/timing/joypad.cpp
index afca7504..b60be020 100755
--- a/snes/cpu/timing/joypad.cpp
+++ b/snes/cpu/timing/joypad.cpp
@@ -3,11 +3,14 @@
//called every 256 clocks; see CPU::add_clocks()
void CPU::step_auto_joypad_poll() {
if(vcounter() >= (ppu.overscan() == false ? 225 : 240)) {
+ auto cycle = status.auto_joypad_counter & 63;
//cache enable state at first iteration
- if(status.auto_joypad_counter == 0) status.auto_joypad_latch = status.auto_joypad_poll;
- status.auto_joypad_active = status.auto_joypad_counter <= 15;
+ if(cycle == 0) status.auto_joypad_latch = status.auto_joypad_poll;
+ status.auto_joypad_active = cycle <= 15;
if(status.auto_joypad_active && status.auto_joypad_latch) {
- if(status.auto_joypad_counter == 0) {
+ if(cycle == 0) {
+ if(status.auto_joypad_counter & 128)
+ std::cerr << "step_auto_joypad_poll(): bus fixes set (counter=" << status.auto_joypad_counter << ")???" << std::endl;
if(dma_trace_fn) dma_trace_fn("-- Start automatic polling --");
interface->notifyLatched();
input.port1->latch(1);
@@ -23,7 +26,7 @@ void CPU::step_auto_joypad_poll() {
status.joy2 = (status.joy2 << 1) | (bool)(port1 & 1);
status.joy3 = (status.joy3 << 1) | (bool)(port0 & 2);
status.joy4 = (status.joy4 << 1) | (bool)(port1 & 2);
- if(status.auto_joypad_counter == 15) {
+ if(cycle == 15) {
char buf[512];
sprintf(buf, "-- End automatic polling [%04x %04x %04x %04x] --",
status.joy1, status.joy2, status.joy3, status.joy4);
@@ -31,32 +34,129 @@ void CPU::step_auto_joypad_poll() {
}
}
- status.auto_joypad_counter++;
+ //Only bits 0-5 are supposed to increment.
+ if(cycle < 60)
+ status.auto_joypad_counter++;
}
}
//called every 128 clocks; see CPU::add_clocks()
-void CPU::step_auto_joypad_poll_NEW(bool polarity) {
- if(status.auto_joypad_counter > 0 && status.auto_joypad_counter <= 34) {
+void CPU::step_auto_joypad_poll_NEW2(bool polarity) {
+ //Poll starts on multiple of 128 mod 256 clocks (polarity=false) on first
+ //vblank scanline. If autopoller is off, mark as done for the frame.
+ if(vcounter() >= (ppu.overscan() == false ? 225 : 240) && !polarity &&
+ (status.auto_joypad_counter & 63) == 0) {
+ if(!(status.auto_joypad_counter & 128))
+ std::cerr << "step_auto_joypad_poll_NEW2(): bus fixes clear???" << std::endl;
+ //Preserve high bits of autopoll counter.
+ auto x = status.auto_joypad_counter & ~63;
+ status.auto_joypad_counter = x | (status.auto_joypad_poll ? 1 : 36);
+ status.auto_joypad_latch = status.auto_joypad_poll;
+ }
+ //Abuse bit 6 of counter for "manual" poll flag. Bit 7 is supposed to be
+ //always set.
+ auto cycle = status.auto_joypad_counter & 63;
+ auto old_latchstate = (status.auto_joypad_counter & 320) != 0;
+ //If not enabled... This is not latched, as autopoll can be aborted.
+ if(!status.auto_joypad_poll && cycle > 0 && cycle < 36) {
+ if(dma_trace_fn) dma_trace_fn("-- Automatic polling ABORTED --");
+ status.auto_joypad_counter += (36 - cycle);
+ status.auto_joypad_active = false;
+ status.auto_joypad_latch = false;
+ //Release autopoll latch.
+ status.auto_joypad_counter &= ~256; //Autopoll clears latch.
+ auto new_latchstate = (status.auto_joypad_counter & 320) != 0;
+ if(old_latchstate && !new_latchstate) {
+ input.port1->latch(0);
+ input.port2->latch(0);
+ }
+ return;
+ }
+ //On cycle #1, latch is asserted (unless latch is already high, in this
+ //case the autopoller is supposed to force latch high too).
+ if(cycle == 1) {
+ if(dma_trace_fn) dma_trace_fn("-- Start automatic polling --");
+ //Assert autopoll latch.
+ status.auto_joypad_counter |= 256;
+ auto new_latchstate = (status.auto_joypad_counter & 320) != 0;
+ if(!old_latchstate && new_latchstate) {
+ interface->notifyLatched();
+ input.port1->latch(1);
+ input.port2->latch(1);
+ }
+ }
+ //On cycle #2, busy is asserted and controllers are cleared.
+ if(cycle == 2) {
+ status.joy1 = 0;
+ status.joy2 = 0;
+ status.joy3 = 0;
+ status.joy4 = 0;
+ status.auto_joypad_active = true;
+ }
+ //Then, on cycle #3, latch is deasserted, unless "manual" latch forces
+ //real latch high.
+ if(cycle == 3) {
+ //Release autopoll latch.
+ status.auto_joypad_counter &= ~256;
+ auto new_latchstate = (status.auto_joypad_counter & 320) != 0;
+ if(old_latchstate && !new_latchstate) {
+ input.port1->latch(0);
+ input.port2->latch(0);
+ }
+ }
+ //Then on cycles #4, #6, #8, ..., #34, a bit is shifted. Also, clock would
+ //go low, but we can not emulate that.
+ if(cycle >= 4 && cycle <= 34 && cycle % 2 == 0) {
+ uint2 port0 = input.port1->data();
+ uint2 port1 = input.port2->data();
+ status.joy1 = (status.joy1 << 1) | (bool)(port0 & 1);
+ status.joy2 = (status.joy2 << 1) | (bool)(port1 & 1);
+ status.joy3 = (status.joy3 << 1) | (bool)(port0 & 2);
+ status.joy4 = (status.joy4 << 1) | (bool)(port1 & 2);
+ }
+ //Then on cycles #5, #7, #9, ..., #35, clock drops high, But we can not
+ //emulate that.
+ //Then on cycle #35, busy flag is deasserted and poll is complete.
+ if(cycle == 35) {
+ status.auto_joypad_active = false;
+ char buf[512];
+ sprintf(buf, "-- End automatic polling [%04x %04x %04x %04x] --",
+ status.joy1, status.joy2, status.joy3, status.joy4);
+ if(dma_trace_fn) dma_trace_fn(buf);
+ }
+ //The entiere train is 35 cycles.
+ if(cycle > 0 && cycle < 36) {
+ status.auto_joypad_counter++;
+ }
+}
+
+
+//called every 128 clocks; see CPU::add_clocks()
+void CPU::step_auto_joypad_poll_NEW(bool polarity, bool new2) {
+ if(new2) return step_auto_joypad_poll_NEW2(polarity);
+ auto cycle = status.auto_joypad_counter & 63;
+ if(cycle > 0 && cycle <= 34) {
if(!status.auto_joypad_latch) {
//FIXME: Is this right, busy flag goes on even if not enabled???
- if(status.auto_joypad_counter == 1)
+ if(cycle == 1)
status.auto_joypad_active = true;
- if(status.auto_joypad_counter == 34)
+ if(cycle == 34)
status.auto_joypad_active = false;
} else {
- if(status.auto_joypad_counter == 1) {
+ if(cycle == 1) {
+ if(status.auto_joypad_counter & 128)
+ std::cerr << "step_auto_joypad_poll_NEW(): bus fixes set???" << std::endl;
if(dma_trace_fn) dma_trace_fn("-- Start automatic polling --");
status.auto_joypad_active = true;
interface->notifyLatched();
input.port1->latch(1);
input.port2->latch(1);
}
- if(status.auto_joypad_counter == 3) {
+ if(cycle == 3) {
input.port1->latch(0);
input.port2->latch(0);
}
- if((status.auto_joypad_counter & 1) != 0 && status.auto_joypad_counter != 1) {
+ if((cycle & 1) != 0 && cycle != 1) {
uint2 port0 = input.port1->data();
uint2 port1 = input.port2->data();
@@ -65,7 +165,7 @@ void CPU::step_auto_joypad_poll_NEW(bool polarity) {
status.joy3 = (status.joy3 << 1) | (bool)(port0 & 2);
status.joy4 = (status.joy4 << 1) | (bool)(port1 & 2);
}
- if(status.auto_joypad_counter == 34) {
+ if(cycle == 34) {
status.auto_joypad_active = false;
char buf[512];
sprintf(buf, "-- End automatic polling [%04x %04x %04x %04x] --",
@@ -75,9 +175,11 @@ void CPU::step_auto_joypad_poll_NEW(bool polarity) {
}
status.auto_joypad_counter++;
}
- if(vcounter() >= (ppu.overscan() == false ? 225 : 240) && status.auto_joypad_counter == 0 && !polarity) {
+ if(vcounter() >= (ppu.overscan() == false ? 225 : 240) && cycle == 0 && !polarity) {
+ //Preserve high bits of autopoller counter.
+ auto x = status.auto_joypad_counter & ~63;
status.auto_joypad_latch = status.auto_joypad_poll;
- status.auto_joypad_counter = 1;
+ status.auto_joypad_counter = x | 1;
}
}
diff --git a/snes/cpu/timing/timing.cpp b/snes/cpu/timing/timing.cpp
index d7cf24f3..ef81d891 100755
--- a/snes/cpu/timing/timing.cpp
+++ b/snes/cpu/timing/timing.cpp
@@ -17,12 +17,12 @@ void CPU::add_clocks(unsigned clocks) {
step(clocks);
- if(config.cpu.alt_poll_timings) {
+ if(config.cpu.alt_poll_timings || config.cpu.bus_fixes) {
bool opolarity = (status.auto_joypad_clock & 128);
status.auto_joypad_clock = (status.auto_joypad_clock + clocks) & 0xFF;
bool npolarity = (status.auto_joypad_clock & 128);
if(opolarity != npolarity)
- step_auto_joypad_poll_NEW(opolarity);
+ step_auto_joypad_poll_NEW(opolarity, config.cpu.bus_fixes);
} else {
status.auto_joypad_clock += clocks;
if(status.auto_joypad_clock >= 256) {
@@ -53,7 +53,8 @@ void CPU::scanline() {
status.hdma_init_position = (cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter());
status.hdma_init_triggered = false;
- status.auto_joypad_counter = 0;
+ //Only clear the low 6 bits (counter).
+ status.auto_joypad_counter &= ~63;
}
//DRAM refresh occurs once every scanline
@@ -200,7 +201,9 @@ void CPU::timing_reset() {
status.auto_joypad_active = false;
status.auto_joypad_latch = false;
- status.auto_joypad_counter = 0;
+ //Set bit 7 of joypad counter if bus fixes are active (for combined
+ //latch behavior).
+ status.auto_joypad_counter = config.cpu.bus_fixes ? 128 : 0;
status.auto_joypad_clock = 0;
}
diff --git a/snes/cpu/timing/timing.hpp b/snes/cpu/timing/timing.hpp
index bf15a727..8be2b830 100755
--- a/snes/cpu/timing/timing.hpp
+++ b/snes/cpu/timing/timing.hpp
@@ -22,4 +22,5 @@ alwaysinline bool irq_test();
//joypad.cpp
void step_auto_joypad_poll();
-void step_auto_joypad_poll_NEW(bool polarity);
+void step_auto_joypad_poll_NEW(bool polarity, bool new2);
+void step_auto_joypad_poll_NEW2(bool polarity);
diff --git a/snes/snes.hpp b/snes/snes.hpp
index 3a65e360..961842b3 100755
--- a/snes/snes.hpp
+++ b/snes/snes.hpp
@@ -3,6 +3,7 @@
#define BSNES_SUPPORTS_ADV_BREAKPOINTS
#define BSNES_SUPPORTS_ADV_BREAKPOINTS_PPU
#define BSNES_SUPPORTS_ALT_TIMINGS
+#define BSNES_SUPPORTS_BUS_FIXES
#define BSNES_SUPPORTS_TRACE_SA1
#define BSNES_SUPPORTS_DMA_TRACE
--
2.15.0.rc1

View file

@ -1,17 +1,17 @@
From 6c3da8eb6516d25e97b46d97fb0d3d24ca9ecfd0 Mon Sep 17 00:00:00 2001
From f66f4b9ecfcccb22b113acc6e5e92c93ed8890a9 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 9 Nov 2011 00:37:44 +0200
Subject: [PATCH 1/8] Don't use time() in emulating chips
Subject: [PATCH 1/4] Don't use time() in emulating chips
Instead of using time() in chip emulation, create new interface method
currentTime(), defaulting to time(0). This way frontend can cleanly
override the current time bsnes is using.
---
snes/chip/bsx/satellaview/satellaview.cpp | 2 +-
snes/chip/spc7110/spc7110.cpp | 2 +-
snes/chip/srtc/srtc.cpp | 2 +-
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
snes/chip/bsx/satellaview/satellaview.cpp | 2 +-
snes/chip/spc7110/spc7110.cpp | 2 +-
snes/chip/srtc/srtc.cpp | 2 +-
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
5 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/snes/chip/bsx/satellaview/satellaview.cpp b/snes/chip/bsx/satellaview/satellaview.cpp
@ -80,5 +80,5 @@ index f1a48c0..df975e8 100755
extern Interface *interface;
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,26 +1,26 @@
From c87e7d9288a91db3b32b5ba4b2b74e52c0d3c11d Mon Sep 17 00:00:00 2001
From b02a77dd57546588a44b70bec3d6772e8ed5c11d Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 9 Nov 2011 01:52:08 +0200
Subject: [PATCH 2/8] Save controller state when savestating
Subject: [PATCH 2/4] Save controller state when savestating
When savestating, save the controller state and restore it upon loadstate.
Prevents libsnes from mixing up buttons.
---
snes/controller/controller.cpp | 8 +++++++
snes/controller/controller.hpp | 2 ++
snes/controller/gamepad/gamepad.cpp | 13 +++++++++++
snes/controller/gamepad/gamepad.hpp | 2 +-
snes/controller/justifier/justifier.cpp | 36 +++++++++++++++++++++++++++++++
snes/controller/justifier/justifier.hpp | 1 +
snes/controller/mouse/mouse.cpp | 13 +++++++++++
snes/controller/mouse/mouse.hpp | 2 +-
snes/controller/multitap/multitap.cpp | 16 ++++++++++++++
snes/controller/multitap/multitap.hpp | 2 +-
snes/controller/superscope/superscope.cpp | 31 ++++++++++++++++++++++++++
snes/controller/superscope/superscope.hpp | 1 +
snes/system/input.cpp | 16 ++++++++++++++
snes/system/input.hpp | 1 +
snes/system/serialization.cpp | 1 +
snes/controller/controller.cpp | 8 ++++++
snes/controller/controller.hpp | 2 +
snes/controller/gamepad/gamepad.cpp | 13 ++++++++++
snes/controller/gamepad/gamepad.hpp | 2 +-
snes/controller/justifier/justifier.cpp | 36 +++++++++++++++++++++++++++++
snes/controller/justifier/justifier.hpp | 1 +
snes/controller/mouse/mouse.cpp | 13 ++++++++++
snes/controller/mouse/mouse.hpp | 2 +-
snes/controller/multitap/multitap.cpp | 16 +++++++++++++
snes/controller/multitap/multitap.hpp | 2 +-
snes/controller/superscope/superscope.cpp | 31 +++++++++++++++++++++++++
snes/controller/superscope/superscope.hpp | 1 +
snes/system/input.cpp | 16 +++++++++++++
snes/system/input.hpp | 1 +
snes/system/serialization.cpp | 1 +
15 files changed, 142 insertions(+), 3 deletions(-)
diff --git a/snes/controller/controller.cpp b/snes/controller/controller.cpp
@ -342,5 +342,5 @@ index 9f5273d..005e731 100755
if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.serialize(s);
#if defined(GAMEBOY)
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,13 +1,13 @@
From a62794b0bfa1d2bfc8907a1e4d4e5aa6fe3ee426 Mon Sep 17 00:00:00 2001
From a47431385fedf705a3c9c1b820c116c230632943 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Fri, 11 Nov 2011 19:49:46 +0200
Subject: [PATCH 3/8] Allow frontend to control random number seed
Subject: [PATCH 3/4] Allow frontend to control random number seed
---
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
snes/system/system.cpp | 2 +-
3 files changed, 7 insertions(+), 1 deletion(-)
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
snes/system/system.cpp | 2 +-
3 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp
index b3017c9..0a21a13 100755
@ -49,5 +49,5 @@ index 284e389..99901ff 100755
region = config.region;
expansion = config.expansion_port;
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,63 +1,60 @@
From 33ecd422954b7e15d9e83b7035b07ffb52f4e1e8 Mon Sep 17 00:00:00 2001
From 395130ad02c50c329c0290b675086ff104839943 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 7 Mar 2012 16:57:18 +0200
Subject: [PATCH 4/8] Fix mouse polling
Subject: [PATCH 4/4] Fix mouse polling
Don't poll for mouse motion excessive number of times (no need to poll it for
each bit!)
---
snes/controller/mouse/mouse.cpp | 14 ++++++++++++--
snes/controller/mouse/mouse.hpp | 2 ++
2 files changed, 14 insertions(+), 2 deletions(-)
snes/controller/mouse/mouse.cpp | 12 ++++++++++--
snes/controller/mouse/mouse.hpp | 2 ++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp
index 6b26fae..1a066b9 100755
index 6b26fae..824ecd3 100755
--- a/snes/controller/mouse/mouse.cpp
+++ b/snes/controller/mouse/mouse.cpp
@@ -3,9 +3,13 @@
@@ -3,8 +3,10 @@
uint2 Mouse::data() {
if(counter >= 32) return 1;
- int position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
- int position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
+ if(counter == 0) {
+ _position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
+ _position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
+ position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
+ position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
+ }
+ int position_x = _position_x;
+ int position_y = _position_y;
bool direction_x = position_x < 0; //0 = right, 1 = left
bool direction_y = position_y < 0; //0 = down, 1 = up
@@ -67,10 +71,16 @@ void Mouse::serialize(serializer& s) {
@@ -67,10 +69,16 @@ void Mouse::serialize(serializer& s) {
unsigned char block[Controller::SaveSize] = {0};
block[0] = latched ? 1 : 0;
block[1] = counter;
+ block[2] = (unsigned short)_position_x >> 8;
+ block[3] = (unsigned short)_position_x;
+ block[4] = (unsigned short)_position_y >> 8;
+ block[5] = (unsigned short)_position_y;
+ block[2] = (unsigned short)position_x >> 8;
+ block[3] = (unsigned short)position_x;
+ block[4] = (unsigned short)position_y >> 8;
+ block[5] = (unsigned short)position_y;
s.array(block, Controller::SaveSize);
if(s.mode() == nall::serializer::Load) {
latched = (block[0] != 0);
counter = block[1];
+ _position_x = (short)(((unsigned short)block[2] << 8) | (unsigned short)block[3]);
+ _position_y = (short)(((unsigned short)block[4] << 8) | (unsigned short)block[5]);
+ position_x = (short)(((unsigned short)block[2] << 8) | (unsigned short)block[3]);
+ position_y = (short)(((unsigned short)block[4] << 8) | (unsigned short)block[5]);
}
}
diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp
index b66ea51..b07c8ab 100755
index b66ea51..6074f34 100755
--- a/snes/controller/mouse/mouse.hpp
+++ b/snes/controller/mouse/mouse.hpp
@@ -6,4 +6,6 @@ struct Mouse : Controller {
private:
bool latched;
unsigned counter;
+ int _position_x;
+ int _position_y;
+ int position_x;
+ int position_y;
};
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,12 +1,12 @@
From 52a1a595f4473b4de0cdedcb018aef68108a2c73 Mon Sep 17 00:00:00 2001
From 574754de0ed7da044d3c559bb2c8bbca895c1e97 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Mon, 24 Sep 2012 21:46:09 +0300
Subject: [PATCH 5/8] Add needed support for detecting true polls as opposed to
Subject: [PATCH] Add needed support for detecting true polls as opposed to
just autopolling
---
snes/cpu/cpu.hpp | 1 +
snes/cpu/mmio/mmio.cpp | 18 ++++++++++--------
snes/cpu/cpu.hpp | 1 +
snes/cpu/mmio/mmio.cpp | 18 ++++++++++--------
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/snes/cpu/cpu.hpp b/snes/cpu/cpu.hpp
@ -65,5 +65,5 @@ index 8b6aaa6..c5ee930 100755
//DMAPx
uint8 CPU::mmio_r43x0(uint8 i) {
--
1.8.4.4
1.7.10.4

View file

@ -1,11 +1,11 @@
From 74b67f36961839fcbc1caa23930151bd9b3e9d7e Mon Sep 17 00:00:00 2001
From 919c8935121c2ec7cb96ce561044981526c1ca7e Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sun, 14 Oct 2012 23:29:40 +0300
Subject: [PATCH 6/8] Fix compiling on GCC 4.7
Subject: [PATCH] Fix compiling on GCC 4.7
---
nall/string.hpp | 2 +-
ui-libsnes/libsnes.cpp | 1 +
nall/string.hpp | 2 +-
ui-libsnes/libsnes.cpp | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/nall/string.hpp b/nall/string.hpp
@ -34,5 +34,5 @@ index 3b2be7a..ca90762 100755
#include <nall/snes/cartridge.hpp>
#include <nall/gameboy/cartridge.hpp>
--
1.8.4.4
1.7.10.4

View file

@ -1,65 +0,0 @@
From 5dc532e67245f1e83504be4a21fef1ab15b08af2 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sun, 27 Oct 2013 10:52:45 +0200
Subject: [PATCH 7/8] Support notifying latches
---
snes/cpu/mmio/mmio.cpp | 1 +
snes/cpu/timing/joypad.cpp | 1 +
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
4 files changed, 8 insertions(+)
diff --git a/snes/cpu/mmio/mmio.cpp b/snes/cpu/mmio/mmio.cpp
index c5ee930..b7afff0 100755
--- a/snes/cpu/mmio/mmio.cpp
+++ b/snes/cpu/mmio/mmio.cpp
@@ -33,6 +33,7 @@ void CPU::mmio_w2183(uint8 data) {
//strobing $4016.d0 affects both controller port latches.
//$4017 bit 0 writes are ignored.
void CPU::mmio_w4016(uint8 data) {
+ if(data&1) interface->notifyLatched();
input.port1->latch(data & 1);
input.port2->latch(data & 1);
}
diff --git a/snes/cpu/timing/joypad.cpp b/snes/cpu/timing/joypad.cpp
index 179df27..6a98de0 100755
--- a/snes/cpu/timing/joypad.cpp
+++ b/snes/cpu/timing/joypad.cpp
@@ -9,6 +9,7 @@ void CPU::step_auto_joypad_poll() {
if(status.auto_joypad_active && status.auto_joypad_latch) {
if(status.auto_joypad_counter == 0) {
+ interface->notifyLatched();
input.port1->latch(1);
input.port2->latch(1);
input.port1->latch(0);
diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp
index 0a21a13..6685556 100755
--- a/snes/interface/interface.cpp
+++ b/snes/interface/interface.cpp
@@ -28,4 +28,9 @@ time_t Interface::randomSeed()
return time(0);
}
+void Interface::notifyLatched()
+{
+ //Nothing.
+}
+
}
diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp
index 30ee7fd..203f7b0 100755
--- a/snes/interface/interface.hpp
+++ b/snes/interface/interface.hpp
@@ -7,6 +7,7 @@ struct Interface {
virtual void message(const string &text);
virtual time_t currentTime();
virtual time_t randomSeed();
+ virtual void notifyLatched();
};
extern Interface *interface;
--
1.8.4.4

View file

@ -1,22 +0,0 @@
From ce0634fe5a8dea973ca9c357ec788740fbcfcf09 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sat, 30 Nov 2013 10:28:05 +0200
Subject: [PATCH 8/8] Support auto-detecting bsnes version
---
bsnes.mk | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 bsnes.mk
diff --git a/bsnes.mk b/bsnes.mk
new file mode 100644
index 0000000..2248b71
--- /dev/null
+++ b/bsnes.mk
@@ -0,0 +1,3 @@
+BSNES_SUPPORTS_DEBUGGER=
+LIBSNES_DIR=ui-libsnes
+BSNES_VERSION=086
--
1.8.4.4

View file

@ -1,17 +1,17 @@
From a8018b3c90314bd0c112842fe81b27e978b891eb Mon Sep 17 00:00:00 2001
From 22205d4d339cfa11f6d53e644eae1c859a56d349 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 9 Nov 2011 00:37:44 +0200
Subject: [PATCH 1/8] Don't use time() in emulating chips
Subject: [PATCH 1/4] Don't use time() in emulating chips
Instead of using time() in chip emulation, create new interface method
currentTime(), defaulting to time(0). This way frontend can cleanly
override the current time bsnes is using.
---
snes/chip/bsx/satellaview/satellaview.cpp | 2 +-
snes/chip/spc7110/spc7110.cpp | 2 +-
snes/chip/srtc/srtc.cpp | 2 +-
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
snes/chip/bsx/satellaview/satellaview.cpp | 2 +-
snes/chip/spc7110/spc7110.cpp | 2 +-
snes/chip/srtc/srtc.cpp | 2 +-
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
5 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/snes/chip/bsx/satellaview/satellaview.cpp b/snes/chip/bsx/satellaview/satellaview.cpp
@ -80,5 +80,5 @@ index f1a48c0..df975e8 100755
extern Interface *interface;
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,26 +1,26 @@
From de423d6ec33a20f33652c6b9c8ce703b867b51bd Mon Sep 17 00:00:00 2001
From fe11984ad18561506a7cc874cb7c0421f1e21ad1 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 9 Nov 2011 01:52:08 +0200
Subject: [PATCH 2/8] Save controller state when savestating
Subject: [PATCH 2/4] Save controller state when savestating
When savestating, save the controller state and restore it upon loadstate.
Prevents libsnes from mixing up buttons.
---
snes/controller/controller.cpp | 8 +++++++
snes/controller/controller.hpp | 2 ++
snes/controller/gamepad/gamepad.cpp | 13 +++++++++++
snes/controller/gamepad/gamepad.hpp | 2 +-
snes/controller/justifier/justifier.cpp | 36 +++++++++++++++++++++++++++++++
snes/controller/justifier/justifier.hpp | 1 +
snes/controller/mouse/mouse.cpp | 13 +++++++++++
snes/controller/mouse/mouse.hpp | 2 +-
snes/controller/multitap/multitap.cpp | 16 ++++++++++++++
snes/controller/multitap/multitap.hpp | 2 +-
snes/controller/superscope/superscope.cpp | 31 ++++++++++++++++++++++++++
snes/controller/superscope/superscope.hpp | 1 +
snes/system/input.cpp | 16 ++++++++++++++
snes/system/input.hpp | 1 +
snes/system/serialization.cpp | 1 +
snes/controller/controller.cpp | 8 ++++++
snes/controller/controller.hpp | 2 +
snes/controller/gamepad/gamepad.cpp | 13 ++++++++++
snes/controller/gamepad/gamepad.hpp | 2 +-
snes/controller/justifier/justifier.cpp | 36 +++++++++++++++++++++++++++++
snes/controller/justifier/justifier.hpp | 1 +
snes/controller/mouse/mouse.cpp | 13 ++++++++++
snes/controller/mouse/mouse.hpp | 2 +-
snes/controller/multitap/multitap.cpp | 16 +++++++++++++
snes/controller/multitap/multitap.hpp | 2 +-
snes/controller/superscope/superscope.cpp | 31 +++++++++++++++++++++++++
snes/controller/superscope/superscope.hpp | 1 +
snes/system/input.cpp | 16 +++++++++++++
snes/system/input.hpp | 1 +
snes/system/serialization.cpp | 1 +
15 files changed, 142 insertions(+), 3 deletions(-)
diff --git a/snes/controller/controller.cpp b/snes/controller/controller.cpp
@ -342,5 +342,5 @@ index f746c3a..67e08a2 100755
if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.serialize(s);
#if defined(GAMEBOY)
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,13 +1,13 @@
From e1fce124df0a1ea43324df65b9d0ee7262eda988 Mon Sep 17 00:00:00 2001
From 5f76449a70c9a546e18c2fdebe7588bbe90b56d2 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Fri, 11 Nov 2011 19:49:46 +0200
Subject: [PATCH 3/8] Allow frontend to control random number seed
Subject: [PATCH 3/4] Allow frontend to control random number seed
---
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
snes/system/system.cpp | 2 +-
3 files changed, 7 insertions(+), 1 deletion(-)
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
snes/system/system.cpp | 2 +-
3 files changed, 7 insertions(+), 1 deletions(-)
diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp
index b3017c9..0a21a13 100755
@ -49,5 +49,5 @@ index 9b70bbf..cbd096c 100755
region = config.region;
expansion = config.expansion_port;
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,63 +1,60 @@
From 21e21c3b953f499bb3e309ff6a04b38763e7910a Mon Sep 17 00:00:00 2001
From 160dedf35571478781737ee35307b9321cfb41bb Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 7 Mar 2012 16:57:18 +0200
Subject: [PATCH 4/8] Fix mouse polling
Subject: [PATCH 4/4] Fix mouse polling
Don't poll for mouse motion excessive number of times (no need to poll it for
each bit!)
---
snes/controller/mouse/mouse.cpp | 14 ++++++++++++--
snes/controller/mouse/mouse.hpp | 2 ++
2 files changed, 14 insertions(+), 2 deletions(-)
snes/controller/mouse/mouse.cpp | 12 ++++++++++--
snes/controller/mouse/mouse.hpp | 2 ++
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp
index 6b26fae..1a066b9 100755
index 6b26fae..824ecd3 100755
--- a/snes/controller/mouse/mouse.cpp
+++ b/snes/controller/mouse/mouse.cpp
@@ -3,9 +3,13 @@
@@ -3,8 +3,10 @@
uint2 Mouse::data() {
if(counter >= 32) return 1;
- int position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
- int position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
+ if(counter == 0) {
+ _position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
+ _position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
+ position_x = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::X); //-n = left, 0 = center, +n = right
+ position_y = interface->inputPoll(port, Input::Device::Mouse, 0, (unsigned)Input::MouseID::Y); //-n = up, 0 = center, +n = down
+ }
+ int position_x = _position_x;
+ int position_y = _position_y;
bool direction_x = position_x < 0; //0 = right, 1 = left
bool direction_y = position_y < 0; //0 = down, 1 = up
@@ -67,10 +71,16 @@ void Mouse::serialize(serializer& s) {
@@ -67,10 +69,16 @@ void Mouse::serialize(serializer& s) {
unsigned char block[Controller::SaveSize] = {0};
block[0] = latched ? 1 : 0;
block[1] = counter;
+ block[2] = (unsigned short)_position_x >> 8;
+ block[3] = (unsigned short)_position_x;
+ block[4] = (unsigned short)_position_y >> 8;
+ block[5] = (unsigned short)_position_y;
+ block[2] = (unsigned short)position_x >> 8;
+ block[3] = (unsigned short)position_x;
+ block[4] = (unsigned short)position_y >> 8;
+ block[5] = (unsigned short)position_y;
s.array(block, Controller::SaveSize);
if(s.mode() == nall::serializer::Load) {
latched = (block[0] != 0);
counter = block[1];
+ _position_x = (short)(((unsigned short)block[2] << 8) | (unsigned short)block[3]);
+ _position_y = (short)(((unsigned short)block[4] << 8) | (unsigned short)block[5]);
+ position_x = (short)(((unsigned short)block[2] << 8) | (unsigned short)block[3]);
+ position_y = (short)(((unsigned short)block[4] << 8) | (unsigned short)block[5]);
}
}
diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp
index b66ea51..b07c8ab 100755
index b66ea51..6074f34 100755
--- a/snes/controller/mouse/mouse.hpp
+++ b/snes/controller/mouse/mouse.hpp
@@ -6,4 +6,6 @@ struct Mouse : Controller {
private:
bool latched;
unsigned counter;
+ int _position_x;
+ int _position_y;
+ int position_x;
+ int position_y;
};
--
1.8.4.4
1.7.9.48.g85da4d

View file

@ -1,12 +1,12 @@
From 9b14075f51587694015f8507f1c7cb565fee8225 Mon Sep 17 00:00:00 2001
From f22d7a2b57d57959ac947465323870a8772d15ad Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Mon, 24 Sep 2012 21:46:09 +0300
Subject: [PATCH 5/8] Add needed support for detecting true polls as opposed to
Subject: [PATCH] Add needed support for detecting true polls as opposed to
just autopolling
---
snes/cpu/cpu.hpp | 1 +
snes/cpu/mmio/mmio.cpp | 18 ++++++++++--------
snes/cpu/cpu.hpp | 1 +
snes/cpu/mmio/mmio.cpp | 18 ++++++++++--------
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/snes/cpu/cpu.hpp b/snes/cpu/cpu.hpp
@ -65,5 +65,5 @@ index 8b6aaa6..c5ee930 100755
//DMAPx
uint8 CPU::mmio_r43x0(uint8 i) {
--
1.8.4.4
1.7.10.4

View file

@ -1,10 +1,10 @@
From 8c41bf9b792c08ecbf22a87d4e85f3e4801e62d2 Mon Sep 17 00:00:00 2001
From d4a3678c9cfbca544af8069b42b9eaa0205f8ea3 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sun, 14 Oct 2012 23:25:33 +0300
Subject: [PATCH 6/8] Add missing include to libsnes.cpp
Subject: [PATCH] Add missing include to libsnes.cpp
---
target-libsnes/libsnes.cpp | 1 +
target-libsnes/libsnes.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/target-libsnes/libsnes.cpp b/target-libsnes/libsnes.cpp
@ -19,5 +19,5 @@ index 3b2be7a..ca90762 100755
#include <nall/snes/cartridge.hpp>
#include <nall/gameboy/cartridge.hpp>
--
1.8.4.4
1.7.10.4

View file

@ -1,65 +0,0 @@
From 13643c86bfff3871968cf6e8b4f991465d4e81e7 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sun, 27 Oct 2013 10:52:45 +0200
Subject: [PATCH 7/8] Support notifying latches
---
snes/cpu/mmio/mmio.cpp | 1 +
snes/cpu/timing/joypad.cpp | 1 +
snes/interface/interface.cpp | 5 +++++
snes/interface/interface.hpp | 1 +
4 files changed, 8 insertions(+)
diff --git a/snes/cpu/mmio/mmio.cpp b/snes/cpu/mmio/mmio.cpp
index c5ee930..b7afff0 100755
--- a/snes/cpu/mmio/mmio.cpp
+++ b/snes/cpu/mmio/mmio.cpp
@@ -33,6 +33,7 @@ void CPU::mmio_w2183(uint8 data) {
//strobing $4016.d0 affects both controller port latches.
//$4017 bit 0 writes are ignored.
void CPU::mmio_w4016(uint8 data) {
+ if(data&1) interface->notifyLatched();
input.port1->latch(data & 1);
input.port2->latch(data & 1);
}
diff --git a/snes/cpu/timing/joypad.cpp b/snes/cpu/timing/joypad.cpp
index 179df27..6a98de0 100755
--- a/snes/cpu/timing/joypad.cpp
+++ b/snes/cpu/timing/joypad.cpp
@@ -9,6 +9,7 @@ void CPU::step_auto_joypad_poll() {
if(status.auto_joypad_active && status.auto_joypad_latch) {
if(status.auto_joypad_counter == 0) {
+ interface->notifyLatched();
input.port1->latch(1);
input.port2->latch(1);
input.port1->latch(0);
diff --git a/snes/interface/interface.cpp b/snes/interface/interface.cpp
index 0a21a13..6685556 100755
--- a/snes/interface/interface.cpp
+++ b/snes/interface/interface.cpp
@@ -28,4 +28,9 @@ time_t Interface::randomSeed()
return time(0);
}
+void Interface::notifyLatched()
+{
+ //Nothing.
+}
+
}
diff --git a/snes/interface/interface.hpp b/snes/interface/interface.hpp
index 30ee7fd..203f7b0 100755
--- a/snes/interface/interface.hpp
+++ b/snes/interface/interface.hpp
@@ -7,6 +7,7 @@ struct Interface {
virtual void message(const string &text);
virtual time_t currentTime();
virtual time_t randomSeed();
+ virtual void notifyLatched();
};
extern Interface *interface;
--
1.8.4.4

View file

@ -1,22 +0,0 @@
From e74f6d6ce7b369d82abf1eed6d7c3e99af0d8f64 Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Sat, 30 Nov 2013 10:28:40 +0200
Subject: [PATCH 8/8] Support auto-dectecting bsnes version
---
bsnes.mk | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 bsnes.mk
diff --git a/bsnes.mk b/bsnes.mk
new file mode 100644
index 0000000..c31911f
--- /dev/null
+++ b/bsnes.mk
@@ -0,0 +1,3 @@
+BSNES_SUPPORTS_DEBUGGER=
+LIBSNES_DIR=target-libsnes
+BSNES_VERSION=087
--
1.8.4.4

View file

@ -1,124 +0,0 @@
#include <boost/filesystem.hpp>
#include <sys/time.h>
#include <fstream>
#include <cctype>
#include <set>
#include <map>
#include <iostream>
#include <string>
namespace boost_fs = boost::filesystem;
bool is_cmdhelp_file(const std::string& filename)
{
std::string _filename = filename;
return (_filename.length() > 8 && _filename.substr(0, 8) == "cmdhelp/");
}
std::string search_include(const std::list<std::string>& searchpath, const std::string& _filename,
const std::string& ref_by)
{
std::string filename = _filename;
//Hack: process cmdhelp includes internally as the date were for the JSON include.
if(is_cmdhelp_file(filename)) {
if(filename != "cmdhelp/inverselist.hpp") {
filename = "../src/" + filename;
//Replace the extension with .json.
size_t split = filename.find_last_of("./\\");
if(split < filename.length() && filename[split] == '.') {
filename = filename.substr(0, split) + ".json";
}
}
}
size_t p = ref_by.find_last_of("/");
if(p < ref_by.length()) {
std::string i = ref_by;
i = i.substr(0, p);
std::string real_fn = i + "/" + filename;
boost_fs::path p(real_fn);
if(boost_fs::exists(p) && boost_fs::is_regular_file(p))
return real_fn;
}
for(auto& i : searchpath) {
std::string real_fn = i + "/" + filename;
boost_fs::path p(real_fn);
if(boost_fs::exists(p) && boost_fs::is_regular_file(p))
return real_fn;
}
std::cerr << "WARNING: Include file '" << filename << "' not found." << std::endl;
return "";
}
time_t get_timestamp(const std::string& path)
{
boost_fs::path p(path);
if(!boost_fs::exists(p)) return 0;
return boost_fs::last_write_time(p);
}
time_t recursive_scan(const std::list<std::string>& searchpath, const std::string& filename,
std::map<std::string, time_t>& scanned)
{
if(filename == "")
return 0;
if(scanned.count(filename))
return 0;
std::ifstream fp(filename);
if(!fp) {
std::cerr << "WARNING: File '" << filename << "' can't be opened." << std::endl;
return 0;
}
time_t newest = get_timestamp(filename);
scanned[filename] = newest;
std::string tmp;
while(std::getline(fp, tmp)) {
if(tmp.length() > 0 && tmp[0] == '#') {
//Possibly include.
std::string included;
if(strncmp(tmp.c_str(), "#include", 8))
continue;
size_t ptr = 8;
while(ptr < tmp.length() && isspace((unsigned char)tmp[ptr]))
ptr++;
if(ptr == tmp.length())
continue;
if(tmp[ptr] != '\"')
continue;
size_t iptr = ++ptr;
while(ptr < tmp.length() && tmp[ptr] != '\"')
ptr++;
if(ptr == tmp.length())
continue;
included = tmp.substr(iptr, ptr - iptr);
newest = std::max(newest, recursive_scan(searchpath, search_include(searchpath, included,
filename), scanned));
}
}
return newest;
}
int main(int argc, char** argv)
{
std::list<std::string> searchpath;
std::list<std::string> files;
bool step = false;
for(int i = 1; i < argc; i++) {
if(!step && !strcmp(argv[i], "--"))
step = true;
else if(!step)
searchpath.push_back(argv[i]);
else
files.push_back(argv[i]);
}
searchpath.push_back(".");
for(auto& i : files) {
std::map<std::string, time_t> x;
time_t t = recursive_scan(searchpath, i, x);
if(get_timestamp(i + ".dep") < t) {
std::ofstream y(i + ".dep");
for(auto& j : x)
y << j.second << " " << j.first << std::endl;
}
}
return 0;
}

View file

@ -1,91 +0,0 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <cstring>
const char* hexes = "0123456789ABCDEF";
struct encoder
{
encoder(std::ostream& _output) : output(_output)
{
have_quote = false;
}
size_t operator()(unsigned char* buf, size_t bufuse, bool eof)
{
if(!bufuse) return 0;
std::ostringstream out;
size_t i = 0;
while(i < bufuse) {
if(!have_quote) {
out << "\"";
have_quote = true;
}
unsigned char ch = buf[i];
if(ch == 9) {
out << "\\t";
} else if(ch == 10) {
out << "\\n\"" << std::endl;
have_quote = false;
} else if(ch == 13) {
out << "\\r";
} else if(ch < 32) {
out << "\\x" << hexes[(ch >> 4)] << hexes[ch & 15];
} else if(ch == '\"') {
out << "\\\"";
} else if(ch == '\\') {
out << "\\\\";
} else if(ch < 127) {
out << ch;
} else {
out << "\\x" << hexes[(ch >> 4)] << hexes[ch & 15];
}
i++;
}
output << out.str();
return i;
}
size_t operator()()
{
if(have_quote) {
output << "\"";
have_quote = false;
}
}
private:
std::ostream& output;
bool have_quote;
};
void do_encode(std::istream& input, std::ostream& output)
{
char buf[4096];
size_t bufuse = 0;
bool eof = false;
encoder e(output);
while(true) {
if(!eof) {
input.read(buf + bufuse, 4096 - bufuse);
bufuse += input.gcount();
}
if(!input)
eof = true;
size_t bytes = e(reinterpret_cast<unsigned char*>(buf), bufuse, eof);
memmove(buf, buf + bytes, bufuse - bytes);
bufuse -= bytes;
if(eof && !bufuse) break;
}
e();
}
int main(int argc, char** argv)
{
if(argc != 3) {
std::cerr << "Usage: txt2cstr <symbol> <file>" << std::endl;
return 1;
}
std::ifstream in(argv[2], std::ios::binary);
std::cout << "const char* " << argv[1] << " =" << std::endl;
do_encode(in, std::cout);
std::cout << ";" << std::endl;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

@ -1 +0,0 @@
Subproject commit a77b5548ae91cf66d1d18d4fbe2aa76eb39c7ea3

View file

@ -1,2 +0,0 @@
#pragma once
namespace STUBS { extern const char* inverse_cmd_list[]; }

View file

@ -4,48 +4,30 @@
#include <string>
#include <set>
#include <stdexcept>
#include <iostream>
#include <functional>
#include "library/framebuffer.hpp"
#include "library/dispatch.hpp"
#include "library/threads.hpp"
class master_dumper;
class dumper_factory_base;
class dumper_base;
class lua_state;
class dumper_factory_base
class adv_dumper
{
public:
/**
* Notifier base.
*/
class notifier
{
public:
virtual ~notifier() throw();
virtual void dumpers_updated() throw() = 0;
};
/**
* Detail flags.
*/
static const unsigned target_type_mask;
static const unsigned target_type_file;
static const unsigned target_type_prefix;
static const unsigned target_type_special;
static unsigned target_type_mask;
static unsigned target_type_file;
static unsigned target_type_prefix;
static unsigned target_type_special;
/**
* Register a dumper.
*
* Parameter id: The ID of dumper.
* Throws std::bad_alloc: Not enough memory.
*/
dumper_factory_base(const std::string& id);
adv_dumper(const std::string& id) throw(std::bad_alloc);
/**
* Unregister a dumper.
*/
~dumper_factory_base();
~adv_dumper();
/**
* Get ID of dumper.
*
@ -58,14 +40,14 @@ public:
* Returns: The set.
* Throws std::bad_alloc: Not enough memory.
*/
static std::set<dumper_factory_base*> get_dumper_set();
static std::set<adv_dumper*> get_dumper_set() throw(std::bad_alloc);
/**
* List all valid submodes.
*
* Returns: List of all valid submodes. Empty list means this dumper has no submodes.
* Throws std::bad_alloc: Not enough memory.
*/
virtual std::set<std::string> list_submodes() = 0;
virtual std::set<std::string> list_submodes() throw(std::bad_alloc) = 0;
/**
* Get mode details
*
@ -86,7 +68,7 @@ public:
* Returns: The name.
* Throws std::bad_alloc: Not enough memory.
*/
virtual std::string name() = 0;
virtual std::string name() throw(std::bad_alloc) = 0;
/**
* Get human-readable name for submode.
*
@ -94,193 +76,31 @@ public:
* Returns: The name.
* Throws std::bad_alloc: Not enough memory.
*/
virtual std::string modename(const std::string& mode) = 0;
virtual std::string modename(const std::string& mode) throw(std::bad_alloc) = 0;
/**
* Is this dumper busy dumping?
*
* Return: True if busy, false if not.
*/
virtual bool busy() = 0;
/**
* Start dump.
*
* parameter mode: The mode to dump using.
* parameter targetname: The target filename or prefix.
* returns: The dumper object.
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Can't start dump.
*/
virtual dumper_base* start(master_dumper& _mdumper, const std::string& mode, const std::string& targetname)
= 0;
virtual void start(const std::string& mode, const std::string& targetname) throw(std::bad_alloc,
std::runtime_error) = 0;
/**
* Is hidden?
* End current dump.
*/
virtual bool hidden() const { return false; }
/**
* Add dumper update notifier object.
*/
static void add_notifier(notifier& n);
/**
* Remove dumper update notifier object.
*/
static void drop_notifier(notifier& n);
/**
* Notify ctor finished.
*/
void ctor_notify();
/**
* Notify dumper change.
*/
static void run_notify();
virtual void end() throw() = 0;
private:
std::string d_id;
};
class master_dumper
{
public:
/**
* Information about run.
*/
struct gameinfo
{
public:
/**
* Construct game info.
*/
gameinfo();
/**
* Game name.
*/
std::string gamename;
/**
* Run length in seconds.
*/
double length;
/**
* Rerecord count (base 10 ASCII)
*/
std::string rerecords;
/**
* Authors. The first components are real names, the second components are nicknames. Either (but not both) may be
* blank.
*/
std::vector<std::pair<std::string, std::string>> authors;
/**
* Format human-redable representation of the length.
*
* Parameter digits: Number of sub-second digits to use.
* Returns: The time formated.
* Throws std::bad_alloc: Not enough memory.
*/
std::string get_readable_time(unsigned digits) const;
/**
* Get number of authors.
*
* Returns: Number of authors.
*/
size_t get_author_count() const throw();
/**
* Get short name of author (nickname if present, otherwise full name).
*
* Parameter idx: Index of author (0-based).
* Returns: The short name.
* Throws std::bad_alloc: Not enough memory.
*/
std::string get_author_short(size_t idx) const;
/**
* Get long name of author (full name and nickname if present).
*
* Parameter idx: Index of author (0-based).
* Returns: The long name.
* Throws std::bad_alloc: Not enough memory.
*/
std::string get_author_long(size_t idx) const;
/**
* Get rerecord count as a number. If rerecord count is too high, returns the maximum representatible count.
*
* Returns: The rerecord count.
*/
uint64_t get_rerecords() const throw();
};
/**
* Notifier.
*/
class notifier
{
public:
virtual ~notifier() throw();
virtual void dump_status_change() = 0;
};
/**
* Ctor.
*/
master_dumper(lua_state& _lua2);
/**
* Get instance for specified dumper.
*/
dumper_base* get_instance(dumper_factory_base* dumper) throw();
/**
* Is dumper busy in this instance?
*/
bool busy(dumper_factory_base* dumper) throw()
{
return get_instance(dumper) != NULL;
}
/**
* Call start on dumper.
*/
dumper_base* start(dumper_factory_base& factory, const std::string& mode, const std::string& targetname);
/**
* Add dumper update notifier object.
*/
void add_notifier(notifier& n);
/**
* Remove dumper update notifier object.
*/
void drop_notifier(notifier& n);
/**
* Add dumper update notifier object.
*/
void add_dumper(dumper_base& n);
/**
* Remove dumper update notifier object.
*/
void drop_dumper(dumper_base& n);
/**
* Get number of active dumpers.
*/
unsigned get_dumper_count() throw();
/**
* Call all notifiers (on_frame).
*/
void on_frame(struct framebuffer::raw& _frame, uint32_t fps_n, uint32_t fps_d);
/**
* Call all notifiers (on_sample).
*/
void on_sample(short l, short r);
/**
* Call all notifiers (on_rate_change)
*
* Also changes builtin rate variables.
*/
void on_rate_change(uint32_t n, uint32_t d);
/**
* Call all notifiers (on_gameinfo_change)
*
* Also changes builtin gameinfo structure.
*/
void on_gameinfo_change(const gameinfo& gi);
/**
* Get current sound rate in effect.
*/
std::pair<uint32_t, uint32_t> get_rate();
/**
* Get current gameinfo in effect.
*/
const gameinfo& get_gameinfo();
/**
* End all dumps.
*/
void end_dumps();
/**
* Set output stream.
*/
void set_output(std::ostream* _output);
/**
* Render Lua HUD on video.
*
@ -288,91 +108,17 @@ public:
* Parameter source: The source screen to read.
* Parameter hscl: The horizontal scale factor.
* Parameter vscl: The vertical scale factor.
* Parameter roffset: Red offset.
* Parameter goffset: Green offset.
* Parameter boffset: Blue offset.
* Parameter lgap: Left gap.
* Parameter tgap: Top gap.
* Parameter rgap: Right gap
* Parameter bgap: Bottom gap.
* Parameter fn: Function to call between running lua hooks and actually rendering.
* Returns: True if frame should be dumped, false if not.
*/
template<bool X> bool render_video_hud(struct framebuffer::fb<X>& target, struct framebuffer::raw& source,
uint32_t hscl, uint32_t vscl, uint32_t lgap, uint32_t tgap, uint32_t rgap, uint32_t bgap,
std::function<void()> fn);
/**
* Calculate number of sound samples to drop due to dropped frame.
*/
uint64_t killed_audio_length(uint32_t fps_n, uint32_t fps_d, double& fraction);
private:
void statuschange();
friend class dumper_base;
std::map<dumper_factory_base*, dumper_base*> dumpers;
std::set<notifier*> notifications;
std::set<dumper_base*> sdumpers;
uint32_t current_rate_n;
uint32_t current_rate_d;
gameinfo current_gi;
std::ostream* output;
threads::rlock lock;
lua_state& lua2;
};
class dumper_base
{
public:
dumper_base();
dumper_base(master_dumper& _mdumper, dumper_factory_base& _fbase);
virtual ~dumper_base() throw();
/**
* New frame available.
*/
virtual void on_frame(struct framebuffer::raw& _frame, uint32_t fps_n, uint32_t fps_d) = 0;
/**
* New sample available.
*/
virtual void on_sample(short l, short r) = 0;
/**
* Sample rate is changing.
*/
virtual void on_rate_change(uint32_t n, uint32_t d) = 0;
/**
* Gameinfo is changing.
*/
virtual void on_gameinfo_change(const master_dumper::gameinfo& gi) = 0;
/**
* Dump is being forcibly ended.
*/
virtual void on_end() = 0;
/**
* Render Lua HUD on video. samples_killed is incremented if needed.
*
* Parameter target: The target screen to render on.
* Parameter source: The source screen to read.
* Parameter fps_n: Fps numerator.
* Parameter fps_d: Fps denominator.
* Parameter hscl: The horizontal scale factor.
* Parameter vscl: The vertical scale factor.
* Parameter lgap: Left gap.
* Parameter tgap: Top gap.
* Parameter rgap: Right gap
* Parameter bgap: Bottom gap.
* Parameter fn: Function to call between running lua hooks and actually rendering.
* Returns: True if frame should be dumped, false if not.
*/
template<bool X> bool render_video_hud(struct framebuffer::fb<X>& target, struct framebuffer::raw& source,
uint32_t fps_n, uint32_t fps_d, uint32_t hscl, uint32_t vscl, uint32_t lgap, uint32_t tgap,
uint32_t rgap, uint32_t bgap, std::function<void()> fn)
{
bool r = mdumper->render_video_hud(target, source, hscl, vscl, lgap, tgap, rgap, bgap, fn);
if(!r)
samples_killed += mdumper->killed_audio_length(fps_n, fps_d, akillfrac);
return r;
}
private:
friend class master_dumper;
uint64_t samples_killed;
master_dumper* mdumper;
dumper_factory_base* fbase;
double akillfrac;
};
template<bool X> void render_video_hud(struct framebuffer<X>& target, struct framebuffer_raw& source, uint32_t hscl,
uint32_t vscl, uint32_t roffset, uint32_t goffset, uint32_t boffset, uint32_t lgap, uint32_t tgap,
uint32_t rgap, uint32_t bgap, void(*fn)());
#endif

View file

@ -1,108 +0,0 @@
#ifndef _audioapi_driver__hpp__included__
#define _audioapi_driver__hpp__included__
#include <stdexcept>
#include <string>
#include <map>
class audioapi_instance;
//All the following need to be implemented by the sound driver itself
struct _audioapi_driver
{
//These correspond to various audioapi_driver_* functions.
void (*init)() throw();
void (*quit)() throw();
void (*enable)(bool enable);
bool (*initialized)();
void (*set_device)(const std::string& pdev, const std::string& rdev);
std::string (*get_device)(bool rec);
std::map<std::string, std::string> (*get_devices)(bool rec);
const char* (*name)();
};
struct audioapi_driver
{
audioapi_driver(struct _audioapi_driver driver);
};
/**
* Initialize the driver.
*/
void audioapi_driver_init() throw();
/**
* Deinitialize the driver.
*/
void audioapi_driver_quit() throw();
/**
* Enable or disable sound.
*
* parameter enable: Enable sounds if true, otherwise disable sounds.
*/
void audioapi_driver_enable(bool enable) throw();
/**
* Has the sound system been successfully initialized?
*
* Returns: True if sound system has successfully initialized, false otherwise.
*/
bool audioapi_driver_initialized();
/**
* Set sound device (playback).
*
* - If new sound device is invalid, the sound device is not changed.
*
* Parameter pdev: The new sound device (playback).
* Parameter rdev: The new sound device (recording)
*/
void audioapi_driver_set_device(const std::string& pdev, const std::string& rdev);
/**
* Get current sound device (playback).
*
* Returns: The current sound device.
*/
std::string audioapi_driver_get_device(bool rec);
/**
* Get available sound devices (playback).
*
* Returns: The map of devices. Keyed by name of the device, values are human-readable names for devices.
*/
std::map<std::string, std::string> audioapi_driver_get_devices(bool rec);
/**
* Identification for sound plugin.
*/
const char* audioapi_driver_name() throw();
/**
* Add an instance to be mixed.
*/
void audioapi_connect_instance(audioapi_instance& instance);
/**
* Remove an instance from being mixed.
*/
void audioapi_disconnect_instance(audioapi_instance& instance);
/**
* Send a rate change.
*/
void audioapi_send_rate_change(unsigned rrate, unsigned prate);
/**
* Broadcast voice input to all instances.
*/
void audioapi_put_voice(float* samples, size_t count);
/**
* Get mixed music + voice out from all instances.
*/
void audioapi_get_mixed(int16_t* samples, size_t count, bool stereo);
#endif

View file

@ -1,55 +1,50 @@
#ifndef _audioapi__hpp__included__
#define _audioapi__hpp__included__
#include "library/threads.hpp"
#include <map>
#include <cstdint>
#include <cstdlib>
#include <string>
#include <stdexcept>
class audioapi_instance
{
public:
/**
* Audio API music buffer.
*/
struct buffer
{
struct audioapi_buffer
{
/**
* The samples.
*
* Note: May be NULL if no samples are available..
*/
int16_t* samples;
int16_t* samples;
/**
* Playback pointer in samples structure.
*/
size_t pointer;
size_t pointer;
/**
* Total number of samples in this buffer.
*/
size_t total;
size_t total;
/**
* True if buffer is stereo, false if mono.
*/
bool stereo;
bool stereo;
/**
* The rate in samples per second the buffer is supposed to be played at.
*/
double rate;
};
double rate;
};
/**
* Audio API VU calculator.
*/
struct vumeter
{
struct audioapi_vumeter
{
/**
* Initialize.
*/
vumeter();
audioapi_vumeter();
/**
* Submit samples.
*
@ -59,35 +54,39 @@ public:
* Parameter rate: Sound sampling rate.
* Parameter scale: Value to scale the samples by.
*/
void operator()(float* samples, size_t count, bool stereo, double rate, double scale);
void operator()(float* samples, size_t count, bool stereo, double rate, double scale);
/**
* Get VU value in dB.
*/
operator float() const throw() { return vu; }
private:
double accumulator;
size_t samples;
float vu;
void update_vu();
};
//Resampler.
class resampler
{
public:
resampler();
//After call, either insize or outsize is zero.
void resample(float*& in, size_t& insize, float*& out, size_t& outsize, double ratio, bool stereo);
private:
double position;
double vAl, vBl, vCl, vDl, vAr, vBr, vCr, vDr;
};
/**
* Ctor.
*/
audioapi_instance();
~audioapi_instance();
operator float() const throw() { return vu; }
private:
double accumulator;
size_t samples;
float vu;
void update_vu();
};
//VU values.
extern audioapi_vumeter audioapi_vu_mleft;
extern audioapi_vumeter audioapi_vu_mright;
extern audioapi_vumeter audioapi_vu_vout;
extern audioapi_vumeter audioapi_vu_vin;
//Resampler.
class audioapi_resampler
{
public:
audioapi_resampler();
//After call, either insize or outsize is zero.
void resample(float*& in, size_t& insize, float*& out, size_t& outsize, double ratio, bool stereo);
private:
double position;
double vAl, vBl, vCl, vDl, vAr, vBr, vCr, vDr;
};
//The following are intended to be used by the emulator core.
/**
/**
* Submit a buffer for playback on music channel.
*
* Parameter samples: The samples in the buffer. If stereo is true, each sample takes two elements (L, R).
@ -95,97 +94,125 @@ public:
* Parameter stereo: If true, the signal is stereo. If false, mono.
* Parameter rate: Rate of buffer in samples per second.
*/
void submit_buffer(int16_t* samples, size_t count, bool stereo, double rate);
void audioapi_submit_buffer(int16_t* samples, size_t count, bool stereo, double rate);
/**
* Get the voice channel playback/record rate.
*
* Returns: The rate in samples per second (first for recording, then for playback).
* Returns: The rate in samples per second.
*/
std::pair<unsigned,unsigned> voice_rate();
unsigned audioapi_voice_rate();
/**
* Get the voice channel nominal playback/record rate.
*
* Returns: The rate in samples per second.
*/
unsigned orig_voice_rate();
unsigned audioapi_orig_voice_rate();
/**
* Get the voice channel playback status register.
*
* Returns: The number of samples free for playback.
*/
unsigned voice_p_status();
unsigned audioapi_voice_p_status();
/**
* Get the voice channel playback status register2.
*
* Returns: The number of samples in playback buffer.
*/
unsigned voice_p_status2();
unsigned audioapi_voice_p_status2();
/**
* Get the voice channel record status register.
*
* Returns: The number of samples in capture buffer.
*/
unsigned voice_r_status();
unsigned audioapi_voice_r_status();
/**
* Play sound on voice channel.
*
* Parameter samples: The samples to play.
* Parameter count: Number of samples to play. Must be less than number of samples free for playback.
*/
void play_voice(float* samples, size_t count);
void audioapi_play_voice(float* samples, size_t count);
/**
* Capture sound on voice channel.
*
* Parameter samples: The buffer to store captured samples to.
* Parameter count: Number of samples to capture. Must be less than number of samples used for capture.
*/
void record_voice(float* samples, size_t count);
void audioapi_record_voice(float* samples, size_t count);
/**
* Init the audio. Call on emulator startup.
*/
void init();
void audioapi_init();
/**
* Quit the audio. Call on emulator shutdown.
*/
void quit();
void audioapi_quit();
/**
* Set music volume.
*
* Parameter volume: The volume (0-1).
*/
void music_volume(float volume);
void audioapi_music_volume(float volume);
/**
* Get music volume.
*
* Returns: The music volume.
*/
float music_volume();
float audioapi_music_volume();
/**
* Set voice playback volume.
*
* Parameter volume: The volume (0-1).
*/
void voicep_volume(float volume);
void audioapi_voicep_volume(float volume);
/**
* Get voice playback volume.
*
* Returns: The voice playback volume.
*/
float voicep_volume();
float audioapi_voicep_volume();
/**
* Set voice capture volume.
*
* Parameter volume: The volume (0-1).
*/
void voicer_volume(float volume);
void audioapi_voicer_volume(float volume);
/**
* Get voice capture volume.
*
* Returns: The voice capture volume.
*/
float voicer_volume();
float audioapi_voicer_volume();
//The following are intender to be used by the driver.
/**
* Set dummy CB enable flag.
*
* Parameter enable: The new state for enable flag.
*
* Note: Dummy CB enable should be set when the audio driver itself does not have active CB running.
* Note: After negative edge, reprogram voice rate.
*/
void audioapi_set_dummy_cb(bool enable);
//The following are intended to be used by the driver from the callback
/**
* Get mixed music + voice buffer to play (at voice rate).
*
@ -193,7 +220,8 @@ public:
* Parameter count: Number of samples to generate.
* Parameter stereo: If true, return stereo buffer, else mono.
*/
void get_mixed(int16_t* samples, size_t count, bool stereo);
void audioapi_get_mixed(int16_t* samples, size_t count, bool stereo);
/**
* Get music channel buffer to play.
*
@ -202,7 +230,8 @@ public:
*
* Note: This should only be called from the sound driver.
*/
struct buffer get_music(size_t played);
struct audioapi_buffer audioapi_get_music(size_t played);
/**
* Get voice channel buffer to play.
*
@ -211,7 +240,8 @@ public:
*
* Note: This should only be called from the sound driver.
*/
void get_voice(float* samples, size_t count);
void audioapi_get_voice(float* samples, size_t count);
/**
* Put recorded voice channel buffer.
*
@ -221,66 +251,69 @@ public:
* Note: Even if audio driver does not support capture, one should send in silence.
* Note: This should only be called from the sound driver.
*/
void put_voice(float* samples, size_t count);
void audioapi_put_voice(float* samples, size_t count);
/**
* Set the voice channel playback/record rate.
*
* Parameter rate_r: The recording rate in samples per second.
* Parameter rate_p: The playback rate in samples per second.
* Parameter rate: The rate in samples per second.
*
* Note: This should only be called from the sound driver.
* Note: Setting rate to 0 enables dummy callbacks.
*/
void voice_rate(unsigned rate_r, unsigned rate_p);
/**
* Suppress all future VU updates.
*/
static void disable_vu_updates();
//Vu values.
vumeter vu_mleft;
vumeter vu_mright;
vumeter vu_vout;
vumeter vu_vin;
private:
struct dummy_cb_proc
{
dummy_cb_proc(audioapi_instance& _parent);
int operator()();
audioapi_instance& parent;
};
dummy_cb_proc dummyproc;
threads::thread* dummythread;
//3 music buffers is not enough due to huge blocksizes used by SDL.
const static unsigned MUSIC_BUFFERS = 8;
const static unsigned voicep_bufsize = 65536;
const static unsigned voicer_bufsize = 65536;
const static unsigned music_bufsize = 8192;
float voicep_buffer[voicep_bufsize];
float voicer_buffer[voicer_bufsize];
int16_t music_buffer[MUSIC_BUFFERS * music_bufsize];
volatile bool music_stereo[MUSIC_BUFFERS];
volatile double music_rate[MUSIC_BUFFERS];
volatile size_t music_size[MUSIC_BUFFERS];
unsigned music_ptr;
unsigned last_complete_music_seen;
volatile unsigned last_complete_music;
volatile unsigned voicep_get;
volatile unsigned voicep_put;
volatile unsigned voicer_get;
volatile unsigned voicer_put;
volatile unsigned voice_rate_play;
volatile unsigned orig_voice_rate_play;
volatile unsigned voice_rate_rec;
volatile bool dummy_cb_active_record;
volatile bool dummy_cb_active_play;
volatile bool dummy_cb_quit;
volatile float _music_volume;
volatile float _voicep_volume;
volatile float _voicer_volume;
resampler music_resampler;
bool last_adjust; //Adjusting consequtively is too hard.
static bool vu_disabled;
};
void audioapi_voice_rate(unsigned rate);
//All the following need to be implemented by the sound driver itself
/**
* Initialize the driver.
*/
void audioapi_driver_init() throw();
/**
* Deinitialize the driver.
*/
void audioapi_driver_quit() throw();
/**
* Enable or disable sound.
*
* parameter enable: Enable sounds if true, otherwise disable sounds.
*/
void audioapi_driver_enable(bool enable) throw();
/**
* Has the sound system been successfully initialized?
*
* Returns: True if sound system has successfully initialized, false otherwise.
*/
bool audioapi_driver_initialized();
/**
* Set sound device.
*
* - If new sound device is invalid, the sound device is not changed.
*
* Parameter dev: The new sound device.
*/
void audioapi_driver_set_device(const std::string& dev) throw(std::bad_alloc, std::runtime_error);
/**
* Get current sound device.
*
* Returns: The current sound device.
*/
std::string audioapi_driver_get_device() throw(std::bad_alloc);
/**
* Get available sound devices.
*
* Returns: The map of devices. Keyed by name of the device, values are human-readable names for devices.
*/
std::map<std::string, std::string> audioapi_driver_get_devices() throw(std::bad_alloc);
/**
* Identification for sound plugin.
*/
extern const char* audioapi_driver_name;
#endif

View file

@ -1,31 +1,164 @@
#ifndef _command__hpp__included__
#define _command__hpp__included__
#include "library/command.hpp"
#include "library/threads.hpp"
#include <stdexcept>
#include <string>
#include <set>
extern command::set lsnes_cmds;
namespace keyboard
{
class mapper;
class invbind;
}
class alias_binds_manager
/**
* A command.
*/
class command
{
public:
alias_binds_manager(keyboard::mapper& _mapper, command::group& _command);
~alias_binds_manager();
void operator()();
/**
* Register a new command.
*
* parameter cmd: The command to register.
* throws std::bad_alloc: Not enough memory.
*/
command(const std::string& cmd) throw(std::bad_alloc);
/**
* Deregister a command.
*/
virtual ~command() throw();
/**
* Invoke a command.
*
* parameter arguments: Arguments to command.
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: Command execution failed.
*/
virtual void invoke(const std::string& arguments) throw(std::bad_alloc, std::runtime_error) = 0;
/**
* Look up and invoke a command. The command will undergo alias expansion and recursion checking.
*
* parameter cmd: Command to exeucte.
*/
static void invokeC(const std::string& cmd) throw();
/**
* Get set of aliases.
*/
static std::set<std::string> get_aliases() throw(std::bad_alloc);
/**
* Get alias
*/
static std::string get_alias_for(const std::string& aname) throw(std::bad_alloc);
/**
* Set alias
*/
static void set_alias_for(const std::string& aname, const std::string& avalue) throw(std::bad_alloc);
/**
* Is alias name valid.
*/
static bool valid_alias_name(const std::string& aname) throw(std::bad_alloc);
/**
* Get short help for command.
*/
virtual std::string get_short_help() throw(std::bad_alloc);
/**
* Get long help for command.
*/
virtual std::string get_long_help() throw(std::bad_alloc);
private:
keyboard::mapper& mapper;
command::group& command;
threads::lock mut;
std::map<std::string, keyboard::invbind*> alias_binds;
command(const command&);
command& operator=(const command&);
std::string commandname;
};
/**
* Mandatory filename
*/
struct arg_filename
{
/**
* The filename itself.
*/
std::string v;
/**
* Return the filename.
*
* returns: The filename.
*/
operator std::string() { return v; }
};
/**
* Run command function helper.
*
* parameter fn: Function pointer to invoke.
* parameter a: The arguments to pass.
*/
template<typename... args>
void invoke_command_fn(void (*fn)(args... arguments), const std::string& a);
/**
* Warp function pointer as command.
*/
template<typename... args>
class function_ptr_command : public command
{
public:
/**
* Create a new command.
*
* parameter name: Name of the command
* parameter description Description for the command
* parameter help: Help for the command.
* parameter fn: Function to call on command.
*/
function_ptr_command(const std::string& name, const std::string& _description, const std::string& _help,
void (*_fn)(args... arguments)) throw(std::bad_alloc)
: command(name)
{
description = _description;
help = _help;
fn = _fn;
}
/**
* Destroy a commnad.
*/
~function_ptr_command() throw()
{
}
/**
* Invoke a command.
*
* parameter a: Arguments to function.
*/
void invoke(const std::string& a) throw(std::bad_alloc, std::runtime_error)
{
invoke_command_fn(fn, a);
}
/**
* Get short description.
*
* returns: Description.
* throw std::bad_alloc: Not enough memory.
*/
std::string get_short_help() throw(std::bad_alloc)
{
return description;
}
/**
* Get long help.
*
* returns: help.
* throw std::bad_alloc: Not enough memory.
*/
std::string get_long_help() throw(std::bad_alloc)
{
return help;
}
private:
void (*fn)(args... arguments);
std::string description;
std::string help;
};
#endif

View file

@ -1,154 +1,8 @@
#ifndef _controller__hpp__included__
#define _controller__hpp__included__
#include <string>
#include <map>
#include "library/dispatch.hpp"
#include "library/command.hpp"
struct project_info;
struct controller_state;
struct emu_framebuffer;
struct emulator_dispatch;
struct lua_state;
struct core_core;
namespace keyboard { class invbind; }
namespace keyboard { class ctrlrkey; }
namespace keyboard { class mapper; }
namespace keyboard { class keyboard; }
namespace portctrl { struct type; }
namespace portctrl { struct controller; }
class button_mapping
{
public:
struct controller_bind
{
std::string cclass;
unsigned number;
std::string name;
int mode; //0 => Button, 1 => Axis pair, 2 => Single axis.
bool xrel;
bool yrel;
unsigned control1;
unsigned control2; //Axis only, UINT_MAX if not valid.
int16_t rmin;
int16_t rmax;
bool centered;
};
struct active_bind
{
unsigned port;
unsigned controller;
struct controller_bind bind;
};
struct controller_triple
{
std::string cclass;
unsigned port;
unsigned controller;
bool operator<(const struct controller_triple& t) const throw()
{
if(cclass < t.cclass) return true;
if(cclass > t.cclass) return false;
if(port < t.port) return true;
if(port > t.port) return false;
if(controller < t.controller) return true;
if(controller > t.controller) return false;
return false;
}
bool operator==(const struct controller_triple& t) const throw()
{
return (cclass == t.cclass && port == t.port && controller == t.controller);
}
};
/**
* Ctor.
*/
button_mapping(controller_state& _controls, keyboard::mapper& mapper, keyboard::keyboard& keyboard,
emu_framebuffer& fbuf, emulator_dispatch& _dispatch, lua_state& _lua2, command::group& _cmd);
/**
* Dtor.
*/
~button_mapping();
/**
* Reread active buttons.
*/
void reread();
/**
* Reinitialize buttons.
*/
void reinit();
/**
* Load macros.
*/
void load(controller_state& ctrlstate);
/**
* Load macros (from project).
*/
void load(controller_state& ctrlstate, project_info& pinfo);
/**
* Cleanup memory used.
*/
void cleanup();
/**
* Lookup button by name.
*/
std::pair<int, int> byname(const std::string& name);
/**
* Map of button keys.
*/
std::map<std::string, std::string> button_keys;
private:
void do_analog_action(const std::string& a);
void do_autofire_action(const std::string& a, int mode);
void do_action(const std::string& name, short state, int mode);
void promote_key(keyboard::ctrlrkey& k);
void add_button(const std::string& name, const controller_bind& binding);
void process_controller(portctrl::controller& controller, unsigned number);
void process_controller(std::map<std::string, unsigned>& allocated,
std::map<controller_triple, unsigned>& assigned, portctrl::controller& controller, unsigned port,
unsigned number_in_port);
void process_port(std::map<std::string, unsigned>& allocated,
std::map<controller_triple, unsigned>& assigned, unsigned port, portctrl::type& ptype);
void init();
bool check_button_active(const std::string& name);
void do_button_action(const std::string& name, short newstate, int mode);
void send_analog(const std::string& name, int32_t x, int32_t y);
std::map<std::string, keyboard::invbind*> macro_binds;
std::map<std::string, keyboard::invbind*> macro_binds2;
std::map<std::string, controller_bind> all_buttons;
std::map<std::string, active_bind> active_buttons;
std::map<std::string, keyboard::ctrlrkey*> added_keys;
std::set<core_core*> cores_done;
bool promote_autohold;
bool promote_autofire;
bool promote_typed;
controller_state& controls;
keyboard::mapper& mapper;
keyboard::keyboard& keyboard;
emu_framebuffer& fbuf;
emulator_dispatch& edispatch;
lua_state& lua2;
command::group& cmd;
struct dispatch::target<> ncore;
command::_fnptr<const std::string&> button_p;
command::_fnptr<const std::string&> button_r;
command::_fnptr<const std::string&> button_h;
command::_fnptr<const std::string&> button_t;
command::_fnptr<const std::string&> button_d;
command::_fnptr<const std::string&> button_ap;
command::_fnptr<const std::string&> button_ar;
command::_fnptr<const std::string&> button_at;
command::_fnptr<const std::string&> button_a;
command::_fnptr<> afire_p;
command::_fnptr<> afire_n;
command::_fnptr<> ahold_p;
command::_fnptr<> ahold_n;
command::_fnptr<> typed_p;
command::_fnptr<> typed_n;
};
#include "controllerframe.hpp"
extern controller_state controls;
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,203 +0,0 @@
#ifndef _debug__hpp__included__
#define _debug__hpp__included__
#include <functional>
#include <fstream>
#include <cstdint>
#include "library/command.hpp"
#include "library/dispatch.hpp"
class emulator_dispatch;
class loaded_rom;
class memory_space;
/**
* Debugging context.
*/
class debug_context
{
public:
debug_context(emulator_dispatch& _dispatch, loaded_rom& _rom, memory_space& _mspace, command::group& _cmd);
/**
* Type of event.
*/
enum etype
{
DEBUG_READ,
DEBUG_WRITE,
DEBUG_EXEC,
DEBUG_TRACE,
DEBUG_FRAME,
};
/**
* Parameters for read/write/execute event.
*/
struct params_rwx
{
uint64_t addr; //Address.
uint64_t value; //Value/CPU.
};
/**
* Parameters for trace event.
*/
struct params_trace
{
uint64_t cpu; //CPU number.
const char* decoded_insn; //Decoded instruction
bool true_insn; //True instruction flag.
};
/**
* Parameters for frame event.
*/
struct params_frame
{
uint64_t frame; //Frame number.
bool loadstated; //Loadstate flag.
};
/**
* Parameters for debug callback.
*/
struct params
{
etype type;
union {
params_rwx rwx; //READ/WRITE/EXECUTE
params_trace trace; //TRACE.
params_frame frame; //FRAME.
};
};
/**
* Base class of debugging callbacks.
*/
struct callback_base
{
/**
* Destructor.
*/
virtual ~callback_base();
/**
* Do a callback.
*/
virtual void callback(const params& p) = 0;
/**
* Notify about killed callback.
*/
virtual void killed(uint64_t addr, etype type) = 0;
};
/**
* Placeholder for all addresses.
*/
static const uint64_t all_addresses;
/**
* Add a callback.
*/
void add_callback(uint64_t addr, etype type, callback_base& cb);
/**
* Remove a callback.
*/
void remove_callback(uint64_t addr, etype type, callback_base& cb);
/**
* Fire a read callback.
*/
void do_callback_read(uint64_t addr, uint64_t value);
/**
* Fire a write callback.
*/
void do_callback_write(uint64_t addr, uint64_t value);
/**
* Fire a exec callback.
*/
void do_callback_exec(uint64_t addr, uint64_t value);
/**
* Fire a trace callback.
*/
void do_callback_trace(uint64_t cpu, const char* str, bool true_insn = true);
/**
* Fire a frame callback.
*/
void do_callback_frame(uint64_t frame, bool loadstate);
/**
* Set a cheat.
*/
void set_cheat(uint64_t addr, uint64_t value);
/**
* Clear a cheat.
*/
void clear_cheat(uint64_t addr);
/**
* Set execute callback mask.
*/
void setxmask(uint64_t mask);
/**
* Set tracelog file.
*/
void tracelog(uint64_t cpu, const std::string& filename);
/**
* Tracelogging on?
*/
bool is_tracelogging(uint64_t cpu);
/**
* Change tracelog change callback.
*/
void set_tracelog_change_cb(std::function<void()> cb);
/**
* Notify a core change.
*/
void core_change();
/**
* Request a break.
*/
void request_break();
//These are public only for some debugging stuff.
typedef std::list<callback_base*> cb_list;
std::map<uint64_t, cb_list> read_cb;
std::map<uint64_t, cb_list> write_cb;
std::map<uint64_t, cb_list> exec_cb;
std::map<uint64_t, cb_list> trace_cb;
std::map<uint64_t, cb_list> frame_cb;
private:
void do_showhooks();
void do_genevent(const std::string& a);
void do_tracecmd(const std::string& a);
cb_list dummy_cb; //Always empty.
uint64_t xmask = 1;
std::function<void()> tracelog_change_cb;
emulator_dispatch& edispatch;
loaded_rom& rom;
memory_space& mspace;
command::group& cmd;
struct dispatch::target<> corechange;
bool corechange_r = false;
bool requesting_break = false;
command::_fnptr<> showhooks;
command::_fnptr<const std::string&> genevent;
command::_fnptr<const std::string&> tracecmd;
struct tracelog_file : public callback_base
{
std::ofstream stream;
std::string full_filename;
unsigned refcnt;
tracelog_file(debug_context& parent);
~tracelog_file();
void callback(const params& p);
void killed(uint64_t addr, etype type);
private:
debug_context& parent;
};
std::map<uint64_t, tracelog_file*> trace_outputs;
std::map<uint64_t, cb_list>& get_lists(etype type)
{
switch(type) {
case DEBUG_READ: return read_cb;
case DEBUG_WRITE: return write_cb;
case DEBUG_EXEC: return exec_cb;
case DEBUG_TRACE: return trace_cb;
case DEBUG_FRAME: return frame_cb;
default: throw std::runtime_error("Invalid debug callback type");
}
}
};
#endif

View file

@ -1,8 +1,8 @@
#ifndef _dispatch__hpp__included__
#define _dispatch__hpp__included__
#include "core/keymapper.hpp"
#include "library/framebuffer.hpp"
#include "library/dispatch.hpp"
#include <cstdint>
#include <string>
@ -10,32 +10,452 @@
#include <set>
#include <map>
struct emulator_dispatch
/**
* Video data region is NTSC.
*/
#define VIDEO_REGION_NTSC 0
/**
* Video data region is PAL.
*/
#define VIDEO_REGION_PAL 1
/**
* Information about run.
*/
struct gameinfo_struct
{
emulator_dispatch();
void set_error_streams(std::ostream* stream);
dispatch::source<> autohold_reconfigure;
dispatch::source<unsigned, unsigned, unsigned, bool> autohold_update;
dispatch::source<unsigned, unsigned, unsigned, unsigned, unsigned> autofire_update;
dispatch::source<> close;
dispatch::source<std::pair<std::string, std::string>> sound_change;
dispatch::source<> screen_update;
dispatch::source<> status_update;
dispatch::source<bool> sound_unmute;
dispatch::source<bool> mode_change;
dispatch::source<> core_change;
dispatch::source<> title_change;
dispatch::source<> branch_change;
dispatch::source<> mbranch_change;
dispatch::source<bool> core_changed;
dispatch::source<> voice_stream_change;
dispatch::source<> vu_change;
dispatch::source<> subtitle_change;
dispatch::source<unsigned, unsigned, int> multitrack_change;
dispatch::source<> action_update;
public:
/**
* Construct game info.
*/
gameinfo_struct() throw(std::bad_alloc);
/**
* Game name.
*/
std::string gamename;
/**
* Run length in seconds.
*/
double length;
/**
* Rerecord count (base 10 ASCII)
*/
std::string rerecords;
/**
* Authors. The first components are real names, the second components are nicknames. Either (but not both) may be
* blank.
*/
std::vector<std::pair<std::string, std::string>> authors;
/**
* Format human-redable representation of the length.
*
* Parameter digits: Number of sub-second digits to use.
* Returns: The time formated.
* Throws std::bad_alloc: Not enough memory.
*/
std::string get_readable_time(unsigned digits) const throw(std::bad_alloc);
/**
* Get number of authors.
*
* Returns: Number of authors.
*/
size_t get_author_count() const throw();
/**
* Get short name of author (nickname if present, otherwise full name).
*
* Parameter idx: Index of author (0-based).
* Returns: The short name.
* Throws std::bad_alloc: Not enough memory.
*/
std::string get_author_short(size_t idx) const throw(std::bad_alloc);
/**
* Get rerecord count as a number. If rerecord count is too high, returns the maximum representatible count.
*
* Returns: The rerecord count.
*/
uint64_t get_rerecords() const throw();
};
extern dispatch::source<> notify_new_core;
/**
* Information dispatch.
*
* This class handles dispatching information between the components of the emulator.
*
* Each kind of information has virtual method on_foo() which can be overridden to handle events of that type, and
* static method do_foo(), which calls on_foo on all known objects.
*
* The information is delivered to each instance of this class.
*/
class information_dispatch
{
public:
/**
* Create new object to receive information dispatch events.
*
* Parameter name: The name for the object.
* Throws std::bad_alloc: Not enough memory.
*/
information_dispatch(const std::string& name) throw(std::bad_alloc);
/**
* Destroy object.
*/
virtual ~information_dispatch() throw();
/**
* Window close event received (this is not emulator close!)
*
* The default handler does nothing.
*/
virtual void on_close();
/**
* Call all on_close() handlers.
*/
static void do_close() throw();
/**
* Sound mute/unmute status might have been changed.
*
* The default handler does nothing.
*
* Parameter unmuted: If true, the sound is now enabled. If false, the sound is now disabled.
*/
virtual void on_sound_unmute(bool unmuted);
/**
* Call all on_sound_unmute() handlers.
*/
static void do_sound_unmute(bool unmuted) throw();
/**
* Sound device might have been changed.
*
* The default handler does nothing.
*
* Parameter dev: The device name sound is now playing (if enabled) from.
*/
virtual void on_sound_change(const std::string& dev);
/**
* Call all on_sound_change() handlers.
*/
static void do_sound_change(const std::string& dev) throw();
/**
* Emulator mode might have been changed.
*
* The default handler does nothing.
*
* Parameter readonly: True if readonly mode is now active, false if now in readwrite mode.
*/
virtual void on_mode_change(bool readonly);
/**
* Call all on_mode_change() handlers.
*/
static void do_mode_change(bool readonly) throw();
/**
* Autohold on button might have been changed.
*
* The default handler does nothing.
*
* Parameter pid: The physical ID of controller (0-7).
* Parameter ctrlnum: Physical control number (0-15).
* Parameter newstate: True if autohold is now active, false if autohold is now inactive.
*/
virtual void on_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate);
/**
* Call all on_autohold_update() handlers.
*/
static void do_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate) throw();
/**
* Controller configuration may have been changed.
*
* The default handler does nothing.
*/
virtual void on_autohold_reconfigure();
/**
* Call all on_autohold_reconfigure() handlers.
*/
static void do_autohold_reconfigure() throw();
/**
* A setting may have changed.
*
* The default handler does nothing.
*
* Parameter setting: The setting that has possibly changed.
* Parameter value: The new value for the setting.
*/
virtual void on_setting_change(const std::string& setting, const std::string& value);
/**
* Call all on_setting_change() handlers.
*/
static void do_setting_change(const std::string& setting, const std::string& value) throw();
/**
* A setting has been cleared (but it might have been cleared already).
*
* The default handler does nothing.
*
* Parameter setting: The setting that is now clear.
*/
virtual void on_setting_clear(const std::string& setting);
/**
* Call all on_setting_clear() handlers
*/
static void do_setting_clear(const std::string& setting) throw();
/**
* A raw frame has been received.
*
* The default handler does nothing.
*
* Parameter raw: The raw frame data. 512*512 element array.
* Parameter hires: True if in hires mode (512 wide), false if not (256-wide).
* Parameter interlaced: True if in interlaced mode (448/478 high), false if not (224/239 high).
* Parameter overscan: True if overscan is active, false if not.
* Parameter region: One of VIDEO_REGION_* contstants, giving the region this frame is from.
*/
virtual void on_raw_frame(const uint32_t* raw, bool hires, bool interlaced, bool overscan, unsigned region);
/**
* Call all on_raw_frame() handlers.
*
* Calls on_new_dumper() on dumpers that had that not yet called.
*/
static void do_raw_frame(const uint32_t* raw, bool hires, bool interlaced, bool overscan, unsigned region)
throw();
/**
* A frame has been received.
*
* The default handler does nothing.
*
* Parameter _frame: The frame object.
* Parameter fps_n: Numerator of current video fps.
* Parameter fps_d: Denominator of current video fps.
*/
virtual void on_frame(struct framebuffer_raw& _frame, uint32_t fps_n, uint32_t fps_d);
/**
* Call all on_frame() handlers.
*
* Calls on_new_dumper() on dumpers that had that not yet called.
*/
static void do_frame(struct framebuffer_raw& _frame, uint32_t fps_n, uint32_t fps_d) throw();
/**
* A sample has been received.
*
* The default handler does nothing.
*
* Parameter l: The left channel sample (16 bit signed).
* Parameter r: The right channel sample (16 bit signed).
*/
virtual void on_sample(short l, short r);
/**
* Call all on_sample() handlers.
*
* Calls on_new_dumper() on dumpers that had that not yet called.
*/
static void do_sample(short l, short r) throw();
/**
* Dump is ending.
*
* Calls on_new_dumper() on dumpers that had that not yet called.
*
* The default handler does nothing.
*/
virtual void on_dump_end();
/**
* Call all on_dump_end() handlers.
*/
static void do_dump_end() throw();
/**
* Sound sampling rate is changing
*
* The default handler prints warning if dumper flag is set.
*
* Parameter rate_n: Numerator of the new sampling rate in Hz.
* Parameter rate_d: Denominator of the new sampling rate in Hz.
*/
virtual void on_sound_rate(uint32_t rate_n, uint32_t rate_d);
/**
* Call all on_sound_rate() methods and save the parameters.
*
* Calls on_new_dumper() on dumpers that had that not yet called.
*/
static void do_sound_rate(uint32_t rate_n, uint32_t rate_d) throw();
/**
* Get the sound rate most recently set by on_sound_rate().
*
* Returns: The first component is the numerator, the second is the denominator.
*/
static std::pair<uint32_t, uint32_t> get_sound_rate() throw();
/**
* Game information is changing.
*
* The default handler does nothing.
*
* Parameter gi: The new game info.
*/
virtual void on_gameinfo(const struct gameinfo_struct& gi);
/**
* Call all on_gameinfo() handlers and save the gameinfo.
*/
static void do_gameinfo(const struct gameinfo_struct& gi) throw();
/**
* Get the gameinfo most recently set by do_gameinfo().
*
* Returns: The gameinfo.
*/
static const struct gameinfo_struct& get_gameinfo() throw();
/**
* Return the dumper flag for this dispatch target.
*
* The default implementation returns false.
*
* If dumper flag is set:
* - on_sound_rate() default handler prints a warning.
* - All dumping related do_* functions triggers calls to to on_new_dumper() on all handlers the next time they
* are called.
* - Destroying the handler triggers calls to on_destroy_dumper() on all handlers (if on_new_dumper() has been
* called).
*/
virtual bool get_dumper_flag() throw();
/**
* Notify that a new dumper is joining.
*
* Parameter dumper: The name of the dumper object.
*/
virtual void on_new_dumper(const std::string& dumper);
/**
* Notify that a dumper is leaving.
*
* Parameter dumper: The name of the dumper object.
*/
virtual void on_destroy_dumper(const std::string& dumper);
/**
* Get number of active dumpers.
*
* Calls on_new_dumper() on dumpers that had that not yet called.
*
* Returns: The dumper count.
*/
static unsigned get_dumper_count() throw();
/**
* Get set of active dumpers.
*
* Calls on_new_dumper() on dumpers that had that not yet called.
*
* Returns: The set of dumper names.
* Throws std::bad_alloc: Not enough memory.
*/
static std::set<std::string> get_dumpers() throw(std::bad_alloc);
/**
* (Pseudo-)key has been pressed or released.
*
* Parameter modifiers: The modifier set currently active.
* Parameter keygroup: The key group the (pseudo-)key is from.
* Parameter subkey: Subkey index within the key group.
* Parameter polarity: True if key is being pressed, false if being released.
* Parameter name: Name of the key being pressed/released.
*/
virtual void on_key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey,
bool polarity, const std::string& name);
/**
* Call on_key_event() for all event handlers (or just one if keys are being grabbed).
*/
static void do_key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey,
bool polarity, const std::string& name) throw();
/**
* Grab all key events.
*
* While key events are grabbed, do_key_event() only calls on_key_event() for the grabbing object.
*/
void grab_keys() throw();
/**
* Ungrab all key events.
*
* While key events are grabbed, do_key_event() only calls on_key_event() for the grabbing object.
*/
void ungrab_keys() throw();
/**
* Get name of target.
*/
const std::string& get_name() throw();
/**
* Render buffer needs to be (possibly) resized, so that graphics plugin can update the mappings.
*
* Default implementation does nothing.
*
* parameter scr: The render buffer object.
*/
virtual void on_set_screen(framebuffer<false>& scr);
/**
* Call on_set_screen on all objects.
*/
static void do_set_screen(framebuffer<false>& scr) throw();
/**
* Notify that new frame is available.
*
* Default implementation does nothing.
*/
virtual void on_screen_update();
/**
* Call on_screen_update() in all objects.
*/
static void do_screen_update() throw();
/**
* Notify that status buffer has been updated.
*
* Default implementation does nothing.
*/
virtual void on_status_update();
/**
* Call on_status_update() in all objects.
*/
static void do_status_update() throw();
/**
* Notify that some dumper has attached, deattached, popped into existence or disappeared.
*
* Default implementation does nothing.
*/
virtual void on_dumper_update();
/**
* Call on_dumper_update on on all objects.
*/
static void do_dumper_update() throw();
/**
* Notify about changes to voice streams.
*
* Default implementation does nothing.
*/
virtual void on_voice_stream_change();
/**
* Call on_voice_stream_change on all objects.
*/
static void do_voice_stream_change() throw();
/**
* Notify about changes to subtitles.
*
* Default implementation does nothing.
*/
virtual void on_subtitle_change();
/**
* Call on_subtitle_change on all objects.
*/
static void do_subtitle_change() throw();
/**
* Notify about changes to VU levels.
*
* Default implementation does nothing.
*/
virtual void on_vu_change();
/**
* Call on_vu_change on all objects.
*/
static void do_vu_change() throw();
protected:
/**
* Call to indicate this target is interested in sound sample data.
*/
void enable_send_sound() throw(std::bad_alloc);
private:
static void update_dumpers(bool nocalls = false) throw();
bool known_if_dumper;
bool marked_as_dumper;
std::string target_name;
bool notified_as_dumper;
bool grabbing_keys;
};
#endif

121
include/core/emucore.hpp Normal file
View file

@ -0,0 +1,121 @@
#ifndef _emucore__hpp__included__
#define _emucore__hpp__included__
#include <map>
#include <list>
#include <cstdlib>
#include <string>
#include <set>
#include <vector>
#include "library/framebuffer.hpp"
#include "core/romtype.hpp"
//Get the CPU rate.
uint32_t get_snes_cpu_rate();
//Get the APU rate.
uint32_t get_snes_apu_rate();
//Get the core identifier.
std::string get_core_identifier();
//Get maximum number of logical controllers and buttons.
std::pair<unsigned, unsigned> get_core_logical_controller_limits();
//Needs analog action?
bool get_core_need_analog();
//Get the default controller type for specified port.
std::string get_core_default_port(unsigned port);
//Do basic core initialization (to get it to stable state).
void do_basic_core_init();
//Get set of SRAMs.
std::set<std::string> get_sram_set();
//Get region.
core_region& core_get_region();
//Get the current video rate.
std::pair<uint32_t, uint32_t> get_video_rate();
//Get the current audio rate.
std::pair<uint32_t, uint32_t> get_audio_rate();
//Set preload settings.
void set_preload_settings();
//Set the region.
bool core_set_region(core_region& region);
//Power the core.
void core_power();
//Unload the cartridge.
void core_unload_cartridge();
//Save SRAM set.
std::map<std::string, std::vector<char>> save_sram() throw(std::bad_alloc);
//Load SRAM set.
void load_sram(std::map<std::string, std::vector<char>>& sram) throw(std::bad_alloc);
//Serialize state.
void core_serialize(std::vector<char>& out);
//Unserialize state.
void core_unserialize(const char* in, size_t insize);
//Install handler.
void core_install_handler();
//Uninstall handler.
void core_uninstall_handler();
//Emulate a frame.
void core_emulate_frame();
//Run specified number of frames inside frame.
std::pair<bool, uint32_t> core_emulate_cycles(uint32_t cycles);
//Do soft reset.
void core_reset();
//Run to point save.
void core_runtosave();
//Button symbols.
extern const char* button_symbols;
//Get the scale factors.
std::pair<uint32_t, uint32_t> get_scale_factors(uint32_t width, uint32_t height);
//Get bus map range.
std::pair<uint64_t, uint64_t> core_get_bus_map();
//Get poll flag (set to 1 on each real poll, except if 2.
unsigned core_get_poll_flag();
//Set poll flag (set to 1 on each real poll, except if 2.
void core_set_poll_flag(unsigned pflag);
/**
* Get name of logical button.
*
* Parameter lbid: ID of logical button.
* Returns: The name of button.
* Throws std::bad_alloc: Not enough memory.
*/
std::string get_logical_button_name(unsigned lbid) throw(std::bad_alloc);
//Callbacks.
struct emucore_callbacks
{
public:
virtual ~emucore_callbacks() throw();
//Get the input for specified control.
virtual int16_t get_input(unsigned port, unsigned index, unsigned control) = 0;
//Do timer tick.
virtual void timer_tick(uint32_t increment, uint32_t per_second) = 0;
//Get the firmware path.
virtual std::string get_firmware_path() = 0;
//Get the base path.
virtual std::string get_base_path() = 0;
//Get the current time.
virtual time_t get_time() = 0;
//Get random seed.
virtual time_t get_randomseed() = 0;
//Output frame.
virtual void output_frame(framebuffer_raw& screen, uint32_t fps_n, uint32_t fps_d) = 0;
};
extern struct emucore_callbacks* ecore_callbacks;
//A VMA.
struct vma_info
{
std::string name;
uint64_t base;
uint64_t size;
void* backing_ram;
bool readonly;
bool native_endian;
uint8_t (*iospace_rw)(uint64_t offset, uint8_t data, bool write);
};
std::list<vma_info> get_vma_list();
#endif

View file

@ -1,99 +0,0 @@
#ifndef _emustatus__hpp__included__
#define _emustatus__hpp__included__
#include <stdexcept>
#include <string>
#include <set>
#include <map>
#include "library/command.hpp"
#include "library/triplebuffer.hpp"
class movie_logic;
class project_state;
class voice_commentary;
class emulator_runmode;
class master_dumper;
class save_jukebox;
class slotinfo_cache;
class framerate_regulator;
class controller_state;
class multitrack_edit;
class lua_state;
class loaded_rom;
class memwatch_set;
class emulator_dispatch;
struct _lsnes_status
{
const static int pause_none; //pause: No pause.
const static int pause_normal; //pause: Normal pause.
const static int pause_break; //pause: Break pause.
const static uint64_t subframe_savepoint; //subframe: Point of save.
const static uint64_t subframe_video; //subframe: Point of video output.
bool valid;
bool movie_valid; //The movie state variables are valid?
uint64_t curframe; //Current frame number.
uint64_t length; //Movie length.
uint64_t lag; //Lag counter.
uint64_t subframe; //Subframe number.
bool dumping; //Video dump active.
unsigned speed; //Speed%
bool saveslot_valid; //Save slot number/info valid.
uint64_t saveslot; //Save slot number.
std::u32string slotinfo; //Save slot info.
bool branch_valid; //Branch info valid?
std::u32string branch; //Current branch.
bool mbranch_valid; //Movie branch info valid?
std::u32string mbranch; //Current movie branch.
std::u32string macros; //Currently active macros.
int pause; //Pause mode.
char mode; //Movie mode: C:Corrupt, R:Readwrite, P:Readonly, F:Finished.
bool rtc_valid; //RTC time valid?
std::u32string rtc; //RTC time.
std::vector<std::u32string> inputs; //Input display.
std::map<std::string, std::u32string> mvars; //Memory watches.
std::map<std::string, std::u32string> lvars; //Lua variables.
};
struct slotinfo_cache
{
slotinfo_cache(movie_logic& _mlogic, command::group& _cmd);
std::string get(const std::string& _filename);
void flush(const std::string& _filename);
void flush();
private:
std::map<std::string, std::string> cache;
movie_logic& mlogic;
command::group& cmd;
command::_fnptr<> flushcmd;
};
struct status_updater
{
public:
status_updater(project_state& _project, movie_logic& _mlogic, voice_commentary& _commentary,
triplebuffer::triplebuffer<_lsnes_status>& _status, emulator_runmode& _runmode, master_dumper& _mdumper,
save_jukebox& _jukebox, slotinfo_cache& _slotcache, framerate_regulator& _framerate,
controller_state& _controls, multitrack_edit& _mteditor, lua_state& _lua2, loaded_rom& _rom,
memwatch_set& _mwatch, emulator_dispatch& _dispatch);
void update();
private:
project_state& project;
movie_logic& mlogic;
voice_commentary& commentary;
triplebuffer::triplebuffer<_lsnes_status>& status;
emulator_runmode& runmode;
master_dumper& mdumper;
save_jukebox& jukebox;
slotinfo_cache& slotcache;
framerate_regulator& framerate;
controller_state& controls;
multitrack_edit& mteditor;
lua_state& lua2;
loaded_rom& rom;
memwatch_set& mwatch;
emulator_dispatch& dispatch;
};
#endif

View file

@ -1,39 +0,0 @@
#ifndef _filedownload__hpp__included__
#define _filedownload__hpp__included__
#include "library/threads.hpp"
#include "library/httpreq.hpp"
#include "library/urirewrite.hpp"
#include <string>
#include <list>
#include <vector>
class loaded_rom;
struct file_download
{
//Variables.
std::string url;
std::string target_slot;
//Ctor
file_download();
~file_download();
//Lauch.
void do_async(loaded_rom& rom);
void cancel();
//Status.
volatile bool finished; //This signals download finishing, call finish().
std::string errormsg;
http_async_request req;
std::string statusmsg();
threads::cv cond;
threads::lock m;
//Internal.
void _do_async(loaded_rom& rom);
std::string tempname;
std::string tempname2;
};
extern urirewrite::rewriter lsnes_uri_rewrite;
#endif

View file

@ -1,44 +0,0 @@
#ifndef _fileupload__hpp__included__
#define _fileupload__hpp__included__
#include "library/threads.hpp"
#include "library/httpreq.hpp"
#include "library/httpauth.hpp"
#include <string>
#include <list>
#include <vector>
struct file_upload
{
//Variables.
std::string base_url;
std::vector<char> content;
std::string filename;
std::string title;
std::string description;
std::string gamename;
bool hidden;
//Ctor
file_upload();
~file_upload();
//Lauch.
void do_async();
void _do_async();
void cancel();
//Status.
std::list<std::string> get_messages();
int get_progress_ppm(); //-1 => No progress.
volatile bool finished;
volatile bool success;
std::string final_url;
//Vars.
dh25519_http_auth* dh25519;
http_async_request* req;
std::list<std::string> msgs;
threads::lock m;
void add_msg(const std::string& msg);
};
void get_dh25519_pubkey(uint8_t* out);
#endif

View file

@ -2,117 +2,108 @@
#define _framebuffer__hpp__included__
#include "core/window.hpp"
#include "core/queue.hpp"
#include "library/command.hpp"
#include "library/framebuffer.hpp"
#include "library/triplebuffer.hpp"
#include <stdexcept>
class subtitle_commentary;
class memwatch_set;
class emulator_dispatch;
class lua_state;
class loaded_rom;
class status_updater;
namespace settingvar
{
class group;
}
namespace keyboard
{
class keyboard;
}
/**
* Emulator frame buffer.
* Triple buffering logic.
*/
class emu_framebuffer
class triplebuffer_logic
{
public:
emu_framebuffer(subtitle_commentary& _subtitles, settingvar::group& _settings, memwatch_set& _mwatch,
keyboard::keyboard& _keyboard, emulator_dispatch& _dispatch, lua_state& _lua2, loaded_rom& _rom,
status_updater& _supdater, command::group& _cmd, input_queue& _iqueue);
/**
* Create new triple buffer logic.
*/
triplebuffer_logic() throw(std::bad_alloc);
/**
* Destructor.
*/
~triplebuffer_logic() throw();
/**
* Get index for write buffer.Also starts write cycle.
*
* Returns: Write buffer index (0-2).
*/
unsigned start_write() throw();
/**
* Notify that write cycle has ended.
*/
void end_write() throw();
/**
* Get index for read buffer. Also starts read cycle.
*
* Returns: Read buffer index (0-2).
*/
unsigned start_read() throw();
/**
* Notify that read cycle has ended.
*/
void end_read() throw();
private:
triplebuffer_logic(triplebuffer_logic&);
triplebuffer_logic& operator=(triplebuffer_logic&);
mutex* mut;
unsigned read_active;
unsigned write_active;
unsigned read_active_slot;
unsigned write_active_slot;
unsigned last_complete_slot;
};
/**
* The main framebuffer.
*/
framebuffer::raw main_framebuffer;
extern framebuffer_raw main_framebuffer;
/**
* Special screen: "NO SIGNAL".
*/
extern framebuffer_raw screen_nosignal;
/**
* Special screen: "SYSTEM STATE CORRUPT".
*/
static framebuffer::raw screen_corrupt;
extern framebuffer_raw screen_corrupt;
/**
* The main screen to draw on.
*/
framebuffer::fb<false> main_screen;
extern framebuffer<false> main_screen;
/**
* Initialize special screens.
*
* throws std::bad_alloc: Not enough memory.
*/
static void init_special_screens();
void init_special_screens() throw(std::bad_alloc);
/**
* Copy framebuffer to backing store, running Lua hooks if any.
*/
void redraw_framebuffer(framebuffer::raw& torender, bool no_lua = false, bool spontaneous = false);
void redraw_framebuffer(framebuffer_raw& torender, bool no_lua = false, bool spontaneous = false);
/**
* Redraw the framebuffer, reusing contents from last redraw. Runs lua hooks if last redraw ran them.
*/
void redraw_framebuffer();
void redraw_framebuffer();
/**
* Return last complete framebuffer.
*/
framebuffer::raw get_framebuffer();
framebuffer_raw get_framebuffer() throw(std::bad_alloc);
/**
* Render framebuffer to main screen.
*/
void render_framebuffer();
void render_framebuffer();
/**
* Get the size of current framebuffer.
*/
std::pair<uint32_t, uint32_t> get_framebuffer_size();
std::pair<uint32_t, uint32_t> get_framebuffer_size();
/**
* Take a screenshot to specified file.
*/
void take_screenshot(const std::string& file);
void take_screenshot(const std::string& file) throw(std::bad_alloc, std::runtime_error);
/**
* Get scale factors.
*/
std::pair<uint32_t, uint32_t> get_scale_factors(uint32_t width, uint32_t height);
/**
* Kill pending requests associated with object.
*/
void render_kill_request(void* obj);
/**
* Get latest screen received from core.
*/
framebuffer::raw& render_get_latest_screen();
void render_get_latest_screen_end();
private:
void do_screenshot(command::arg_filename a);
struct render_info
{
framebuffer::raw fbuf;
framebuffer::queue rq;
uint32_t hscl;
uint32_t vscl;
uint32_t lgap;
uint32_t rgap;
uint32_t tgap;
uint32_t bgap;
};
render_info buffer1;
render_info buffer2;
render_info buffer3;
triplebuffer::triplebuffer<render_info> buffering;
bool last_redraw_no_lua;
subtitle_commentary& subtitles;
settingvar::group& settings;
memwatch_set& mwatch;
keyboard::keyboard& keyboard;
emulator_dispatch& edispatch;
lua_state& lua2;
loaded_rom& rom;
status_updater& supdater;
command::group& cmd;
input_queue& iqueue;
command::_fnptr<command::arg_filename> screenshot;
};
void render_kill_request(void* obj);
#endif

View file

@ -2,75 +2,41 @@
#define _framerate__hpp__included__
#include <cstdint>
#include "library/threads.hpp"
#include "library/command.hpp"
#define FRAMERATE_HISTORY_FRAMES 10
/**
* Framerate regulator.
*/
class framerate_regulator
{
public:
framerate_regulator(command::group& _cmd);
/**
* Set the target speed multiplier.
*
* Parameter multiplier: The multiplier target. May be INFINITE.
*/
void set_speed_multiplier(double multiplier) throw();
/**
* Increase the speed to next step.
*/
void increase_speed() throw();
/**
* Decrease the speed to next step.
*/
void decrease_speed() throw();
/**
* Get the target speed multiplier.
*
* Returns: The multiplier. May be INFINITE.
*/
double get_speed_multiplier() throw();
/**
* Sets the nominal frame rate. Framerate limiting tries to maintain the nominal framerate when there is no other
* explict framerate to maintain.
*/
void set_nominal_framerate(double fps) throw();
void set_nominal_framerate(double fps) throw();
/**
* Returns the current realized framerate multiplier.
* Returns the current realized framerate.
*
* returns: The framerate multiplier the system is currently archiving.
* returns: The framerate the system is currently archiving.
*/
double get_realized_multiplier() throw();
double get_framerate() throw();
/**
* Freeze time.
*
* Parameter usec: Current time in microseconds.
*/
void freeze_time(uint64_t usec);
void freeze_time(uint64_t usec);
/**
* Unfreeze time.
*
* Parameter usec: Current time in microseconds.
*/
void unfreeze_time(uint64_t usec);
void unfreeze_time(uint64_t usec);
/**
* Acknowledge frame start for timing purposes. If time is frozen, it is automatically unfrozen.
*
* parameter usec: Current time (relative to some unknown epoch) in microseconds.
*/
void ack_frame_tick(uint64_t usec) throw();
void ack_frame_tick(uint64_t usec) throw();
/**
* Computes the number of microseconds to wait for next frame.
@ -78,48 +44,16 @@ public:
* parameter usec: Current time (relative to some unknown epoch) in microseconds.
* returns: Number of more microseconds to wait.
*/
uint64_t to_wait_frame(uint64_t usec) throw();
uint64_t to_wait_frame(uint64_t usec) throw();
/**
* Return microsecond-resolution time since unix epoch.
*/
static uint64_t get_utime();
uint64_t get_utime();
/**
* Wait specified number of microseconds.
*/
void wait_usec(uint64_t usec);
/**
* Turbo flag.
*/
bool turboed;
private:
void set_speed_cmd(const std::string& args);
uint64_t get_time(uint64_t curtime, bool update);
double get_realized_fps();
void add_frame(uint64_t linear_time);
std::pair<bool, double> read_fps();
//Step should be ODD.
void set_speedstep(unsigned step);
//Step can be EVEN if between steps.
unsigned get_speedstep();
uint64_t last_time_update;
uint64_t time_at_last_update;
bool time_frozen;
uint64_t frame_number;
uint64_t frame_start_times[FRAMERATE_HISTORY_FRAMES];
//Framerate.
double nominal_framerate;
double multiplier_framerate;
bool framerate_realtime_locked;
threads::lock framerate_lock;
command::group& cmd;
command::_fnptr<> turbo_p;
command::_fnptr<> turbo_r;
command::_fnptr<> turbo_t;
command::_fnptr<const std::string&> setspeed_t;
command::_fnptr<> spd_inc;
command::_fnptr<> spd_dec;
};
void wait_usec(uint64_t usec);
#endif

View file

@ -0,0 +1,27 @@
#ifndef _globalwrap__hpp__included__
#define _globalwrap__hpp__included__
/**
* Wrapper for glboal/module-local objects accessable in global ctor context.
*/
template<class T>
class globalwrap
{
public:
/**
* Get the wrapped object.
*
* returns: The wrapped object.
* throws std::bad_alloc: Not enough memory.
*/
T& operator()() throw(std::bad_alloc)
{
if(!storage)
storage = new T();
return *storage;
}
private:
T* storage;
};
#endif

View file

@ -1,74 +0,0 @@
#ifndef _instance_map__hpp__included__
#define _instance_map__hpp__included__
#include <map>
class emulator_instance;
template<typename T> class instance_map
{
public:
/**
* Destroy a instance map.
*/
~instance_map()
{
for(auto i : instances)
delete i.second;
instances.clear();
}
/**
* Does this instance exist?
*/
bool exists(emulator_instance& inst)
{
return instances.count(&inst);
}
/**
* Lookup a instance. Returns NULL if none.
*/
T* lookup(emulator_instance& inst)
{
if(!instances.count(&inst))
return NULL;
return instances[&inst];
}
/**
* Create a new instance.
*/
template<typename... U> T* create(emulator_instance& inst, U... args)
{
T* out = NULL;
try {
out = new T(inst, args...);
instances[&inst] = out;
return out;
} catch(...) {
if(out) delete out;
throw;
}
}
/**
* Erase a instance.
*/
void destroy(emulator_instance& inst)
{
if(instances.count(&inst)) {
delete instances[&inst];
instances.erase(&inst);
}
}
/**
* Remove a instance.
*/
void remove(emulator_instance& inst)
{
if(instances.count(&inst)) {
instances.erase(&inst);
}
}
private:
std::map<emulator_instance*, T*> instances;
};
#endif

View file

@ -1,143 +0,0 @@
#ifndef _instance__hpp__included__
#define _instance__hpp__included__
#include "library/threads.hpp"
#include <cstring>
class movie_logic;
class memory_space;
class memwatch_set;
class voice_commentary;
class subtitle_commentary;
class movie_branches;
class multitrack_edit;
class _lsnes_status;
class alias_binds_manager;
class rrdata;
class cart_mappings_refresher;
class controller_state;
class project_state;
class debug_context;
class framerate_regulator;
class emu_framebuffer;
class input_queue;
class master_dumper;
class button_mapping;
class emulator_dispatch;
class slotinfo_cache;
class lua_state;
class audioapi_instance;
class loaded_rom;
class save_jukebox;
class emulator_runmode;
class status_updater;
namespace command { class group; }
namespace lua { class state; }
namespace settingvar { class group; }
namespace settingvar { class cache; }
namespace keyboard { class keyboard; }
namespace keyboard { class mapper; }
namespace triplebuffer { template<typename T> class triplebuffer; }
class dtor_list
{
struct entry
{
void* ptr;
void (*free1)(void* ptr);
void (*free2)(void* ptr);
entry* prev;
};
public:
dtor_list();
~dtor_list();
void destroy();
template<typename T> void prealloc(T*& ptr)
{
entry e;
e.ptr = ptr = reinterpret_cast<T*>(new char[sizeof(T) + 32]);
memset((char*)ptr, 0, sizeof(T) + 32);
e.free1 = null;
e.free2 = free2;
e.prev = list;
list = new entry(e);
}
template<typename T, typename... U> void init(T*& ptr, U&... args)
{
if(ptr) {
//Find the entry.
entry* e = list;
while(e->ptr != ptr)
e = e->prev;
new(ptr) T(args...);
e->free1 = free1_p<T>;
} else {
entry e;
e.ptr = ptr = new T(args...);
e.free1 = free1<T>;
e.free2 = null;
e.prev = list;
list = new entry(e);
}
}
private:
entry* list;
static void null(void* ptr) {}
static void free2(void* ptr) { delete[] reinterpret_cast<char*>(ptr); }
template<typename T> static void free1(void* ptr) { delete reinterpret_cast<T*>(ptr); }
template<typename T> static void free1_p(void* ptr) { reinterpret_cast<T*>(ptr)->~T(); }
};
struct emulator_instance
{
emulator_instance();
~emulator_instance();
emulator_dispatch* dispatch;
movie_logic* mlogic;
memory_space* memory;
lua::state* lua;
lua_state* lua2;
memwatch_set* mwatch;
settingvar::group* settings;
settingvar::cache* setcache;
voice_commentary* commentary;
subtitle_commentary* subtitles;
movie_branches* mbranch;
controller_state* controls;
button_mapping* buttons;
multitrack_edit* mteditor;
_lsnes_status* status_A;
_lsnes_status* status_B;
_lsnes_status* status_C;
triplebuffer::triplebuffer<_lsnes_status>* status;
keyboard::keyboard* keyboard;
command::group* command;
keyboard::mapper* mapper;
alias_binds_manager* abindmanager;
rrdata* nrrdata;
cart_mappings_refresher* cmapper;
project_state* project;
debug_context* dbg;
framerate_regulator* framerate;
emu_framebuffer* fbuf;
input_queue* iqueue;
master_dumper* mdumper;
slotinfo_cache* slotcache;
audioapi_instance* audio;
loaded_rom* rom;
save_jukebox* jukebox;
emulator_runmode* runmode;
status_updater* supdater;
threads::id emu_thread;
time_t random_seed_value;
dtor_list D;
private:
emulator_instance(const emulator_instance&);
emulator_instance& operator=(const emulator_instance&);
};
extern emulator_instance lsnes_instance;
emulator_instance& CORE();
#endif

View file

@ -4,60 +4,38 @@
#include <list>
#include <cstdint>
#include <string>
#include "library/command.hpp"
class emulator_dispatch;
void voicethread_task();
void voicethread_kill();
void voice_frame_number(uint64_t newframe, double rate);
namespace settingvar
enum external_stream_format
{
class group;
}
class voice_commentary
{
public:
enum external_stream_format
{
EXTFMT_SOX,
EXTFMT_OGGOPUS
};
struct playback_stream_info
{
uint64_t id;
uint64_t base;
uint64_t length;
};
voice_commentary(settingvar::group& _settings, emulator_dispatch& _dispatch, audioapi_instance& _audio,
command::group& _cmd);
~voice_commentary();
void init();
void kill();
void frame_number(uint64_t newframe, double rate);
bool collection_loaded();
std::list<playback_stream_info> get_stream_info();
void play_stream(uint64_t id);
void export_stream(uint64_t id, const std::string& filename, external_stream_format fmt);
uint64_t import_stream(uint64_t ts, const std::string& filename, external_stream_format fmt);
void delete_stream(uint64_t id);
void export_superstream(const std::string& filename);
void load_collection(const std::string& filename);
void unload_collection();
void alter_timebase(uint64_t id, uint64_t ts);
uint64_t parse_timebase(const std::string& n);
double ts_seconds(uint64_t ts);
float get_gain(uint64_t id);
void set_gain(uint64_t id, float gain);
void set_active_flag(bool flag);
private:
void* internal;
settingvar::group& settings;
emulator_dispatch& edispatch;
audioapi_instance& audio;
command::group& cmd;
command::_fnptr<> tangentp;
command::_fnptr<> tangentr;
EXTFMT_OPUSDEMO,
EXTFMT_SOX,
EXTFMT_OGGOPUS
};
struct playback_stream_info
{
uint64_t id;
uint64_t base;
uint64_t length;
};
bool voicesub_collection_loaded();
std::list<playback_stream_info> voicesub_get_stream_info();
void voicesub_play_stream(uint64_t id);
void voicesub_export_stream(uint64_t id, const std::string& filename, external_stream_format fmt);
uint64_t voicesub_import_stream(uint64_t ts, const std::string& filename, external_stream_format fmt);
void voicesub_delete_stream(uint64_t id);
void voicesub_export_superstream(const std::string& filename);
void voicesub_load_collection(const std::string& filename);
void voicesub_unload_collection();
void voicesub_alter_timebase(uint64_t id, uint64_t ts);
uint64_t voicesub_parse_timebase(const std::string& n);
double voicesub_ts_seconds(uint64_t ts);
float voicesub_get_gain(uint64_t id);
void voicesub_set_gain(uint64_t id, float gain);
#endif

105
include/core/joystick.hpp Normal file
View file

@ -0,0 +1,105 @@
#ifndef _joystick__hpp__included__
#define _joystick__hpp__included__
#include "core/keymapper.hpp"
/**
* Create a new joystick.
*
* Parameter id: The id of new joystick.
* Parameter xname: The name of new joystick.
*/
void joystick_create(uint64_t id, const std::string& xname);
/**
* Free all joysticks.
*/
void joystick_quit();
/**
* Create a new axis.
*
* Parameter jid: The id of joystick.
* Parameter id: The id of the axis.
* Parameter minv: The minimal calibration value.
* Parameter maxv: The maximal calibration value.
* Parameter xname: The name of axis.
* Parameter atype: The axis type.
*/
void joystick_new_axis(uint64_t jid, uint64_t id, int64_t minv, int64_t maxv, const std::string& xname,
enum keygroup::type atype);
/**
* Create a new button.
*
* Parameter jid: The id of joystick.
* Parameter id: The id of button.
* Parameter xname: The name of button.
* Returns: The number of button.
*/
void joystick_new_button(uint64_t jid, uint64_t id, const std::string& xname);
/**
* Create a new hat from pair of axes.
*
* Parameter jid: The id of joystick.
* Parameter id_x: The id of x axis of the hat.
* Parameter id_y: The id of y axis of the hat.
* Parameter min_dev: The smallest deviation from zero to react to.
* Parameter xname_x: The name of x axis.
* Parameter xname_y: The name of y axis.
* Returns: The number of hat.
*/
void joystick_new_hat(uint64_t jid, uint64_t id_x, uint64_t id_y, int64_t min_dev, const std::string& xname_x,
const std::string& xname_y);
/**
* Create a new hat from POV control.
*
* Parameter jid: The id of joystick.
* Parameter id: The id of POV control.
* Parameter xname: The name of POV control.
* Returns: The number of hat.
*/
void joystick_new_hat(uint64_t jid, uint64_t id, const std::string& xname);
/**
* Report possible change in axis value.
*
* Requests to update unknown axes are ignored.
*
* Parameter jid: The id of joystick.
* Parameter id: The ID of axis.
* Parameter value: The value.
*/
void joystick_report_axis(uint64_t jid, uint64_t id, int64_t value);
/**
* Report possible change in button value.
*
* Requests to update unknown buttons are ignored.
*
* Parameter jid: The id of joystick.
* Parameter id: The ID of button.
* Parameter value: The value.
*/
void joystick_report_button(uint64_t jid, uint64_t id, bool value);
/**
* Report possible change in POV value.
*
* Requests to update unknown POVs are ignored.
*
* Parameter jid: The id of joystick.
* Parameter id: The ID of POV.
* Parameter value: The angle in hundredths of degree clockwise from up, or negative if centered.
*/
void joystick_report_pov(uint64_t jid, uint64_t id, int angle);
/**
* Print message about joystick.
*
* Parameter jid: The joystick id.
*/
void joystick_message(uint64_t jid);
/**
* Get set of all joysticks.
*/
std::set<uint64_t> joystick_set();
/**
* Flush all pending joystick requests.
*/
void joystick_flush();
#endif

View file

@ -1,44 +0,0 @@
#ifndef _joystickapi__hpp__included__
#define _joystickapi__hpp__included__
//These correspond to various joystick_driver_* functions.
struct _joystick_driver
{
void (*init)();
void (*quit)();
void (*thread_fn)();
void (*signal)();
const char* (*name)();
};
struct joystick_driver
{
joystick_driver(_joystick_driver drv);
};
/**
* Joystick initialization function.
*
* - The third initialization function to be called by window_init().
* - The call occurs in the main thread.
* - Implemented by the joystick plugin.
*/
void joystick_driver_init(bool soft = false) throw();
/**
* Joystick quit function.
*
* - The third last quit function to be called by window_quit().
* - The call occurs in the main thread.
* - Implemented by the joystick plugin.
*/
void joystick_driver_quit(bool soft = false) throw();
/**
* Signal the joystick thread to quit.
*/
void joystick_driver_signal() throw();
/**
* Identification for joystick plugin.
*/
const char* joystick_driver_name();
#endif

View file

@ -1,88 +0,0 @@
#ifndef _jukebox__hpp__included__
#define _jukebox__hpp__included__
#include <functional>
#include <cstdlib>
#include <string>
namespace settingvar { class group; }
class save_jukebox_listener;
/**
* Save jukebox.
*/
class save_jukebox
{
public:
/**
* Ctor.
*/
save_jukebox(settingvar::group& _settings, command::group& _cmd);
/**
* Dtor.
*/
~save_jukebox();
/**
* Get current slot.
*
* Throws std::runtime_exception: No slot selected.
*/
size_t get_slot();
/**
* Set current slot.
*
* Parameter slot: The slot to select.
* Throws std::runtime_exception: Slot out of range.
*/
void set_slot(size_t slot);
/**
* Cycle next slot.
*
* Throws std::runtime_exception: No slot selected.
*/
void cycle_next();
/**
* Cycle previous slot.
*
* Throws std::runtime_exception: No slot selected.
*/
void cycle_prev();
/**
* Get save as binary flag.
*/
bool save_binary();
/**
* Get name of current jukebox slot.
*
* Throws std::runtime_exception: No slot selected.
*/
std::string get_slot_name();
/**
* Set size of jukebox.
*
* Parameter size: The new size.
*/
void set_size(size_t size);
/**
* Set update function.
*/
void set_update(std::function<void()> _update);
/**
* Unset update function.
*/
void unset_update();
private:
void do_slotsel(const std::string& arg);
settingvar::group& settings;
size_t current_slot;
size_t current_size;
std::function<void()> update;
save_jukebox_listener* listener;
command::group& cmd;
command::_fnptr<const std::string&> slotsel;
command::_fnptr<> cycleprev;
command::_fnptr<> cyclenext;
};
#endif

View file

@ -9,29 +9,466 @@
#include <map>
#include <iostream>
#include "misc.hpp"
#include "library/keyboard.hpp"
#include "library/keyboard-mapper.hpp"
#include "library/gamepad.hpp"
/**
* Inverse bindings set.
* Takes in a raw command and returns the command that should be actually executed given the key polarity.
*
* parameter cmd: Raw command.
* parameter polarity: Polarity (True => Being pressed, False => Being released).
* returns: The fixed command, "" if no command should be executed.
* throws std::bad_alloc: Not enough memory.
*/
extern keyboard::invbind_set lsnes_invbinds;
std::string fixup_command_polarity(std::string cmd, bool polarity) throw(std::bad_alloc);
/**
* Gamepad HW.
* Modifier key.
*
* Each object of this class is a modifier key (e.g. left control) or group of modifier keys (e.g. control).
*/
extern gamepad::set lsnes_gamepads;
class modifier
{
public:
/**
* Initialize gamepads (need to be called before initializing joysticks).
* Create a new modifier.
*
* parameter name: Name of the modifier.
* throws std::bad_alloc: Not enough memory.
*/
void lsnes_gamepads_init();
modifier(const std::string& name) throw(std::bad_alloc);
/**
* Deinitialize gamepads (need to be called after deinitializing joysticks).
* Create a new linked modifier.
*
* If modifiers A and B are both linked to C, then:
* - It is legal to specify A and/or B as modifier when modifier mask contains C.
* - If modifier contains C, then both A and B activate it.
*
* The usual use for linked modifiers is when there are two closely related keys (e.g. left ctrl and right ctrl)
* one wants to be able to be referred with single name.
*
* parameter name: Name of the modifier.
* parameter linkgroup: The name of modifier this modifier is linked to (this modifier should be created).
* throws std::bad_alloc: Not enough memory.
*/
void lsnes_gamepads_deinit();
modifier(const std::string& name, const std::string& linkgroup) throw(std::bad_alloc);
/**
* Cleanup the keymapper stuff.
* Destructor
*/
void cleanup_keymapper();
~modifier() throw();
/**
* Look up a modifier.
*
* parameter name: The name of the modifier to look up.
* returns: The looked up modifier.
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: No such modifier is known.
*/
static modifier& lookup(const std::string& name) throw(std::bad_alloc, std::runtime_error);
/**
* Get name of modifier.
*
* returns: The name of this modifier.
* throws: std::bad_alloc: Not enough memory.
*/
std::string name() const throw(std::bad_alloc);
/**
* Get name of linked modifier.
*
* returns: The name of linked modifier, "" if none.
* throws: std::bad_alloc: Not enough memory.
*/
std::string linked_name() const throw(std::bad_alloc);
/**
* Get set of all modifiers.
*/
static std::set<std::string> get_set() throw(std::bad_alloc);
private:
modifier(const modifier&);
modifier& operator=(const modifier&);
std::string modname;
};
/**
* A set of modifier keys.
*/
class modifier_set
{
public:
/**
* Add a modifier into the set.
*
* parameter mod: The modifier to add.
* parameter really: If true, actually add the key. If false, do nothing.
* throws std::bad_alloc: Not enough memory.
*/
void add(const modifier& mod, bool really = true) throw(std::bad_alloc);
/**
* Remove a modifier from the set.
*
* parameter mod: The modifier to remove.
* parameter really: If true, actually remove the key. If false, do nothing.
* throws std::bad_alloc: Not enough memory.
*/
void remove(const modifier& mod, bool really = true) throw(std::bad_alloc);
/**
* Construct modifier set from comma-separated string.
*
* parameter modifiers: The modifiers as string
* returns: The constructed modifier set.
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: Illegal modifier or wrong syntax.
*/
static modifier_set construct(const std::string& modifiers) throw(std::bad_alloc, std::runtime_error);
/**
* Check modifier against its mask for validity.
*
* This method checks that:
* - for each modifier in set, either that or its linkage group is in mask.
* - Both modifier and its linkage group isn't in either set or mask.
*
* parameter set: The set to check.
* parameter mask: The mask to check against.
* returns: True if set is valid, false if not.
* throws std::bad_alloc: Not enough memory.
*/
static bool valid(const modifier_set& set, const modifier_set& mask) throw(std::bad_alloc);
/**
* Check if this modifier set triggers the action.
*
* Modifier set triggers another if for each modifier or linkage group in mask:
* - Modifier appears in both set and trigger.
* - At least one modifier with this linkage group appears in both set and trigger.
* - Modifiers with this linkage group do not appear in either set nor trigger.
*
*/
static bool triggers(const modifier_set& set, const modifier_set& trigger, const modifier_set& mask)
throw(std::bad_alloc);
/**
* Equality check.
*
* parameter m: Another set.
* returns: True if two sets are equal, false if not.
*/
bool operator==(const modifier_set& m) const throw();
private:
friend std::ostream& operator<<(std::ostream& os, const modifier_set& m);
std::set<const modifier*> set;
};
/**
* Debugging print. Prints textual version of set into stream.
*
* parameter os: The stream to print to.
* parameter m: The modifier set to print.
* returns: reference to os.
*/
std::ostream& operator<<(std::ostream& os, const modifier_set& m);
/**
* Key or key group.
*
* Each object of this type is either one key or group of keys.
*/
class keygroup
{
public:
/**
* Key group type.
*/
enum type
{
/**
* Disabled.
*/
KT_DISABLED,
/**
* Singular button.
*/
KT_KEY,
/**
* Pressure-sensitive button
*/
KT_PRESSURE_PM,
KT_PRESSURE_MP,
KT_PRESSURE_0P,
KT_PRESSURE_0M,
KT_PRESSURE_P0,
KT_PRESSURE_M0,
/**
* Axis key pair.
*/
KT_AXIS_PAIR,
KT_AXIS_PAIR_INVERSE,
/**
* Hat.
*/
KT_HAT,
/**
* Mouse axis (this is not a real axis!).
*/
KT_MOUSE
};
/**
* Create a new key group.
*
* parameter name: Name of the key group.
* parameter _clazz: The key class.
* parameter t: Initial type of the key group.
* throws std::bad_alloc: Not enough memory.
*/
keygroup(const std::string& name, const std::string& _clazz, enum type t) throw(std::bad_alloc);
/**
* Destructor
*/
~keygroup() throw();
/**
* Lookup key group by name.
*
* Parameter name: The key group name.
* Returns: The looked up key group, or NULL if not found.
*/
static keygroup* lookup_by_name(const std::string& name) throw();
/**
* Get the set of axes.
*
* Returns: The axis set (all axes).
* Throws std::bad_alloc: Not enough memory.
*/
static std::set<std::string> get_axis_set() throw(std::bad_alloc);
/**
* Change type of key group.
*
* parameter t: New type for the key group.
*/
void change_type(enum type t) throw();
/**
* Change calibration (Axis pairs and pressure buttons only).
*
* parameter left: The control value at extreme negative position.
* parameter center: The control value at center position.
* parameter right: The control value at extreme positive position.
* parameter tolerance: How wide is the neutral zone (must be larger than 0 and smaller than 1).
*/
void change_calibration(short left, short center, short right, double tolerance);
/**
* Change state of this key group.
*
* For KT_KEY, value is zero/nonzero.
* For KT_PRESSURE_* and KT_AXIS_PAIR*, value is -32768...32767.
* For KT_HAT, 1 is up, 2 is right, 4 is down, 8 is left (may be ORed).
* For KT_MOUSE, value is -32768...32767.
*
* parameter pos: New position.
* parameter modifiers: The modifier set that was pressed during the change.
*/
void set_position(short pos, const modifier_set& modifiers) throw();
/**
* Look up individual key by name.
*
* parameter name: The name of the key to look up.
* returns: First element is pointer to key group, second is key index within the group.
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: No such key known.
*/
static std::pair<keygroup*, unsigned> lookup(const std::string& name) throw(std::bad_alloc,
std::runtime_error);
/**
* Look up key group name.
*
* returns: The name of the key group.
* throws std::bad_alloc: Not enough memory.
*/
std::string name() throw(std::bad_alloc);
/**
* Get set of all keys (including subkeys).
*/
static std::set<std::string> get_keys() throw(std::bad_alloc);
/**
* Key group parameters.
*/
struct parameters
{
/**
* Type
*/
enum type ktype;
/**
* Last known raw value.
*/
short last_rawval;
/**
* Calibration left.
*/
short cal_left;
/**
* Calibration center.
*/
short cal_center;
/**
* Calibration right.
*/
short cal_right;
/**
* Calibration tolerance.
*/
double cal_tolerance;
};
/**
* Get parameters.
*/
struct parameters get_parameters();
/**
* Get all key parameters.
*/
static std::map<std::string, struct parameters> get_all_parameters();
/**
* Set callback requests on/off
*/
void request_hook_callback(bool state);
/**
* Get status value.
*/
signed get_value();
/**
* Get class.
*/
const std::string& get_class();
private:
signed state;
enum type ktype;
short last_rawval;
short cal_left;
short cal_center;
short cal_right;
double cal_tolerance;
double compensate(short value);
double compensate2(double value);
void run_listeners(const modifier_set& modifiers, unsigned subkey, bool polarity, bool really, double x);
std::string keyname;
std::string clazz;
bool requests_hook;
};
/**
* This class handles internals of mapping events from keyboard buttons and pseudo-buttons.
*/
class keymapper
{
public:
/**
* Binds a key, erroring out if binding would conflict with existing one.
*
* parameter mod: Modifier set to require to be pressed.
* parameter modmask: Modifier set to take into account.
* parameter keyname: Key to bind the action to.
* parameter command: The command to bind.
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: The binding would conflict with existing one or invalid modifier/key.
*/
static void bind(std::string mod, std::string modmask, std::string keyname, std::string command)
throw(std::bad_alloc, std::runtime_error);
/**
* Unbinds a key, erroring out if binding does not exist..
*
* parameter mod: Modifier set to require to be pressed.
* parameter modmask: Modifier set to take into account.
* parameter keyname: Key to bind the action to.
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: The binding does not exist.
*/
static void unbind(std::string mod, std::string modmask, std::string keyname) throw(std::bad_alloc,
std::runtime_error);
/**
* Dump list of bindigns as message to console.
*
* throws std::bad_alloc: Not enough memory.
*/
static void dumpbindings() throw(std::bad_alloc);
/**
* Get keys bound.
*/
static std::set<std::string> get_bindings() throw(std::bad_alloc);
/**
* Get command for key.
*/
static std::string get_command_for(const std::string& keyspec) throw(std::bad_alloc);
/**
* Bind command for key.
*/
static void bind_for(const std::string& keyspec, const std::string& cmd) throw(std::bad_alloc,
std::runtime_error);
};
class inverse_key
{
public:
/**
* Create inverse key.
*
* Parameter command: Command this is for.
* Parameter name: Name of inverse key.
*/
inverse_key(const std::string& command, const std::string& name) throw(std::bad_alloc);
/**
* Destructor.
*/
~inverse_key();
/**
* Get set of inverse keys.
*
* Returns: The set of all inverses.
*/
static std::set<inverse_key*> get_ikeys() throw(std::bad_alloc);
/**
* Find by command.
*
* Parameter command: The command.
* Returns: The instance.
*/
static inverse_key* get_for(const std::string& command) throw(std::bad_alloc);
/**
* Get keyspec.
*
* Parameter primary: If true, get the primary key, else secondary key.
* Returns: The keyspec.
*/
std::string get(bool primary) throw(std::bad_alloc);
/**
* Clear key (if primary is cleared, secondary becomes primary).
*
* Parameter primary: If true, clear the primary, else the secondary.
*/
void clear(bool primary) throw(std::bad_alloc);
/**
* Set key.
*
* Parameter keyspec: The new keyspec.
* Parameter primary: If true, set the primary, else the secondary.
*/
void set(std::string keyspec, bool primary) throw(std::bad_alloc);
/**
* Notify updated mapping.
*/
static void notify_update(const std::string& keyspec, const std::string& command);
/**
* Get name for command.
*
* Returns: The name.
*/
std::string getname() throw(std::bad_alloc);
private:
inverse_key(const inverse_key&);
inverse_key& operator=(const inverse_key&);
static std::set<inverse_key*>& ikeys();
static std::map<std::string, inverse_key*>& forkey();
void addkey(const std::string& keyspec);
std::string cmd;
std::string oname;
std::string primary_spec;
std::string secondary_spec;
};
#endif

View file

@ -1,14 +1,10 @@
#ifndef _loadlib__hpp__included__
#define _loadlib__hpp__included__
#include "library/loadlib.hpp"
#include <string>
void handle_post_loadlibrary();
void autoload_libraries(void(*on_error)(const std::string& libname, const std::string& err, bool system) = NULL);
void with_loaded_library(const loadlib::module& l);
bool with_unloaded_library(loadlib::module& l);
std::string loadlib_debug_get_user_library_dir();
std::string loadlib_debug_get_system_library_dir();
void load_library(const std::string& filename);
extern const bool load_library_supported;
extern const char* library_is_called;
#endif
#endif

View file

@ -1,7 +1,6 @@
#ifndef _mainloop__hpp__included__
#define _mainloop__hpp__included__
#include "settings.hpp"
#include "rom.hpp"
#include "moviefile.hpp"
#include "movie.hpp"
@ -9,10 +8,11 @@
/**
* \brief Emulator main loop.
*/
void main_loop(struct loaded_rom& rom, struct moviefile& settings, bool load_has_to_succeed = false);
void main_loop(struct loaded_rom& rom, struct moviefile& settings, bool load_has_to_succeed = false)
throw(std::bad_alloc, std::runtime_error);
std::vector<std::string> get_jukebox_names();
void set_jukebox_names(const std::vector<std::string>& newj);
void init_main_callbacks();
void update_movie_state();
extern std::string msu1_base_path;
/**
@ -24,14 +24,5 @@ extern std::string msu1_base_path;
void mainloop_signal_need_rewind(void* ptr);
void set_stop_at_frame(uint64_t frame = 0);
void switch_projects(const std::string& newproj);
void close_rom();
void load_new_rom(const romload_request& req);
void reload_current_rom();
void do_break_pause();
void convert_break_to_pause();
extern settingvar::supervariable<settingvar::model_bool<settingvar::yes_no>> movie_dflt_binary;
extern settingvar::supervariable<settingvar::model_bool<settingvar::yes_no>> save_dflt_binary;
#endif

View file

@ -1,32 +0,0 @@
#ifndef _mbranch__hpp__included__
#define _mbranch__hpp__included__
#define MBRANCH_IMPORT_TEXT 0
#define MBRANCH_IMPORT_BINARY 1
#define MBRANCH_IMPORT_MOVIE 2
class emulator_dispatch;
class status_updater;
class movie_logic;
struct movie_branches
{
movie_branches(movie_logic& _mlogic, emulator_dispatch& _dispatch, status_updater& _supdater);
std::string name(const std::string& internal);
std::set<std::string> enumerate();
std::string get();
void set(const std::string& branch);
void _new(const std::string& branch, const std::string& from);
void rename(const std::string& oldn, const std::string& newn);
void _delete(const std::string& branch);
std::set<std::string> _movie_branches(const std::string& filename);
void import_branch(const std::string& filename, const std::string& ibranch, const std::string& branchname,
int mode);
void export_branch(const std::string& filename, const std::string& branchname, bool binary);
private:
movie_logic& mlogic;
emulator_dispatch& edispatch;
status_updater& supdater;
};
#endif

View file

@ -7,19 +7,481 @@
#include <cstdint>
#include <stdexcept>
class memory_space;
class movie_logic;
class loaded_rom;
/**
* \brief Information about region of memory
*
* This structure contains information about memory region.
*/
struct memory_region
{
/**
* \brief Name of region.
*
* This is name of region, mainly for debugging and showing to the user.
*/
std::string region_name;
/**
* \brief Base address of region.
*/
uint64_t baseaddr;
/**
* \brief Size of region in bytes.
*/
uint64_t size;
/**
* \brief Last valid address in this region.
*/
uint64_t lastaddr;
/**
* \brief True for ROM, false for RAM.
*/
bool readonly;
/**
* \brief True for I/O space, false for fixed memory.
*/
bool iospace;
/**
* \brief Endianess of the region.
*
* If true, region uses host endian.
* If false, region uses SNES (big) endian.
*/
bool native_endian;
};
class cart_mappings_refresher
/**
* \brief Refresh cart memory mappings
*
* This function rereads cartridge memory map. Call after loading a new cartridge.
*
* \throws std::bad_alloc Not enough memory.
*/
void refresh_cart_mappings() throw(std::bad_alloc);
/**
* \brief Get listing of all regions
*
* This function returns a list of all known regions.
*
* \return All regions
* \throws std::bad_alloc Not enough memory.
*/
std::vector<struct memory_region> get_regions() throw(std::bad_alloc);
/**
* \brief Read byte from memory
*
* This function reads one byte from memory.
*
* \param addr The address to read.
* \return The byte read.
*/
uint8_t memory_read_byte(uint64_t addr) throw();
/**
* \brief Read bytes from memory
*
* This function read table of bytes from memory.
*
* \param addr The address to read.
* \param size The size to read.
* \param data The place to store values read.
*
* \note This does not cross VMAs.
*/
void memory_read_bytes(uint64_t addr, uint64_t size, char* data) throw();
/**
* \brief Read word from memory
*
* This function reads two bytes from memory.
*
* \param addr The address to read.
* \return The word read.
*/
uint16_t memory_read_word(uint64_t addr) throw();
/**
* \brief Read dword from memory
*
* This function reads four bytes from memory.
*
* \param addr The address to read.
* \return The dword read.
*/
uint32_t memory_read_dword(uint64_t addr) throw();
/**
* \brief Read qword from memory
*
* This function reads eight bytes from memory.
*
* \param addr The address to read.
* \return The qword read.
*/
uint64_t memory_read_qword(uint64_t addr) throw();
/**
* \brief Write byte to memory
*
* This function writes one byte to memory.
*
* \param addr The address to write.
* \param data The value to write.
* \return true if the write succeeded.
*/
bool memory_write_byte(uint64_t addr, uint8_t data) throw();
/**
* \brief Write bytes to memory
*
* This function writes table of bytes to memory.
*
* \param addr The address to write.
* \param size The size of area to write.
* \param data The value to write.
*
* \note This does not cross VMAs.
*/
void memory_write_bytes(uint64_t addr, uint64_t size, const char* data) throw();
/**
* \brief Write word to memory
*
* This function writes two bytes to memory.
*
* \param addr The address to write.
* \param data The value to write.
* \return true if the write succeeded.
*/
bool memory_write_word(uint64_t addr, uint16_t data) throw();
/**
* \brief Write dword to memory
*
* This function writes four bytes to memory.
*
* \param addr The address to write.
* \param data The value to write.
* \return true if the write succeeded.
*/
bool memory_write_dword(uint64_t addr, uint32_t data) throw();
/**
* \brief Write qword to memory
*
* This function writes eight bytes to memory.
*
* \param addr The address to write.
* \param data The value to write.
* \return true if the write succeeded.
*/
bool memory_write_qword(uint64_t addr, uint64_t data) throw();
/**
* \brief Memory search context
*
* Context for memory search. Each individual context is independent.
*/
class memorysearch
{
public:
cart_mappings_refresher(memory_space& _mspace, movie_logic& _mlogic, loaded_rom& _rom);
void operator()();
/**
* \brief Create new memory search context.
*
* Creates a new memory search context with all addresses.
*
* \throws std::bad_alloc Not enough memory.
*/
memorysearch() throw(std::bad_alloc);
/**
* \brief Reset the context
*
* Reset the context so all addresses are candidates again.
*
* \throws std::bad_alloc Not enough memory.
*/
void reset() throw(std::bad_alloc);
/**
* \brief Search for address satisfying criteria
*
* This searches the memory space, leaving those addresses for which condition object returns true.
*
* \param obj The condition to search for.
*/
template<class T>
void search(const T& obj) throw();
/**
* \brief Search for byte with specified value
* \param value The value to search for
*/
void byte_value(uint8_t value) throw();
void byte_difference(uint8_t value) throw();
/**
* \brief Search for bytes that are signed less
*/
void byte_slt() throw();
/**
* \brief Search for bytes that are signed less or equal
*/
void byte_sle() throw();
/**
* \brief Search for bytes that are signed equal
*/
void byte_seq() throw();
/**
* \brief Search for bytes that are signed not equal
*/
void byte_sne() throw();
/**
* \brief Search for bytes that are signed greater or equal
*/
void byte_sge() throw();
/**
* \brief Search for bytes that are signed greater
*/
void byte_sgt() throw();
/**
* \brief Search for bytes that are unsigned less
*/
void byte_ult() throw();
/**
* \brief Search for bytes that are unsigned less or equal
*/
void byte_ule() throw();
/**
* \brief Search for bytes that are unsigned equal
*/
void byte_ueq() throw();
/**
* \brief Search for bytes that are unsigned not equal
*/
void byte_une() throw();
/**
* \brief Search for bytes that are unsigned greater or equal
*/
void byte_uge() throw();
/**
* \brief Search for bytes that are unsigned greater
*/
void byte_ugt() throw();
void byte_seqlt() throw();
void byte_seqle() throw();
void byte_seqge() throw();
void byte_seqgt() throw();
/**
* \brief Search for word with specified value
* \param value The value to search for
*/
void word_value(uint16_t value) throw();
void word_difference(uint16_t value) throw();
/**
* \brief Search for words that are signed less
*/
void word_slt() throw();
/**
* \brief Search for words that are signed less or equal
*/
void word_sle() throw();
/**
* \brief Search for words that are signed equal
*/
void word_seq() throw();
/**
* \brief Search for words that are signed not equal
*/
void word_sne() throw();
/**
* \brief Search for words that are signed greater or equal
*/
void word_sge() throw();
/**
* \brief Search for words that are signed greater
*/
void word_sgt() throw();
/**
* \brief Search for words that are unsigned less
*/
void word_ult() throw();
/**
* \brief Search for words that are unsigned less or equal
*/
void word_ule() throw();
/**
* \brief Search for words that are unsigned equal
*/
void word_ueq() throw();
/**
* \brief Search for words that are unsigned not equal
*/
void word_une() throw();
/**
* \brief Search for words that are unsigned greater or equal
*/
void word_uge() throw();
/**
* \brief Search for words that are unsigned greater
*/
void word_ugt() throw();
void word_seqlt() throw();
void word_seqle() throw();
void word_seqge() throw();
void word_seqgt() throw();
/**
* \brief Search for dword with specified value
* \param value The value to search for
*/
void dword_value(uint32_t value) throw();
void dword_difference(uint32_t value) throw();
/**
* \brief Search for dwords that are signed less
*/
void dword_slt() throw();
/**
* \brief Search for dwords that are signed less or equal
*/
void dword_sle() throw();
/**
* \brief Search for dwords that are signed equal
*/
void dword_seq() throw();
/**
* \brief Search for dwords that are signed not equal
*/
void dword_sne() throw();
/**
* \brief Search for dwords that are signed greater or equal
*/
void dword_sge() throw();
/**
* \brief Search for dwords that are signed greater
*/
void dword_sgt() throw();
/**
* \brief Search for dwords that are unsigned less
*/
void dword_ult() throw();
/**
* \brief Search for dwords that are unsigned less or equal
*/
void dword_ule() throw();
/**
* \brief Search for dwords that are unsigned equal
*/
void dword_ueq() throw();
/**
* \brief Search for dwords that are unsigned not equal
*/
void dword_une() throw();
/**
* \brief Search for dwords that are unsigned greater or equal
*/
void dword_uge() throw();
/**
* \brief Search for dwords that are unsigned greater
*/
void dword_ugt() throw();
void dword_seqlt() throw();
void dword_seqle() throw();
void dword_seqge() throw();
void dword_seqgt() throw();
/**
* \brief Search for qword with specified value
* \param value The value to search for
*/
void qword_value(uint64_t value) throw();
void qword_difference(uint64_t value) throw();
/**
* \brief Search for qwords that are signed less
*/
void qword_slt() throw();
/**
* \brief Search for qwords that are signed less or equal
*/
void qword_sle() throw();
/**
* \brief Search for qwords that are signed equal
*/
void qword_seq() throw();
/**
* \brief Search for qwords that are signed not equal
*/
void qword_sne() throw();
/**
* \brief Search for qwords that are signed greater or equal
*/
void qword_sge() throw();
/**
* \brief Search for qwords that are signed greater
*/
void qword_sgt() throw();
/**
* \brief Search for qwords that are unsigned less
*/
void qword_ult() throw();
/**
* \brief Search for qwords that are unsigned less or equal
*/
void qword_ule() throw();
/**
* \brief Search for qwords that are unsigned equal
*/
void qword_ueq() throw();
/**
* \brief Search for qwords that are unsigned not equal
*/
void qword_une() throw();
/**
* \brief Search for qwords that are unsigned greater or equal
*/
void qword_uge() throw();
/**
* \brief Search for qwords that are unsigned greater
*/
void qword_ugt() throw();
void qword_seqlt() throw();
void qword_seqle() throw();
void qword_seqge() throw();
void qword_seqgt() throw();
/**
* \brief DQ a range of addresses (inclusive on both ends!).
*/
void dq_range(uint64_t first, uint64_t last);
/**
* \brief Search for all bytes (update values)
*/
void update() throw();
/**
* \brief Get number of memory addresses that are still candidates
*
* This returns the number of memory addresses satisfying constraints so far.
*
* \return The number of candidates
*/
uint64_t get_candidate_count() throw();
/**
* \brief Get List of all candidate addresses
*
* Returns list of all candidates. This function isn't lazy, so be careful when calling with many candidates.
*
* \return Candidate address list
* \throws std::bad_alloc Not enough memory.
*/
std::list<uint64_t> get_candidates() throw(std::bad_alloc);
private:
memory_space& mspace;
movie_logic& mlogic;
loaded_rom& rom;
std::vector<uint8_t> previous_content;
std::vector<uint64_t> still_in;
uint64_t candidates;
};
#endif

View file

@ -4,189 +4,11 @@
#include <string>
#include <stdexcept>
#include <set>
#include <functional>
#include "library/memorywatch.hpp"
#include "library/json.hpp"
class memory_space;
class project_state;
class loaded_rom;
class emu_framebuffer;
namespace framebuffer { class queue; }
std::string evaluate_watch(const std::string& expr) throw(std::bad_alloc);
std::set<std::string> get_watches() throw(std::bad_alloc);
std::string get_watchexpr_for(const std::string& w) throw(std::bad_alloc);
void set_watchexpr_for(const std::string& w, const std::string& expr) throw(std::bad_alloc);
void do_watch_memory();
/**
* lsnes memory watch printer variables.
*/
struct memwatch_printer
{
/**
* Ctor.
*/
memwatch_printer();
/**
* Serialize the printer to JSON value.
*/
JSON::node serialize();
/**
* Unserialize the printer from JSON value.
*/
void unserialize(const JSON::node& node);
/**
* Get a printer object corresponding to this object.
*/
GC::pointer<memorywatch::item_printer> get_printer_obj(
std::function<GC::pointer<mathexpr::mathexpr>(const std::string& n)> vars);
//Fields.
enum position_category {
PC_DISABLED,
PC_MEMORYWATCH,
PC_ONSCREEN
} position;
bool cond_enable; //Ignored for disabled.
std::string enabled; //Ignored for disabled.
std::string onscreen_xpos;
std::string onscreen_ypos;
bool onscreen_alt_origin_x;
bool onscreen_alt_origin_y;
bool onscreen_cliprange_x;
bool onscreen_cliprange_y;
std::string onscreen_font; //"" is system default.
int64_t onscreen_fg_color;
int64_t onscreen_bg_color;
int64_t onscreen_halo_color;
};
/**
* lsnes memory watch item.
*/
struct memwatch_item
{
/**
* Ctor.
*/
memwatch_item();
/**
* Serialize the item to JSON value.
*/
JSON::node serialize();
/**
* Unserialize the item from JSON value.
*/
void unserialize(const JSON::node& node);
/**
* Get memory read operator.
*
* If bytes == 0, returns NULL.
*/
mathexpr::operinfo* get_memread_oper(memory_space& memory, loaded_rom& rom);
/**
* Translate compatiblity item.
*/
void compatiblity_unserialize(memory_space& memory, const std::string& item);
//Fields
memwatch_printer printer; //The printer.
std::string expr; //The main expression.
std::string format; //Format.
unsigned bytes; //Number of bytes to read (0 => Not memory read operator).
bool signed_flag; //Is signed?
bool float_flag; //Is float?
int endianess; //Endianess (-1 => little, 0 => host, 1 => Big).
uint64_t scale_div; //Scale divisor.
uint64_t addr_base; //Address base.
uint64_t addr_size; //Address size (0 => All).
};
struct memwatch_set
{
memwatch_set(memory_space& _memory, project_state& _project, emu_framebuffer& _fbuf,
loaded_rom& rom);
/**
* Get the specified memory watch item.
*/
memwatch_item& get(const std::string& name);
/**
* Get the specified memory watch item as JSON serialization.
*
* Parameter name: The item name.
* Parameter printer: JSON pretty-printer to use.
*/
std::string get_string(const std::string& name, JSON::printer* printer = NULL);
/**
* Set the specified memory watch item. Fills the runtime variables.
*
* Parameter name: The name of the new item.
* Parameter item: The item to insert. Fields are shallow-copied.
*/
void set(const std::string& name, memwatch_item& item);
/**
* Set the specified memory watch item from JSON serialization. Fills the runtime variables.
*
* Parameter name: The name of the new item.
* Parameter item: The serialization of item to insert.
*/
void set(const std::string& name, const std::string& item);
/**
* Set multiple items at once.
*
* Parameter list: The list of items.
*/
void set_multi(std::list<std::pair<std::string, memwatch_item>>& list);
/**
* Set multiple items at once from JSON descriptions.
*
* Parameter list: The list of items.
*/
void set_multi(std::list<std::pair<std::string, std::string>>& list);
/**
* Rename a memory watch item.
*
* Parameter oname: The old name.
* Parameter newname: The new name.
* Returns: True on success, false if failed (new item already exists).
*/
bool rename(const std::string& oname, const std::string& newname);
/**
* Delete an item.
*
* Parameter name: The name of the item to delete.
*/
void clear(const std::string& name);
/**
* Delete multiple items.
*
* Parameter names: The names of the items to delete.
*/
void clear_multi(const std::set<std::string>& name);
/**
* Enumerate item names.
*/
std::set<std::string> enumerate();
/**
* Get value of specified memory watch as a string.
*/
std::string get_value(const std::string& name);
/**
* Watch all the items.
*
* Parameter rq: The render queue to use.
*/
void watch(struct framebuffer::queue& rq);
/**
* Get memory watch vars that go to window.
*/
const std::map<std::string, std::u32string>& get_window_vars() { return window_vars; }
private:
void rebuild(std::map<std::string, memwatch_item>& nitems);
std::map<std::string, memwatch_item> items;
std::map<std::string, std::u32string> window_vars;
std::map<std::string, bool> used_memorywatches;
void erase_unused_watches();
void watch_output(const std::string& name, const std::string& value);
memorywatch::set watch_set;
memory_space& memory;
project_state& project;
emu_framebuffer& fbuf;
loaded_rom& rom;
};
#endif
#endif

View file

@ -1,5 +1,5 @@
#ifndef _library__messagebuffer__hpp__included__
#define _library__messagebuffer__hpp__included__
#ifndef _messagebuffer__hpp__included__
#define _messagebuffer__hpp__included__
#include <stdexcept>
#include <map>
@ -23,7 +23,7 @@ public:
/**
* Handle update.
*/
virtual void messagebuffer_update() = 0;
virtual void messagebuffer_update() throw(std::bad_alloc, std::runtime_error) = 0;
};
/**
* Create new message buffer with specified maximum message count.
@ -33,7 +33,7 @@ public:
* Throws std::bad_alloc: Not enough memory.
* Throws std::logic_error: Windowsize is greater than maxmessages or maxmessages is zero.
*/
messagebuffer(size_t maxmessages, size_t windowsize);
messagebuffer(size_t maxmessages, size_t windowsize) throw(std::bad_alloc, std::logic_error);
/**
* Add a new message to the buffer.
@ -42,7 +42,7 @@ public:
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Thrown through from update handler.
*/
void add_message(const std::string& msg);
void add_message(const std::string& msg) throw(std::bad_alloc, std::runtime_error);
/**
* Read a message.
@ -52,7 +52,7 @@ public:
* Throws std::bad_alloc: Not enough memory.
* Throws std::logic_error: Invalid message number.
*/
const std::string& get_message(size_t msgnum);
const std::string& get_message(size_t msgnum) throw(std::bad_alloc, std::logic_error);
/**
* Get the number of first message present.
@ -117,7 +117,7 @@ public:
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Thrown through from update handler.
*/
void scroll_beginning();
void scroll_beginning() throw(std::bad_alloc, std::runtime_error);
/**
* Scroll up one page.
@ -125,7 +125,7 @@ public:
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Thrown through from update handler.
*/
void scroll_up_page();
void scroll_up_page() throw(std::bad_alloc, std::runtime_error);
/**
* Scroll up one line.
@ -133,7 +133,7 @@ public:
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Thrown through from update handler.
*/
void scroll_up_line();
void scroll_up_line() throw(std::bad_alloc, std::runtime_error);
/**
* Scroll down one line.
@ -141,7 +141,7 @@ public:
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Thrown through from update handler.
*/
void scroll_down_line();
void scroll_down_line() throw(std::bad_alloc, std::runtime_error);
/**
* Scroll down one page.
@ -149,7 +149,7 @@ public:
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Thrown through from update handler.
*/
void scroll_down_page();
void scroll_down_page() throw(std::bad_alloc, std::runtime_error);
/**
* Scroll to beginning.
@ -157,7 +157,7 @@ public:
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Thrown through from update handler.
*/
void scroll_end();
void scroll_end() throw(std::bad_alloc, std::runtime_error);
/**
* Register an update handler.
@ -165,7 +165,7 @@ public:
* Parameter handler: The new handler.
* Throws std::bad_alloc: Not enough memory.
*/
void register_handler(update_handler& handler);
void register_handler(update_handler& handler) throw(std::bad_alloc);
/**
* Unregister an update handler.
@ -182,16 +182,12 @@ public:
* Throws std::bad_alloc: Not enough memory.
* Throws std::logic_error: Windowsize is greater than maxmessages or maxmessages is zero.
*/
void set_max_window_size(size_t windowsize);
void set_max_window_size(size_t windowsize) throw(std::bad_alloc, std::logic_error);
/**
* Read the window size.
*/
size_t get_max_window_size() throw();
/**
* Read the last message.
*/
std::string get_last_message();
private:
void send_notifications();
std::map<uint64_t, std::string> messages_buf;

View file

@ -1,25 +0,0 @@
#ifndef _messages__hpp__included__
#define _messages__hpp__included__
#include <iostream>
/**
* messages -> window::out().
*/
class messages_relay_class
{
public:
operator std::ostream&() { return getstream(); }
static std::ostream& getstream();
};
template<typename T> inline std::ostream& operator<<(messages_relay_class& x, T value)
{
return messages_relay_class::getstream() << value;
};
inline std::ostream& operator<<(messages_relay_class& x, std::ostream& (*fn)(std::ostream& o))
{
return fn(messages_relay_class::getstream());
};
extern messages_relay_class messages;
#endif

View file

@ -4,8 +4,57 @@
#include <string>
#include <vector>
#include <stdexcept>
#include "library/string.hpp"
#include "library/memtracker.hpp"
/**
* \brief Get random hexes
*
* Get string of random hex characters of specified length.
*
* \param length The number of hex characters to return.
* \return The random hexadecimal string.
* \throws std::bad_alloc Not enough memory.
*/
std::string get_random_hexstring(size_t length) throw(std::bad_alloc);
/**
* \brief Set random seed
*
* This function sets the random seed to use.
*
* \param seed The value to use as seed.
* \throw std::bad_alloc Not enough memory.
*/
void set_random_seed(const std::string& seed) throw(std::bad_alloc);
/**
* \brief Set random seed to (hopefully) unique value
*
* This function sets the random seed to value that should only be used once. Note, the value is not necressarily
* crypto-secure, even if it is unique.
*
* \throw std::bad_alloc Not enough memory.
*/
void set_random_seed() throw(std::bad_alloc);
/**
* \brief Load a ROM.
*
* Given commandline arguments, load a ROM.
*
* \param cmdline The command line.
* \return The loaded ROM set.
* \throws std::bad_alloc Not enough memory.
* \throws std::runtime_error Can't load the ROMset.
*/
struct loaded_rom load_rom_from_commandline(std::vector<std::string> cmdline) throw(std::bad_alloc,
std::runtime_error);
/**
* \brief Dump listing of regions to graphics system messages.
*
* \throws std::bad_alloc Not enough memory.
*/
void dump_region_map() throw(std::bad_alloc);
/**
* \brief Fatal error.
@ -20,16 +69,36 @@ void fatal_error() throw();
* \return The config directory path.
* \throw std::bad_alloc Not enough memory.
*/
std::string get_config_path();
std::string get_config_path() throw(std::bad_alloc);
/**
* \brief Panic on OOM.
*/
void OOM_panic();
/**
* messages -> window::out().
*/
class messages_relay_class
{
public:
operator std::ostream&() { return getstream(); }
static std::ostream& getstream();
};
template<typename T> inline std::ostream& operator<<(messages_relay_class& x, T value)
{
return messages_relay_class::getstream() << value;
};
inline std::ostream& operator<<(messages_relay_class& x, std::ostream& (*fn)(std::ostream& o))
{
return fn(messages_relay_class::getstream());
};
extern messages_relay_class messages;
uint32_t gcd(uint32_t a, uint32_t b) throw();
void create_lsnesrc();
/**
* Return hexadecimal representation of address
*/
@ -44,19 +113,4 @@ bool in_global_ctors();
*/
void reached_main();
/**
* Clean up filename from dangerous chars
*/
std::string safe_filename(const std::string& str);
/**
* Mangle some characters ()|/
*/
std::string mangle_name(const std::string& orig);
/**
* Return a new temporary file. The file will be created.
*/
std::string get_temp_file();
#endif

View file

@ -4,13 +4,316 @@
#include <string>
#include <cstdint>
#include <stdexcept>
#include "core/controllerframe.hpp"
#include "core/moviefile.hpp"
#include "library/rrdata.hpp"
#include "library/movie.hpp"
#include "controllerframe.hpp"
/**
* Class encapsulating bridge logic between core interface and movie code.
* Movie being played back or recorded
*/
class movie
{
public:
/**
* Construct new empty movie.
*
* throws std::bad_alloc: Not enough memory.
*/
movie() throw(std::bad_alloc);
/**
* Is the movie in readonly mode?
*
* returns: True if in read-only mode, false if in read-write mode.
*/
bool readonly_mode() throw();
/**
* Switches movie to read-only or read-write mode. If switching to read-write mode, the movie is truncated.
*
* parameter enable: If true, switch to read-only mode, else to read-write mode.
* throws std::bad_alloc: Not enough memory.
*/
void readonly_mode(bool enable) throw(std::bad_alloc);
/**
* Returns the movie rerecord count (this is not the same thing as global rerecord count).
*
* returns: The movie rerecord count
* throws std::bad_alloc: Not enough memory.
*/
std::string rerecord_count() throw(std::bad_alloc);
/**
* Sets the movie rerecord count (this is not the same thing as global rerecord count).
*
* parameter count: The new rerecord count
* throws std::bad_alloc: Not enough memory.
*/
void rerecord_count(const std::string& count) throw(std::bad_alloc);
/**
* Read project ID
*
* returns: The project ID
* throws std::bad_alloc: Not enough memory.
*/
std::string project_id() throw(std::bad_alloc);
/**
* brief Set project ID
*
* parameter id: New project ID.
* throws std::bad_alloc: Not enough memory.
*/
void project_id(const std::string& id) throw(std::bad_alloc);
/**
* Get number of frames in movie
*
* returns: The number of frames.
*/
uint64_t get_frame_count() throw();
/**
* Get number of current frame in movie
*
* The first frame in movie is 1. 0 is "before first frame" value.
*
* returns: The number of frame
*/
uint64_t get_current_frame() throw();
/**
* Get number of lag frames so far
*
* returns: The number of lag frames.
*/
uint64_t get_lag_frames() throw();
/**
* This function advances to next frame in movie, discarding subframes not used. If the frame is lag frame, it is
* counted as lag frame and subframe entry for it is made (if in readwrite mode).
*
* throws std::bad_alloc: Not enough memory.
*/
void next_frame() throw(std::bad_alloc);
/**
* Reads the data ready flag. On new frame, all data ready flags are unset. On reading control, its data ready
* flag is unset.
*
* parameter pid: Physical controller id.
* parameter index: Control ID.
* returns: The read value.
* throws std::logic_error: Invalid control index.
*/
bool get_DRDY(unsigned pid, unsigned index) throw(std::logic_error);
/**
* Set all data ready flags
*/
void set_all_DRDY() throw();
/**
* Poll a control by (port, controller, index) tuple.
*
* parameter pid: Physical controller ID.
* parameter index: The index of control in controller (0 to 11)
* returns: The read value
* throws std::bad_alloc: Not enough memory.
* throws std::logic_error: Invalid port, controller or index or before movie start.
*/
short next_input(unsigned pid, unsigned index) throw(std::bad_alloc, std::logic_error);
/**
* Set current control values. These are read in readwrite mode.
*
* parameter controls: The new controls.
*/
void set_controls(controller_frame controls) throw();
/**
* Get current control values in effect.
*
* returns: Controls
*/
controller_frame get_controls() throw();
/**
* Loads a movie plus some other parameters. The playback pointer is positioned to start of movie and readonly
* mode is enabled.
*
* parameter rerecs: Movie rerecord count.
* parameter project_id: Project ID of movie.
* parameter input: The input track.
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: Bad movie data.
*/
void load(const std::string& rerecs, const std::string& project_id, controller_frame_vector& input)
throw(std::bad_alloc, std::runtime_error);
/**
* Saves the movie data.
*
* returns: The movie data.
* throws std::bad_alloc: Not enough memory.
*/
controller_frame_vector save() throw(std::bad_alloc);
/**
* This method serializes the state of movie code.
*
* Parameter proj_id: The project ID is written here.
* Parameter curframe: Current frame is written here.
* Parameter lagframes: Lag counter is written here.
* Parameter pcounters: Poll counters are written here.
* throws std::bad_alloc: Not enough memory.
*/
void save_state(std::string& proj_id, uint64_t& curframe, uint64_t& lagframes,
std::vector<uint32_t>& pcounters) throw(std::bad_alloc);
/**
* Given previous serialized state from this movie, restore the state.
*
* Parameter curframe: Current frame.
* Parameter lagframe: Lag counter.
* Parameter pcounters: Poll counters.
* Parameter ro: If true, restore in readonly mode.
* Parameter old_movie: Old movie to check for compatiblity against.
* Parameter old_projectid: Old project ID to check against.
* Returns: ???
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Movie check failure.
*/
size_t restore_state(uint64_t curframe, uint64_t lagframe, const std::vector<uint32_t>& pcounters, bool ro,
controller_frame_vector* old_movie, const std::string& old_projectid) throw(std::bad_alloc,
std::runtime_error);
/**
* Reset the state of movie to initial state.
*/
void reset_state() throw();
/**
* Get reset status for current frame.
*
* returns: -1 if current frame doesn't have a reset. Otherwise number of cycles to wait for delayed reset (0 is
* immediate reset).
*/
long get_reset_status() throw();
/**
* Commit a reset (writes a reset into current frame in readwrite mode).
*
* parameter delay: The number of cycles to delay the reset.
*/
void commit_reset(long delay) throw(std::bad_alloc);
/**
* Get how manyth poll in the frame next poll would be?
*
* returns: Poll number.
*/
unsigned next_poll_number();
/**
* Get how many subframes there are in specified frame.
*
* parameter frame: The frame number.
* returns: Number of subframes (0 if outside movie).
*/
uint64_t frame_subframes(uint64_t frame) throw();
/**
* Read controls from specified subframe of specified frame.
*
* parameter frame: The frame number.
* parameter subframe: Subframe within frame (first is 0).
* returns: The controls for subframe. If subframe is too great, reads last present subframe. If frame is outside
* movie, reads all released.
*/
controller_frame read_subframe(uint64_t frame, uint64_t subframe) throw();
/**
* Fast save.
*/
void fast_save(uint64_t& _frame, uint64_t& _ptr, uint64_t& _lagc, std::vector<uint32_t>& counters);
/**
* Fast load.
*/
void fast_load(uint64_t& _frame, uint64_t& _ptr, uint64_t& _lagc, std::vector<uint32_t>& counters);
/**
* Get the internal controller frame vector.
*/
controller_frame_vector& get_frame_vector() throw() { return movie_data; }
/**
* Flush caches.
*/
void clear_caches() throw();
/**
* Get sequence number (increments by 1 each time whole data is reloaded).
*/
uint64_t get_seqno() throw() { return seqno; }
/**
* Assignment.
*/
movie& operator=(const movie& m);
/**
* Get pollcounter vector.
*/
pollcounter_vector& get_pollcounters() { return pollcounters; }
/**
* Get first subframe of this frame.
*/
uint64_t get_current_frame_first_subframe() { return current_frame_first_subframe; }
/**
* Recount frames.
*/
void recount_frames() { frames_in_movie = movie_data.count_frames(); }
/**
* Adjust frame count.
*/
void adjust_frame_count(int64_t adjust) { frames_in_movie += adjust; }
/**
* Set reload mode flag (only effective in readonly mode).
*/
void set_reload_mode(bool newstate) throw() { reload_mode = newstate; }
/**
* Get reload mode flag.
*/
bool get_reload_mode() const throw() { return reload_mode; }
/**
* Read the current subframe.
*/
controller_frame current_subframe() throw(std::bad_alloc);
private:
//TRUE if readonly mode is active.
bool readonly;
//Movie (not global!) rerecord count.
std::string rerecords;
//Project ID.
std::string _project_id;
//The actual controller data.
controller_frame_vector movie_data;
//Current frame + 1 (0 before next_frame() has been called.
uint64_t current_frame;
//First subframe in current frame (movie_data.size() if no subframes have been stored).
uint64_t current_frame_first_subframe;
//How many times has each control been polled (bit 31 is data ready bit)?
pollcounter_vector pollcounters;
//Current state of buttons.
controller_frame current_controls;
//Number of known lag frames.
uint64_t lag_frames;
//Number of frames in movie.
uint64_t frames_in_movie;
//Cached subframes.
uint64_t cached_frame;
uint64_t cached_subframe;
//Count present subframes in frame starting from first_subframe (returns 0 if out of movie).
uint32_t count_changes(uint64_t first_subframe) throw();
//Sequence number.
uint64_t seqno;
//Reload mode flag.
bool reload_mode;
};
/**
* Class encapsulating bridge logic between bsnes interface and movie code.
*/
class movie_logic
{
@ -19,46 +322,20 @@ public:
* Create new bridge.
*/
movie_logic() throw();
/**
* Has movie?
*/
operator bool() throw() { return mov; }
bool operator!() throw() { return !mov; }
/**
* Get the movie instance associated.
*
* returns: The movie instance.
*/
movie& get_movie();
/**
* Set the movie instance associated.
*/
void set_movie(movie& _mov, bool free_old = false) throw();
/**
* Get the current movie file.
*/
moviefile& get_mfile();
/**
* Set the current movie file.
*/
void set_mfile(moviefile& _mf, bool free_old = false) throw();
/**
* Get current rrdata.
*/
rrdata_set& get_rrdata();
/**
* Set current rrdata.
*/
void set_rrdata(rrdata_set& _rrd, bool free_old = false) throw();
movie& get_movie() throw();
/**
* Notify about new frame starting.
*
* returns: Reset status for the new frame.
*/
void new_frame_starting(bool dont_poll);
long new_frame_starting(bool dont_poll) throw(std::bad_alloc, std::runtime_error);
/**
* Poll for input.
@ -70,36 +347,21 @@ public:
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: Error polling for input.
*/
short input_poll(unsigned port, unsigned dev, unsigned id);
short input_poll(bool port, unsigned dev, unsigned id) throw(std::bad_alloc, std::runtime_error);
/**
* Called when movie code needs new controls snapshot.
*
* parameter subframe: True if this is for subframe update, false if for frame update.
*/
portctrl::frame update_controls(bool subframe, bool forced = false);
/**
* Notify user poll (exit poll advance).
*
* returns: If true, update_controls is forced.
*/
bool notify_user_poll();
/**
* Release memory for mov, mf and rrd.
*/
void release_memory();
/**
* Set frob with data routine.
*/
void set_frob_with_value(std::function<void(unsigned,unsigned,unsigned,short&)> func);
controller_frame update_controls(bool subframe) throw(std::bad_alloc, std::runtime_error);
private:
std::function<void(unsigned,unsigned,unsigned,short&)> frob_with_value;
movie_logic(const movie_logic&);
movie_logic& operator=(const movie_logic&);
movie* mov;
moviefile* mf;
rrdata_set* rrd;
movie mov;
};
/**
* Extended mode flag.
*/
extern unsigned extended_mode;
#endif

Some files were not shown because too many files have changed in this diff Show more