Compare commits

..

4 Commits
v050 ... v054

Author SHA1 Message Date
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
269 changed files with 4120 additions and 21273 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,26 +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 += 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
######################
### implicit rules ###
######################
@@ -121,9 +111,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 ###
@@ -196,37 +183,6 @@ 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/*
###############
### targets ###
###############
@@ -265,9 +221,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.050";
static const char bsnesVersion[] = "0.054";
static const char bsnesTitle[] = "bsnes";
static const unsigned bsnesSaveStateVersion = 2;
static const unsigned bsnesSaveStateVersion = 3;
//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,5 +1,6 @@
#include <../base.hpp>
#include <nall/crc32.hpp>
#include <nall/sha256.hpp>
#define CARTRIDGE_CPP
namespace SNES {
@@ -24,25 +25,25 @@ 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()) memory::gbram.map(allocate<uint8_t>(64 * 1024, 0xff), 64 * 1024);
}
memory::cartrom.write_protect(true);
@@ -70,6 +71,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);

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;
}

View File

@@ -26,10 +26,6 @@ private:
int16 C4WFXVal, C4WFYVal, C4WFZVal, C4WFX2Val, C4WFY2Val, C4WFDist, C4WFScale;
int16 C41FXVal, C41FYVal, C41FAngleRes, C41FDist, C41FDistVal;
//todo: get rid of floating-point values, replace with integers
double tanval;
double c4x,c4y,c4z, c4x2,c4y2,c4z2;
void C4TransfWireFrame();
void C4TransfWireFrame2();
void C4CalcWireFrame();

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

@@ -34,14 +34,6 @@ void Cx4::serialize(serializer &s) {
s.integer(C41FAngleRes);
s.integer(C41FDist);
s.integer(C41FDistVal);
s.floatingpoint(tanval);
s.floatingpoint(c4x);
s.floatingpoint(c4y);
s.floatingpoint(c4z);
s.floatingpoint(c4x2);
s.floatingpoint(c4y2);
s.floatingpoint(c4z2);
}
#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() {}
@@ -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

@@ -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

@@ -1,28 +1,15 @@
#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);
@@ -33,40 +20,15 @@ void sCPUdebug::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;
}
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);
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;
debugger.breakpoint[i].counter++;
debugger.breakpoint_hit = i;
debugger.break_event = Debugger::BreakpointHit;
scheduler.exit();
break;
}
debugger.breakpoint_test(Debugger::Breakpoint::CPUBus, Debugger::Breakpoint::Write, addr, data);
}
#endif

View File

@@ -1,4 +1,4 @@
class sCPUdebug : public sCPU {
class sCPUDebug : public sCPU {
public:
void op_step();
uint8 op_read(uint32 addr);

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, SMC:</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: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 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: 440 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 935 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: 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,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"
}

View File

@@ -1,24 +0,0 @@
#ifndef LIBFILTER_H
#define LIBFILTER_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <nall/algorithm.hpp>
#include <nall/platform.hpp>
#include <nall/stdint.hpp>
namespace libfilter {
#include "colortable.hpp"
#include "filter.hpp"
#include "direct.hpp"
#include "scanline.hpp"
#include "scale2x.hpp"
#include "lq2x.hpp"
#include "hq2x.hpp"
#include "ntsc.hpp"
};
#endif

View File

@@ -1,57 +0,0 @@
LQ2xFilter filter_lq2x;
void LQ2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
if(width <= 256 && height <= 240) {
outwidth *= 2;
outheight *= 2;
}
}
void LQ2xFilter::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;
for(unsigned x = 0; x < 256; x++) {
uint16_t A = *(input - prevline);
uint16_t B = (x > 0) ? *(input - 1) : *input;
uint16_t C = *input;
uint16_t D = (x < 255) ? *(input + 1) : *input;
uint16_t E = *(input++ + nextline);
uint32_t c = colortable[C];
if(A != E && B != D) {
*out0++ = (A == B ? colortable[C + A - ((C ^ A) & 0x0421) >> 1] : c);
*out0++ = (A == D ? colortable[C + A - ((C ^ A) & 0x0421) >> 1] : c);
*out1++ = (E == B ? colortable[C + E - ((C ^ E) & 0x0421) >> 1] : c);
*out1++ = (E == D ? colortable[C + E - ((C ^ E) & 0x0421) >> 1] : c);
} else {
*out0++ = c;
*out0++ = c;
*out1++ = c;
*out1++ = c;
}
}
input += pitch - 256;
out0 += outpitch + outpitch - 512;
out1 += outpitch + outpitch - 512;
}
}

View File

@@ -1,7 +0,0 @@
class LQ2xFilter : 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 LQ2xFilter filter_lq2x;

View File

@@ -1,79 +0,0 @@
#include "snes_ntsc/snes_ntsc.c"
NTSCFilter filter_ntsc;
void NTSCFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = SNES_NTSC_OUT_WIDTH(256);
outheight = height;
}
void NTSCFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
if(!ntsc) return;
width = SNES_NTSC_OUT_WIDTH(256);
burst ^= burst_toggle;
pitch >>= 1;
outpitch >>= 2;
unsigned line_burst = burst;
for(unsigned y = 0; y < height; y++) {
uint16_t *in = input + y * pitch;
uint32_t *out = output + y * outpitch;
//render as many lines in one snes_ntsc_blit as possible:
//do this by determining for how many lines the width stays the same
unsigned rheight = 1;
unsigned rwidth = line[y];
while(y + rheight < height && rwidth == line[y + rheight]) rheight++;
if(rwidth == 256) {
snes_ntsc_blit (ntsc, in, pitch, line_burst, rwidth, rheight, out, outpitch << 2);
} else {
snes_ntsc_blit_hires(ntsc, in, pitch, line_burst, rwidth, rheight, out, outpitch << 2);
}
line_burst = (line_burst + rheight) % 3;
y += rheight;
}
}
void NTSCFilter::adjust(
float hue, float saturation, float contrast,
float brightness, float sharpness, bool merge_fields
) {
static snes_ntsc_setup_t defaults;
snes_ntsc_setup_t setup = defaults;
setup.hue = hue;
setup.saturation = saturation;
setup.contrast = contrast;
setup.brightness = brightness;
setup.sharpness = sharpness;
setup.resolution = sharpness;
setup.merge_fields = merge_fields;
setup.bsnes_colortbl = 0;
if(!ntsc) {
ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc);
if(!ntsc) {
fprintf(stderr, "error: snes_ntsc: out of memory\n");
return;
}
}
burst = 0;
burst_toggle = (merge_fields ? 0 : 1); //don't toggle burst when fields are merged
snes_ntsc_init(ntsc, &setup);
}
NTSCFilter::NTSCFilter() {
ntsc = 0;
adjust(0, 0, 0, 0, 0, false);
}
NTSCFilter::~NTSCFilter() {
if(ntsc) free(ntsc);
}

View File

@@ -1,17 +0,0 @@
#include "snes_ntsc/snes_ntsc.h"
class NTSCFilter : public Filter {
public:
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
void adjust(float hue, float saturation, float contrast, float brightness, float sharpness, bool merge_fields);
NTSCFilter();
~NTSCFilter();
private:
struct snes_ntsc_t *ntsc;
int burst, burst_toggle;
};
extern NTSCFilter filter_ntsc;

View File

@@ -1,57 +0,0 @@
Scale2xFilter filter_scale2x;
void Scale2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
if(width <= 256 && height <= 240) {
outwidth *= 2;
outheight *= 2;
}
}
void Scale2xFilter::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;
for(unsigned x = 0; x < 256; x++) {
uint16_t A = *(input - prevline);
uint16_t B = (x > 0) ? *(input - 1) : *input;
uint16_t C = *input;
uint16_t D = (x < 255) ? *(input + 1) : *input;
uint16_t E = *(input++ + nextline);
uint32_t c = colortable[C];
if(A != E && B != D) {
*out0++ = (A == B ? colortable[A] : c);
*out0++ = (A == D ? colortable[A] : c);
*out1++ = (E == B ? colortable[E] : c);
*out1++ = (E == D ? colortable[E] : c);
} else {
*out0++ = c;
*out0++ = c;
*out1++ = c;
*out1++ = c;
}
}
input += pitch - 256;
out0 += outpitch + outpitch - 512;
out1 += outpitch + outpitch - 512;
}
}

View File

@@ -1,7 +0,0 @@
class Scale2xFilter : 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 Scale2xFilter filter_scale2x;

View File

@@ -1,42 +0,0 @@
ScanlineFilter filter_scanline;
void ScanlineFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height > 240 ? height : height * 2;
}
void ScanlineFilter::render(
uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
unsigned *line, unsigned width, unsigned height
) {
if(height > 240) {
filter_direct.render(output, outpitch, input, pitch, line, width, height);
return;
}
pitch >>= 1;
outpitch >>= 2;
for(unsigned y = 0; y < height; y++) {
uint32_t *out0 = output;
uint32_t *out1 = output + outpitch;
if(width == 512 && line[y] == 256) {
for(unsigned x = 0; x < 256; x++) {
uint16_t p = *input++;
*out0++ = colortable[p];
*out0++ = colortable[p];
*out1++ = (colortable[p] >> 1) & 0x7f7f7f;
*out1++ = (colortable[p] >> 1) & 0x7f7f7f;
}
input += 256;
} else {
for(unsigned x = 0; x < width; x++) {
uint16_t p = *input++;
*out0++ = colortable[p];
*out1++ = (colortable[p] >> 1) & 0x7f7f7f;
}
}
input += pitch - width;
output += outpitch * 2;
}
}

View File

@@ -1,7 +0,0 @@
class ScanlineFilter : 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 ScanlineFilter filter_scanline;

View File

@@ -1,251 +0,0 @@
/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */
#include "snes_ntsc.h"
/* Copyright (C) 2006-2007 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
snes_ntsc_setup_t const snes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0 };
snes_ntsc_setup_t const snes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0 };
#define alignment_count 3
#define burst_count 3
#define rescale_in 8
#define rescale_out 7
#define artifacts_mid 1.0f
#define fringing_mid 1.0f
#define std_decoder_hue 0
#define rgb_bits 7 /* half normal range to allow for doubled hires pixels */
#define gamma_size 32
#include "snes_ntsc_impl.h"
/* 3 input pixels -> 8 composite samples */
pixel_info_t const snes_ntsc_pixels [alignment_count] = {
{ PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } },
{ PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } },
{ PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } },
};
static void merge_kernel_fields( snes_ntsc_rgb_t* io )
{
int n;
for ( n = burst_size; n; --n )
{
snes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias;
snes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias;
snes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias;
/* merge colors without losing precision */
io [burst_size * 0] =
((p0 + p1 - ((p0 ^ p1) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
io [burst_size * 1] =
((p1 + p2 - ((p1 ^ p2) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
io [burst_size * 2] =
((p2 + p0 - ((p2 ^ p0) & snes_ntsc_rgb_builder)) >> 1) - rgb_bias;
++io;
}
}
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out )
{
int n;
for ( n = burst_count; n; --n )
{
unsigned i;
for ( i = 0; i < rgb_kernel_size / 2; i++ )
{
snes_ntsc_rgb_t error = color -
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] -
out [i + 7] - out [i + 5 +14] - out [i + 3 +28];
DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 );
}
out += alignment_count * rgb_kernel_size;
}
}
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup )
{
int merge_fields;
int entry;
init_t impl;
if ( !setup )
setup = &snes_ntsc_composite;
init( &impl, setup );
merge_fields = setup->merge_fields;
if ( setup->artifacts <= -1 && setup->fringing <= -1 )
merge_fields = 1;
for ( entry = 0; entry < snes_ntsc_palette_size; entry++ )
{
/* Reduce number of significant bits of source color. Clearing the
low bits of R and B were least notictable. Modifying green was too
noticeable. */
int ir = entry >> 8 & 0x1E;
int ig = entry >> 4 & 0x1F;
int ib = entry << 1 & 0x1E;
#if SNES_NTSC_BSNES_COLORTBL
if ( setup->bsnes_colortbl )
{
int bgr15 = (ib << 10) | (ig << 5) | ir;
unsigned long rgb16 = setup->bsnes_colortbl [bgr15];
ir = rgb16 >> 11 & 0x1E;
ig = rgb16 >> 6 & 0x1F;
ib = rgb16 & 0x1E;
}
#endif
{
float rr = impl.to_float [ir];
float gg = impl.to_float [ig];
float bb = impl.to_float [ib];
float y, i, q = RGB_TO_YIQ( rr, gg, bb, y, i );
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
snes_ntsc_rgb_t rgb = PACK_RGB( r, g, b );
snes_ntsc_rgb_t* out = ntsc->table [entry];
gen_kernel( &impl, y, i, q, out );
if ( merge_fields )
merge_kernel_fields( out );
correct_errors( rgb, out );
}
}
}
#ifndef SNES_NTSC_NO_BLITTERS
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 1) / snes_ntsc_in_chunk;
for ( ; in_height; --in_height )
{
SNES_NTSC_IN_T const* line_in = input;
SNES_NTSC_BEGIN_ROW( ntsc, burst_phase,
snes_ntsc_black, snes_ntsc_black, SNES_NTSC_ADJ_IN( *line_in ) );
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
int n;
++line_in;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
line_in += 3;
line_out += 7;
}
/* finish final pixels */
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
SNES_NTSC_RGB_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_RGB_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input, long in_row_width,
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
{
int chunk_count = (in_width - 2) / (snes_ntsc_in_chunk * 2);
for ( ; in_height; --in_height )
{
SNES_NTSC_IN_T const* line_in = input;
SNES_NTSC_HIRES_ROW( ntsc, burst_phase,
snes_ntsc_black, snes_ntsc_black, snes_ntsc_black,
SNES_NTSC_ADJ_IN( line_in [0] ),
SNES_NTSC_ADJ_IN( line_in [1] ) );
snes_ntsc_out_t* restrict line_out = (snes_ntsc_out_t*) rgb_out;
int n;
line_in += 2;
for ( n = chunk_count; n; --n )
{
/* twice as many input pixels per chunk */
SNES_NTSC_COLOR_IN( 0, SNES_NTSC_ADJ_IN( line_in [0] ) );
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, SNES_NTSC_ADJ_IN( line_in [1] ) );
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, SNES_NTSC_ADJ_IN( line_in [2] ) );
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 3, SNES_NTSC_ADJ_IN( line_in [3] ) );
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 4, SNES_NTSC_ADJ_IN( line_in [4] ) );
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 5, SNES_NTSC_ADJ_IN( line_in [5] ) );
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
line_in += 6;
line_out += 7;
}
SNES_NTSC_COLOR_IN( 0, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 0, line_out [0], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 1, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 1, line_out [1], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 2, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 2, line_out [2], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 3, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 3, line_out [3], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 4, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 4, line_out [4], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_COLOR_IN( 5, snes_ntsc_black );
SNES_NTSC_HIRES_OUT( 5, line_out [5], SNES_NTSC_OUT_DEPTH );
SNES_NTSC_HIRES_OUT( 6, line_out [6], SNES_NTSC_OUT_DEPTH );
burst_phase = (burst_phase + 1) % snes_ntsc_burst_count;
input += in_row_width;
rgb_out = (char*) rgb_out + out_pitch;
}
}
#endif

View File

@@ -1,228 +0,0 @@
/* SNES NTSC video filter */
/* snes_ntsc 0.2.2 */
#ifndef SNES_NTSC_H
#define SNES_NTSC_H
#include "snes_ntsc_config.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
in parenthesis and should remain fairly stable in future versions. */
typedef struct snes_ntsc_setup_t
{
/* Basic parameters */
double hue; /* -1 = -180 degrees +1 = +180 degrees */
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
double sharpness; /* edge contrast enhancement/blurring */
/* Advanced parameters */
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
double resolution; /* image resolution */
double artifacts; /* artifacts caused by color changes */
double fringing; /* color artifacts caused by brightness changes */
double bleed; /* color bleed (color resolution reduction) */
int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
unsigned long const* bsnes_colortbl; /* undocumented; set to 0 */
} snes_ntsc_setup_t;
/* Video format presets */
extern snes_ntsc_setup_t const snes_ntsc_composite; /* color bleeding + artifacts */
extern snes_ntsc_setup_t const snes_ntsc_svideo; /* color bleeding only */
extern snes_ntsc_setup_t const snes_ntsc_rgb; /* crisp image */
extern snes_ntsc_setup_t const snes_ntsc_monochrome;/* desaturated + artifacts */
/* Initializes and adjusts parameters. Can be called multiple times on the same
snes_ntsc_t object. Can pass NULL for either parameter. */
typedef struct snes_ntsc_t snes_ntsc_t;
void snes_ntsc_init( snes_ntsc_t* ntsc, snes_ntsc_setup_t const* setup );
/* Filters one or more rows of pixels. Input pixel format is set by SNES_NTSC_IN_FORMAT
and output RGB depth is set by SNES_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
In_row_width is the number of pixels to get to the next input row. Out_pitch
is the number of *bytes* to get to the next output row. */
void snes_ntsc_blit( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
long in_row_width, int burst_phase, int in_width, int in_height,
void* rgb_out, long out_pitch );
void snes_ntsc_blit_hires( snes_ntsc_t const* ntsc, SNES_NTSC_IN_T const* input,
long in_row_width, int burst_phase, int in_width, int in_height,
void* rgb_out, long out_pitch );
/* Number of output pixels written by low-res blitter for given input width. Width
might be rounded down slightly; use SNES_NTSC_IN_WIDTH() on result to find rounded
value. Guaranteed not to round 256 down at all. */
#define SNES_NTSC_OUT_WIDTH( in_width ) \
((((in_width) - 1) / snes_ntsc_in_chunk + 1) * snes_ntsc_out_chunk)
/* Number of low-res input pixels that will fit within given output width. Might be
rounded down slightly; use SNES_NTSC_OUT_WIDTH() on result to find rounded
value. */
#define SNES_NTSC_IN_WIDTH( out_width ) \
(((out_width) / snes_ntsc_out_chunk - 1) * snes_ntsc_in_chunk + 1)
/* Interface for user-defined custom blitters */
enum { snes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */
enum { snes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
enum { snes_ntsc_black = 0 }; /* palette index for black */
enum { snes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */
/* Begins outputting row and starts three pixels. First pixel will be cut off a bit.
Use snes_ntsc_black for unused pixels. Declares variables, so must be before first
statement in a block (unless you're using C++). */
#define SNES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \
char const* ktable = \
(char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\
SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, SNES_NTSC_IN_FORMAT, ktable )
/* Begins input pixel */
#define SNES_NTSC_COLOR_IN( index, color ) \
SNES_NTSC_COLOR_IN_( index, color, SNES_NTSC_IN_FORMAT, ktable )
/* Generates output pixel. Bits can be 24, 16, 15, 14, 32 (treated as 24), or 0:
24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB)
16: RRRRRGGG GGGBBBBB (5-6-5 RGB)
15: RRRRRGG GGGBBBBB (5-5-5 RGB)
14: BBBBBGG GGGRRRRR (5-5-5 BGR, native SNES format)
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
#define SNES_NTSC_RGB_OUT( index, rgb_out, bits ) \
SNES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 1 )
/* Hires equivalents */
#define SNES_NTSC_HIRES_ROW( ntsc, burst, pixel1, pixel2, pixel3, pixel4, pixel5 ) \
char const* ktable = \
(char const*) (ntsc)->table + burst * (snes_ntsc_burst_size * sizeof (snes_ntsc_rgb_t));\
unsigned const snes_ntsc_pixel1_ = (pixel1);\
snes_ntsc_rgb_t const* kernel1 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel1_ );\
unsigned const snes_ntsc_pixel2_ = (pixel2);\
snes_ntsc_rgb_t const* kernel2 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel2_ );\
unsigned const snes_ntsc_pixel3_ = (pixel3);\
snes_ntsc_rgb_t const* kernel3 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel3_ );\
unsigned const snes_ntsc_pixel4_ = (pixel4);\
snes_ntsc_rgb_t const* kernel4 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel4_ );\
unsigned const snes_ntsc_pixel5_ = (pixel5);\
snes_ntsc_rgb_t const* kernel5 = SNES_NTSC_IN_FORMAT( ktable, snes_ntsc_pixel5_ );\
snes_ntsc_rgb_t const* kernel0 = kernel1;\
snes_ntsc_rgb_t const* kernelx0;\
snes_ntsc_rgb_t const* kernelx1 = kernel1;\
snes_ntsc_rgb_t const* kernelx2 = kernel1;\
snes_ntsc_rgb_t const* kernelx3 = kernel1;\
snes_ntsc_rgb_t const* kernelx4 = kernel1;\
snes_ntsc_rgb_t const* kernelx5 = kernel1
#define SNES_NTSC_HIRES_OUT( x, rgb_out, bits ) {\
snes_ntsc_rgb_t raw_ =\
kernel0 [ x ] + kernel2 [(x+5)%7+14] + kernel4 [(x+3)%7+28] +\
kernelx0 [(x+7)%7+7] + kernelx2 [(x+5)%7+21] + kernelx4 [(x+3)%7+35] +\
kernel1 [(x+6)%7 ] + kernel3 [(x+4)%7+14] + kernel5 [(x+2)%7+28] +\
kernelx1 [(x+6)%7+7] + kernelx3 [(x+4)%7+21] + kernelx5 [(x+2)%7+35];\
SNES_NTSC_CLAMP_( raw_, 0 );\
SNES_NTSC_RGB_OUT_( rgb_out, (bits), 0 );\
}
/* private */
enum { snes_ntsc_entry_size = 128 };
enum { snes_ntsc_palette_size = 0x2000 };
typedef unsigned long snes_ntsc_rgb_t;
struct snes_ntsc_t {
snes_ntsc_rgb_t table [snes_ntsc_palette_size] [snes_ntsc_entry_size];
};
enum { snes_ntsc_burst_size = snes_ntsc_entry_size / snes_ntsc_burst_count };
#define SNES_NTSC_RGB16( ktable, n ) \
(snes_ntsc_rgb_t const*) (ktable + ((n & 0x001E) | (n >> 1 & 0x03E0) | (n >> 2 & 0x3C00)) * \
(snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t)))
#define SNES_NTSC_BGR15( ktable, n ) \
(snes_ntsc_rgb_t const*) (ktable + ((n << 9 & 0x3C00) | (n & 0x03E0) | (n >> 10 & 0x001E)) * \
(snes_ntsc_entry_size / 2 * sizeof (snes_ntsc_rgb_t)))
/* common 3->7 ntsc macros */
#define SNES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \
unsigned const snes_ntsc_pixel0_ = (pixel0);\
snes_ntsc_rgb_t const* kernel0 = ENTRY( table, snes_ntsc_pixel0_ );\
unsigned const snes_ntsc_pixel1_ = (pixel1);\
snes_ntsc_rgb_t const* kernel1 = ENTRY( table, snes_ntsc_pixel1_ );\
unsigned const snes_ntsc_pixel2_ = (pixel2);\
snes_ntsc_rgb_t const* kernel2 = ENTRY( table, snes_ntsc_pixel2_ );\
snes_ntsc_rgb_t const* kernelx0;\
snes_ntsc_rgb_t const* kernelx1 = kernel0;\
snes_ntsc_rgb_t const* kernelx2 = kernel0
#define SNES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
snes_ntsc_rgb_t raw_ =\
kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\
kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\
SNES_NTSC_CLAMP_( raw_, shift );\
SNES_NTSC_RGB_OUT_( rgb_out, bits, shift );\
}
/* common ntsc macros */
#define snes_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
#define snes_ntsc_clamp_mask (snes_ntsc_rgb_builder * 3 / 2)
#define snes_ntsc_clamp_add (snes_ntsc_rgb_builder * 0x101)
#define SNES_NTSC_CLAMP_( io, shift ) {\
snes_ntsc_rgb_t sub = (io) >> (9-(shift)) & snes_ntsc_clamp_mask;\
snes_ntsc_rgb_t clamp = snes_ntsc_clamp_add - sub;\
io |= clamp;\
clamp -= sub;\
io &= clamp;\
}
#define SNES_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
unsigned color_;\
kernelx##index = kernel##index;\
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
}
/* x is always zero except in snes_ntsc library */
/* original routine */
/*
#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
if ( bits == 16 )\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
if ( bits == 24 || bits == 32 )\
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
if ( bits == 15 )\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
if ( bits == 14 )\
rgb_out = (raw_>>(24-x)& 0x001F)|(raw_>>(9-x)&0x03E0)|(raw_<<(6+x)&0x7C00);\
if ( bits == 0 )\
rgb_out = raw_ << x;\
}
*/
/* custom bsnes routine -- hooks into bsnes colortable */
#define SNES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
if ( bits == 16 ) {\
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
rgb_out = ((rgb_out&0xf800)>>11)|((rgb_out&0x07c0)>>1)|((rgb_out&0x001f)<<10);\
rgb_out = colortable[rgb_out];\
} else if ( bits == 24 || bits == 32 ) {\
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
rgb_out = ((rgb_out&0xf80000)>>19)|((rgb_out&0x00f800)>>6)|((rgb_out&0x0000f8)<<7);\
rgb_out = colortable[rgb_out];\
} else if ( bits == 15 ) {\
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
rgb_out = ((rgb_out&0x7c00)>>10)|((rgb_out&0x03e0))|((rgb_out&0x001f)<<10);\
rgb_out = colortable[rgb_out];\
} else {\
rgb_out = raw_ << x;\
}\
}
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,26 +0,0 @@
/* Configure library by modifying this file */
#ifndef SNES_NTSC_CONFIG_H
#define SNES_NTSC_CONFIG_H
/* Format of source pixels */
/* #define SNES_NTSC_IN_FORMAT SNES_NTSC_RGB16 */
#define SNES_NTSC_IN_FORMAT SNES_NTSC_BGR15
/* The following affect the built-in blitter only; a custom blitter can
handle things however it wants. */
/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */
#define SNES_NTSC_OUT_DEPTH 32
/* Type of input pixel values */
#define SNES_NTSC_IN_T unsigned short
/* Each raw pixel input value is passed through this. You might want to mask
the pixel index if you use the high bits as flags, etc. */
#define SNES_NTSC_ADJ_IN( in ) in
/* For each pixel, this is the basic operation:
output_color = SNES_NTSC_ADJ_IN( SNES_NTSC_IN_T ) */
#endif

View File

@@ -1,439 +0,0 @@
/* snes_ntsc 0.2.2. http://www.slack.net/~ant/ */
/* Common implementation of NTSC filters */
#include <assert.h>
#include <math.h>
/* Copyright (C) 2006 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#define DISABLE_CORRECTION 0
#undef PI
#define PI 3.14159265358979323846f
#ifndef LUMA_CUTOFF
#define LUMA_CUTOFF 0.20
#endif
#ifndef gamma_size
#define gamma_size 1
#endif
#ifndef rgb_bits
#define rgb_bits 8
#endif
#ifndef artifacts_max
#define artifacts_max (artifacts_mid * 1.5f)
#endif
#ifndef fringing_max
#define fringing_max (fringing_mid * 2)
#endif
#ifndef STD_HUE_CONDITION
#define STD_HUE_CONDITION( setup ) 1
#endif
#define ext_decoder_hue (std_decoder_hue + 15)
#define rgb_unit (1 << rgb_bits)
#define rgb_offset (rgb_unit * 2 + 0.5f)
enum { burst_size = snes_ntsc_entry_size / burst_count };
enum { kernel_half = 16 };
enum { kernel_size = kernel_half * 2 + 1 };
typedef struct init_t
{
float to_rgb [burst_count * 6];
float to_float [gamma_size];
float contrast;
float brightness;
float artifacts;
float fringing;
float kernel [rescale_out * kernel_size * 2];
} init_t;
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
float t;\
t = i * cos_b - q * sin_b;\
q = i * sin_b + q * cos_b;\
i = t;\
}
static void init_filters( init_t* impl, snes_ntsc_setup_t const* setup )
{
#if rescale_out > 1
float kernels [kernel_size * 2];
#else
float* const kernels = impl->kernel;
#endif
/* generate luma (y) filter using sinc kernel */
{
/* sinc with rolloff (dsf) */
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
float const maxh = 32;
float const pow_a_n = (float) pow( rolloff, maxh );
float sum;
int i;
/* quadratic mapping to reduce negative (blurring) range */
float to_angle = (float) setup->resolution + 1;
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
kernels [kernel_size * 3 / 2] = maxh; /* default center value */
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
int x = i - kernel_half;
float angle = x * to_angle;
/* instability occurs at center point with rolloff very close to 1.0 */
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
{
float rolloff_cos_a = rolloff * (float) cos( angle );
float num = 1 - rolloff_cos_a -
pow_a_n * (float) cos( maxh * angle ) +
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
float dsf = num / den;
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
}
}
/* apply blackman window and find sum */
sum = 0;
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
float x = PI * 2 / (kernel_half * 2) * i;
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
}
/* normalize kernel */
sum = 1.0f / sum;
for ( i = 0; i < kernel_half * 2 + 1; i++ )
{
int x = kernel_size * 3 / 2 - kernel_half + i;
kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
}
}
/* generate chroma (iq) filter using gaussian kernel */
{
float const cutoff_factor = -0.03125f;
float cutoff = (float) setup->bleed;
int i;
if ( cutoff < 0 )
{
/* keep extreme value accessible only near upper end of scale (1.0) */
cutoff *= cutoff;
cutoff *= cutoff;
cutoff *= cutoff;
cutoff *= -30.0f / 0.65f;
}
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
for ( i = -kernel_half; i <= kernel_half; i++ )
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
/* normalize even and odd phases separately */
for ( i = 0; i < 2; i++ )
{
float sum = 0;
int x;
for ( x = i; x < kernel_size; x += 2 )
sum += kernels [x];
sum = 1.0f / sum;
for ( x = i; x < kernel_size; x += 2 )
{
kernels [x] *= sum;
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
}
}
}
/*
printf( "luma:\n" );
for ( i = kernel_size; i < kernel_size * 2; i++ )
printf( "%f\n", kernels [i] );
printf( "chroma:\n" );
for ( i = 0; i < kernel_size; i++ )
printf( "%f\n", kernels [i] );
*/
/* generate linear rescale kernels */
#if rescale_out > 1
{
float weight = 1.0f;
float* out = impl->kernel;
int n = rescale_out;
do
{
float remain = 0;
int i;
weight -= 1.0f / rescale_in;
for ( i = 0; i < kernel_size * 2; i++ )
{
float cur = kernels [i];
float m = cur * weight;
*out++ = m + remain;
remain = cur - m;
}
}
while ( --n );
}
#endif
}
static float const default_decoder [6] =
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
static void init( init_t* impl, snes_ntsc_setup_t const* setup )
{
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
#ifdef default_palette_contrast
if ( !setup->palette )
impl->contrast *= default_palette_contrast;
#endif
impl->artifacts = (float) setup->artifacts;
if ( impl->artifacts > 0 )
impl->artifacts *= artifacts_max - artifacts_mid;
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
impl->fringing = (float) setup->fringing;
if ( impl->fringing > 0 )
impl->fringing *= fringing_max - fringing_mid;
impl->fringing = impl->fringing * fringing_mid + fringing_mid;
init_filters( impl, setup );
/* generate gamma table */
if ( gamma_size > 1 )
{
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
int i;
for ( i = 0; i < gamma_size; i++ )
impl->to_float [i] =
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
}
/* setup decoder matricies */
{
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
float sat = (float) setup->saturation + 1;
float const* decoder = setup->decoder_matrix;
if ( !decoder )
{
decoder = default_decoder;
if ( STD_HUE_CONDITION( setup ) )
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
}
{
float s = (float) sin( hue ) * sat;
float c = (float) cos( hue ) * sat;
float* out = impl->to_rgb;
int n;
n = burst_count;
do
{
float const* in = decoder;
int n = 3;
do
{
float i = *in++;
float q = *in++;
*out++ = i * c - q * s;
*out++ = i * s + q * c;
}
while ( --n );
if ( burst_count <= 1 )
break;
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
}
while ( --n );
}
}
}
/* kernel generation */
#define RGB_TO_YIQ( r, g, b, y, i ) (\
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
(i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\
((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\
)
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
)
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
enum { rgb_kernel_size = burst_size / alignment_count };
enum { rgb_bias = rgb_unit * 2 * snes_ntsc_rgb_builder };
typedef struct pixel_info_t
{
int offset;
float negate;
float kernel [4];
} pixel_info_t;
#if rescale_in > 1
#define PIXEL_OFFSET_( ntsc, scaled ) \
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
(kernel_size * 2 * scaled))
#define PIXEL_OFFSET( ntsc, scaled ) \
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
(((scaled) + rescale_out * 10) % rescale_out) ),\
(1.0f - (((ntsc) + 100) & 2))
#else
#define PIXEL_OFFSET( ntsc, scaled ) \
(kernel_size / 2 + (ntsc) - (scaled)),\
(1.0f - (((ntsc) + 100) & 2))
#endif
extern pixel_info_t const snes_ntsc_pixels [alignment_count];
/* Generate pixel at all burst phases and column alignments */
static void gen_kernel( init_t* impl, float y, float i, float q, snes_ntsc_rgb_t* out )
{
/* generate for each scanline burst phase */
float const* to_rgb = impl->to_rgb;
int burst_remain = burst_count;
y -= rgb_offset;
do
{
/* Encode yiq into *two* composite signals (to allow control over artifacting).
Convolve these with kernels which: filter respective components, apply
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
into integer. Based on algorithm by NewRisingSun. */
pixel_info_t const* pixel = snes_ntsc_pixels;
int alignment_remain = alignment_count;
do
{
/* negate is -1 when composite starts at odd multiple of 2 */
float const yy = y * impl->fringing * pixel->negate;
float const ic0 = (i + yy) * pixel->kernel [0];
float const qc1 = (q + yy) * pixel->kernel [1];
float const ic2 = (i - yy) * pixel->kernel [2];
float const qc3 = (q - yy) * pixel->kernel [3];
float const factor = impl->artifacts * pixel->negate;
float const ii = i * factor;
float const yc0 = (y + ii) * pixel->kernel [0];
float const yc2 = (y - ii) * pixel->kernel [2];
float const qq = q * factor;
float const yc1 = (y + qq) * pixel->kernel [1];
float const yc3 = (y - qq) * pixel->kernel [3];
float const* k = &impl->kernel [pixel->offset];
int n;
++pixel;
for ( n = rgb_kernel_size; n; --n )
{
float i = k[0]*ic0 + k[2]*ic2;
float q = k[1]*qc1 + k[3]*qc3;
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
if ( rescale_out <= 1 )
k--;
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
k += kernel_size * 2 - 1;
else
k -= kernel_size * 2 * (rescale_out - 1) + 2;
{
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
*out++ = PACK_RGB( r, g, b ) - rgb_bias;
}
}
}
while ( alignment_count > 1 && --alignment_remain );
if ( burst_count <= 1 )
break;
to_rgb += 6;
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
}
while ( --burst_remain );
}
static void correct_errors( snes_ntsc_rgb_t color, snes_ntsc_rgb_t* out );
#if DISABLE_CORRECTION
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
#else
#define CORRECT_ERROR( a ) { out [a] += error; }
#define DISTRIBUTE_ERROR( a, b, c ) {\
snes_ntsc_rgb_t fourth = (error + 2 * snes_ntsc_rgb_builder) >> 2;\
fourth &= (rgb_bias >> 1) - snes_ntsc_rgb_builder;\
fourth -= rgb_bias >> 2;\
out [a] += fourth;\
out [b] += fourth;\
out [c] += fourth;\
out [i] += error - (fourth * 3);\
}
#endif
#define RGB_PALETTE_OUT( rgb, out_ )\
{\
unsigned char* out = (out_);\
snes_ntsc_rgb_t clamped = (rgb);\
SNES_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
out [0] = (unsigned char) (clamped >> 21);\
out [1] = (unsigned char) (clamped >> 11);\
out [2] = (unsigned char) (clamped >> 1);\
}
/* blitter related */
#ifndef restrict
#if defined (__GNUC__)
#define restrict __restrict__
#elif defined (_MSC_VER) && _MSC_VER > 1300
#define restrict __restrict
#else
/* no support for restricted pointers */
#define restrict
#endif
#endif
#include <limits.h>
#if SNES_NTSC_OUT_DEPTH <= 16
#if USHRT_MAX == 0xFFFF
typedef unsigned short snes_ntsc_out_t;
#else
#error "Need 16-bit int type"
#endif
#else
#if UINT_MAX == 0xFFFFFFFF
typedef unsigned int snes_ntsc_out_t;
#elif ULONG_MAX == 0xFFFFFFFF
typedef unsigned long snes_ntsc_out_t;
#else
#error "Need 32-bit int type"
#endif
#endif

View File

@@ -1,28 +0,0 @@
/*
Copyright (C) 2005-2007 NSRT Team ( http://nsrt.edgeemu.com )
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License version 2.1 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __7Z_H
#define __7Z_H
#include "iiostrm.h"
bool decompress_lzma_7z(ISequentialInStream& in, unsigned in_size, ISequentialOutStream& out, unsigned out_size) throw ();
bool decompress_lzma_7z(const unsigned char* in_data, unsigned in_size, unsigned char* out_data, unsigned out_size) throw ();
#endif

View File

@@ -1,50 +0,0 @@
/*
Copyright (C) 2005-2007 NSRT Team ( http://nsrt.edgeemu.com )
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License version 2.1 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "7z.h"
#include "lzmadec.h"
bool decompress_lzma_7z(ISequentialInStream& in, unsigned in_size, ISequentialOutStream& out, unsigned out_size) throw ()
{
try
{
NCompress::NLZMA::CDecoder cc;
UINT64 in_size_l = in_size;
UINT64 out_size_l = out_size;
if (cc.ReadCoderProperties(&in) != S_OK) { return(false); }
if (cc.Code(&in, &out, &in_size_l, &out_size_l) != S_OK) { return(false); }
if (out.size_get() != out_size || out.overflow_get()) { return(false); }
return(true);
}
catch (...)
{
return(false);
}
}
bool decompress_lzma_7z(const unsigned char* in_data, unsigned int in_size, unsigned char* out_data, unsigned int out_size) throw ()
{
ISequentialInStream_Array in(reinterpret_cast<const char*>(in_data), in_size);
ISequentialOutStream_Array out(reinterpret_cast<char*>(out_data), out_size);
return(decompress_lzma_7z(in, in_size, out, out_size));
}

View File

@@ -1,73 +0,0 @@
#ifndef __COMPRESSION_BITCODER_H
#define __COMPRESSION_BITCODER_H
#include "rngcoder.h"
namespace NCompression {
namespace NArithmetic {
const int kNumBitModelTotalBits = 11;
const UINT32 kBitModelTotal = (1 << kNumBitModelTotalBits);
const int kNumMoveReducingBits = 2;
/////////////////////////////
// CBitModel
template <int aNumMoveBits>
class CBitModel
{
public:
UINT32 m_Probability;
void UpdateModel(UINT32 aSymbol)
{
/*
m_Probability -= (m_Probability + ((aSymbol - 1) & ((1 << aNumMoveBits) - 1))) >> aNumMoveBits;
m_Probability += (1 - aSymbol) << (kNumBitModelTotalBits - aNumMoveBits);
*/
if (aSymbol == 0)
m_Probability += (kBitModelTotal - m_Probability) >> aNumMoveBits;
else
m_Probability -= (m_Probability) >> aNumMoveBits;
}
public:
void Init() { m_Probability = kBitModelTotal / 2; }
};
template <int aNumMoveBits>
class CBitDecoder: public CBitModel<aNumMoveBits>
{
public:
UINT32 Decode(CRangeDecoder *aRangeDecoder)
{
UINT32 aNewBound = (aRangeDecoder->m_Range >> kNumBitModelTotalBits) * CBitModel<aNumMoveBits>::m_Probability;
if (aRangeDecoder->m_Code < aNewBound)
{
aRangeDecoder->m_Range = aNewBound;
CBitModel<aNumMoveBits>::m_Probability += (kBitModelTotal - CBitModel<aNumMoveBits>::m_Probability) >> aNumMoveBits;
if (aRangeDecoder->m_Range < kTopValue)
{
aRangeDecoder->m_Code = (aRangeDecoder->m_Code << 8) | aRangeDecoder->m_Stream.ReadByte();
aRangeDecoder->m_Range <<= 8;
}
return 0;
}
else
{
aRangeDecoder->m_Range -= aNewBound;
aRangeDecoder->m_Code -= aNewBound;
CBitModel<aNumMoveBits>::m_Probability -= (CBitModel<aNumMoveBits>::m_Probability) >> aNumMoveBits;
if (aRangeDecoder->m_Range < kTopValue)
{
aRangeDecoder->m_Code = (aRangeDecoder->m_Code << 8) | aRangeDecoder->m_Stream.ReadByte();
aRangeDecoder->m_Range <<= 8;
}
return 1;
}
}
};
}}
#endif

View File

@@ -1,29 +0,0 @@
/*
Copyright (C) 2002 Andrea Mazzoleni ( http://advancemame.sf.net )
Copyright (C) 2001-4 Igor Pavlov ( http://www.7-zip.org )
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License version 2.1 as published by the Free Software Foundation.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __ARICONST_H
#define __ARICONST_H
#include "aribitcd.h"
typedef NCompression::NArithmetic::CRangeDecoder CMyRangeDecoder;
template <int aNumMoveBits> class CMyBitDecoder:
public NCompression::NArithmetic::CBitDecoder<aNumMoveBits> {};
#endif

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