Compare commits

...

9 Commits
v049 ... v058

Author SHA1 Message Date
byuu
6ec765f2c4 Update to bsnes v058 release.
We've tested the latest release on at least a dozen computers now, all seems to be in order for a release.
Changelog:
    - added 21fx support (more on this later)
    - added movie recording and playback support
    - added rewind support (enable under Settings->Configuration->Advanced, use backspace key to rewind)
    - added speedup (fast forward) and slowdown key bindings
    - audio no longer stutters on Windows when moving or resizing the main window
    - co-processors can now specify their own clock rates instead of sharing the S-CPU clock rate
    - Super Game Boy 2 now runs at the correct hardware speed, and not 2.4% faster like the Super Game Boy 1 does
    - added Vsync support to the Windows OpenGL driver (Intel graphics drivers do not support this option, because their engineers are lazy)
    - OpenGL driver no longer re-initializes when changing video synchronization, helps pixel shaders
    - refactored user interface compilation; now split into several object files, auto-generated MOC files placed under src/obj/
    - worked around a bug in the PulseAudio sound server that was causing the ALSA output driver to lock up [BearOso]
    - rewrote and simplified the save state manager, it is no longer a part of the core
    - S-DD1 and SPC7110 can now access up to 256MB via their MMCs
    - re-added background and OAM layer toggling under the tools dialog
    - added config file options to adjust emulation speed levels (config.system.speed*)
    - added snesreader, snesfilter and supergameboy support to the OS X port
    - added a really neat pixel shader that can perform point scaling to non-even multiples, eg it looks great even with aspect correction [Fes]
    - upgraded to Qt 4.6.0 official
Debugger changelog:
    - added memory export and import to the memory editor
    - added bus usage analyzer: logs opcodes, memory reads, memory writes and M/X states to usage.bin file
    - added disassembler that can trace both forward and backward from the current execution address
    - extended read/write breakpoints to the S-SMP
    - re-added trace masking option
Errata: there is one known bug in Qt 4.6.0 that affects the Windows port: menus attached to buttons show up as invisible on Windows Vista and above. I only use this on the file load dialog options button, and only to toggle the information pane on and off. Given that this is less severe than the bugs in the beta versions, I've upgraded anyway. I'll submit a bug report to the Qt team for this shortly. Also, my sincerest thanks to Bradley Hughes from the Qt development team for quickly fixing this show-stopper bug that greatly affected performance in bsnes v056.
2009-12-09 13:34:03 +00:00
byuu
54c7b4692d Update to bsnes v057 release.
I'm really sorry about this, but a major issue snuck into v056. It was caused by a bug in the newly released Qt 4.6.0 RC1. Whenever one moved the mouse cursor over the main window in the Windows port, the frame rate was immediately cut in half, which effectively ruined Mouse, Super Scope and Justifier support. As for how this could happen, well ... I'm ... really at a loss for words about this.
This release does not change the source code at all except to increment the version number, and it is built against Qt 4.6.0 beta 1 instead of 4.6.0 release candidate 1 as v055 was.
I will file an official bug complaint and post a link to it here during next week. Again, my apologies for any inconvenience. I incorrectly assumed it would be safe to update to RC1, and didn't spot the bug in time.
2009-11-23 13:24:03 +00:00
byuu
66067f0015 Update to bsnes v056 release.
This release adds a lot of new user interface features, and polishes Super Game Boy support.
Note that many pixel shaders need to be coded specifically for bsnes, eg ones designed for Pete's OpenGL2 plugin will not work. I will maintain a pixelshaders archive on the bsnes download page with a collection of working shaders. Right now, there are three: HDR TV, Scale2x and HQ2x; written by guest(r) and Pete, and ported by myself.
Changelog:
    - lowered Game Boy audio volume so that it matches SNES audio volume
    - fixed Super Game Boy multi-player support
    - fixed Super Game Boy swapped player bug
    - compressed Game Boy cartridges can now be loaded
    - added save state support for Super Game Boy games
    - blocked illegal Super Game Boy packets, fixes Zelda DX, Akumajou Dracula, etc palette issues
    - main window once again shrinks on size changes
    - joypads can now control the file loading window (support is very rudimentary)
    - cleaned up video and audio sliders, increased audio input frequency range for 59hz monitors
    - rewrote all of the input capture system from scratch
    - added dozens of additional GUI hotkey bindings to resize the main window, control synchronization, control speed, etc
    - it is now possible to map keyboard modifiers (shift, control, alt, super) to any input or hotkey; eg alt+enter = fullscreen
    - merged all input capture windows into the main settings panel
    - added turbo button support; hold down turbo buttons to send a 30hz input pulse
    - added asciiPad controller emulation; contains off/turbo/auto fire toggles and slow-motion mode
    - asciiPad support allows for quick switching between keyboard and gamepad input
    - merged scanline filter into the user interface (under Video Settings) to allow it to work on all filters; including the NTSC filter
    - killed off an evil QString <> string intermediary class called utf8; string class can convert to and from QString directly now
    - added fast BS-X, Sufami Turbo and Game Boy cartridge loading: use the filter list under "Load Cartridge" to bypass the BIOS selection screen
    - added pixel shader support to the OpenGL driver on Windows and Linux; note that it only really works well on Linux at the moment
    - added proper Vsync support to the OpenGL driver on Windows and Linux using GL extensions; again this really only works well on Linux
    - added unique path memory for shaders, folders, cartridges, BS-X, Sufami Turbo and Game Boy images
    - upgraded to Qt 4.6.0 release candidate 1; fixes an issue with the first checkbox in lists not updating when clicked
2009-11-22 14:48:58 +00:00
byuu
4c66de6f27 Update to bsnes v055 release.
Happy Halloween, this release adds full Super Game Boy support ... but is it a trick, or a treat? ;) ::cough::, lameness aside ...
The Game Boy emulation core is courtesy of gambatte, and excellent, accuracy-focused, open source, and lightning fast Game Boy Color emulator. Now I know what you're thinking, using a Game Boy Color emulator with the Super Game Boy? The truth is, gambatte was just such an amazingly perfect fit that nothing else compared. I fully believe that even as a CGB emulator, gambatte will do a better job than any pure DMG emulator could.
The emulation of the ICD2 chip (aka the Super Game Boy) was fully reverse engineered by myself. Eventually I'll get an updated document put up explaining how it works.
The next question might be, "why emulate the Super Game Boy when existing Game Boy emulators do?"; well, they can only simulate part of the SGB. Features such as custom SNES sound effects, hand-drawn borders, multi-tap support and custom SNES code execution can only be accomplished by a true SNES emulator. Space Invaders is perhaps the most impressive demonstration, as it contains an entire SNES game embedded inside the Game Boy cartridge.
bsnes' SGB emulation supports virtually every command, full sound mixing from both the SNES and Game Boy sides, both BIOS revisions, etc. The only thing that is not fully functional yet is the multi-player support, but it should be in due time. Save state support is also planned for a later date.
Changelog:
    - added Super Game Boy emulation (thanks to gambatte for the Game Boy core)
    - extended hybrid scanline/cycle PPU renderer to support Mode7 register caching; fixes scanline flickering on NHL '94 title screen
    - all windows (other than the main window) can be closed with the escape key now
    - file dialog path selection now accepts typed paths; can be used to access hidden directories and network shares
    - file dialog's game information panel can now be disabled
    - fixed a crashing issue when the file dialog was given an invalid path
    - fixed screenshot capture save location
    - added screenshot capture option to tools menu
    - state manager now auto-closes when loading a state; it can be reopened quickly with F3
    - fixed GZip archive loading
    - fixed NTSC off-by-one filter bug on hires screens
    - extended Scale2x, LQ2x and HQ2x to properly filter hires screens
    - added Pixellate2x filter
2009-11-01 14:30:51 +00:00
byuu
6a17b5ed4f Update to bsnes v054 release.
After a half-dozen hours of installing and compiling various combinations of MinGW and Qt, I've finally found a combination that once again allows for profile-guided optimizations: MinGW GCC 4.3.3 and Qt 4.6.0-beta 1. Though Qt 4.4 still has broken PGO, the latest Qt beta no longer has the process freeze issue upon termination.
This release is essentially the same as v053, but it's now at least as fast as v052 was, and ~10% faster than v053, which lacked profiling.
I did add in two quick changes, however: first, when starting in fullscreen mode, the video output size was being incorrectly set to the windowed size; second, by requiring save states to match the CRC32 of games, it made debugging with them impossible, so I've turned off the CRC32 matching.
2009-10-19 16:58:29 +00:00
byuu
8135dfdac9 Update to bsnes v053 release.
This release greatly polishes the user interface, adds a new cheat code search utility, adds the snesfilter library, and adds Qt-based GUI support to both snesfilter and snesreader. snesfilter gains 2xSaI, Super 2xSaI and Super Eagle support, plus full configuration for both the NTSC and scanline filters; and snesreader gains support support for multi-file ROM archives (eg GoodMerge sets.)
Statically linking Qt to bsnes, snesfilter and snesreader would be too prohibitive size-wise (~10MB or so.) I have to link dynamically so that all three can share the same Qt runtime, which gets all of bsnes and its modules to ~1MB (including the debugger build); and Qt itself to about ~2.5MB.
However, there is some bad news. There's a serious bug in MinGW 4.4+, where it is not generating profile-guided input files (*.gcno files.) There is also a serious bug in Qt 4.5.2/Windows when using dynamic linking: the library is hanging indefinitely, forcing me to manually terminate the process upon exit. This prevents the creation of profile-guided output files (*.gcda files.) It would be tough enough to work around one, but facing both of these issues at once is too much.
I'm afraid I have no choice but to disable profile-guided optimizations until these issues can be addressed. I did not know about these bugs until trying to build the official v053 release, so it's too late to revert to an all-in-one binary now. And I'm simply not willing to stop releasing new builds because of bugs in third-party software. As soon as I can work around this, I'll post a new optimized binary. In the mean time, despite the fact that this release is actually more optimized, please understand that the Windows binary will run approximately ~10% slower than previous releases. I recommend keeping v052 for now if you need the performance. Linux and OS X users are unaffected.
Changelog:
    - save RAM is initialized to 0xff again to work around Ken Griffey Jr Baseball issue
    - libco adds assembly-optimized targets for Win64 and PPC-ELF [the latter courtesy of Kernigh]
    - libco/x86 and libco/amd64 use pre-assembled blocks now, obviates need for custom compilation flags
    - added a new cheat code search utility to the tools menu
    - separated filters from main bsnes binary to libsnesfilter / snesfilter.dll
    - added 2xSaI, Super 2xSaI and Super Eagle filters [kode54]
    - added full configuration settings for NTSC and scanline filters (12+ new options)
    - further optimized HQ2x filter [blargg]
    - added Vsync support to the Mac OS X OpenGL driver
    - added folder creation button to custom file load dialog
    - fixed a few oddities with loading of "game folders" (see older news for an explanation on what this is)
    - updated to blargg's file_extractor v1.0.0
    - added full support for multi-file archives (eg GoodMerge sets)
    - split multi-cart loading again (BS-X, Sufami Turbo, etc) as required for multi-file support
    - cleaned up handling of file placement detection for save files (.srm, .cht, etc)
    - file load dialog now remembers your previous folder path across runs even without a custom games folder assigned
    - windows now save their exact positioning and size across runs, they no longer forcibly center
    - menus now have radio button and check box icons where appropriate
    - debugger's hex editor now has a working scrollbar widget
    - added resize splitter to settings and tools windows
    - worked around Qt style sheet bug where subclassed widgets were not properly applying style properties
2009-10-18 17:33:04 +00:00
byuu
a0000c7846 Update to bsnes v052 release.
This is a maintenance release, which fixes a few important bugs. It also adds some graphical icons to soften the user interface. Note that if you have set any custom paths with v051, you'll need to set them again for the fix to work. As always, my apologies for releasing two versions so close together. I felt the bugs were important enough to warrant it.
Changelog:
    - fixed loading of files and folders containing non-ANSI characters (Chinese, Japanese, etc)
    - fixed a slight lag on startup due to the new file browser
    - fixed path selection setting, screenshots will now be saved to the correct directory
    - hid memory editor scrollbar since it does not work yet
    - disabled window positioning on Linux due to bugs in the Compiz compositor
    - added icons from the Tango icon library to the menus and panels
2009-09-29 12:25:41 +00:00
byuu
b6a85353bf Update to bsnes v051 release.
Starting with this release, I wish to take bsnes in a new direction. It has always excelled in accuracy, as the only SNES emulator to offer a full 100% compatibility rate with all known commercial software. But over the years, it has also gained an impressive array of features and enhancements not found anywhere else. It is also the only actively developed SNES emulator with rapid, periodic releases. Its only achilles heel is the steep system requirements, which is quickly being overcome by aggressive new optimizations and steadily-increasing hardware speeds.
In an effort to make bsnes even more accessible to everyone, starting with this release, bsnes is now fully open source software, licensed under the terms of the GNU General Public License. I would like to work toward positioning bsnes as a truly general use emulator, and would welcome any help with this.
Specifically, I am looking for an interested Debian maintainer to package bsnes for Linux users; as well as for anyone interested in helping to optimize and improve bsnes as a whole. It also seems that many still do not know about bsnes, I'd appreciate advice and help on spreading the word. Please leave a message on my forum if you are interested.
I would also welcome and support any forks that target specific areas: a speed-oriented version, a tool-assisted speedrun version, netplay bindings, and so on. As part of this targeting, I've also released a custom debugger-enabled version, which trades a bit of speed in turn for best-in-class debugging capabilities.
Please check back here over the following few days, I'll be writing up documentation explaining all of the various unique features of bsnes, as well as detailed compilation instructions for programmers.
Changelog:
    - corrected a small bug in HDMA processing; fixes College Football '97 flickering
    - corrected ROMBR and PBR SuperFX register masking; fixes Voxel demo [MooglyGuy]
    - DSP-4 driver AI bug fixed [Jonas Quinn]
    - added save state support to the S-DD1, S-RTC, DSP-1, DSP-2 and ST-0010 co-processors
    - fixed a freeze issue when the S-SMP encounters STOP and SLEEP opcodes
    - Cx4 save states no longer need floating-point values, and are thus fully portable now
    - added new custom file loading dialog; allows non-modal usage, screenshot previews and ROM info summary, among many other benefits
    - added support for IPS soft-patching
    - added blargg's File_Extractor library
    - added support for archives compressed using 7-zip, RAR and BZip2; which is in addition to existing support for Gzip, ZIP and JMA
    - state manager now properly updates the timestamp column on saves [FitzRoy]
    - added OpenGL renderer to OS X port
    - fixed system beep issue with keyboard input on OS X port
    - fixed menubar visibility issue on OS X port
    - fixed a Display handle leak on Linux port [snzzbk]
    - X-video driver now releases SHM memory properly upon exit [emon]
    - fixed Direct3D rendering issue that was blurring video on some cards [Fes]
    - enhanced window positioning code for all platforms
    - debugger is now GUI-driven instead of via command-line
    - memory hex editor is now fully usable
    - added PPU video RAM viewer to debugger
    - added S-CPU and S-SMP tracing capabilities to debugger
    - Qt version upgraded to 4.5.2, and compiled with optimizations enabled; runs faster but makes the binary slightly larger
    - too many code cleanups to list
2009-09-27 11:40:16 +00:00
byuu
c2453cb634 Update to bsnes v050 release.
I always regret having to post new releases so quickly, but a semi-major bug crept into v049. I'd rather fix it now, before I start making major changes that will need testing again. The problem was that the S-PPU was not being synchronized as often as it should have been, resulting in titles such as F-Zero and Super Mario Kart showing flickering lines here and there. This release fixes that.
This release also adds savestate support for Mega Man X2 and Mega Man X3, which utilize the Cx4 coprocessor; and it fixes a bug where input was still accepted even when the main window was minimized.
2009-08-25 16:00:26 +00:00
349 changed files with 10565 additions and 25337 deletions

View File

@@ -25,25 +25,25 @@ link :=
ifeq ($(platform),x)
link += -s
ruby := video.glx video.xv video.sdl video.qtimage
ruby := video.glx video.xv video.qtraster video.sdl
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.ao
ruby += input.sdl input.x
link += $(if $(findstring audio.openal,$(ruby)),-lopenal)
else ifeq ($(platform),osx)
ruby := video.qtimage
ruby := video.qtopengl video.qtraster
ruby += audio.openal
ruby += input.carbon
link += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL)
else ifeq ($(platform),win)
link += -mwindows
# link += -mconsole
link += -mwindows -mthreads
# link += -mconsole -mthreads
link += -s -luuid -lkernel32 -luser32 -lgdi32 -lshell32
# statically link Qt for Windows build
link += -enable-stdcall-fixup -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
ruby := video.direct3d video.wgl video.directdraw video.gdi video.qtimage
ruby := video.direct3d video.wgl video.directdraw video.gdi video.qtraster
ruby += audio.directsound
ruby += input.rawinput input.directinput
@@ -72,25 +72,16 @@ link += $(call ifhas,audio.pulseaudio,$(ruby),-lpulse-simple)
link += $(call ifhas,input.directinput,$(ruby),-ldinput8 -ldxguid)
link += $(call ifhas,input.rawinput,$(ruby),-ldinput8 -ldxguid)
####################
### core objects ###
####################
###############
### objects ###
###############
objects := libco ruby libreader libfilter
objects := libco ruby
objects += system cartridge cheat
objects += memory smemory cpu cpucore scpu smp smpcore ssmp sdsp ppu bppu
objects += sgb superfx sa1
objects += supergameboy superfx sa1
objects += bsx srtc sdd1 spc7110 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010 st011 st018
ifeq ($(enable_gzip),true)
objects += adler32 compress crc32 deflate gzio inffast inflate inftrees ioapi trees unzip zip zutil
flags += -DGZIP_SUPPORT
endif
ifeq ($(enable_jma),true)
objects += jma jcrc32 lzmadec 7zlzma iiostrm inbyte lzma winout
flags += -DJMA_SUPPORT
endif
objects += 21fx
######################
### implicit rules ###
@@ -121,9 +112,6 @@ rubydef := $(foreach c,$(subst .,_,$(call strupper,$(ruby))),-D$c)
obj/ruby.o: lib/ruby/ruby.cpp $(call rwildcard,lib/ruby/*)
$(call compile,$(rubydef) $(rubyflags))
obj/libco.o: lib/libco/libco.c lib/libco/*
$(c) -O3 -fomit-frame-pointer -static -Ilib -c $< -o $@
obj/libreader.o: lib/libreader/libreader.cpp lib/libreader/*
obj/libfilter.o: lib/libfilter/libfilter.cpp lib/libfilter/*
#################
### utilities ###
@@ -179,53 +167,23 @@ obj/system.o: system/system.cpp $(call rwildcard,system/)
### special chips ###
#####################
obj/sgb.o : chip/sgb/sgb.cpp $(call rwildcard,chip/sgb/)
obj/superfx.o: chip/superfx/superfx.cpp $(call rwildcard,chip/superfx/)
obj/sa1.o : chip/sa1/sa1.cpp $(call rwildcard,chip/sa1/)
obj/bsx.o : chip/bsx/bsx.cpp chip/bsx/*
obj/srtc.o : chip/srtc/srtc.cpp chip/srtc/*
obj/sdd1.o : chip/sdd1/sdd1.cpp chip/sdd1/*
obj/spc7110.o: chip/spc7110/spc7110.cpp chip/spc7110/*
obj/cx4.o : chip/cx4/cx4.cpp chip/cx4/*
obj/dsp1.o : chip/dsp1/dsp1.cpp chip/dsp1/*
obj/dsp2.o : chip/dsp2/dsp2.cpp chip/dsp2/*
obj/dsp3.o : chip/dsp3/dsp3.cpp chip/dsp3/*
obj/dsp4.o : chip/dsp4/dsp4.cpp chip/dsp4/*
obj/obc1.o : chip/obc1/obc1.cpp chip/obc1/*
obj/st010.o : chip/st010/st010.cpp chip/st010/*
obj/st011.o : chip/st011/st011.cpp chip/st011/*
obj/st018.o : chip/st018/st018.cpp chip/st018/*
############
### zlib ###
############
obj/adler32.o : lib/zlib/adler32.c lib/zlib/*
obj/compress.o: lib/zlib/compress.c lib/zlib/*
obj/crc32.o : lib/zlib/crc32.c lib/zlib/*
obj/deflate.o : lib/zlib/deflate.c lib/zlib/*
obj/gzio.o : lib/zlib/gzio.c lib/zlib/*
obj/inffast.o : lib/zlib/inffast.c lib/zlib/*
obj/inflate.o : lib/zlib/inflate.c lib/zlib/*
obj/inftrees.o: lib/zlib/inftrees.c lib/zlib/*
obj/ioapi.o : lib/zlib/ioapi.c lib/zlib/*
obj/trees.o : lib/zlib/trees.c lib/zlib/*
obj/unzip.o : lib/zlib/unzip.c lib/zlib/*
obj/zip.o : lib/zlib/zip.c lib/zlib/*
obj/zutil.o : lib/zlib/zutil.c lib/zlib/*
##############
### libjma ###
##############
obj/jma.o : lib/libjma/jma.cpp lib/libjma/*
obj/jcrc32.o : lib/libjma/jcrc32.cpp lib/libjma/*
obj/lzmadec.o: lib/libjma/lzmadec.cpp lib/libjma/*
obj/7zlzma.o : lib/libjma/7zlzma.cpp lib/libjma/*
obj/iiostrm.o: lib/libjma/iiostrm.cpp lib/libjma/*
obj/inbyte.o : lib/libjma/inbyte.cpp lib/libjma/*
obj/lzma.o : lib/libjma/lzma.cpp lib/libjma/*
obj/winout.o : lib/libjma/winout.cpp lib/libjma/*
obj/supergameboy.o: chip/supergameboy/supergameboy.cpp $(call rwildcard,chip/supergameboy/)
obj/superfx.o : chip/superfx/superfx.cpp $(call rwildcard,chip/superfx/)
obj/sa1.o : chip/sa1/sa1.cpp $(call rwildcard,chip/sa1/)
obj/bsx.o : chip/bsx/bsx.cpp chip/bsx/*
obj/srtc.o : chip/srtc/srtc.cpp chip/srtc/*
obj/sdd1.o : chip/sdd1/sdd1.cpp chip/sdd1/*
obj/spc7110.o : chip/spc7110/spc7110.cpp chip/spc7110/*
obj/cx4.o : chip/cx4/cx4.cpp chip/cx4/*
obj/dsp1.o : chip/dsp1/dsp1.cpp chip/dsp1/*
obj/dsp2.o : chip/dsp2/dsp2.cpp chip/dsp2/*
obj/dsp3.o : chip/dsp3/dsp3.cpp chip/dsp3/*
obj/dsp4.o : chip/dsp4/dsp4.cpp chip/dsp4/*
obj/obc1.o : chip/obc1/obc1.cpp chip/obc1/*
obj/st010.o : chip/st010/st010.cpp chip/st010/*
obj/st011.o : chip/st011/st011.cpp chip/st011/*
obj/st018.o : chip/st018/st018.cpp chip/st018/*
obj/21fx.o : chip/21fx/21fx.cpp chip/21fx/*
###############
### targets ###
@@ -265,9 +223,5 @@ help:
@echo " mingw32-gcc - MinGW compiler"
@echo " i586-mingw32-gcc - MinGW cross compiler"
@echo ""
@echo "Available options:"
@echo " enable_gzip=[true|false] - Enable ZIP / GZ support (default=false)"
@echo " enable_jma=[true|false] - Enable JMA support (default=false)"
@echo ""
@echo "Example: $(MAKE) platform=x compiler=gcc enable_gzip=true"
@echo "Example: $(MAKE) platform=x compiler=gcc"
@echo ""

View File

@@ -1,6 +1,6 @@
static const char bsnesVersion[] = "0.049";
static const char bsnesVersion[] = "0.058";
static const char bsnesTitle[] = "bsnes";
static const unsigned bsnesSaveStateVersion = 2;
static const unsigned bsnesSerializerVersion = 4;
//S-DSP can be encapsulated into a state machine using #define magic
//this avoids ~2.048m co_switch() calls per second (~5% speedup)
@@ -23,7 +23,6 @@ static const unsigned bsnesSaveStateVersion = 2;
#include <nall/file.hpp>
#include <nall/function.hpp>
#include <nall/moduloarray.hpp>
#include <nall/new.hpp>
#include <nall/platform.hpp>
#include <nall/priorityqueue.hpp>
#include <nall/property.hpp>

View File

@@ -1,17 +1,19 @@
#include <../base.hpp>
#include <nall/crc32.hpp>
#include <nall/sha256.hpp>
#define CARTRIDGE_CPP
namespace SNES {
#include "header.cpp"
#include "gameboyheader.cpp"
namespace memory {
MappedRAM cartrom, cartram, cartrtc;
MappedRAM bsxflash, bsxram, bsxpram;
MappedRAM stArom, stAram;
MappedRAM stBrom, stBram;
MappedRAM gbrom, gbram;
MappedRAM gbrom, gbram, gbrtc;
};
Cartridge cartridge;
@@ -24,25 +26,31 @@ void Cartridge::load(Mode cartridge_mode) {
set(mode, cartridge_mode);
if(cartinfo.ram_size > 0) {
memory::cartram.map(new(zeromemory) uint8_t[cartinfo.ram_size], cartinfo.ram_size);
memory::cartram.map(allocate<uint8_t>(cartinfo.ram_size, 0xff), cartinfo.ram_size);
}
if(cartinfo.srtc || cartinfo.spc7110rtc) {
memory::cartrtc.map(new(zeromemory) uint8_t[20], 20);
memory::cartrtc.map(allocate<uint8_t>(20, 0xff), 20);
}
if(mode() == ModeBsx) {
memory::bsxram.map (new(zeromemory) uint8_t[ 32 * 1024], 32 * 1024);
memory::bsxpram.map(new(zeromemory) uint8_t[512 * 1024], 512 * 1024);
memory::bsxram.map (allocate<uint8_t>( 32 * 1024, 0xff), 32 * 1024);
memory::bsxpram.map(allocate<uint8_t>(512 * 1024, 0xff), 512 * 1024);
}
if(mode() == ModeSufamiTurbo) {
if(memory::stArom.data()) memory::stAram.map(new(zeromemory) uint8_t[128 * 1024], 128 * 1024);
if(memory::stBrom.data()) memory::stBram.map(new(zeromemory) uint8_t[128 * 1024], 128 * 1024);
if(memory::stArom.data()) memory::stAram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
if(memory::stBrom.data()) memory::stBram.map(allocate<uint8_t>(128 * 1024, 0xff), 128 * 1024);
}
if(mode() == ModeSuperGameBoy) {
if(memory::gbrom.data()) memory::gbram.map(new(zeromemory) uint8_t[64 * 1024], 64 * 1024);
if(memory::gbrom.data()) {
unsigned ram_size = gameboy_ram_size();
unsigned rtc_size = gameboy_rtc_size();
if(ram_size) memory::gbram.map(allocate<uint8_t>(ram_size, 0xff), ram_size);
if(rtc_size) memory::gbrtc.map(allocate<uint8_t>(rtc_size, 0x00), rtc_size);
}
}
memory::cartrom.write_protect(true);
@@ -57,6 +65,7 @@ void Cartridge::load(Mode cartridge_mode) {
memory::stBram.write_protect(false);
memory::gbrom.write_protect(true);
memory::gbram.write_protect(false);
memory::gbrtc.write_protect(false);
unsigned checksum = ~0;
for(unsigned n = 0; n < memory::cartrom.size(); n++) checksum = crc32_adjust(checksum, memory::cartrom[n]);
@@ -70,6 +79,21 @@ void Cartridge::load(Mode cartridge_mode) {
for(unsigned n = 0; n < memory::gbrom.size(); n++) checksum = crc32_adjust(checksum, memory::gbrom[n]);
set(crc32, ~checksum);
#if 0
fprintf(stdout, "crc32 = %.8x\n", crc32());
sha256_ctx sha;
uint8_t shahash[32];
sha256_init(&sha);
sha256_chunk(&sha, memory::cartrom.data(), memory::cartrom.size());
sha256_final(&sha);
sha256_hash(&sha, shahash);
fprintf(stdout, "sha256 = ");
for(unsigned i = 0; i < 32; i++) fprintf(stdout, "%.2x", shahash[i]);
fprintf(stdout, "\n");
#endif
bus.load_cart();
system.serialize_init();
set(loaded, true);
@@ -88,6 +112,7 @@ void Cartridge::unload() {
memory::stBram.reset();
memory::gbrom.reset();
memory::gbram.reset();
memory::gbrtc.reset();
if(loaded() == false) return;
bus.unload_cart();
@@ -100,6 +125,8 @@ Cartridge::Type Cartridge::detect_image_type(uint8_t *data, unsigned size) const
return info.type;
}
bool Cartridge::has_21fx() const { return s21fx.exists(); }
void Cartridge::serialize(serializer &s) {
if(memory::cartram.size() != 0 && memory::cartram.size() != ~0) {
s.array(memory::cartram.data(), memory::cartram.size());
@@ -128,6 +155,10 @@ void Cartridge::serialize(serializer &s) {
if(memory::gbram.size() != 0 && memory::gbram.size() != ~0) {
s.array(memory::gbram.data(), memory::gbram.size());
}
if(memory::gbrtc.size() != 0 && memory::gbrtc.size() != ~0) {
s.array(memory::gbrtc.data(), memory::gbrtc.size());
}
}
Cartridge::Cartridge() {
@@ -197,5 +228,4 @@ Cartridge::cartinfo_t::cartinfo_t() {
reset();
}
};
}

View File

@@ -67,6 +67,7 @@ public:
property_t<bool> has_dsp1, has_dsp2, has_dsp3, has_dsp4;
property_t<bool> has_obc1;
property_t<bool> has_st010, has_st011, has_st018;
bool has_21fx() const;
//main interface
void load(Mode);
@@ -118,6 +119,9 @@ private:
unsigned find_header(const uint8_t *data, unsigned size) const;
unsigned score_header(const uint8_t *data, unsigned size, unsigned addr) const;
void set_cartinfo(const cartinfo_t&);
unsigned gameboy_ram_size() const;
unsigned gameboy_rtc_size() const;
};
namespace memory {
@@ -125,7 +129,7 @@ namespace memory {
extern MappedRAM bsxflash, bsxram, bsxpram;
extern MappedRAM stArom, stAram;
extern MappedRAM stBrom, stBram;
extern MappedRAM gbrom, gbram;
extern MappedRAM gbrom, gbram, gbrtc;
};
extern Cartridge cartridge;

View File

@@ -0,0 +1,22 @@
#ifdef CARTRIDGE_CPP
unsigned Cartridge::gameboy_ram_size() const {
if(memory::gbrom.size() < 512) return 0;
switch(memory::gbrom[0x0149]) {
case 0x00: return 0 * 1024;
case 0x01: return 8 * 1024;
case 0x02: return 8 * 1024;
case 0x03: return 32 * 1024;
case 0x04: return 128 * 1024;
case 0x05: return 128 * 1024;
default: return 128 * 1024;
}
}
unsigned Cartridge::gameboy_rtc_size() const {
if(memory::gbrom.size() < 512) return 0;
if(memory::gbrom[0x0147] == 0x0f || memory::gbrom[0x0147] == 0x10) return 4;
return 0;
}
#endif

View File

@@ -1,5 +1,3 @@
@mingw32-make
::@mingw32-make enable_gzip=true enable_jma=true
@pause

View File

@@ -186,7 +186,7 @@ void Cheat::disable(unsigned i) {
//===============================
void Cheat::load(string data) {
data.replace("\r\n", "\n");
data.replace("\r", "");
data.qreplace(" ", "");
lstring line;
@@ -195,17 +195,17 @@ void Cheat::load(string data) {
lstring part;
part.qsplit(",", line[i]);
if(part.size() != 3) continue;
trim(part[0], "\"");
add(part[1] == "enabled", /* code = */ part[2], /* desc = */ part[0]);
trim(part[2], "\"");
add(part[0] == "enabled", /* code = */ part[1], /* desc = */ part[2]);
}
}
string Cheat::save() const {
string data;
for(unsigned i = 0; i < code.size(); i++) {
data << "\"" << code[i].desc << "\", "
<< (code[i].enabled ? "enabled, " : "disabled, ")
<< code[i].code << "\r\n";
data << (code[i].enabled ? "enabled," : "disabled,")
<< code[i].code << ","
<< "\"" << code[i].desc << "\"\r\n";
}
return data;
}

165
src/chip/21fx/21fx.cpp Normal file
View File

@@ -0,0 +1,165 @@
#include <../base.hpp>
//$21f0 command port (r/w)
//-------------------
//$00 set data port address (sr[3-0] = address)
//$01 set audio track number (sr[1-0] = track number)
//$02 set volume (sr[1] = left, sr[0] = right)
//$03 set audio state (sr[0].d1 = pause, sr[0].d0 = repeat)
//
//d7 = data port busy
//d6 = audio port busy
//d5 = audio playing
//d4 = reserved (0)
//d3-d0 = version (1)
//
//
//$21f1 parameter port (w)
//---------------------
//(shift register)
//
//
//$21f2 data port (r)
//----------------
//(auto-increment read port)
#define S21FX_CPP
namespace SNES {
S21fx s21fx;
#include "serialization.cpp"
void S21fx::enter() {
scheduler.clock.cop_freq = 44100;
while(true) {
int16 left = 0, right = 0;
if((mmio.status & AudioPlaying) && !mmio.audio_pause) {
if(audiofile.open()) {
if(audiofile.end()) {
if(!mmio.audio_repeat) mmio.status &= ~AudioPlaying;
audiofile.seek(mmio.audio_offset = 58);
} else {
mmio.audio_offset += 4;
left = audiofile.readl(2);
right = audiofile.readl(2);
}
} else {
mmio.status &= ~AudioPlaying;
}
}
left = sclamp<16>((double)left * (double)mmio.audio_volume_left / 255.0);
right = sclamp<16>((double)right * (double)mmio.audio_volume_right / 255.0);
audio.coprocessor_sample(left, right);
scheduler.addclocks_cop(1);
scheduler.sync_copcpu();
}
}
void S21fx::init() {
}
void S21fx::enable() {
audio.coprocessor_enable(true);
audio.coprocessor_frequency(44100.0);
for(unsigned i = 0x21f0; i <= 0x21f7; i++) {
memory::mmio.map(i, *this);
}
if(datafile.open()) datafile.close();
datafile.open(string() << basepath << "21fx.bin", file::mode_read);
}
void S21fx::power() {
reset();
}
void S21fx::reset() {
mmio.status = DataPortBusy | AudioBusy;
mmio.shift_register = 0;
mmio.data_offset = 0;
mmio.audio_offset = 0;
mmio.audio_track = 0;
mmio.audio_volume_left = 255;
mmio.audio_volume_right = 255;
mmio.audio_repeat = false;
mmio.audio_pause = false;
}
uint8 S21fx::mmio_read(unsigned addr) {
addr &= 0xffff;
if(addr == 0x21f0) {
return mmio.status | 0x01;
}
if(addr == 0x21f2) {
if(mmio.status & DataPortBusy) return 0x00;
mmio.data_offset++;
if(datafile.open()) return datafile.read();
return 0x00;
}
return 0x00;
}
void S21fx::mmio_write(unsigned addr, uint8 data) {
addr &= 0xffff;
if(addr == 0x21f0) {
if(data == 0x00) {
mmio.data_offset = mmio.shift_register & 0xffffffff;
if(datafile.open()) {
datafile.seek(mmio.data_offset);
}
mmio.status &= ~DataPortBusy;
}
if(data == 0x01) {
mmio.audio_track = mmio.shift_register & 0xffff;
if(audiofile.open()) audiofile.close();
char track[16];
sprintf(track, "%.5u", mmio.audio_track);
if(audiofile.open(string() << basepath << "audio" << track << ".wav", file::mode_read)) {
audiofile.seek(mmio.audio_offset = 58); //skip WAV header
}
mmio.status &= ~(AudioBusy | AudioPlaying);
}
if(data == 0x02) {
mmio.audio_volume_left = mmio.shift_register >> 8;
mmio.audio_volume_right = mmio.shift_register >> 0;
}
if(data == 0x03) {
mmio.status |= AudioPlaying;
mmio.audio_repeat = mmio.shift_register & 1;
mmio.audio_pause = mmio.shift_register & 2;
}
mmio.shift_register = 0;
}
if(addr == 0x21f1) {
mmio.shift_register = (mmio.shift_register << 8) | data;
}
}
void S21fx::base(const string& path) {
basepath = path;
}
bool S21fx::exists() {
return file::exists(string() << basepath << "21fx.bin");
}
S21fx::S21fx() {
}
}

44
src/chip/21fx/21fx.hpp Normal file
View File

@@ -0,0 +1,44 @@
class S21fx : public MMIO {
public:
void enter();
void init();
void enable();
void power();
void reset();
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
void base(const string &path);
bool exists();
void serialize(serializer&);
S21fx();
private:
string basepath;
file datafile;
file audiofile;
enum Flag {
DataPortBusy = 0x80,
AudioBusy = 0x40,
AudioPlaying = 0x20,
};
struct MMIO {
uint8 status;
uint64 shift_register;
uint32 data_offset;
uint32 audio_offset;
uint16 audio_track;
uint8 audio_volume_left;
uint8 audio_volume_right;
bool audio_repeat;
bool audio_pause;
} mmio;
};
extern S21fx s21fx;

View File

@@ -0,0 +1,31 @@
#ifdef S21FX_CPP
void S21fx::serialize(serializer &s) {
s.integer(mmio.status);
s.integer(mmio.shift_register);
s.integer(mmio.data_offset);
s.integer(mmio.audio_offset);
s.integer(mmio.audio_track);
s.integer(mmio.audio_volume_left);
s.integer(mmio.audio_volume_right);
s.integer(mmio.audio_repeat);
s.integer(mmio.audio_pause);
//flush file handles and indices, as a different track may be playing,
//or the file offsets may be at the wrong location ...
if(datafile.open()) datafile.close();
if(datafile.open(string() << basepath << "21fx.bin", file::mode_read)) {
datafile.seek(mmio.data_offset);
}
if(audiofile.open()) audiofile.close();
char track[16];
sprintf(track, "%.5u", mmio.audio_track);
if(audiofile.open(string() << basepath << "audio" << track << ".wav", file::mode_read)) {
audiofile.seek(mmio.audio_offset);
}
}
#endif

View File

@@ -1,4 +1,4 @@
#include "sgb/sgb.hpp"
#include "supergameboy/supergameboy.hpp"
#include "superfx/superfx.hpp"
#include "sa1/sa1.hpp"
#include "bsx/bsx.hpp"
@@ -14,3 +14,4 @@
#include "st010/st010.hpp"
#include "st011/st011.hpp"
#include "st018/st018.hpp"
#include "21fx/21fx.hpp"

View File

@@ -11,10 +11,11 @@ namespace SNES {
Cx4 cx4;
#include "cx4data.cpp"
#include "cx4fn.cpp"
#include "cx4oam.cpp"
#include "cx4ops.cpp"
#include "serialization.cpp"
#include "data.cpp"
#include "functions.cpp"
#include "oam.cpp"
#include "opcodes.cpp"
void Cx4::init() {
}

View File

@@ -1,4 +1,15 @@
class Cx4 : public Memory {
public:
void init();
void enable();
void power();
void reset();
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
void serialize(serializer&);
private:
uint8 ram[0x0c00];
uint8 reg[0x0100];
@@ -15,9 +26,6 @@ private:
int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
double tanval;
double c4x,c4y,c4z, c4x2,c4y2,c4z2;
void C4TransfWireFrame();
void C4TransfWireFrame2();
void C4CalcWireFrame();
@@ -82,16 +90,6 @@ public:
void writeb(uint16 addr, uint8 data);
void writew(uint16 addr, uint16 data);
void writel(uint16 addr, uint32 data);
//
void init();
void enable();
void power();
void reset();
uint8 read (unsigned addr);
void write(unsigned addr, uint8 data);
};
extern Cx4 cx4;

View File

@@ -10,9 +10,10 @@
//Wireframe Helpers
void Cx4::C4TransfWireFrame() {
c4x = (double)C4WFXVal;
c4y = (double)C4WFYVal;
c4z = (double)C4WFZVal - 0x95;
double c4x = (double)C4WFXVal;
double c4y = (double)C4WFYVal;
double c4z = (double)C4WFZVal - 0x95;
double tanval, c4x2, c4y2, c4z2;
//Rotate X
tanval = -(double)C4WFX2Val * PI * 2 / 128;
@@ -52,9 +53,10 @@ void Cx4::C4CalcWireFrame() {
}
void Cx4::C4TransfWireFrame2() {
c4x = (double)C4WFXVal;
c4y = (double)C4WFYVal;
c4z = (double)C4WFZVal;
double c4x = (double)C4WFXVal;
double c4y = (double)C4WFYVal;
double c4z = (double)C4WFZVal;
double tanval, c4x2, c4y2, c4z2;
//Rotate X
tanval = -(double)C4WFX2Val * PI * 2 / 128;
@@ -140,8 +142,8 @@ void Cx4::C4DrawLine(int32 X1, int32 Y1, int16 Z1, int32 X2, int32 Y2, int16 Z2,
uint8 bit = 0x80 >> ((X1 >> 8) & 7);
ram[addr + 0x300] &= ~bit;
ram[addr + 0x301] &= ~bit;
if(Color & 1) { ram[addr + 0x300] |= bit; }
if(Color & 2) { ram[addr + 0x301] |= bit; }
if(Color & 1) ram[addr + 0x300] |= bit;
if(Color & 2) ram[addr + 0x301] |= bit;
}
X1 += X2;
Y1 += Y2;
@@ -158,22 +160,22 @@ void Cx4::C4DoScaleRotate(int row_padding) {
if(XScale & 0x8000)XScale = 0x7fff;
if(YScale & 0x8000)YScale = 0x7fff;
if(readw(0x1f80) == 0) { //no rotation
if(readw(0x1f80) == 0) { //no rotation
A = (int16)XScale;
B = 0;
C = 0;
D = (int16)YScale;
} else if(readw(0x1f80) == 128) { //90 degree rotation
} else if(readw(0x1f80) == 128) { //90 degree rotation
A = 0;
B = (int16)(-YScale);
C = (int16)XScale;
D = 0;
} else if(readw(0x1f80) == 256) { //180 degree rotation
} else if(readw(0x1f80) == 256) { //180 degree rotation
A = (int16)(-XScale);
B = 0;
C = 0;
D = (int16)(-YScale);
} else if(readw(0x1f80) == 384) { //270 degree rotation
} else if(readw(0x1f80) == 384) { //270 degree rotation
A = 0;
B = (int16)YScale;
C = (int16)(-XScale);
@@ -221,10 +223,10 @@ void Cx4::C4DoScaleRotate(int row_padding) {
}
//De-bitplanify
if(byte & 1) { ram[outidx ] |= bit; }
if(byte & 2) { ram[outidx + 1] |= bit; }
if(byte & 4) { ram[outidx + 16] |= bit; }
if(byte & 8) { ram[outidx + 17] |= bit; }
if(byte & 1) ram[outidx ] |= bit;
if(byte & 2) ram[outidx + 1] |= bit;
if(byte & 4) ram[outidx + 16] |= bit;
if(byte & 8) ram[outidx + 17] |= bit;
bit >>= 1;
if(!bit) {
@@ -232,7 +234,7 @@ void Cx4::C4DoScaleRotate(int row_padding) {
outidx += 32;
}
X += A; //Add 1 to output x => add an A and a C
X += A; //Add 1 to output x => add an A and a C
Y += C;
}
outidx += 2 + row_padding;
@@ -241,7 +243,7 @@ void Cx4::C4DoScaleRotate(int row_padding) {
} else {
outidx -= w * 4 + row_padding;
}
LineX += B; //Add 1 to output y => add a B and a D
LineX += B; //Add 1 to output y => add a B and a D
LineY += D;
}
}

View File

@@ -5,7 +5,7 @@ void Cx4::op00_00() {
uint32 oamptr = ram[0x626] << 2;
for(int32 i = 0x1fd; i > oamptr && i >= 0; i -= 4) {
//clear oam-to-be
if(i >= 0)ram[i] = 0xe0;
if(i >= 0) ram[i] = 0xe0;
}
uint16 globalx, globaly;
@@ -18,7 +18,7 @@ void Cx4::op00_00() {
globaly = readw(0x623);
oamptr2 = 0x200 + (ram[0x626] >> 2);
if(!ram[0x620])return;
if(!ram[0x620]) return;
sprcount = 128 - ram[0x626];
uint8 offset = (ram[0x626] & 3) * 2;
@@ -51,8 +51,8 @@ void Cx4::op00_00() {
ram[oamptr + 2] = sprname + bus.read(spraddr + 3);
ram[oamptr + 3] = sprattr ^ (bus.read(spraddr) & 0xc0);
ram[oamptr2] &= ~(3 << offset);
if(x & 0x100)ram[oamptr2] |= 1 << offset;
if(bus.read(spraddr) & 0x20)ram[oamptr2] |= 2 << offset;
if(x & 0x100) ram[oamptr2] |= 1 << offset;
if(bus.read(spraddr) & 0x20) ram[oamptr2] |= 2 << offset;
oamptr += 4;
sprcount--;
offset = (offset + 2) & 6;
@@ -66,12 +66,12 @@ void Cx4::op00_00() {
ram[oamptr + 2] = sprname;
ram[oamptr + 3] = sprattr;
ram[oamptr2] &= ~(3 << offset);
if(sprx & 0x100)ram[oamptr2] |= 3 << offset;
if(sprx & 0x100) ram[oamptr2] |= 3 << offset;
else ram[oamptr2] |= 2 << offset;
oamptr += 4;
sprcount--;
offset = (offset + 2) & 6;
if(!offset)oamptr2++;
if(!offset) oamptr2++;
}
}
}
@@ -165,12 +165,12 @@ void Cx4::op00_0b() {
int32 index = (y >> 11) * width * 4 + (x >> 11) * 32 + ((y >> 8) & 7) * 2;
uint8 mask = 0x80 >> ((x >> 8) & 7);
if(pixel & 1)ram[index ] |= mask;
if(pixel & 2)ram[index + 1] |= mask;
if(pixel & 4)ram[index + 16] |= mask;
if(pixel & 8)ram[index + 17] |= mask;
if(pixel & 1) ram[index ] |= mask;
if(pixel & 2) ram[index + 1] |= mask;
if(pixel & 4) ram[index + 16] |= mask;
if(pixel & 8) ram[index + 17] |= mask;
}
if(j & 1)srcptr++;
if(j & 1) srcptr++;
}
}
}

View File

@@ -33,7 +33,7 @@ void Cx4::op0d() {
C41FXVal = readw(0x1f80);
C41FYVal = readw(0x1f83);
C41FDistVal = readw(0x1f86);
tanval = sqrt(((double)C41FYVal) * ((double)C41FYVal) + ((double)C41FXVal) * ((double)C41FXVal));
double tanval = sqrt(((double)C41FYVal) * ((double)C41FYVal) + ((double)C41FXVal) * ((double)C41FXVal));
tanval = (double)C41FDistVal / tanval;
C41FYVal = (int16)(((double)C41FYVal * tanval) * 0.99);
C41FXVal = (int16)(((double)C41FXVal * tanval) * 0.98);
@@ -103,7 +103,7 @@ void Cx4::op1f() {
if(!C41FXVal) {
C41FAngleRes = (C41FYVal > 0) ? 0x080 : 0x180;
} else {
tanval = ((double)C41FYVal) / ((double)C41FXVal);
double tanval = ((double)C41FYVal) / ((double)C41FXVal);
C41FAngleRes = (short)(atan(tanval) / (PI * 2) * 512);
C41FAngleRes = C41FAngleRes;
if(C41FXVal < 0) {

View File

@@ -0,0 +1,39 @@
#ifdef CX4_CPP
void Cx4::serialize(serializer &s) {
s.array(ram);
s.array(reg);
s.integer(r0);
s.integer(r1);
s.integer(r2);
s.integer(r3);
s.integer(r4);
s.integer(r5);
s.integer(r6);
s.integer(r7);
s.integer(r8);
s.integer(r9);
s.integer(r10);
s.integer(r11);
s.integer(r12);
s.integer(r13);
s.integer(r14);
s.integer(r15);
s.integer(C4WFXVal);
s.integer(C4WFYVal);
s.integer(C4WFZVal);
s.integer(C4WFX2Val);
s.integer(C4WFY2Val);
s.integer(C4WFDist);
s.integer(C4WFScale);
s.integer(C41FXVal);
s.integer(C41FYVal);
s.integer(C41FAngleRes);
s.integer(C41FDist);
s.integer(C41FDistVal);
}
#endif

View File

@@ -5,6 +5,7 @@ namespace SNES {
DSP1 dsp1;
#include "serialization.cpp"
#include "dsp1emu.cpp"
void DSP1::init() {
@@ -78,5 +79,5 @@ void DSP1::write(unsigned addr, uint8 data) {
dsp1.setDr(data);
}
}
};
};

View File

@@ -1,10 +1,6 @@
#include "dsp1emu.hpp"
class DSP1 : public Memory {
private:
Dsp1 dsp1;
bool addr_decode(uint16 addr);
public:
void init();
void enable();
@@ -13,6 +9,12 @@ public:
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
void serialize(serializer&);
private:
Dsp1 dsp1;
bool addr_decode(uint16 addr);
};
extern DSP1 dsp1;

View File

@@ -33,6 +33,8 @@ class Dsp1
void setDr(uint8 iDr);
void reset();
void serialize(serializer&);
private:
enum FsmMajorState {WAIT_COMMAND, READ_DATA, WRITE_DATA};
enum MaxDataAccesses {MAX_READS=7, MAX_WRITES=1024};
@@ -72,7 +74,7 @@ class Dsp1
uint8 mSr; // status register
int mSrLowByteAccess;
uint16 mDr; // "internal" representation of the data register
FsmMajorState mFsmMajorState; // current major state of the FSM
unsigned mFsmMajorState; // current major state of the FSM
uint8 mCommand; // current command processed by the FSM
uint8 mDataCounter; // #uint16 read/writes counter used by the FSM
int16 mReadBuffer[MAX_READS];

View File

@@ -0,0 +1,56 @@
#ifdef DSP1_CPP
void DSP1::serialize(serializer &s) {
dsp1.serialize(s);
}
void Dsp1::serialize(serializer &s) {
for(unsigned i = 0; i < 3; i++) {
s.array(shared.MatrixA[i]);
s.array(shared.MatrixB[i]);
s.array(shared.MatrixC[i]);
}
s.integer(shared.CentreX);
s.integer(shared.CentreY);
s.integer(shared.CentreZ);
s.integer(shared.CentreZ_C);
s.integer(shared.CentreZ_E);
s.integer(shared.VOffset);
s.integer(shared.Les);
s.integer(shared.C_Les);
s.integer(shared.E_Les);
s.integer(shared.SinAas);
s.integer(shared.CosAas);
s.integer(shared.SinAzs);
s.integer(shared.CosAzs);
s.integer(shared.SinAZS);
s.integer(shared.CosAZS);
s.integer(shared.SecAZS_C1);
s.integer(shared.SecAZS_E1);
s.integer(shared.SecAZS_C2);
s.integer(shared.SecAZS_E2);
s.integer(shared.Nx);
s.integer(shared.Ny);
s.integer(shared.Nz);
s.integer(shared.Gx);
s.integer(shared.Gy);
s.integer(shared.Gz);
s.integer(shared.Hx);
s.integer(shared.Hy);
s.integer(shared.Vx);
s.integer(shared.Vy);
s.integer(shared.Vz);
s.integer(mSr);
s.integer(mSrLowByteAccess);
s.integer(mDr);
s.integer(mFsmMajorState);
s.integer(mCommand);
s.integer(mDataCounter);
s.array(mReadBuffer);
s.array(mWriteBuffer);
s.integer(mFreeze);
}
#endif

View File

@@ -5,7 +5,8 @@ namespace SNES {
DSP2 dsp2;
#include "dsp2_op.cpp"
#include "serialization.cpp"
#include "opcodes.cpp"
void DSP2::init() {
}

View File

@@ -29,6 +29,7 @@ public:
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
void serialize(serializer&);
DSP2();
~DSP2();

View File

@@ -0,0 +1,26 @@
#ifdef DSP2_CPP
void DSP2::serialize(serializer &s) {
s.integer(status.waiting_for_command);
s.integer(status.command);
s.integer(status.in_count);
s.integer(status.in_index);
s.integer(status.out_count);
s.integer(status.out_index);
s.array(status.parameters);
s.array(status.output);
s.integer(status.op05transparent);
s.integer(status.op05haslen);
s.integer(status.op05len);
s.integer(status.op06haslen);
s.integer(status.op06len);
s.integer(status.op09word1);
s.integer(status.op09word2);
s.integer(status.op0dhaslen);
s.integer(status.op0doutlen);
s.integer(status.op0dinlen);
}
#endif

View File

@@ -2062,9 +2062,9 @@ void DSP4SetByte()
// unknown
case 0x000A:
{
//int16 in1a = DSP4_READ_WORD();
int16 in1a = DSP4_READ_WORD();
int16 in2a = DSP4_READ_WORD();
//int16 in3a = DSP4_READ_WORD();
int16 in3a = DSP4_READ_WORD();
int16 out1a, out2a, out3a, out4a;
DSP4_OP0A(in2a, &out2a, &out1a, &out4a, &out3a);

View File

@@ -5,6 +5,7 @@ namespace SNES {
SDD1 sdd1;
#include "serialization.cpp"
#include "sdd1emu.cpp"
void SDD1::init() {}
@@ -54,10 +55,10 @@ uint8 SDD1::mmio_read(unsigned addr) {
}
switch(addr) {
case 0x4804: return (mmc[0] >> 20) & 7;
case 0x4805: return (mmc[1] >> 20) & 7;
case 0x4806: return (mmc[2] >> 20) & 7;
case 0x4807: return (mmc[3] >> 20) & 7;
case 0x4804: return mmc[0] >> 20;
case 0x4805: return mmc[1] >> 20;
case 0x4806: return mmc[2] >> 20;
case 0x4807: return mmc[3] >> 20;
}
return cpu.regs.mdr;
@@ -83,10 +84,10 @@ void SDD1::mmio_write(unsigned addr, uint8 data) {
case 0x4800: sdd1_enable = data; break;
case 0x4801: xfer_enable = data; break;
case 0x4804: mmc[0] = (data & 7) << 20; break;
case 0x4805: mmc[1] = (data & 7) << 20; break;
case 0x4806: mmc[2] = (data & 7) << 20; break;
case 0x4807: mmc[3] = (data & 7) << 20; break;
case 0x4804: mmc[0] = data << 20; break;
case 0x4805: mmc[1] = data << 20; break;
case 0x4806: mmc[2] = data << 20; break;
case 0x4807: mmc[3] = data << 20; break;
}
}
@@ -152,11 +153,9 @@ void SDD1::write(unsigned addr, uint8 data) {
}
SDD1::SDD1() {
buffer.data = new uint8[65536];
}
SDD1::~SDD1() {
delete[] buffer.data;
}
};

View File

@@ -13,6 +13,7 @@ public:
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
void serialize(serializer&);
SDD1();
~SDD1();
@@ -30,7 +31,7 @@ private:
SDD1emu sdd1emu;
struct {
uint8 *data; //pointer to decompressed S-DD1 data (65536 bytes)
uint8 data[65536]; //pointer to decompressed S-DD1 data
uint16 offset; //read index into S-DD1 decompression buffer
unsigned size; //length of data buffer; reads decrement counter, set ready to false at 0
bool ready; //true when data[] is valid; false to invoke sdd1emu.decompress()

View File

@@ -0,0 +1,19 @@
#ifdef SDD1_CPP
void SDD1::serialize(serializer &s) {
s.integer(sdd1_enable);
s.integer(xfer_enable);
s.array(mmc);
for(unsigned n = 0; n < 8; n++) {
s.integer(dma[n].addr);
s.integer(dma[n].size);
}
s.array(buffer.data);
s.integer(buffer.offset);
s.integer(buffer.size);
s.integer(buffer.ready);
}
#endif

View File

@@ -1,65 +0,0 @@
#include <../base.hpp>
#define SGB_CPP
namespace SNES {
SuperGameBoy sgb;
void SuperGameBoy::enter() {
while(true) {
if(sgb_run) {
unsigned samples = sgb_run(samplebuffer, 16);
scheduler.addclocks_cop(samples * 10);
scheduler.sync_copcpu();
} else {
scheduler.addclocks_cop(64 * 1024 * 1024);
scheduler.sync_copcpu();
}
}
}
uint8_t SuperGameBoy::read(unsigned addr) {
addr &= 0xffff;
if(sgb_read) return sgb_read(addr);
return 0x00;
}
void SuperGameBoy::write(unsigned addr, uint8_t data) {
addr &= 0xffff;
if(sgb_write) return sgb_write(addr, data);
}
void SuperGameBoy::init() {
if(libsgb.open("SuperGameBoy")) {
sgb_init = libsgb.sym("sgb_init");
sgb_term = libsgb.sym("sgb_term");
sgb_power = libsgb.sym("sgb_power");
sgb_reset = libsgb.sym("sgb_reset");
sgb_read = libsgb.sym("sgb_read");
sgb_write = libsgb.sym("sgb_write");
sgb_run = libsgb.sym("sgb_run");
}
}
void SuperGameBoy::enable() {
}
void SuperGameBoy::power() {
bus.map(Bus::MapDirect, 0x00, 0x3f, 0x6000, 0x7fff, *this);
bus.map(Bus::MapDirect, 0x80, 0xbf, 0x6000, 0x7fff, *this);
if(sgb_init) {
sgb_init(SGB2,
memory::gbrom.data(), memory::gbrom.size(),
memory::gbram.data(), memory::gbram.size()
);
}
if(sgb_power) sgb_power();
}
void SuperGameBoy::reset() {
if(sgb_reset) sgb_reset();
}
};

View File

@@ -1,27 +0,0 @@
class SuperGameBoy : public Memory {
public:
void enter();
uint8_t read(unsigned addr);
void write(unsigned addr, uint8_t data);
void init();
void enable();
void power();
void reset();
private:
library libsgb;
uint32_t samplebuffer[4096];
enum { SGB1 = 0, SGB2 = 1 };
function<bool (bool, uint8_t*, unsigned, uint8_t*, unsigned)> sgb_init;
function<void ()> sgb_term;
function<void ()> sgb_power;
function<void ()> sgb_reset;
function<uint8_t (unsigned)> sgb_read;
function<void (unsigned, uint8_t)> sgb_write;
function<unsigned (uint32_t*, unsigned)> sgb_run;
};
extern SuperGameBoy sgb;

View File

@@ -535,17 +535,17 @@ void SPC7110::mmio_write(unsigned addr, uint8 data) {
case 0x4831: {
r4831 = data;
dx_offset = datarom_addr((data & 7) * 0x100000);
dx_offset = datarom_addr(data * 0x100000);
} break;
case 0x4832: {
r4832 = data;
ex_offset = datarom_addr((data & 7) * 0x100000);
ex_offset = datarom_addr(data * 0x100000);
} break;
case 0x4833: {
r4833 = data;
fx_offset = datarom_addr((data & 7) * 0x100000);
fx_offset = datarom_addr(data * 0x100000);
} break;
case 0x4834: r4834 = data; break;

View File

@@ -0,0 +1,8 @@
#ifdef SRTC_CPP
void SRTC::serialize(serializer &s) {
s.integer(rtc_mode);
s.integer(rtc_index);
}
#endif

View File

@@ -5,6 +5,8 @@ namespace SNES {
SRTC srtc;
#include "serialization.cpp"
const unsigned SRTC::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
void SRTC::init() {
@@ -20,7 +22,7 @@ void SRTC::power() {
}
void SRTC::reset() {
rtc_mode = RTCM_Read;
rtc_mode = RtcRead;
rtc_index = -1;
update_time();
}
@@ -159,7 +161,7 @@ uint8 SRTC::mmio_read(unsigned addr) {
addr &= 0xffff;
if(addr == 0x2800) {
if(rtc_mode != RTCM_Read) return 0x00;
if(rtc_mode != RtcRead) return 0x00;
if(rtc_index < 0) {
update_time();
@@ -183,19 +185,19 @@ void SRTC::mmio_write(unsigned addr, uint8 data) {
data &= 0x0f; //only the low four bits are used
if(data == 0x0d) {
rtc_mode = RTCM_Read;
rtc_mode = RtcRead;
rtc_index = -1;
return;
}
if(data == 0x0e) {
rtc_mode = RTCM_Command;
rtc_mode = RtcCommand;
return;
}
if(data == 0x0f) return; //unknown behavior
if(rtc_mode == RTCM_Write) {
if(rtc_mode == RtcWrite) {
if(rtc_index >= 0 && rtc_index < 12) {
memory::cartrtc.write(rtc_index++, data);
@@ -209,17 +211,17 @@ void SRTC::mmio_write(unsigned addr, uint8 data) {
memory::cartrtc.write(rtc_index++, weekday(year, month, day));
}
}
} else if(rtc_mode == RTCM_Command) {
} else if(rtc_mode == RtcCommand) {
if(data == 0) {
rtc_mode = RTCM_Write;
rtc_mode = RtcWrite;
rtc_index = 0;
} else if(data == 4) {
rtc_mode = RTCM_Ready;
rtc_mode = RtcReady;
rtc_index = -1;
for(unsigned i = 0; i < 13; i++) memory::cartrtc.write(i, 0);
} else {
//unknown behavior
rtc_mode = RTCM_Ready;
rtc_mode = RtcReady;
}
}
}

View File

@@ -1,22 +1,24 @@
class SRTC : public MMIO {
public:
void update_time();
unsigned weekday(unsigned year, unsigned month, unsigned day);
void init();
void enable();
void power();
void reset();
uint8 mmio_read (unsigned addr);
void mmio_write(unsigned addr, uint8 data);
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
void serialize(serializer&);
SRTC();
private:
static const unsigned months[12];
enum RTC_Mode { RTCM_Ready, RTCM_Command, RTCM_Read, RTCM_Write } rtc_mode;
enum RtcMode { RtcReady, RtcCommand, RtcRead, RtcWrite };
unsigned rtc_mode;
signed rtc_index;
void update_time();
unsigned weekday(unsigned year, unsigned month, unsigned day);
};
extern SRTC srtc;

View File

@@ -0,0 +1,7 @@
#ifdef ST010_CPP
void ST010::serialize(serializer &s) {
s.array(ram);
}
#endif

View File

@@ -5,6 +5,10 @@ namespace SNES {
ST010 st010;
#include "st010_data.hpp"
#include "serialization.cpp"
#include "st010_op.cpp"
void ST010::init() {
}
@@ -13,9 +17,6 @@ void ST010::enable() {
bus.map(Bus::MapDirect, 0xe8, 0xef, 0x0000, 0x0fff, *this);
}
#include "st010_data.hpp"
#include "st010_op.cpp"
int16 ST010::sin(int16 theta) {
return sin_table[(theta >> 8) & 0xff];
}

View File

@@ -8,6 +8,8 @@ public:
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
void serialize(serializer&);
private:
uint8 ram[0x1000];
static const int16 sin_table[256];

View File

@@ -453,7 +453,7 @@ template<int n> void SuperFX::op_jmp_r() {
//$98-9d(alt1): ljmp rN
template<int n> void SuperFX::op_ljmp_r() {
regs.pbr = regs.r[n];
regs.pbr = regs.r[n] & 0x7f;
regs.r[15] = regs.sr();
regs.cbr = regs.r[15] & 0xfff0;
cache_flush();
@@ -593,7 +593,7 @@ void SuperFX::op_ramb() {
//$df(alt3): romb
void SuperFX::op_romb() {
rombuffer_sync();
regs.rombr = regs.sr();
regs.rombr = regs.sr() & 0x7f;
regs.reset();
}

View File

@@ -91,7 +91,7 @@ void SuperFX::mmio_write(unsigned addr, uint8 data) {
} break;
case 0x3034: {
regs.pbr = data;
regs.pbr = data & 0x7f;
cache_flush();
} break;

View File

@@ -0,0 +1,133 @@
#include <../base.hpp>
#define SUPERGAMEBOY_CPP
namespace SNES {
SuperGameBoy supergameboy;
void SuperGameBoy::enter() {
scheduler.clock.cop_freq = (version == SuperGameBoy1 ? 2147727 : 2097152);
if(!sgb_run) while(true) {
audio.coprocessor_sample(0, 0);
scheduler.addclocks_cop(1);
scheduler.sync_copcpu();
}
while(true) {
unsigned samples = sgb_run(samplebuffer, 16);
for(unsigned i = 0; i < samples; i++) {
int16 left = samplebuffer[i] >> 0;
int16 right = samplebuffer[i] >> 16;
//SNES audio is notoriously quiet; lower Game Boy samples to match SGB sound effects
audio.coprocessor_sample(left / 3, right / 3);
}
scheduler.addclocks_cop(samples);
scheduler.sync_copcpu();
}
}
uint8 SuperGameBoy::mmio_read(unsigned addr) {
addr &= 0xffff;
if(addr == 0x2181) return mmio[0]->mmio_read(addr);
if(addr == 0x2182) return mmio[1]->mmio_read(addr);
if(addr == 0x420b) return mmio[2]->mmio_read(addr);
return 0x00;
}
void SuperGameBoy::mmio_write(unsigned addr, uint8 data) {
addr &= 0xffff;
if(addr == 0x2181) {
row = (row & 0xff00) | (data << 0);
mmio[0]->mmio_write(addr, data);
}
if(addr == 0x2182) {
row = (row & 0x00ff) | (data << 8);
mmio[1]->mmio_write(addr, data);
}
if(addr == 0x420b) {
if(data == 0x10 && sgb_row) {
if(row >= 0x5000 && row <= 0x6540) sgb_row((row - 0x5000) / 320);
if(row >= 0x6800 && row <= 0x7d40) sgb_row((row - 0x6800) / 320);
}
mmio[2]->mmio_write(addr, data);
}
}
uint8 SuperGameBoy::read(unsigned addr) {
if(sgb_read) return sgb_read(addr);
return 0x00;
}
void SuperGameBoy::write(unsigned addr, uint8 data) {
if(sgb_write) sgb_write(addr, data);
}
void SuperGameBoy::init() {
if(open("supergameboy")) {
sgb_rom = sym("sgb_rom");
sgb_ram = sym("sgb_ram");
sgb_rtc = sym("sgb_rtc");
sgb_init = sym("sgb_init");
sgb_term = sym("sgb_term");
sgb_power = sym("sgb_power");
sgb_reset = sym("sgb_reset");
sgb_row = sym("sgb_row");
sgb_read = sym("sgb_read");
sgb_write = sym("sgb_write");
sgb_run = sym("sgb_run");
sgb_save = sym("sgb_save");
sgb_serialize = sym("sgb_serialize");
}
}
void SuperGameBoy::enable() {
mmio[0] = memory::mmio.mmio[0x2181 - 0x2000];
mmio[1] = memory::mmio.mmio[0x2182 - 0x2000];
mmio[2] = memory::mmio.mmio[0x420b - 0x2000];
memory::mmio.map(0x2181, *this);
memory::mmio.map(0x2182, *this);
memory::mmio.map(0x420b, *this);
}
void SuperGameBoy::power() {
//determine whether to use SGB1 or SGB2 mode based on the cartridge title (look for the '2')
version = memory::cartrom[0x7fcd] != 0x32 ? SuperGameBoy1 : SuperGameBoy2;
audio.coprocessor_enable(true);
audio.coprocessor_frequency(version == SuperGameBoy1 ? 2147727.0 : 2097152.0);
bus.map(Bus::MapDirect, 0x00, 0x3f, 0x6000, 0x7fff, *this);
bus.map(Bus::MapDirect, 0x80, 0xbf, 0x6000, 0x7fff, *this);
sgb_rom(memory::gbrom.data(), memory::gbrom.size() == -1U ? 0 : memory::gbrom.size());
sgb_ram(memory::gbram.data(), memory::gbram.size() == -1U ? 0 : memory::gbram.size());
sgb_rtc(memory::gbrtc.data(), memory::gbrtc.size() == -1U ? 0 : memory::gbrtc.size());
//determine whether to use SGB1 or SGB2 mode based on the cartridge title (look for the '2')
if(sgb_init) sgb_init(version);
if(sgb_power) sgb_power();
}
void SuperGameBoy::reset() {
if(sgb_reset) sgb_reset();
}
void SuperGameBoy::unload() {
if(sgb_term) sgb_term();
}
void SuperGameBoy::serialize(serializer &s) {
s.integer(row);
s.integer(version);
if(sgb_serialize) sgb_serialize(s);
}
}

View File

@@ -0,0 +1,41 @@
class SuperGameBoy : public MMIO, public Memory, public library {
public:
void enter();
MMIO *mmio[3];
uint8 mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8 data);
uint8 read(unsigned addr);
void write(unsigned addr, uint8 data);
void init();
void enable();
void power();
void reset();
void unload();
void serialize(serializer&);
private:
uint32_t samplebuffer[4096];
unsigned row;
bool version;
enum { SuperGameBoy1 = 0, SuperGameBoy2 = 1 };
function<void (uint8_t*, unsigned)> sgb_rom;
function<void (uint8_t*, unsigned)> sgb_ram;
function<void (uint8_t*, unsigned)> sgb_rtc;
function<bool (bool)> sgb_init;
function<void ()> sgb_term;
function<void ()> sgb_power;
function<void ()> sgb_reset;
function<void (unsigned)> sgb_row;
function<uint8 (uint16)> sgb_read;
function<void (uint16, uint8)> sgb_write;
function<unsigned (uint32_t*, unsigned)> sgb_run;
function<void ()> sgb_save;
function<void (serializer&)> sgb_serialize;
};
extern SuperGameBoy supergameboy;

View File

@@ -102,7 +102,7 @@ uint32 CPUcore::decode(uint8 offset_type, uint32 addr) {
return(r & 0xffffff);
}
void CPUcore::disassemble_opcode(char *output) {
void CPUcore::disassemble_opcode(char *output, uint32 addr) {
static reg24_t pc;
char t[256];
char *s = output;
@@ -112,7 +112,7 @@ void CPUcore::disassemble_opcode(char *output) {
return;
}
pc.d = regs.pc.d;
pc.d = addr;
sprintf(s, "%.6x ", (uint32)pc.d);
uint8 op = dreadb(pc.d); pc.w++;

View File

@@ -22,7 +22,7 @@
OPTYPE_RELW, //relw
};
void disassemble_opcode(char *output);
void disassemble_opcode(char *output, uint32 addr);
uint8 dreadb(uint32 addr);
uint16 dreadw(uint32 addr);
uint32 dreadl(uint32 addr);

View File

@@ -1,72 +1,45 @@
#ifdef SCPU_CPP
void sCPUdebug::op_step() {
void sCPUDebug::op_step() {
bool break_event = false;
if(debugger.step_cpu) {
debugger.break_event = Debugger::CPUStep;
break_event = true;
scheduler.exit();
} else {
debugger.breakpoint_test(Debugger::Breakpoint::CPUBus, Debugger::Breakpoint::Exec, regs.pc, 0x00);
}
for(unsigned i = 0; i < Debugger::Breakpoints; i++) {
if(debugger.breakpoint[i].enabled == false) continue;
if(debugger.breakpoint[i].addr != regs.pc) continue;
if(debugger.breakpoint[i].mode != Debugger::Breakpoint::Exec) continue;
if(debugger.breakpoint[i].source != Debugger::Breakpoint::CPUBus) continue;
debugger.breakpoint[i].counter++;
debugger.breakpoint_hit = i;
debugger.break_event = Debugger::BreakpointHit;
break_event = true;
break;
}
if(break_event) scheduler.exit();
if(debugger.trace_cpu) {
char t[256];
disassemble_opcode(t);
debugger.tracefile.print(string() << t << "\n");
}
usage[regs.pc] &= ~(UsageFlagM | UsageFlagX);
usage[regs.pc] |= UsageExec | (regs.p.m << 1) | (regs.p.x << 0);
opcode_pc = regs.pc;
if(step_event) step_event();
sCPU::op_step();
scheduler.sync_cpusmp();
}
uint8 sCPUdebug::op_read(uint32 addr) {
uint8 sCPUDebug::op_read(uint32 addr) {
uint8 data = sCPU::op_read(addr);
for(unsigned i = 0; i < Debugger::Breakpoints; i++) {
if(debugger.breakpoint[i].enabled == false) continue;
if(debugger.breakpoint[i].addr != addr) continue;
if(debugger.breakpoint[i].data != -1 && debugger.breakpoint[i].data != data) continue;
if(debugger.breakpoint[i].mode != Debugger::Breakpoint::Read) continue;
if(debugger.breakpoint[i].source != Debugger::Breakpoint::CPUBus) continue;
debugger.breakpoint[i].counter++;
debugger.breakpoint_hit = i;
debugger.break_event = Debugger::BreakpointHit;
scheduler.exit();
break;
}
usage[addr] |= UsageRead;
debugger.breakpoint_test(Debugger::Breakpoint::CPUBus, Debugger::Breakpoint::Read, addr, data);
return data;
}
void sCPUdebug::op_write(uint32 addr, uint8 data) {
void sCPUDebug::op_write(uint32 addr, uint8 data) {
sCPU::op_write(addr, data);
usage[addr] |= UsageWrite;
usage[addr] &= ~UsageExec;
debugger.breakpoint_test(Debugger::Breakpoint::CPUBus, Debugger::Breakpoint::Write, addr, data);
}
for(unsigned i = 0; i < Debugger::Breakpoints; i++) {
if(debugger.breakpoint[i].enabled == false) continue;
if(debugger.breakpoint[i].addr != addr) continue;
if(debugger.breakpoint[i].data != -1 && debugger.breakpoint[i].data != data) continue;
if(debugger.breakpoint[i].mode != Debugger::Breakpoint::Write) continue;
if(debugger.breakpoint[i].source != Debugger::Breakpoint::CPUBus) continue;
sCPUDebug::sCPUDebug() {
usage = new uint8[1 << 24]();
opcode_pc = 0x8000;
}
debugger.breakpoint[i].counter++;
debugger.breakpoint_hit = i;
debugger.break_event = Debugger::BreakpointHit;
scheduler.exit();
break;
}
sCPUDebug::~sCPUDebug() {
delete[] usage;
}
#endif

View File

@@ -1,6 +1,21 @@
class sCPUdebug : public sCPU {
class sCPUDebug : public sCPU {
public:
function<void ()> step_event;
enum Usage {
UsageRead = 0x80,
UsageWrite = 0x40,
UsageExec = 0x20,
UsageFlagM = 0x02,
UsageFlagX = 0x01,
};
uint8 *usage;
uint32 opcode_pc; //points to the current opcode, used to backtrace on read/write breakpoints
void op_step();
uint8 op_read(uint32 addr);
void op_write(uint32 addr, uint8 data);
sCPUDebug();
~sCPUDebug();
};

View File

@@ -51,8 +51,6 @@ void sCPU::dma_transfer(bool direction, uint8 bbus, uint32 abus) {
}
}
}
cycle_edge();
}
/*****
@@ -118,6 +116,7 @@ void sCPU::dma_run() {
unsigned index = 0;
do {
dma_transfer(channel[i].direction, dma_bbus(i, index++), dma_addr(i));
cycle_edge();
} while(channel[i].dma_enabled && --channel[i].xfersize);
channel[i].dma_enabled = false;

View File

@@ -5,7 +5,7 @@ namespace SNES {
#if defined(DEBUGGER)
#include "debugger/debugger.cpp"
sCPUdebug cpu;
sCPUDebug cpu;
#else
sCPU cpu;
#endif

View File

@@ -1,5 +1,3 @@
class sCPUdebug;
class sCPU : public CPU, public CPUcore {
public:
void enter();
@@ -97,12 +95,12 @@ public:
sCPU();
~sCPU();
friend class sCPUdebug;
friend class sCPUDebug;
};
#if defined(DEBUGGER)
#include "debugger/debugger.hpp"
extern sCPUdebug cpu;
extern sCPUDebug cpu;
#else
extern sCPU cpu;
#endif

View File

@@ -3,7 +3,7 @@
<head></head>
<body>
<h1>bsnes&trade; Usage Documentation</h1><br>
<h2>bsnes Usage Documentation</h2><br>
bsnes is a Super Nintendo / Super Famicom emulator that strives to provide the
most faithful hardware emulation possible. It focuses on accuracy and clean
@@ -12,49 +12,49 @@ emulator to document how the underlying hardware works. It is thus very useful
for development and research. And while it can be used for general purpose
gaming, it will require significantly more powerful hardware than a typical
emulator.
<hr>
<br>
<h2><u>Modes of Operation</u></h2><br>
<h3>Modes of Operation</h3><br>
bsnes is capable of running both in its default multi-user mode, as well as in
single-user mode.<br>
<br>
single-user mode.
<br><br>
In multi-user mode, configuration data is stored inside the user's home
directory. On Windows, this is located at "%APPDATA%/.bsnes". On other operating
systems, this is located at "~/.bsnes".<br>
<br>
systems, this is located at "~/.bsnes".
<br><br>
To enable single-user mode, create a blank "bsnes.cfg" file inside the same
folder as the bsnes executable. bsnes will then use this file to store
configuration data.
<hr>
<br>
<h2><u>Supported Filetypes</u></h2><br>
<h3>Supported Filetypes</h3><br>
<b>SFC, SMC, SWC, FIG:</b> SNES cartridge &mdash; ROM image.<br>
<b>SFC:</b> SNES cartridge &mdash; ROM image.<br>
<b>BS:</b> Satellaview BS-X flash cartridge &mdash; EEPROM image.<br>
<b>ST:</b> Sufami Turbo cartridge &mdash; ROM image.<br>
<b>SRM, PSR:</b> non-volatile memory, often used to save game data &mdash; (P)SRAM image.<br>
<b>RTC:</b> real-time clock non-volatile memory.<br>
<b>UPS:</b> patch data, used to dynamically modify cartridge of same base filename upon load.<br>
<b>CHT:</b> plain-text list of "Game Genie" / "Pro Action Replay" codes.
<hr>
<br>
<h2><u>Known Limitations</u></h2><br>
<h3>Known Limitations</h3><br>
<b>Satellaview BS-X emulation:</b> this hardware is only partially supported.
This is mostly because the satellite network it used (St. GIGA) has been shut
down. Access to this network would be required to properly reverse engineer much
of the hardware. Working around this would require game-specific hacks, which
are contrary to the design goals of this emulator. As a result, most BS-X
software will not function correctly.<br>
<br>
software will not function correctly.
<br><br>
<b>Netplay:</b> internet multiplay is not currently supported nor planned.
<hr>
<br>
<h2><u>Contributors</u></h2>
<h3>Contributors</h3><br>
&bull; Andreas Naive<br>
&bull; anomie<br>
&bull; _Demo_<br>

Binary file not shown.

After

Width:  |  Height:  |  Size: 592 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 672 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 558 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 647 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 668 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 912 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 995 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 900 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 927 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 482 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 966 B

View File

@@ -3,84 +3,75 @@
<head></head>
<body>
<h1>bsnes&trade; Reference License</h1><br>
<b>Copyright &copy; 2004&ndash;2009 byuu<br>
All rights reserved</b>
<hr>
<h2><u>1. Definitions</u></h2><br>
The terms "reproduce", "reproduction", "distribute" and "distribution" have the
same meaning here as under U.S. copyright law.<br><br>
"The software" means this software package as a whole, including, but not
limited to, this license, binaries, source code, documentation, and data.<br><br>
"You" means the licensee of the software.<br><br>
"The licensor" means the copyright holder of the software, byuu.
<hr>
<h2><u>2. Grant of Rights</u></h2><br>
Subject to the terms of this license, the licensor grants you a
non-transferable, non-exclusive, worldwide, royalty-free copyright license to
reproduce the software for non-commercial use only, provided the software
remains unmodified, and there is no charge for the software itself, nor for the
medium upon which the software is distributed. The reproduction of modified or
derivative works of the software is strictly prohibited without the express
consent of the licensor.
<hr>
<h2><u>3. Limitations</u></h2><br>
This license does not grant you any rights to use the licensor's name, logo or
trademarks.<br>
<h2>GNU GENERAL PUBLIC LICENSE<br>
<small>Version 2, June 1991</small></h2>
<br>
The software is provided "as is", and any express or implied warranties,
including, but not limited to, the implied warranties of merchantability and
fitness for a particular purpose are disclaimed. In no event shall the licensor
be liable for any direct, indirect, incidental, special, exemplary, or
consequential damages (including, but not limited to, procurement of sbustitute
goods or services; loss of use, data, or profits; or business interruption)
however caused and on any theory of liability, whether in contract, strict
liability, or tort (including negligence or otherwise) arising in any way out of
the use of the software, even if advised of the possibility of such damage.<br>
<br>
<h3>TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION</h3><br>
In the event that this license is determined to be invalid or unenforceable, the
Grant of Rights will become null and void, and no rights shall be granted to the
licensee, within the scope of U.S. copyright law.
<hr>
<b>0.</b>
This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".<br><br>
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.<br><br>
<h2><u>4. Exemptions</u></h2><br>
<b>1.</b>
You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.<br><br>
You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.<br><br>
The software includes the work of other copyrights holders, which is licensed
under different agreements, and exempt from this license. Below is a complete
list of all such software, and their respective copyright holders and licenses.
Note that explicit permission has been granted to the licensor to use included
software which is ordinarily not compatible with this license, such as the GPL.
<br>
<b>2.</b>
You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:<br><br>
<ul>
<li>a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.</li>
<li>b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.</li>
<li>c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)</li>
</ul>
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.<br><br>
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.<br><br>
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.<br><br>
<table border="1" cellpadding="3">
<tr><td><b>Name</b></td><td><b>License</b></td><td><b>Author(s)</b></td></tr>
<b>3.</b>
You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:
<ul>
<li>a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,</li>
<li>b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,</li>
<li>c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)</li>
</ul>
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.<br><br>
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.<br><br>
<tr><td>Cx4 emulator</td><td></td><td>anomie, Kris Bleakley, Nach, zsKnight</td></tr>
<tr><td>DSP-1 emulator</td><td></td><td>Andreas Naive, John Weidman, Kris Bleakley, neviksti</td></tr>
<tr><td>DSP-2 emulator</td><td></td><td>Kris Bleakley</td></tr>
<tr><td>DSP-3 emulator</td><td></td><td>John Weidman, Kris Bleakley, Lancer, z80 gaiden</td></tr>
<tr><td>DSP-4 emulator</td><td></td><td>Dreamer Nom, John Weidman, Kris Bleakley, Nach, z80 gaiden</td></tr>
<tr><td>S-DD1 decompressor</td><td>Public Domain</td><td>Andreas Naive</td></tr>
<tr><td>S-DSP emulator</td><td>LGPL 2.1</td><td>Shay Green</td></tr>
<tr><td>SPC7110 decompressor</td><td>Public Domain</td><td>neviksti</td></tr>
<tr><td>ST-0010 emulator</td><td></td><td>Feather, John Weidman, Kris Bleakley, Matthew Kendora</td></tr>
<b>4.</b>
You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.<br><br>
<tr><td>Qt toolkit</td><td>LGPL 2.1</td><td>Nokia</td></tr>
<tr><td>JMA decompressor</td><td>GPL 2</td><td>NSRT team</td></tr>
<tr><td>NTSC filter</td><td>LGPL 2.1</td><td>Shay Green</td></tr>
<tr><td>zlib decompressor</td><td>zlib license</td><td>zlib team</td></tr>
</table>
<b>5.</b>
You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.<br><br>
<b>6.</b>
Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.<br><br>
<b>7.</b>
If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.<br><br>
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.<br><br>
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.<br><br>
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.<br><br>
<b>8.</b>
If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.<br><br>
<b>9.</b>
The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.<br><br>
Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.<br><br>
<b>10.</b>
If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.<br><br>
<b>NO WARRANTY</b><br><br>
<b>11.</b>
BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.<br><br>
<b>12.</b>
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.<br>
<h3>END OF TERMS AND CONDITIONS</h3>
</body>
</html>

View File

@@ -0,0 +1,3 @@
#ifdef SDSP_CPP
#endif

View File

@@ -0,0 +1,3 @@
class sDSPDebug : public sDSP {
public:
};

View File

@@ -7,7 +7,12 @@
#define SDSP_CPP
namespace SNES {
sDSP dsp;
#if defined(DEBUGGER)
#include "debugger/debugger.cpp"
sDSPDebug dsp;
#else
sDSP dsp;
#endif
#include "serialization.cpp"

View File

@@ -164,6 +164,13 @@ private:
void echo_28();
void echo_29();
void echo_30();
friend class sDSPDebug;
};
extern sDSP dsp;
#if defined(DEBUGGER)
#include "debugger/debugger.hpp"
extern sDSPDebug dsp;
#else
extern sDSP dsp;
#endif

104
src/lib/libco/amd64.c Normal file
View File

@@ -0,0 +1,104 @@
/*
libco.amd64 (2009-10-12)
author: byuu
license: public domain
*/
#define LIBCO_C
#include "libco.h"
#include <assert.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
static thread_local long long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
static void (*co_swap)(cothread_t, cothread_t) = 0;
#ifdef _WIN32
//ABI: Win64
static unsigned char co_swap_function[] = {
0x48, 0x89, 0x22, 0x48, 0x8B, 0x21, 0x58, 0x48, 0x89, 0x6A, 0x08, 0x48, 0x89, 0x72, 0x10, 0x48,
0x89, 0x7A, 0x18, 0x48, 0x89, 0x5A, 0x20, 0x4C, 0x89, 0x62, 0x28, 0x4C, 0x89, 0x6A, 0x30, 0x4C,
0x89, 0x72, 0x38, 0x4C, 0x89, 0x7A, 0x40, 0x48, 0x81, 0xC2, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83,
0xE2, 0xF0, 0x0F, 0x29, 0x32, 0x0F, 0x29, 0x7A, 0x10, 0x44, 0x0F, 0x29, 0x42, 0x20, 0x44, 0x0F,
0x29, 0x4A, 0x30, 0x44, 0x0F, 0x29, 0x52, 0x40, 0x44, 0x0F, 0x29, 0x5A, 0x50, 0x44, 0x0F, 0x29,
0x62, 0x60, 0x44, 0x0F, 0x29, 0x6A, 0x70, 0x44, 0x0F, 0x29, 0xB2, 0x80, 0x00, 0x00, 0x00, 0x44,
0x0F, 0x29, 0xBA, 0x90, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x69, 0x08, 0x48, 0x8B, 0x71, 0x10, 0x48,
0x8B, 0x79, 0x18, 0x48, 0x8B, 0x59, 0x20, 0x4C, 0x8B, 0x61, 0x28, 0x4C, 0x8B, 0x69, 0x30, 0x4C,
0x8B, 0x71, 0x38, 0x4C, 0x8B, 0x79, 0x40, 0x48, 0x81, 0xC1, 0x80, 0x00, 0x00, 0x00, 0x48, 0x83,
0xE1, 0xF0, 0x0F, 0x29, 0x31, 0x0F, 0x29, 0x79, 0x10, 0x44, 0x0F, 0x29, 0x41, 0x20, 0x44, 0x0F,
0x29, 0x49, 0x30, 0x44, 0x0F, 0x29, 0x51, 0x40, 0x44, 0x0F, 0x29, 0x59, 0x50, 0x44, 0x0F, 0x29,
0x61, 0x60, 0x44, 0x0F, 0x29, 0x69, 0x70, 0x44, 0x0F, 0x29, 0xB1, 0x80, 0x00, 0x00, 0x00, 0x44,
0x0F, 0x29, 0xB9, 0x90, 0x00, 0x00, 0x00, 0xFF, 0xE0,
};
#include <windows.h>
void co_init() {
DWORD old_privileges;
VirtualProtect(co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges);
}
#else
//ABI: SystemV
static unsigned char co_swap_function[] = {
0x48, 0x89, 0x26, 0x48, 0x8B, 0x27, 0x58, 0x48, 0x89, 0x6E, 0x08, 0x48, 0x89, 0x5E, 0x10, 0x4C,
0x89, 0x66, 0x18, 0x4C, 0x89, 0x6E, 0x20, 0x4C, 0x89, 0x76, 0x28, 0x4C, 0x89, 0x7E, 0x30, 0x48,
0x8B, 0x6F, 0x08, 0x48, 0x8B, 0x5F, 0x10, 0x4C, 0x8B, 0x67, 0x18, 0x4C, 0x8B, 0x6F, 0x20, 0x4C,
0x8B, 0x77, 0x28, 0x4C, 0x8B, 0x7F, 0x30, 0xFF, 0xE0,
};
#include <unistd.h>
#include <sys/mman.h>
void co_init() {
unsigned long long addr = (unsigned long long)co_swap_function;
unsigned long long base = addr - (addr % sysconf(_SC_PAGESIZE));
unsigned long long size = (addr - base) + sizeof co_swap_function;
mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
}
#endif
static void crash() {
assert(0); /* called only if cothread_t entrypoint returns */
}
cothread_t co_active() {
if(!co_active_handle) co_active_handle = &co_active_buffer;
return co_active_handle;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
cothread_t handle;
if(!co_swap) {
co_init();
co_swap = (void (*)(cothread_t, cothread_t))co_swap_function;
}
if(!co_active_handle) co_active_handle = &co_active_buffer;
size += 512; /* allocate additional space for storage */
size &= ~15; /* align stack to 16-byte boundary */
if(handle = (cothread_t)malloc(size)) {
long long *p = (long long*)((char*)handle + size); /* seek to top of stack */
*--p = (long long)crash; /* crash if entrypoint returns */
*--p = (long long)entrypoint; /* start of function */
*(long long*)handle = (long long)p; /* stack pointer */
}
return handle;
}
void co_delete(cothread_t handle) {
free(handle);
}
void co_switch(cothread_t handle) {
register cothread_t co_previous_handle = co_active_handle;
co_swap(co_active_handle = handle, co_previous_handle);
}
#ifdef __cplusplus
}
#endif

View File

@@ -6,15 +6,17 @@
#if defined(__GNUC__) && defined(__i386__)
#include "x86.c"
#elif defined(__GNUC__) && defined(__amd64__) && !defined(__MINGW64__)
#include "x86-64.c"
#elif defined(__MINGW64__)
#include "fiber.c"
#elif defined(__GNUC__) && defined(__amd64__)
#include "amd64.c"
#elif defined(__GNUC__) && defined(__powerpc__) && defined(__ELF__)
#include "ppc-elf.c"
#elif defined(__GNUC__)
#include "sjlj.c"
#elif defined(_MSC_VER) && defined(_M_IX86)
#include "x86.c"
#elif defined(_MSC_VER) && defined(_M_AMD64)
#include "amd64.c"
#elif defined(_MSC_VER)
#include "fiber.c"
#else
#error "libco: unsupported processor, compiler or operating system"

View File

@@ -1,6 +1,6 @@
/*
libco
version: 0.13 rc2 (2008-01-28)
version: 0.15 (2009-10-12)
license: public domain
*/

325
src/lib/libco/ppc-elf.c Normal file
View File

@@ -0,0 +1,325 @@
/*
* libco.ppc-elf
* author: Kernigh
* license: public domain
*
* PowerPC 32-bit ELF implementation of libco (for compile with GCC),
* ported from PowerPC Mac OS X implementation (ppc.s) by Vas Crabb.
* This ELF version works for OpenBSD, and might also work for FreeBSD,
* NetBSD and Linux.
*
* Note 1: This implementation does not handle the AltiVec/VMX
* registers, because the ELF ABI does not mention them,
* and my OpenBSD system is not using them.
*
* Note 2: If you want position-independent code, then you must
* define __PIC__. gcc -fpic or -fPIC defines __PIC__, but
* gcc -fpie or -fPIE might not. If you want to use -fpie
* or -fPIE, then you might need a manual definition:
* gcc -fpie -D__PIC__=1
* gcc -fPIE -D__PIC__=2
*
* The ELF ABI is "System V Application Binary Interface, PowerPC
* Processor Supplement", which you can get from
* <http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf>
* (PDF file, hosted by Linux Foundation).
*
* ELF and Mac OS X use similar conventions to allocate the registers,
* and to pass arguments and return values through registers. The main
* differences are that ELF has a slightly different stack format, that
* symbols are different (and without an extra underscore at the start),
* and that the assembly syntax is different.
*
* A function may destroy the values of volatile registers, but must
* preserve the values of nonvolatile registers. So the co_switch()
* function only saves the nonvolatile registers.
*
* [nonvolatile registers in ELF]
* %r1, %r14..%r31
* %f14..%f31
* %cr2..%cr4 in cr
*
* [volatile registers in ELF]
* %r0, %r3..%r10
* %f0..%f13
* %cr0, %cr1, %cr5..%cr7 in cr
* ctr, lr, xer
*
* lr (link register) is volatile, but it contains the return address,
* so co_switch must save lr.
*
* %r13 is the small data pointer. This is constant across threads, so
* co_switch() does not touch %r13.
*
* %r2 is a reserved register, so co_switch() does not touch %r2. Some
* systems might borrow an idea from the PowerPC Embedded ABI, and might
* use %r2 as a small read-only data pointer, which is constant across
* threads.
*/
#ifdef __cplusplus
extern "C" {
#endif
typedef void * cothread_t;
/*
* co_active_context is either in a global offset table (if we are
* compiling -fPIC or -fPIE) or has an absolute position.
*/
static void *co_main_stack_pointer;
static cothread_t co_active_context = &co_main_stack_pointer;
extern cothread_t co_active() {
return co_active_context;
}
/*
* Embedded assembly.
*
* We are not using the percent-sign substitution feature,
* so we must write "%r1", not "%%r1".
*
* We always write 'bl malloc@plt', not 'bl malloc'. The '@plt'
* is necessary in position-indepent code and seems to have no
* significant effect in fixed-position code.
*
* We never use the 'lmw' or 'stmw' instructions. The ELF ABI
* mentions that these instructions "are usually slower than
* a sequence of other instructions that have the same effect."
* We instead use sequences of 'lwz' or 'stz' instructions.
*/
__asm__("\n"
"### embedded assembly \n"
".section \".text\" \n"
" .balign 4 \n"
" \n"
/*
* void co_switch(co_thread to %r3)
*
* Allocate our stack frame of 240 bytes:
* Old New Value
* 4(%r1) 244(%r1) return address, used by us
* 0(%r1) 240(%r1) frame pointer
* 232(%r1) %f31
* 224(%r1) %f30
* ...
* 96(%r1) %f14
* 92(%r1) %r31
* 88(%r1) %r30
* ...
* 24(%r1) %r14
* 20(%r1) condition register
* 8(%r1) padding of 12 bytes
* 4(%r1) return address, never used
* 0(%r1) frame pointer
*
* Save our registers in our stack frame.
* Save our stack pointer in 0(%r4).
* Switch to the stack of the other thread.
* Restore registers and return.
*/
" .globl co_switch \n"
" .type co_switch, @function \n"
"co_switch: \n"
" mflr %r0 # %r0 = return address \n"
" mfcr %r9 # %r9 = condition register \n"
" stwu %r1, -240(%r1) # allocate stack frame \n"
" \n"
" stw %r0, 244(%r1) # save return address \n"
" stfd %f31, 232(%r1) # save floating-point regs \n"
" stfd %f30, 224(%r1) \n"
" stfd %f29, 216(%r1) \n"
" stfd %f28, 208(%r1) \n"
" stfd %f27, 200(%r1) \n"
" stfd %f26, 192(%r1) \n"
" stfd %f25, 184(%r1) \n"
" stfd %f24, 176(%r1) \n"
" stfd %f23, 168(%r1) \n"
" stfd %f22, 160(%r1) \n"
" stfd %f21, 152(%r1) \n"
" stfd %f20, 144(%r1) \n"
" stfd %f19, 136(%r1) \n"
" stfd %f18, 128(%r1) \n"
" stfd %f17, 120(%r1) \n"
" stfd %f16, 112(%r1) \n"
" stfd %f16, 104(%r1) \n"
" stfd %f14, 96(%r1) \n"
" stw %r31, 92(%r1) # save general-purpose regs \n"
" stw %r30, 88(%r1) \n"
" stw %r29, 84(%r1) \n"
" stw %r28, 80(%r1) \n"
" stw %r27, 76(%r1) \n"
" stw %r26, 72(%r1) \n"
" stw %r25, 68(%r1) \n"
" stw %r24, 64(%r1) \n"
" stw %r23, 60(%r1) \n"
" stw %r22, 56(%r1) \n"
" stw %r21, 52(%r1) \n"
" stw %r20, 48(%r1) \n"
" stw %r19, 44(%r1) \n"
" stw %r18, 40(%r1) \n"
" stw %r17, 36(%r1) \n"
" stw %r16, 32(%r1) \n"
" stw %r15, 28(%r1) \n"
" stw %r14, 24(%r1) \n"
" stw %r9, 20(%r1) # save condition reg \n"
" \n"
" # save current context, set new context \n"
" # %r4 = co_active_context \n"
" # co_active_context = %r3 \n"
#if __PIC__ == 2
" # position-independent code, large model (-fPIC) \n"
" bl _GLOBAL_OFFSET_TABLE_@local-4 \n"
" mflr %r8 # %r8 = address of got \n"
" addis %r7, %r8, co_active_context@got@ha \n"
" lwz %r6, co_active_context@got@l(%r7) \n"
" lwz %r4, 0(%r6) \n"
" stw %r3, 0(%r6) \n"
#elif __PIC__ == 1
" # position-independent code, small model (-fpic) \n"
" bl _GLOBAL_OFFSET_TABLE_@local-4 \n"
" mflr %r8 # %r8 = address of got \n"
" lwz %r7, co_active_context@got(%r8) \n"
" lwz %r4, 0(%r7) \n"
" stw %r3, 0(%r7) \n"
#else
" # fixed-position code \n"
" lis %r8, co_active_context@ha \n"
" lwz %r4, co_active_context@l(%r8) \n"
" stw %r3, co_active_context@l(%r8) \n"
#endif
" \n"
" # save current stack pointer \n"
" stw %r1, 0(%r4) \n"
" # get new stack pointer \n"
" lwz %r1, 0(%r3) \n"
" \n"
" lwz %r0, 244(%r1) # get return address \n"
" lfd %f31, 232(%r1) # restore floating-point regs \n"
" lfd %f30, 224(%r1) \n"
" lfd %f29, 216(%r1) \n"
" lfd %f28, 208(%r1) \n"
" lfd %f27, 200(%r1) \n"
" lfd %f26, 192(%r1) \n"
" lfd %f25, 184(%r1) \n"
" lfd %f24, 176(%r1) \n"
" lfd %f23, 168(%r1) \n"
" lfd %f22, 160(%r1) \n"
" lfd %f21, 152(%r1) \n"
" lfd %f20, 144(%r1) \n"
" lfd %f19, 136(%r1) \n"
" lfd %f18, 128(%r1) \n"
" lfd %f17, 120(%r1) \n"
" lfd %f16, 112(%r1) \n"
" lfd %f16, 104(%r1) \n"
" lfd %f14, 96(%r1) \n"
" lwz %r31, 92(%r1) # restore general-purpose regs \n"
" lwz %r30, 88(%r1) \n"
" lwz %r29, 84(%r1) \n"
" lwz %r28, 80(%r1) \n"
" lwz %r27, 76(%r1) \n"
" lwz %r26, 72(%r1) \n"
" lwz %r25, 68(%r1) \n"
" lwz %r24, 64(%r1) \n"
" lwz %r23, 60(%r1) \n"
" lwz %r22, 56(%r1) \n"
" lwz %r21, 52(%r1) \n"
" lwz %r20, 48(%r1) \n"
" lwz %r19, 44(%r1) \n"
" lwz %r18, 40(%r1) \n"
" lwz %r17, 36(%r1) \n"
" lwz %r16, 32(%r1) \n"
" lwz %r15, 28(%r1) \n"
" lwz %r14, 24(%r1) \n"
" lwz %r9, 20(%r1) # get condition reg \n"
" \n"
" addi %r1, %r1, 240 # free stack frame \n"
" mtlr %r0 # restore return address \n"
" mtcr %r9 # restore condition register \n"
" blr # return \n"
" .size co_switch, . - co_switch \n"
" \n"
/*
* cothread_t %r3 co_create(unsigned int stack_size %r3,
* void (*coentry %r4)())
*
* Allocate a new stack, such that when you co_switch to that
* stack, then co_switch returns to coentry.
*/
" .globl co_create \n"
" .type co_create, @function \n"
"co_create: \n"
" mflr %r0 # %r0 = return address \n"
" stwu %r1, -16(%r1) # allocate my stack frame \n"
" stw %r0, 20(%r1) # save return address \n"
" stw %r31, 12(%r1) # save %r31 \n"
" stw %r30, 8(%r1) # save %r30 \n"
" \n"
" mr %r30, %r3 # %r30 = stack_size \n"
" mr %r31, %r4 # %r31 = coentry \n"
" \n"
" # Call malloc(stack_size %r3) to allocate stack; \n"
" # malloc() probably uses good alignment. \n"
" # \n"
" bl malloc@plt # returns %r3 = low end \n"
" cmpwi %r3, 0 # if returned NULL, \n"
" beq- 1f # then abort \n"
" \n"
" # we return %r3 = low end of stack \n"
" add %r4, %r3, %r30 # %r4 = high end of stack \n"
" \n"
" # uncomment if malloc() uses wrong alignment \n"
" #rlwinm %r4,%r4,0,0,27 # force 16-byte alignment \n"
" \n"
/*
* Allocate two stack frames:
* 16 bytes for stack frame with return address
* 240 bytes for co_switch stack frame
*
* Old New Value
* -8(%r4) 248(%r5) padding of 8 bytes
* -12(%r4) 244(%r5) return address = coentry
* -16(%r4) 240(%r5) frame pointer = NULL
* 232(%r5) %f31 = 0
* ...
* 20(%r5) condition register = 0
* 0(%r5) frame pointer
*/
" li %r9, (240-20)/4+1 \n"
" addi %r5, %r4, -16 # allocate first stack frame \n"
" li %r0, 0 \n"
" stwu %r5, -240(%r5) # allocate second stack frame \n"
" li %r8, 20 \n"
" mtctr %r9 # loop %r9 times \n"
"2: # loop to store zero to 20(%r5) through 240(%r5) \n"
" stwx %r0, %r5, %r8 \n"
" addi %r8, %r8, 4 # index += 4 \n"
" bdnz+ 2b # ctr -= 1, branch if nonzero \n"
" \n"
" stw %r31, 244(%r5) # return address = coentry \n"
" stw %r5, 0(%r3) # save stack pointer \n"
" \n"
" lwz %r0, 20(%r1) # get return address \n"
" lwz %r31, 12(%r1) # restore %r31 \n"
" lwz %r30, 8(%r1) # restore %r30 \n"
" mtlr %r0 # restore return address \n"
" addi %r1, %r1, 16 # free stack frame \n"
" blr # return \n"
" \n"
"1: b abort@plt # branch 1f to abort \n"
" .size co_create, . - co_create \n"
" \n"
/*
* void co_delete(cothread_t) => void free(void *)
*/
" .globl co_delete \n"
" .type co_delete, @function \n"
"co_delete: \n"
" b free@plt \n"
" \n"
);
#ifdef __cplusplus
}
#endif

View File

@@ -1,81 +0,0 @@
/*
libco.x86-64 (2008-01-28)
author: byuu
license: public domain
*/
#define LIBCO_C
#include "libco.h"
#include <assert.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
static thread_local long co_active_buffer[32];
static thread_local cothread_t co_active_ = 0;
static void crash() {
assert(0); /* called only if cothread_t entrypoint returns */
}
cothread_t co_active() {
if(!co_active_) co_active_ = &co_active_buffer;
return co_active_;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
cothread_t handle;
assert(sizeof(long) == 8);
if(!co_active_) co_active_ = &co_active_buffer;
size += 128; /* allocate additional space for storage */
size &= ~15; /* align stack to 16-byte boundary */
if(handle = (cothread_t)calloc(size, 1)) {
long *p = (long*)((char*)handle + size); /* seek to top of stack */
*--p = (long)crash; /* crash if entrypoint returns */
*--p = (long)entrypoint; /* start of function */
*(long*)handle = (long)p; /* stack pointer */
}
return handle;
}
void co_delete(cothread_t handle) {
free(handle);
}
void co_switch(cothread_t to) {
register long stack = *(long*)to; /* stack[0] = "to" thread entry point */
register cothread_t from = co_active_;
co_active_ = to;
__asm__ __volatile__(
"movq %%rsp,(%1) \n\t" /* save old stack pointer */
"movq (%0),%%rsp \n\t" /* load new stack pointer */
"addq $8,%%rsp \n\t" /* "pop" return address off stack */
"movq %%rbp, 8(%1) \n\t" /* backup non-volatile registers */
"movq %%rbx,16(%1) \n\t"
"movq %%r12,24(%1) \n\t"
"movq %%r13,32(%1) \n\t"
"movq %%r14,40(%1) \n\t"
"movq %%r15,48(%1) \n\t"
"movq 8(%0),%%rbp \n\t" /* restore non-volatile registers */
"movq 16(%0),%%rbx \n\t"
"movq 24(%0),%%r12 \n\t"
"movq 32(%0),%%r13 \n\t"
"movq 40(%0),%%r14 \n\t"
"movq 48(%0),%%r15 \n\t"
"jmp *(%2) \n\t" /* jump into "to" thread */
: /* no outputs */
: "r" (to), "r" (from), "r" (stack)
);
}
#ifdef __cplusplus
}
#endif

View File

@@ -1,5 +1,5 @@
/*
libco.x86 (2008-01-28)
libco.x86 (2009-10-12)
author: byuu
license: public domain
*/
@@ -13,26 +13,63 @@
extern "C" {
#endif
static thread_local long co_active_buffer[32];
static thread_local cothread_t co_active_ = 0;
#if defined(_MSC_VER)
#define fastcall __fastcall
#elif defined(__GNUC__)
#define fastcall __attribute__((fastcall))
#else
#error "libco: please define fastcall macro"
#endif
static thread_local long co_active_buffer[64];
static thread_local cothread_t co_active_handle = 0;
static void (fastcall *co_swap)(cothread_t, cothread_t) = 0;
//ABI: fastcall
static unsigned char co_swap_function[] = {
0x89, 0x22, 0x8B, 0x21, 0x58, 0x89, 0x6A, 0x04, 0x89, 0x72, 0x08, 0x89, 0x7A, 0x0C, 0x89, 0x5A,
0x10, 0x8B, 0x69, 0x04, 0x8B, 0x71, 0x08, 0x8B, 0x79, 0x0C, 0x8B, 0x59, 0x10, 0xFF, 0xE0,
};
#ifdef _WIN32
#include <windows.h>
void co_init() {
DWORD old_privileges;
VirtualProtect(co_swap_function, sizeof co_swap_function, PAGE_EXECUTE_READWRITE, &old_privileges);
}
#else
#include <unistd.h>
#include <sys/mman.h>
void co_init() {
unsigned long addr = (unsigned long)co_swap_function;
unsigned long base = addr - (addr % sysconf(_SC_PAGESIZE));
unsigned long size = (addr - base) + sizeof co_swap_function;
mprotect((void*)base, size, PROT_READ | PROT_WRITE | PROT_EXEC);
}
#endif
static void crash() {
assert(0); /* called only if cothread_t entrypoint returns */
}
cothread_t co_active() {
if(!co_active_) co_active_ = &co_active_buffer;
return co_active_;
if(!co_active_handle) co_active_handle = &co_active_buffer;
return co_active_handle;
}
cothread_t co_create(unsigned int size, void (*entrypoint)(void)) {
cothread_t handle;
assert(sizeof(long) == 4);
if(!co_active_) co_active_ = &co_active_buffer;
size += 128; /* allocate additional space for storage */
if(!co_swap) {
co_init();
co_swap = (void (fastcall*)(cothread_t, cothread_t))co_swap_function;
}
if(!co_active_handle) co_active_handle = &co_active_buffer;
size += 256; /* allocate additional space for storage */
size &= ~15; /* align stack to 16-byte boundary */
if(handle = (cothread_t)calloc(size, 1)) {
if(handle = (cothread_t)malloc(size)) {
long *p = (long*)((char*)handle + size); /* seek to top of stack */
*--p = (long)crash; /* crash if entrypoint returns */
*--p = (long)entrypoint; /* start of function */
@@ -46,65 +83,11 @@ void co_delete(cothread_t handle) {
free(handle);
}
#if defined(__GNUC__)
void co_switch(cothread_t to) {
register long stack = *(long*)to; /* stack[0] = "to" thread entry point */
register cothread_t from = co_active_;
co_active_ = to;
__asm__ __volatile__(
"movl %%esp,(%1) \n\t" /* save old stack pointer */
"movl (%0),%%esp \n\t" /* load new stack pointer */
"addl $4,%%esp \n\t" /* "pop" return address off stack */
"movl %%ebp, 4(%1) \n\t" /* backup non-volatile registers */
"movl %%esi, 8(%1) \n\t"
"movl %%edi,12(%1) \n\t"
"movl %%ebx,16(%1) \n\t"
"movl 4(%0),%%ebp \n\t" /* restore non-volatile registers */
"movl 8(%0),%%esi \n\t"
"movl 12(%0),%%edi \n\t"
"movl 16(%0),%%ebx \n\t"
"jmp *(%2) \n\t" /* jump into "to" thread */
: /* no outputs */
: "r" (to), "r" (from), "r" (stack)
);
}
#elif defined(_MSC_VER)
__declspec(naked) __declspec(noinline)
static void __fastcall co_swap(register cothread_t to, register cothread_t from) {
/* ecx = to, edx = from */
__asm {
mov [edx],esp
mov esp,[ecx]
pop eax
mov [edx+ 4],ebp
mov [edx+ 8],esi
mov [edx+12],edi
mov [edx+16],ebx
mov ebp,[ecx+ 4]
mov esi,[ecx+ 8]
mov edi,[ecx+12]
mov ebx,[ecx+16]
jmp eax
}
}
void co_switch(cothread_t handle) {
register cothread_t co_prev_ = co_active_;
co_swap(co_active_ = handle, co_prev_);
register cothread_t co_previous_handle = co_active_handle;
co_swap(co_active_handle = handle, co_previous_handle);
}
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -1,138 +0,0 @@
Colortable colortable;
void Colortable::set_format(Format format_) { format = format_; }
void Colortable::set_contrast(signed contrast_) { contrast = contrast_; }
void Colortable::set_brightness(signed brightness_) { brightness = brightness_; }
void Colortable::set_gamma(signed gamma_) { gamma = gamma_; }
void Colortable::enable_gamma_ramp(bool value) { gamma_ramp = value; }
void Colortable::enable_sepia(bool value) { sepia = value; }
void Colortable::enable_grayscale(bool value) { grayscale = value; }
void Colortable::enable_invert(bool value) { invert = value; }
void Colortable::update() {
double kr = 0.2126, kb = 0.0722, kg = (1.0 - kr - kb); //luminance weights
for(unsigned i = 0; i < 32768; i++) {
unsigned color //bgr555->rgb888 conversion
= ((i & 0x001f) << 19) | ((i & 0x001c) << 14)
| ((i & 0x03e0) << 6) | ((i & 0x0380) << 1)
| ((i & 0x7c00) >> 7) | ((i & 0x7000) >> 12);
signed l;
signed r = (color >> 16) & 0xff;
signed g = (color >> 8) & 0xff;
signed b = (color ) & 0xff;
if(gamma_ramp == true) {
r = gamma_ramp_table[r >> 3];
g = gamma_ramp_table[g >> 3];
b = gamma_ramp_table[b >> 3];
}
if(contrast != 0) {
r = contrast_adjust(r);
g = contrast_adjust(g);
b = contrast_adjust(b);
}
if(brightness != 0) {
r = brightness_adjust(r);
g = brightness_adjust(g);
b = brightness_adjust(b);
}
if(gamma != 100) {
r = gamma_adjust(r);
g = gamma_adjust(g);
b = gamma_adjust(b);
}
if(sepia == true) {
l = (signed)((double)r * kr + (double)g * kg + (double)b * kb);
l = max(0, min(255, l));
r = (signed)((double)l * (1.0 + 0.300));
g = (signed)((double)l * (1.0 - 0.055));
b = (signed)((double)l * (1.0 - 0.225));
r = max(0, min(255, r));
g = max(0, min(255, g));
b = max(0, min(255, b));
}
if(grayscale == true) {
l = (signed)((double)r * kr + (double)g * kg + (double)b * kb);
l = max(0, min(255, l));
r = g = b = l;
}
if(invert == true) {
r ^= 0xff;
g ^= 0xff;
b ^= 0xff;
}
switch(format) {
case RGB555: {
r >>= 3;
g >>= 3;
b >>= 3;
table[i] = (r << 10) | (g << 5) | (b);
} break;
case RGB565: {
r >>= 3;
g >>= 2;
b >>= 3;
table[i] = (r << 11) | (g << 5) | (b);
} break;
case RGB888: {
table[i] = (r << 16) | (g << 8) | (b);
} break;
default: {
table[i] = ~0;
} break;
}
}
}
Colortable::Colortable() {
table = new uint32_t[32768];
contrast = 0;
brightness = 0;
gamma = 100;
gamma_ramp = false;
sepia = false;
grayscale = false;
invert = false;
}
Colortable::~Colortable() {
delete[] table;
}
const uint8_t Colortable::gamma_ramp_table[32] = {
0x00, 0x01, 0x03, 0x06, 0x0a, 0x0f, 0x15, 0x1c,
0x24, 0x2d, 0x37, 0x42, 0x4e, 0x5b, 0x69, 0x78,
0x88, 0x90, 0x98, 0xa0, 0xa8, 0xb0, 0xb8, 0xc0,
0xc8, 0xd0, 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, 0xff,
};
uint8_t Colortable::contrast_adjust(uint8_t input) {
signed result = input - contrast + (2 * contrast * input + 127) / 255;
return max(0, min(255, result));
}
uint8_t Colortable::brightness_adjust(uint8_t input) {
signed result = input + brightness;
return max(0, min(255, result));
}
uint8_t Colortable::gamma_adjust(uint8_t input) {
signed result = (signed)(pow(((double)input / 255.0), (double)gamma / 100.0) * 255.0 + 0.5);
return max(0, min(255, result));
}

View File

@@ -1,44 +0,0 @@
class Colortable {
public:
enum Format {
RGB555,
RGB565,
RGB888,
};
const inline uint32_t operator[](uint16_t index) const { return table[index]; }
void set_format(Format);
void set_contrast(signed);
void set_brightness(signed);
void set_gamma(signed);
void enable_gamma_ramp(bool);
void enable_sepia(bool);
void enable_grayscale(bool);
void enable_invert(bool);
void update();
Colortable();
~Colortable();
private:
uint32_t *table;
Format format;
signed contrast;
signed brightness;
signed gamma;
bool gamma_ramp;
bool sepia;
bool grayscale;
bool invert;
static const uint8_t gamma_ramp_table[32];
uint8_t contrast_adjust(uint8_t input);
uint8_t brightness_adjust(uint8_t input);
uint8_t gamma_adjust(uint8_t input);
};
extern Colortable colortable;

View File

@@ -1,32 +0,0 @@
DirectFilter filter_direct;
void DirectFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
}
void DirectFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
pitch >>= 1;
outpitch >>= 2;
for(unsigned y = 0; y < height; y++) {
if(width == 512 && line[y] == 256) {
for(unsigned x = 0; x < 256; x++) {
uint16_t p = *input++;
*output++ = colortable[p];
*output++ = colortable[p];
}
input += 256;
} else {
for(unsigned x = 0; x < width; x++) {
uint16_t p = *input++;
*output++ = colortable[p];
}
}
input += pitch - width;
output += outpitch - width;
}
}

View File

@@ -1,7 +0,0 @@
class DirectFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
};
extern DirectFilter filter_direct;

View File

@@ -1,32 +0,0 @@
FilterInterface filter;
void FilterInterface::set(FilterInterface::FilterType type) {
active_filter = type;
}
void FilterInterface::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
switch(active_filter) { default:
case Direct: return filter_direct.size(outwidth, outheight, width, height);
case Scanline: return filter_scanline.size(outwidth, outheight, width, height);
case Scale2x: return filter_scale2x.size(outwidth, outheight, width, height);
case LQ2x: return filter_lq2x.size(outwidth, outheight, width, height);
case HQ2x: return filter_hq2x.size(outwidth, outheight, width, height);
case NTSC: return filter_ntsc.size(outwidth, outheight, width, height);
}
}
void FilterInterface::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
switch(active_filter) { default:
case Direct: return filter_direct.render(output, outpitch, input, pitch, line, width, height);
case Scanline: return filter_scanline.render(output, outpitch, input, pitch, line, width, height);
case Scale2x: return filter_scale2x.render(output, outpitch, input, pitch, line, width, height);
case LQ2x: return filter_lq2x.render(output, outpitch, input, pitch, line, width, height);
case HQ2x: return filter_hq2x.render(output, outpitch, input, pitch, line, width, height);
case NTSC: return filter_ntsc.render(output, outpitch, input, pitch, line, width, height);
}
}
FilterInterface::FilterInterface() : active_filter(FilterInterface::Direct) {}

View File

@@ -1,37 +0,0 @@
class Filter {
public:
virtual void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) = 0;
virtual void render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) = 0;
};
class FilterInterface : public Filter {
public:
enum FilterType {
Direct,
Scanline,
Scale2x,
LQ2x,
HQ2x,
NTSC,
};
void set(FilterType type);
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
);
FilterInterface();
private:
FilterType active_filter;
};
extern FilterInterface filter;

View File

@@ -1,204 +0,0 @@
//HQ2x filter
//authors: byuu and blargg
//license: public domain
//
//note: this is a clean reimplementation of the original HQ2x filter, which was
//written by Maxim Stepin (MaxSt). it is not 100% identical, but very similar.
HQ2xFilter filter_hq2x;
const uint8_t HQ2xFilter::hqTable[256] = {
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 12, 12, 5, 3, 1, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
4, 4, 6, 18, 4, 4, 6, 18, 5, 3, 16, 12, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 12, 12, 5, 19, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 19, 1, 12, 5, 19, 1, 14,
4, 4, 6, 2, 4, 4, 6, 18, 5, 3, 16, 12, 5, 19, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 15, 12, 5, 3, 17, 13,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 17, 13, 5, 3, 16, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 13, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 16, 13,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 12,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 16, 12, 5, 3, 1, 14,
4, 4, 6, 2, 4, 4, 6, 2, 5, 3, 1, 12, 5, 3, 1, 14,
};
bool HQ2xFilter::same(uint16_t x, uint16_t y) {
return !((yuvTable[x] - yuvTable[y] + diff_offset) & diff_mask);
}
bool HQ2xFilter::diff(uint32_t x, uint16_t y) {
return ((x - yuvTable[y]) & diff_mask);
}
void HQ2xFilter::grow(uint32_t &n) { n |= n << 16; n &= 0x03e07c1f; }
uint16_t HQ2xFilter::pack(uint32_t n) { n &= 0x03e07c1f; return n | (n >> 16); }
uint16_t HQ2xFilter::blend1(uint32_t A, uint32_t B) {
grow(A); grow(B);
A = (A * 3 + B) >> 2;
return pack(A);
}
uint16_t HQ2xFilter::blend2(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 2 + B + C) >> 2);
}
uint16_t HQ2xFilter::blend3(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 5 + B * 2 + C) >> 3);
}
uint16_t HQ2xFilter::blend4(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 6 + B + C) >> 3);
}
uint16_t HQ2xFilter::blend5(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 2 + (B + C) * 3) >> 3);
}
uint16_t HQ2xFilter::blend6(uint32_t A, uint32_t B, uint32_t C) {
grow(A); grow(B); grow(C);
return pack((A * 14 + B + C) >> 4);
}
alwaysinline uint16_t HQ2xFilter::blend(unsigned rule, uint16_t E, uint16_t A, uint16_t B, uint16_t D, uint16_t F, uint16_t H) {
switch(rule) { default:
case 0: return E;
case 1: return blend1(E, A);
case 2: return blend1(E, D);
case 3: return blend1(E, B);
case 4: return blend2(E, D, B);
case 5: return blend2(E, A, B);
case 6: return blend2(E, A, D);
case 7: return blend3(E, B, D);
case 8: return blend3(E, D, B);
case 9: return blend4(E, D, B);
case 10: return blend5(E, D, B);
case 11: return blend6(E, D, B);
case 12: return same(B, D) ? blend2(E, D, B) : E;
case 13: return same(B, D) ? blend5(E, D, B) : E;
case 14: return same(B, D) ? blend6(E, D, B) : E;
case 15: return same(B, D) ? blend2(E, D, B) : blend1(E, A);
case 16: return same(B, D) ? blend4(E, D, B) : blend1(E, A);
case 17: return same(B, D) ? blend5(E, D, B) : blend1(E, A);
case 18: return same(B, F) ? blend3(E, B, D) : blend1(E, D);
case 19: return same(D, H) ? blend3(E, D, B) : blend1(E, B);
}
}
void HQ2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
if(width <= 256 && height <= 240) {
outwidth *= 2;
outheight *= 2;
}
}
void HQ2xFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
if(width > 256 || height > 240) {
filter_direct.render(output, outpitch, input, pitch, line, width, height);
return;
}
pitch >>= 1;
outpitch >>= 2;
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
for(unsigned y = 0; y < height; y++) {
int prevline = (y == 0) ? 0 : pitch;
int nextline = (y == height - 1) ? 0 : pitch;
input++;
*out0++ = 0; *out0++ = 0;
*out1++ = 0; *out1++ = 0;
for(unsigned x = 1; x < 256 - 1; x++) {
uint16_t A = *(input - prevline - 1);
uint16_t B = *(input - prevline + 0);
uint16_t C = *(input - prevline + 1);
uint16_t D = *(input - 1);
uint16_t E = *(input + 0);
uint16_t F = *(input + 1);
uint16_t G = *(input + nextline - 1);
uint16_t H = *(input + nextline + 0);
uint16_t I = *(input + nextline + 1);
uint32_t e = yuvTable[E] + diff_offset;
uint8_t pattern;
pattern = diff(e, A) << 0;
pattern |= diff(e, B) << 1;
pattern |= diff(e, C) << 2;
pattern |= diff(e, D) << 3;
pattern |= diff(e, F) << 4;
pattern |= diff(e, G) << 5;
pattern |= diff(e, H) << 6;
pattern |= diff(e, I) << 7;
*(out0 + 0) = colortable[blend(hqTable[pattern], E, A, B, D, F, H)]; pattern = rotate[pattern];
*(out0 + 1) = colortable[blend(hqTable[pattern], E, C, F, B, H, D)]; pattern = rotate[pattern];
*(out1 + 1) = colortable[blend(hqTable[pattern], E, I, H, F, D, B)]; pattern = rotate[pattern];
*(out1 + 0) = colortable[blend(hqTable[pattern], E, G, D, H, B, F)];
input++;
out0 += 2;
out1 += 2;
}
input++;
*out0++ = 0; *out0++ = 0;
*out1++ = 0; *out1++ = 0;
input += pitch - 256;
out0 += outpitch + outpitch - 512;
out1 += outpitch + outpitch - 512;
}
}
HQ2xFilter::HQ2xFilter() {
yuvTable = new uint32_t[32768];
for(unsigned i = 0; i < 32768; i++) {
uint8_t R = (i >> 0) & 31;
uint8_t G = (i >> 5) & 31;
uint8_t B = (i >> 10) & 31;
//bgr555->bgr888
double r = (R << 3) | (R >> 2);
double g = (G << 3) | (G >> 2);
double b = (B << 3) | (B >> 2);
//bgr888->yuv888
double y = (r + g + b) * (0.25f * (63.5f / 48.0f));
double u = ((r - b) * 0.25f + 128.0f) * (7.5f / 7.0f);
double v = ((g * 2.0f - r - b) * 0.125f + 128.0f) * (7.5f / 6.0f);
yuvTable[i] = ((unsigned)y << 21) + ((unsigned)u << 11) + ((unsigned)v);
}
diff_offset = (0x440 << 21) + (0x207 << 11) + 0x407;
diff_mask = (0x380 << 21) + (0x1f0 << 11) + 0x3f0;
for(unsigned n = 0; n < 256; n++) {
rotate[n] = ((n >> 2) & 0x11) | ((n << 2) & 0x88)
| ((n & 0x01) << 5) | ((n & 0x08) << 3)
| ((n & 0x10) >> 3) | ((n & 0x80) >> 5);
}
}
HQ2xFilter::~HQ2xFilter() {
delete[] yuvTable;
}

View File

@@ -1,31 +0,0 @@
class HQ2xFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
HQ2xFilter();
~HQ2xFilter();
private:
static const uint8_t hqTable[256];
uint32_t *yuvTable;
uint32_t diff_offset;
uint32_t diff_mask;
uint8_t rotate[256];
bool same(uint16_t, uint16_t);
bool diff(uint32_t, uint16_t);
void grow(uint32_t&);
uint16_t pack(uint32_t);
uint16_t blend1(uint32_t, uint32_t);
uint16_t blend2(uint32_t, uint32_t, uint32_t);
uint16_t blend3(uint32_t, uint32_t, uint32_t);
uint16_t blend4(uint32_t, uint32_t, uint32_t);
uint16_t blend5(uint32_t, uint32_t, uint32_t);
uint16_t blend6(uint32_t, uint32_t, uint32_t);
uint16_t blend (unsigned, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t, uint16_t);
};
extern HQ2xFilter filter_hq2x;

View File

@@ -1,15 +0,0 @@
#include "libfilter.hpp"
using nall::min;
using nall::max;
namespace libfilter {
#include "colortable.cpp"
#include "filter.cpp"
#include "direct.cpp"
#include "scanline.cpp"
#include "scale2x.cpp"
#include "lq2x.cpp"
#include "hq2x.cpp"
#include "ntsc.cpp"
}

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