Update to bsnes v047 release.

The most notable feature for this release is the addition of SuperFX support. This enables an additional eight commercial games, and two unreleased betas, to run with full support. Most notably of these would be Super Mario World 2: Yoshi's Island and Starfox. Though timing is not quite perfect just yet, there should be no known issues with any titles at the time of this release. That means there should only be two official, commercially-released titles that are not compatible with bsnes at this time: Quick-move Shogi Match with Nidan Rank-holder Morita 1 and 2 (using the ST011 and ST018 co-processors, respectively.)
SuperFX support was the work of many people. GIGO was a great help by providing the source code to his SuperFX emulator (for reference; the implementation in bsnes is my own design), _Demo_ was very helpful in getting Starfox to work properly, and Jonas Quinn provided roughly a half-dozen very important bug fixes that affected nearly every SuperFX game. Without them, this release would not be possible. So please do thank them if you appreciate SuperFX support in bsnes.
Please note that SuperFX emulation is very demanding. I hate to have to repeat this, but once again: bsnes is a reference emulator. It exists to better understand the SNES hardware. It is written in such a manner as to be friendly to other developers (both emulator authors and game programmers), and the findings are meant to help improve other emulators. As far as I know, bsnes is the first emulator to fully support all SuperFX caching mechanisms (instruction cache, both pixel caches, ROM and RAM buffering caches, ...); as well as many other obscure features, such as full support for ROM / RAM access toggling between the SNES and SuperFX CPUs, and multiplier overhead timing. By emulating these, I was able to discover what additional components are needed to emulate Dirt Racer and Power Slide, two titles that no emulator has yet been able to run (they aren't very good games, you weren't missing much.) It should be possible to backport these fixes to faster emulators now.
That said, with a Core 2 Duo E8400 @ 3GHz, on average I get ~100fps in Super Mario World 2, ~95fps in Starfox and ~85fps in Doom. Compare this to ~165fps in Zelda 3, a game that does not use the SuperFX chip. My binary releases also target 32-bit x86 architecture. For those capable of building 64-bit binaries, especially Linux users, that should provide an additional ~10% speedup. Be sure to profile the application if you build it yourself.
Lastly on the SuperFX front, note that Starfox 2 is fully playable, but that most images floating around have corrupted headers. I do not attempt to repair bad headers, so these images will not work. Please either use NSRT on the Japanese version, or use Gideon Zhi's English fan translation patch, if you are having trouble running this title.
With that out the way, a few other improvements have been made to this release: xinput1_3.dll is no longer required for the Windows port (though you will need it if you want to use an Xbox 360 controller), the video drivers in ruby now allocate the smallest texture size possible for blitting video, and the code has been updated with preliminary compilation support for Mac OS X. Note that I will not be releasing binaries for this: it is primarily meant for developers and for porting my other libraries to the platform. Richard Bannister maintains a much better OS X port with full EE support and a native Apple GUI that follows their interface guidelines much better than a Qt port ever could. He has also synced the Mac port with this release. You can find a link to that in the bsnes download section.
This commit is contained in:
byuu 2009-06-07 11:57:05 +00:00
parent f8e425ff49
commit 7b0e484c18
285 changed files with 30554 additions and 28393 deletions

View File

@ -1,4 +1,5 @@
include lib/nall/Makefile include lib/nall/Makefile
include lib/nall/Makefile-qt
ui = ui_qt ui = ui_qt
################ ################
@ -8,7 +9,7 @@ ui = ui_qt
c := $(compiler) c := $(compiler)
cpp := $(subst cc,++,$(compiler)) cpp := $(subst cc,++,$(compiler))
flags := -O3 -fomit-frame-pointer -Ilib flags := -O3 -fomit-frame-pointer -Ilib
link := -s link :=
# profile-guided instrumentation: # profile-guided instrumentation:
# flags += -fprofile-generate # flags += -fprofile-generate
@ -22,19 +23,31 @@ link := -s
################ ################
ifeq ($(platform),x) ifeq ($(platform),x)
ruby := video.glx video.xv video.sdl link += -s
ruby := video.glx video.xv video.sdl video.qtimage
ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.ao ruby += audio.alsa audio.openal audio.oss audio.pulseaudio audio.ao
ruby += input.sdl input.x ruby += input.sdl input.x
link += $(if $(findstring audio.openal,$(ruby)),-lopenal)
else ifeq ($(platform),osx)
ruby := video.qtimage
ruby += audio.openal
ruby += input.carbon
link += $(if $(findstring audio.openal,$(ruby)),-framework OpenAL)
else ifeq ($(platform),win) else ifeq ($(platform),win)
ruby := video.direct3d video.wgl video.directdraw video.gdi link += -mwindows
# link += -mconsole
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 += audio.directsound ruby += audio.directsound
ruby += input.rawinput input.directinput ruby += input.rawinput input.directinput
link += -mwindows link += $(if $(findstring audio.openal,$(ruby)),-lopenal32)
# link += -mconsole
link += -luuid -lkernel32 -luser32 -lgdi32 -lshell32
# statically link Qt for Windows build
link += -enable-stdcall-fixup -Wl,-s -Wl,-enable-auto-import -Wl,-enable-runtime-pseudo-reloc
else else
unknown_platform: help; unknown_platform: help;
endif endif
@ -43,7 +56,8 @@ endif
### ruby ### ### ruby ###
############ ############
rubyflags = $(call ifhas,.sdl,$(ruby),`sdl-config --cflags`) rubyflags := $(call ifhas,.sdl,$(ruby),`sdl-config --cflags`)
rubyflags += $(call ifhas,.qt,$(ruby),$(qtinc))
link += $(call ifhas,.sdl,$(ruby),`sdl-config --libs`) link += $(call ifhas,.sdl,$(ruby),`sdl-config --libs`)
link += $(call ifhas,video.direct3d,$(ruby),-ld3d9) link += $(call ifhas,video.direct3d,$(ruby),-ld3d9)
@ -54,19 +68,18 @@ link += $(call ifhas,video.xv,$(ruby),-lXv)
link += $(call ifhas,audio.alsa,$(ruby),-lasound) link += $(call ifhas,audio.alsa,$(ruby),-lasound)
link += $(call ifhas,audio.ao,$(ruby),-lao) link += $(call ifhas,audio.ao,$(ruby),-lao)
link += $(call ifhas,audio.directsound,$(ruby),-ldsound) link += $(call ifhas,audio.directsound,$(ruby),-ldsound)
link += $(call ifhas,audio.openal,$(ruby),$(if $(call streq,$(platform),x),-lopenal,-lopenal32))
link += $(call ifhas,audio.pulseaudio,$(ruby),-lpulse-simple) link += $(call ifhas,audio.pulseaudio,$(ruby),-lpulse-simple)
link += $(call ifhas,input.directinput,$(ruby),-ldinput8 -ldxguid) link += $(call ifhas,input.directinput,$(ruby),-ldinput8 -ldxguid)
link += $(call ifhas,input.rawinput,$(ruby),-lxinput -ldinput8 -ldxguid) link += $(call ifhas,input.rawinput,$(ruby),-ldinput8 -ldxguid)
#################### ####################
### core objects ### ### core objects ###
#################### ####################
objects = libco ruby libreader libfilter string \ objects := libco ruby libreader libfilter
system cartridge cheat \ objects += system cartridge cheat
memory smemory cpu cpucore scpu smp smpcore ssmp sdsp ppu bppu \ objects += memory smemory cpu cpucore scpu smp smpcore ssmp sdsp ppu bppu
sgb sa1 bsx srtc sdd1 spc7110 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010 objects += sgb superfx sa1 bsx srtc sdd1 spc7110 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010
ifeq ($(enable_gzip),true) ifeq ($(enable_gzip),true)
objects += adler32 compress crc32 deflate gzio inffast inflate inftrees ioapi trees unzip zip zutil objects += adler32 compress crc32 deflate gzio inffast inflate inftrees ioapi trees unzip zip zutil
@ -110,7 +123,6 @@ obj/libco.o: lib/libco/libco.c lib/libco/*
$(c) -O3 -fomit-frame-pointer -static -Ilib -c $< -o $@ $(c) -O3 -fomit-frame-pointer -static -Ilib -c $< -o $@
obj/libreader.o: lib/libreader/libreader.cpp lib/libreader/* obj/libreader.o: lib/libreader/libreader.cpp lib/libreader/*
obj/libfilter.o: lib/libfilter/libfilter.cpp lib/libfilter/* obj/libfilter.o: lib/libfilter/libfilter.cpp lib/libfilter/*
obj/string.o: lib/nall/string.cpp lib/nall/*
################# #################
### utilities ### ### utilities ###
@ -167,6 +179,7 @@ obj/system.o: system/system.cpp $(call rwildcard,system/)
##################### #####################
obj/sgb.o : chip/sgb/sgb.cpp $(call rwildcard,chip/sgb/) obj/sgb.o : chip/sgb/sgb.cpp $(call rwildcard,chip/sgb/)
obj/superfx.o: chip/superfx/superfx.cpp $(call rwildcard,chip/superfx/)
obj/sa1.o : chip/sa1/sa1.cpp $(call rwildcard,chip/sa1/) obj/sa1.o : chip/sa1/sa1.cpp $(call rwildcard,chip/sa1/)
obj/bsx.o : chip/bsx/bsx.cpp chip/bsx/* obj/bsx.o : chip/bsx/bsx.cpp chip/bsx/*
obj/srtc.o : chip/srtc/srtc.cpp chip/srtc/* obj/srtc.o : chip/srtc/srtc.cpp chip/srtc/*
@ -216,7 +229,12 @@ obj/winout.o : lib/libjma/winout.cpp lib/libjma/*
############### ###############
build: ui_build $(objects) build: ui_build $(objects)
$(strip $(cpp) -o../bsnes $(objects) $(link)) ifeq ($(platform),osx)
test -d ../bsnes.app || mkdir -p ../bsnes.app/Contents/MacOS
$(strip $(cpp) -o ../bsnes.app/Contents/MacOS/bsnes $(objects) $(link))
else
$(strip $(cpp) -o ../bsnes $(objects) $(link))
endif
install: install:
install -D -m 755 ../bsnes $(DESTDIR)$(prefix)/bin/bsnes install -D -m 755 ../bsnes $(DESTDIR)$(prefix)/bin/bsnes
@ -250,4 +268,3 @@ help:
@echo "" @echo ""
@echo "Example: $(MAKE) platform=x compiler=gcc enable_gzip=true" @echo "Example: $(MAKE) platform=x compiler=gcc enable_gzip=true"
@echo "" @echo ""

View File

@ -1,4 +1,4 @@
#define BSNES_VERSION "0.046" #define BSNES_VERSION "0.047"
#define BSNES_TITLE "bsnes v" BSNES_VERSION #define BSNES_TITLE "bsnes v" BSNES_VERSION
#define BUSCORE sBus #define BUSCORE sBus
@ -41,4 +41,3 @@ typedef uint16_t uint16;
typedef uint32_t uint32; typedef uint32_t uint32;
#include "interface.hpp" #include "interface.hpp"

View File

@ -30,6 +30,7 @@ public:
HiROM, HiROM,
ExLoROM, ExLoROM,
ExHiROM, ExHiROM,
SuperFXROM,
SA1ROM, SA1ROM,
SPC7110ROM, SPC7110ROM,
BSCLoROM, BSCLoROM,

View File

@ -22,11 +22,8 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
const uint8 company = data[index + Company]; const uint8 company = data[index + Company];
const uint8 region = data[index + CartRegion] & 0x7f; const uint8 region = data[index + CartRegion] & 0x7f;
if(data[index + RamSize] & 7) {
info.ram_size = 1024 << (data[index + RamSize] & 7); info.ram_size = 1024 << (data[index + RamSize] & 7);
} else { if(info.ram_size == 1024) info.ram_size = 0; //no RAM present, eg RamSize == 0
info.ram_size = 0;
}
//0, 1, 13 = NTSC; 2 - 12 = PAL //0, 1, 13 = NTSC; 2 - 12 = PAL
info.region = (region <= 1 || region >= 13) ? NTSC : PAL; info.region = (region <= 1 || region >= 13) ? NTSC : PAL;
@ -119,6 +116,9 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size
if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) { if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) {
info.superfx = true; info.superfx = true;
info.mapper = SuperFXROM;
info.ram_size = 1024 << (data[index - 3] & 7);
if(info.ram_size == 1024) info.ram_size = 0;
} }
if(mapper == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) { if(mapper == 0x23 && (rom_type == 0x32 || rom_type == 0x34 || rom_type == 0x35)) {

View File

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

View File

@ -1,4 +1,5 @@
#include "sgb/sgb.hpp" #include "sgb/sgb.hpp"
#include "superfx/superfx.hpp"
#include "sa1/sa1.hpp" #include "sa1/sa1.hpp"
#include "bsx/bsx.hpp" #include "bsx/bsx.hpp"
#include "srtc/srtc.hpp" #include "srtc/srtc.hpp"

View File

@ -36,5 +36,5 @@ void DSP3::write(unsigned addr, uint8 data) {
DSP3i::dsp3_byte = data; DSP3i::dsp3_byte = data;
DSP3i::DSP3SetByte(); DSP3i::DSP3SetByte();
} }
};
};

View File

@ -56,5 +56,5 @@ void DSP4::write(unsigned addr, uint8 data) {
DSP4i::DSP4SetByte(); DSP4i::DSP4SetByte();
} }
} }
};
};

View File

@ -75,4 +75,3 @@ OBC1::OBC1() {}
OBC1::~OBC1() {} OBC1::~OBC1() {}
}; };

View File

@ -3,21 +3,16 @@
SA1Bus sa1bus; SA1Bus sa1bus;
namespace memory { namespace memory {
VectorSelectionPage vectorsp; static VectorSelectionPage vectorsp;
StaticRAM iram(2048); static StaticRAM iram(2048);
MappedRAM &bwram = memory::cartram; static MappedRAM &bwram = memory::cartram;
CC1BWRAM cc1bwram; static CC1BWRAM cc1bwram;
BitmapRAM bitmapram; static BitmapRAM bitmapram;
} }
void SA1Bus::init() { void SA1Bus::init() {
for(uint32_t i = 0x0000; i <= 0xffff; i++) { map(MapDirect, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
map(i << 8, memory::memory_unmapped, 0); for(uint16_t i = 0x2200; i <= 0x23ff; i++) memory::mmio.map(i, sa1);
}
for(uint16_t i = 0x2200; i <= 0x23ff; i++) {
memory::mmio.map(i, sa1);
}
map(MapLinear, 0x00, 0x3f, 0x0000, 0x07ff, memory::iram); map(MapLinear, 0x00, 0x3f, 0x0000, 0x07ff, memory::iram);
map(MapDirect, 0x00, 0x3f, 0x2200, 0x23ff, memory::mmio); map(MapDirect, 0x00, 0x3f, 0x2200, 0x23ff, memory::mmio);
@ -120,7 +115,7 @@ uint8_t BitmapRAM::read(unsigned addr) {
//4bpp //4bpp
unsigned shift = addr & 1; unsigned shift = addr & 1;
addr = (addr >> 1) & (memory::cartram.size() - 1); addr = (addr >> 1) & (memory::cartram.size() - 1);
switch(shift) { switch(shift) { default:
case 0: return (memory::cartram.read(addr) >> 0) & 15; case 0: return (memory::cartram.read(addr) >> 0) & 15;
case 1: return (memory::cartram.read(addr) >> 4) & 15; case 1: return (memory::cartram.read(addr) >> 4) & 15;
} }
@ -128,7 +123,7 @@ uint8_t BitmapRAM::read(unsigned addr) {
//2bpp //2bpp
unsigned shift = addr & 3; unsigned shift = addr & 3;
addr = (addr >> 2) & (memory::cartram.size() - 1); addr = (addr >> 2) & (memory::cartram.size() - 1);
switch(shift) { switch(shift) { default:
case 0: return (memory::cartram.read(addr) >> 0) & 3; case 0: return (memory::cartram.read(addr) >> 0) & 3;
case 1: return (memory::cartram.read(addr) >> 2) & 3; case 1: return (memory::cartram.read(addr) >> 2) & 3;
case 2: return (memory::cartram.read(addr) >> 4) & 3; case 2: return (memory::cartram.read(addr) >> 4) & 3;
@ -142,7 +137,7 @@ void BitmapRAM::write(unsigned addr, uint8_t data) {
//4bpp //4bpp
uint8_t shift = addr & 1; uint8_t shift = addr & 1;
addr = (addr >> 1) & (memory::cartram.size() - 1); addr = (addr >> 1) & (memory::cartram.size() - 1);
switch(shift) { switch(shift) { default:
case 0: data = (memory::cartram.read(addr) & 0xf0) | ((data & 15) << 0); break; case 0: data = (memory::cartram.read(addr) & 0xf0) | ((data & 15) << 0); break;
case 1: data = (memory::cartram.read(addr) & 0x0f) | ((data & 15) << 4); break; case 1: data = (memory::cartram.read(addr) & 0x0f) | ((data & 15) << 4); break;
} }
@ -150,7 +145,7 @@ void BitmapRAM::write(unsigned addr, uint8_t data) {
//2bpp //2bpp
uint8_t shift = addr & 3; uint8_t shift = addr & 3;
addr = (addr >> 2) & (memory::cartram.size() - 1); addr = (addr >> 2) & (memory::cartram.size() - 1);
switch(shift) { switch(shift) { default:
case 0: data = (memory::cartram.read(addr) & 0xfc) | ((data & 3) << 0); break; case 0: data = (memory::cartram.read(addr) & 0xfc) | ((data & 3) << 0); break;
case 1: data = (memory::cartram.read(addr) & 0xf3) | ((data & 3) << 2); break; case 1: data = (memory::cartram.read(addr) & 0xf3) | ((data & 3) << 2); break;
case 2: data = (memory::cartram.read(addr) & 0xcf) | ((data & 3) << 4); break; case 2: data = (memory::cartram.read(addr) & 0xcf) | ((data & 3) << 4); break;

View File

@ -21,11 +21,3 @@ struct BitmapRAM : Memory {
alwaysinline uint8_t read(unsigned); alwaysinline uint8_t read(unsigned);
alwaysinline void write(unsigned, uint8_t); alwaysinline void write(unsigned, uint8_t);
}; };
namespace memory {
extern VectorSelectionPage vectorsp;
extern StaticRAM iram;
extern MappedRAM &bwram;
extern CC1BWRAM cc1bwram;
extern BitmapRAM bitmapram;
}

View File

@ -315,4 +315,3 @@ SA1::SA1() {
} }
}; };

View File

@ -158,5 +158,5 @@ SDD1::SDD1() {
SDD1::~SDD1() { SDD1::~SDD1() {
delete[] buffer.data; delete[] buffer.data;
} }
};
};

View File

@ -63,4 +63,3 @@ void SuperGameBoy::reset() {
} }
}; };

View File

@ -25,4 +25,3 @@ private:
}; };
extern SuperGameBoy sgb; extern SuperGameBoy sgb;

View File

@ -674,4 +674,3 @@ SPC7110::SPC7110() {
} }
}; };

View File

@ -229,4 +229,3 @@ SRTC::SRTC() {
} }
}; };

View File

@ -88,5 +88,5 @@ void ST010::write(unsigned addr, uint8 data) {
ram[0x0021] &= ~0x80; ram[0x0021] &= ~0x80;
} }
} }
};
};

View File

@ -0,0 +1,92 @@
#ifdef SUPERFX_CPP
SuperFXBus superfxbus;
namespace memory {
static SuperFXGSUROM gsurom;
static SuperFXGSURAM gsuram;
static SuperFXCPUROM fxrom;
static SuperFXCPURAM fxram;
};
void SuperFXBus::init() {
map(MapDirect, 0x00, 0xff, 0x0000, 0xffff, memory::memory_unmapped);
map(MapLinear, 0x00, 0x3f, 0x0000, 0x7fff, memory::gsurom);
map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::gsurom);
map(MapLinear, 0x40, 0x5f, 0x0000, 0xffff, memory::gsurom);
map(MapLinear, 0x60, 0x7f, 0x0000, 0xffff, memory::gsuram);
bus.map(MapLinear, 0x00, 0x3f, 0x6000, 0x7fff, memory::fxram, 0x0000, 0x2000);
bus.map(MapLinear, 0x00, 0x3f, 0x8000, 0xffff, memory::fxrom);
bus.map(MapLinear, 0x40, 0x5f, 0x0000, 0xffff, memory::fxrom);
bus.map(MapLinear, 0x60, 0x7d, 0x0000, 0xffff, memory::fxram);
bus.map(MapLinear, 0x80, 0xbf, 0x6000, 0x7fff, memory::fxram, 0x0000, 0x2000);
bus.map(MapLinear, 0x80, 0xbf, 0x8000, 0xffff, memory::fxrom);
bus.map(MapLinear, 0xc0, 0xdf, 0x0000, 0xffff, memory::fxrom);
bus.map(MapLinear, 0xe0, 0xff, 0x0000, 0xffff, memory::fxram);
}
//ROM / RAM access from the SuperFX CPU
unsigned SuperFXGSUROM::size() const {
return memory::cartrom.size();
}
uint8_t SuperFXGSUROM::read(unsigned addr) {
while(!superfx.regs.scmr.ron) superfx.add_clocks(2);
return memory::cartrom.read(addr);
}
void SuperFXGSUROM::write(unsigned addr, uint8_t data) {
}
unsigned SuperFXGSURAM::size() const {
return memory::cartram.size();
}
uint8_t SuperFXGSURAM::read(unsigned addr) {
while(!superfx.regs.scmr.ran) superfx.add_clocks(2);
return memory::cartram.read(addr);
}
void SuperFXGSURAM::write(unsigned addr, uint8_t data) {
while(!superfx.regs.scmr.ran) superfx.add_clocks(2);
memory::cartram.write(addr, data);
}
//ROM / RAM access from the S-CPU
unsigned SuperFXCPUROM::size() const {
return memory::cartrom.size();
}
uint8_t SuperFXCPUROM::read(unsigned addr) {
if(superfx.regs.sfr.g && superfx.regs.scmr.ron) {
static const uint8_t data[16] = {
0x00, 0x01, 0x00, 0x01, 0x04, 0x01, 0x00, 0x01,
0x00, 0x01, 0x08, 0x01, 0x00, 0x01, 0x0c, 0x01,
};
return data[addr & 15];
}
return memory::cartrom.read(addr);
}
void SuperFXCPUROM::write(unsigned addr, uint8_t data) {
memory::cartrom.write(addr, data);
}
unsigned SuperFXCPURAM::size() const {
return memory::cartram.size();
}
uint8_t SuperFXCPURAM::read(unsigned addr) {
if(superfx.regs.sfr.g && superfx.regs.scmr.ran) return cpu.regs.mdr;
return memory::cartram.read(addr);
}
void SuperFXCPURAM::write(unsigned addr, uint8_t data) {
memory::cartram.write(addr, data);
}
#endif

View File

@ -0,0 +1,27 @@
struct SuperFXBus : Bus {
void init();
};
struct SuperFXGSUROM : Memory {
unsigned size() const;
uint8_t read(unsigned);
void write(unsigned, uint8_t);
};
struct SuperFXGSURAM : Memory {
unsigned size() const;
uint8_t read(unsigned);
void write(unsigned, uint8_t);
};
struct SuperFXCPUROM : Memory {
unsigned size() const;
uint8_t read(unsigned);
void write(unsigned, uint8_t);
};
struct SuperFXCPURAM : Memory {
unsigned size() const;
uint8_t read(unsigned);
void write(unsigned, uint8_t);
};

View File

@ -0,0 +1,121 @@
#ifdef SUPERFX_CPP
#include "opcodes.cpp"
#include "opcode_table.cpp"
void SuperFX::exec_opcode() {
#if 0
if(!fp) fp = fopen("sfxtrace.log", "wb");
char t[4096];
disassemble_opcode(t);
fprintf(fp, "%s ", t);
for(unsigned i = 0; i < 16; i++) fprintf(fp, "r%u:%.4x ", i, (uint16_t)regs.r[i]);
fprintf(fp, "\n");
#endif
(this->*opcode_table[(regs.sfr & 0x0300) + peekpipe()])();
if(r15_modified == false) regs.r[15]++;
}
uint8_t SuperFX::color(uint8_t source) {
if(regs.por.highnibble) return (regs.colr & 0xf0) | (source >> 4);
if(regs.por.freezehigh) return (regs.colr & 0xf0) | (source & 0x0f);
return source;
}
void SuperFX::plot(uint8_t x, uint8_t y) {
uint8_t color = regs.colr;
if(regs.por.dither && regs.scmr.md != 3) {
if((x ^ y) & 1) color >>= 4;
color &= 0x0f;
}
if(!regs.por.transparent) {
if(regs.scmr.md == 3) {
if(regs.por.freezehigh) {
if((color & 0x0f) == 0) return;
} else {
if(color == 0) return;
}
} else {
if((color & 0x0f) == 0) return;
}
}
uint16_t offset = (y << 5) + (x >> 3);
if(offset != pixelcache[0].offset) {
pixelcache_flush(pixelcache[1]);
pixelcache[1] = pixelcache[0];
pixelcache[0].bitpend = 0x00;
pixelcache[0].offset = offset;
}
x = (x & 7) ^ 7;
pixelcache[0].data[x] = color;
pixelcache[0].bitpend |= 1 << x;
if(pixelcache[0].bitpend == 0xff) {
pixelcache_flush(pixelcache[1]);
pixelcache[1] = pixelcache[0];
pixelcache[0].bitpend = 0x00;
}
}
uint8_t SuperFX::rpix(uint8_t x, uint8_t y) {
pixelcache_flush(pixelcache[1]);
pixelcache_flush(pixelcache[0]);
unsigned cn; //character number
switch(regs.por.obj ? 3 : regs.scmr.ht) {
case 0: cn = ((x & 0xf8) << 1) + ((y & 0xf8) >> 3); break;
case 1: cn = ((x & 0xf8) << 1) + ((x & 0xf8) >> 1) + ((y & 0xf8) >> 3); break;
case 2: cn = ((x & 0xf8) << 1) + ((x & 0xf8) << 0) + ((y & 0xf8) >> 3); break;
case 3: cn = ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); break;
}
unsigned bpp = 2 << (regs.scmr.md - (regs.scmr.md >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 };
unsigned addr = 0x700000 + (cn * (bpp << 3)) + (regs.scbr << 10) + ((y & 0x07) * 2);
uint8_t data = 0x00;
x = (x & 7) ^ 7;
for(unsigned n = 0; n < bpp; n++) {
unsigned byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 };
add_clocks(memory_access_speed);
data |= ((superfxbus.read(addr + byte) >> x) & 1) << n;
}
return data;
}
void SuperFX::pixelcache_flush(pixelcache_t &cache) {
if(cache.bitpend == 0x00) return;
uint8_t x = cache.offset << 3;
uint8_t y = cache.offset >> 5;
unsigned cn; //character number
switch(regs.por.obj ? 3 : regs.scmr.ht) {
case 0: cn = ((x & 0xf8) << 1) + ((y & 0xf8) >> 3); break;
case 1: cn = ((x & 0xf8) << 1) + ((x & 0xf8) >> 1) + ((y & 0xf8) >> 3); break;
case 2: cn = ((x & 0xf8) << 1) + ((x & 0xf8) << 0) + ((y & 0xf8) >> 3); break;
case 3: cn = ((y & 0x80) << 2) + ((x & 0x80) << 1) + ((y & 0x78) << 1) + ((x & 0x78) >> 3); break;
}
unsigned bpp = 2 << (regs.scmr.md - (regs.scmr.md >> 1)); // = [regs.scmr.md]{ 2, 4, 4, 8 };
unsigned addr = 0x700000 + (cn * (bpp << 3)) + (regs.scbr << 10) + ((y & 0x07) * 2);
for(unsigned n = 0; n < bpp; n++) {
unsigned byte = ((n >> 1) << 4) + (n & 1); // = [n]{ 0, 1, 16, 17, 32, 33, 48, 49 };
uint8_t data = 0x00;
for(unsigned x = 0; x < 8; x++) data |= ((cache.data[x] >> n) & 1) << x;
if(cache.bitpend != 0xff) {
add_clocks(memory_access_speed);
data &= cache.bitpend;
data |= superfxbus.read(addr + byte) & ~cache.bitpend;
}
add_clocks(memory_access_speed);
superfxbus.write(addr + byte, data);
}
cache.bitpend = 0x00;
}
#endif

View File

@ -0,0 +1,93 @@
#include "registers.hpp"
void exec_opcode();
uint8_t color(uint8_t source);
void plot(uint8_t x, uint8_t y);
uint8_t rpix(uint8_t x, uint8_t y);
void pixelcache_flush(pixelcache_t &cache);
void (SuperFX::*opcode_table[1024])();
void initialize_opcode_table();
//opcodes.cpp
template<int> void op_adc_i();
template<int> void op_adc_r();
template<int> void op_add_i();
template<int> void op_add_r();
void op_alt1();
void op_alt2();
void op_alt3();
template<int> void op_and_i();
template<int> void op_and_r();
void op_asr();
void op_bge();
void op_bcc();
void op_bcs();
void op_beq();
template<int> void op_bic_i();
template<int> void op_bic_r();
void op_blt();
void op_bmi();
void op_bne();
void op_bpl();
void op_bra();
void op_bvc();
void op_bvs();
void op_cache();
void op_cmode();
template<int> void op_cmp_r();
void op_color();
template<int> void op_dec_r();
void op_div2();
void op_fmult();
template<int> void op_from_r();
void op_getb();
void op_getbl();
void op_getbh();
void op_getbs();
void op_getc();
void op_hib();
template<int> void op_ibt_r();
template<int> void op_inc_r();
template<int> void op_iwt_r();
template<int> void op_jmp_r();
template<int> void op_ldb_ir();
template<int> void op_ldw_ir();
template<int> void op_link();
template<int> void op_ljmp_r();
template<int> void op_lm_r();
template<int> void op_lms_r();
void op_lmult();
void op_lob();
void op_loop();
void op_lsr();
void op_merge();
template<int> void op_mult_i();
template<int> void op_mult_r();
void op_nop();
void op_not();
template<int> void op_or_i();
template<int> void op_or_r();
void op_plot();
void op_ramb();
void op_rol();
void op_romb();
void op_ror();
void op_rpix();
template<int> void op_sbc_r();
void op_sbk();
void op_sex();
template<int> void op_sm_r();
template<int> void op_sms_r();
template<int> void op_stb_ir();
void op_stop();
template<int> void op_stw_ir();
template<int> void op_sub_i();
template<int> void op_sub_r();
void op_swap();
template<int> void op_to_r();
template<int> void op_umult_i();
template<int> void op_umult_r();
template<int> void op_with_r();
template<int> void op_xor_i();
template<int> void op_xor_r();

View File

@ -0,0 +1,270 @@
#ifdef SUPERFX_CPP
void SuperFX::initialize_opcode_table() {
#define op4(id, name) \
op(id+ 0, name< 1>) op(id+ 1, name< 2>) op(id+ 2, name< 3>) op(id+ 3, name< 4>)
#define op6(id, name) \
op(id+ 0, name< 8>) op(id+ 1, name< 9>) op(id+ 2, name<10>) op(id+ 3, name<11>) \
op(id+ 4, name<12>) op(id+ 5, name<13>)
#define op12(id, name) \
op(id+ 0, name< 0>) op(id+ 1, name< 1>) op(id+ 2, name< 2>) op(id+ 3, name< 3>) \
op(id+ 4, name< 4>) op(id+ 5, name< 5>) op(id+ 6, name< 6>) op(id+ 7, name< 7>) \
op(id+ 8, name< 8>) op(id+ 9, name< 9>) op(id+10, name<10>) op(id+11, name<11>)
#define op15l(id, name) \
op(id+ 0, name< 0>) op(id+ 1, name< 1>) op(id+ 2, name< 2>) op(id+ 3, name< 3>) \
op(id+ 4, name< 4>) op(id+ 5, name< 5>) op(id+ 6, name< 6>) op(id+ 7, name< 7>) \
op(id+ 8, name< 8>) op(id+ 9, name< 9>) op(id+10, name<10>) op(id+11, name<11>) \
op(id+12, name<12>) op(id+13, name<13>) op(id+14, name<14>)
#define op15h(id, name) \
op(id+ 0, name< 1>) op(id+ 1, name< 2>) op(id+ 2, name< 3>) op(id+ 3, name< 4>) \
op(id+ 4, name< 5>) op(id+ 5, name< 6>) op(id+ 6, name< 7>) op(id+ 7, name< 8>) \
op(id+ 8, name< 9>) op(id+ 9, name<10>) op(id+10, name<11>) op(id+11, name<12>) \
op(id+12, name<13>) op(id+13, name<14>) op(id+14, name<15>)
#define op16(id, name) \
op(id+ 0, name< 0>) op(id+ 1, name< 1>) op(id+ 2, name< 2>) op(id+ 3, name< 3>) \
op(id+ 4, name< 4>) op(id+ 5, name< 5>) op(id+ 6, name< 6>) op(id+ 7, name< 7>) \
op(id+ 8, name< 8>) op(id+ 9, name< 9>) op(id+10, name<10>) op(id+11, name<11>) \
op(id+12, name<12>) op(id+13, name<13>) op(id+14, name<14>) op(id+15, name<15>)
//======
// ALT0
//======
#define op(id, name) opcode_table[ 0 + id] = &SuperFX::op_##name;
op (0x00, stop)
op (0x01, nop)
op (0x02, cache)
op (0x03, lsr)
op (0x04, rol)
op (0x05, bra)
op (0x06, blt)
op (0x07, bge)
op (0x08, bne)
op (0x09, beq)
op (0x0a, bpl)
op (0x0b, bmi)
op (0x0c, bcc)
op (0x0d, bcs)
op (0x0e, bvc)
op (0x0f, bvs)
op16 (0x10, to_r)
op16 (0x20, with_r)
op12 (0x30, stw_ir)
op (0x3c, loop)
op (0x3d, alt1)
op (0x3e, alt2)
op (0x3f, alt3)
op12 (0x40, ldw_ir)
op (0x4c, plot)
op (0x4d, swap)
op (0x4e, color)
op (0x4f, not)
op16 (0x50, add_r)
op16 (0x60, sub_r)
op (0x70, merge)
op15h(0x71, and_r)
op16 (0x80, mult_r)
op (0x90, sbk)
op4 (0x91, link)
op (0x95, sex)
op (0x96, asr)
op (0x97, ror)
op6 (0x98, jmp_r)
op (0x9e, lob)
op (0x9f, fmult)
op16 (0xa0, ibt_r)
op16 (0xb0, from_r)
op (0xc0, hib)
op15h(0xc1, or_r)
op15l(0xd0, inc_r)
op (0xdf, getc)
op15l(0xe0, dec_r)
op (0xef, getb)
op16 (0xf0, iwt_r)
#undef op
//======
// ALT1
//======
#define op(id, name) opcode_table[256 + id] = &SuperFX::op_##name;
op (0x00, stop)
op (0x01, nop)
op (0x02, cache)
op (0x03, lsr)
op (0x04, rol)
op (0x05, bra)
op (0x06, blt)
op (0x07, bge)
op (0x08, bne)
op (0x09, beq)
op (0x0a, bpl)
op (0x0b, bmi)
op (0x0c, bcc)
op (0x0d, bcs)
op (0x0e, bvc)
op (0x0f, bvs)
op16 (0x10, to_r)
op16 (0x20, with_r)
op12 (0x30, stb_ir)
op (0x3c, loop)
op (0x3d, alt1)
op (0x3e, alt2)
op (0x3f, alt3)
op12 (0x40, ldb_ir)
op (0x4c, rpix)
op (0x4d, swap)
op (0x4e, cmode)
op (0x4f, not)
op16 (0x50, adc_r)
op16 (0x60, sbc_r)
op (0x70, merge)
op15h(0x71, bic_r)
op16 (0x80, umult_r)
op (0x90, sbk)
op4 (0x91, link)
op (0x95, sex)
op (0x96, div2)
op (0x97, ror)
op6 (0x98, ljmp_r)
op (0x9e, lob)
op (0x9f, lmult)
op16 (0xa0, lms_r)
op16 (0xb0, from_r)
op (0xc0, hib)
op15h(0xc1, xor_r)
op15l(0xd0, inc_r)
op (0xdf, getc)
op15l(0xe0, dec_r)
op (0xef, getbh)
op16 (0xf0, lm_r)
#undef op
//======
// ALT2
//======
#define op(id, name) opcode_table[512 + id] = &SuperFX::op_##name;
op (0x00, stop)
op (0x01, nop)
op (0x02, cache)
op (0x03, lsr)
op (0x04, rol)
op (0x05, bra)
op (0x06, blt)
op (0x07, bge)
op (0x08, bne)
op (0x09, beq)
op (0x0a, bpl)
op (0x0b, bmi)
op (0x0c, bcc)
op (0x0d, bcs)
op (0x0e, bvc)
op (0x0f, bvs)
op16 (0x10, to_r)
op16 (0x20, with_r)
op12 (0x30, stw_ir)
op (0x3c, loop)
op (0x3d, alt1)
op (0x3e, alt2)
op (0x3f, alt3)
op12 (0x40, ldw_ir)
op (0x4c, plot)
op (0x4d, swap)
op (0x4e, color)
op (0x4f, not)
op16 (0x50, add_i)
op16 (0x60, sub_i)
op (0x70, merge)
op15h(0x71, and_i)
op16 (0x80, mult_i)
op (0x90, sbk)
op4 (0x91, link)
op (0x95, sex)
op (0x96, asr)
op (0x97, ror)
op6 (0x98, jmp_r)
op (0x9e, lob)
op (0x9f, fmult)
op16 (0xa0, sms_r)
op16 (0xb0, from_r)
op (0xc0, hib)
op15h(0xc1, or_i)
op15l(0xd0, inc_r)
op (0xdf, ramb)
op15l(0xe0, dec_r)
op (0xef, getbl)
op16 (0xf0, sm_r)
#undef op
//======
// ALT3
//======
#define op(id, name) opcode_table[768 + id] = &SuperFX::op_##name;
op (0x00, stop)
op (0x01, nop)
op (0x02, cache)
op (0x03, lsr)
op (0x04, rol)
op (0x05, bra)
op (0x06, blt)
op (0x07, bge)
op (0x08, bne)
op (0x09, beq)
op (0x0a, bpl)
op (0x0b, bmi)
op (0x0c, bcc)
op (0x0d, bcs)
op (0x0e, bvc)
op (0x0f, bvs)
op16 (0x10, to_r)
op16 (0x20, with_r)
op12 (0x30, stb_ir)
op (0x3c, loop)
op (0x3d, alt1)
op (0x3e, alt2)
op (0x3f, alt3)
op12 (0x40, ldb_ir)
op (0x4c, rpix)
op (0x4d, swap)
op (0x4e, cmode)
op (0x4f, not)
op16 (0x50, adc_i)
op16 (0x60, cmp_r)
op (0x70, merge)
op15h(0x71, bic_i)
op16 (0x80, umult_i)
op (0x90, sbk)
op4 (0x91, link)
op (0x95, sex)
op (0x96, div2)
op (0x97, ror)
op6 (0x98, ljmp_r)
op (0x9e, lob)
op (0x9f, lmult)
op16 (0xa0, lms_r)
op16 (0xb0, from_r)
op (0xc0, hib)
op15h(0xc1, xor_i)
op15l(0xd0, inc_r)
op (0xdf, romb)
op15l(0xe0, dec_r)
op (0xef, getbs)
op16 (0xf0, lm_r)
#undef op
#undef op4
#undef op6
#undef op12
#undef op15l
#undef op15h
#undef op16
}
#endif

View File

@ -0,0 +1,661 @@
#ifdef SUPERFX_CPP
//$00 stop
void SuperFX::op_stop() {
if(regs.cfgr.irq == 0) {
regs.sfr.irq = 1;
cpu.regs.irq = 1;
}
regs.sfr.g = 0;
regs.pipeline = 0x01;
regs.reset();
}
//$01 nop
void SuperFX::op_nop() {
regs.reset();
}
//$02 cache
void SuperFX::op_cache() {
if(regs.cbr != (regs.r[15] & 0xfff0)) {
regs.cbr = regs.r[15] & 0xfff0;
cache_flush();
}
regs.reset();
}
//$03 lsr
void SuperFX::op_lsr() {
regs.sfr.cy = (regs.sr() & 1);
regs.dr() = regs.sr() >> 1;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$04 rol
void SuperFX::op_rol() {
bool carry = (regs.sr() & 0x8000);
regs.dr() = (regs.sr() << 1) | regs.sfr.cy;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.cy = carry;
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$05 bra e
void SuperFX::op_bra() {
regs.r[15] += (int8_t)pipe();
}
//$06 blt e
void SuperFX::op_blt() {
int e = (int8_t)pipe();
if((regs.sfr.s ^ regs.sfr.ov) == 0) regs.r[15] += e;
}
//$07 bge e
void SuperFX::op_bge() {
int e = (int8_t)pipe();
if((regs.sfr.s ^ regs.sfr.ov) == 1) regs.r[15] += e;
}
//$08 bne e
void SuperFX::op_bne() {
int e = (int8_t)pipe();
if(regs.sfr.z == 0) regs.r[15] += e;
}
//$09 beq e
void SuperFX::op_beq() {
int e = (int8_t)pipe();
if(regs.sfr.z == 1) regs.r[15] += e;
}
//$0a bpl e
void SuperFX::op_bpl() {
int e = (int8_t)pipe();
if(regs.sfr.s == 0) regs.r[15] += e;
}
//$0b bmi e
void SuperFX::op_bmi() {
int e = (int8_t)pipe();
if(regs.sfr.s == 1) regs.r[15] += e;
}
//$0c bcc e
void SuperFX::op_bcc() {
int e = (int8_t)pipe();
if(regs.sfr.cy == 0) regs.r[15] += e;
}
//$0d bcs e
void SuperFX::op_bcs() {
int e = (int8_t)pipe();
if(regs.sfr.cy == 1) regs.r[15] += e;
}
//$0e bvc e
void SuperFX::op_bvc() {
int e = (int8_t)pipe();
if(regs.sfr.ov == 0) regs.r[15] += e;
}
//$0f bvs e
void SuperFX::op_bvs() {
int e = (int8_t)pipe();
if(regs.sfr.ov == 1) regs.r[15] += e;
}
//$10-1f(b0): to rN
//$10-1f(b1): move rN
template<int n> void SuperFX::op_to_r() {
if(regs.sfr.b == 0) {
regs.dreg = &regs.r[n];
} else {
regs.r[n] = regs.sr();
regs.reset();
}
}
//$20-2f: with rN
template<int n> void SuperFX::op_with_r() {
regs.sreg = &regs.r[n];
regs.dreg = &regs.r[n];
regs.sfr.b = 1;
}
//$30-3b(alt0): stw (rN)
template<int n> void SuperFX::op_stw_ir() {
regs.ramaddr = regs.r[n];
rambuffer_write(regs.ramaddr ^ 0, regs.sr() >> 0);
rambuffer_write(regs.ramaddr ^ 1, regs.sr() >> 8);
regs.reset();
}
//$30-3b(alt1): stb (rN)
template<int n> void SuperFX::op_stb_ir() {
regs.ramaddr = regs.r[n];
rambuffer_write(regs.ramaddr, regs.sr());
regs.reset();
}
//$3c loop
void SuperFX::op_loop() {
regs.r[12]--;
regs.sfr.s = (regs.r[12] & 0x8000);
regs.sfr.z = (regs.r[12] == 0);
if(!regs.sfr.z) regs.r[15] = regs.r[13];
regs.reset();
}
//$3d alt1
void SuperFX::op_alt1() {
regs.sfr.b = 0;
regs.sfr.alt1 = 1;
}
//$3e alt2
void SuperFX::op_alt2() {
regs.sfr.b = 0;
regs.sfr.alt2 = 1;
}
//$3f alt3
void SuperFX::op_alt3() {
regs.sfr.b = 0;
regs.sfr.alt1 = 1;
regs.sfr.alt2 = 1;
}
//$40-4b(alt0): ldw (rN)
template<int n> void SuperFX::op_ldw_ir() {
regs.ramaddr = regs.r[n];
uint16_t data;
data = rambuffer_read(regs.ramaddr ^ 0) << 0;
data |= rambuffer_read(regs.ramaddr ^ 1) << 8;
regs.dr() = data;
regs.reset();
}
//$40-4b(alt1): ldb (rN)
template<int n> void SuperFX::op_ldb_ir() {
regs.ramaddr = regs.r[n];
regs.dr() = rambuffer_read(regs.ramaddr);
regs.reset();
}
//$4c(alt0): plot
void SuperFX::op_plot() {
plot(regs.r[1], regs.r[2]);
regs.r[1]++;
regs.reset();
}
//$4c(alt1): rpix
void SuperFX::op_rpix() {
regs.dr() = rpix(regs.r[1], regs.r[2]);
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$4d: swap
void SuperFX::op_swap() {
regs.dr() = (regs.sr() >> 8) | (regs.sr() << 8);
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$4e(alt0): color
void SuperFX::op_color() {
regs.colr = color(regs.sr());
regs.reset();
}
//$4e(alt1): cmode
void SuperFX::op_cmode() {
regs.por = regs.sr();
regs.reset();
}
//$4f: not
void SuperFX::op_not() {
regs.dr() = ~regs.sr();
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$50-5f(alt0): add rN
template<int n> void SuperFX::op_add_r() {
int r = regs.sr() + regs.r[n];
regs.sfr.ov = ~(regs.sr() ^ regs.r[n]) & (regs.r[n] ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0x10000);
regs.sfr.z = ((uint16_t)r == 0);
regs.dr() = r;
regs.reset();
}
//$50-5f(alt1): adc rN
template<int n> void SuperFX::op_adc_r() {
int r = regs.sr() + regs.r[n] + regs.sfr.cy;
regs.sfr.ov = ~(regs.sr() ^ regs.r[n]) & (regs.r[n] ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0x10000);
regs.sfr.z = ((uint16_t)r == 0);
regs.dr() = r;
regs.reset();
}
//$50-5f(alt2): add #N
template<int n> void SuperFX::op_add_i() {
int r = regs.sr() + n;
regs.sfr.ov = ~(regs.sr() ^ n) & (n ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0x10000);
regs.sfr.z = ((uint16_t)r == 0);
regs.dr() = r;
regs.reset();
}
//$50-5f(alt3): adc #N
template<int n> void SuperFX::op_adc_i() {
int r = regs.sr() + n + regs.sfr.cy;
regs.sfr.ov = ~(regs.sr() ^ n) & (n ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0x10000);
regs.sfr.z = ((uint16_t)r == 0);
regs.dr() = r;
regs.reset();
}
//$60-6f(alt0): sub rN
template<int n> void SuperFX::op_sub_r() {
int r = regs.sr() - regs.r[n];
regs.sfr.ov = (regs.sr() ^ regs.r[n]) & (regs.sr() ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0);
regs.sfr.z = ((uint16_t)r == 0);
regs.dr() = r;
regs.reset();
}
//$60-6f(alt1): sbc rN
template<int n> void SuperFX::op_sbc_r() {
int r = regs.sr() - regs.r[n] - !regs.sfr.cy;
regs.sfr.ov = (regs.sr() ^ regs.r[n]) & (regs.sr() ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0);
regs.sfr.z = ((uint16_t)r == 0);
regs.dr() = r;
regs.reset();
}
//$60-6f(alt2): sub #N
template<int n> void SuperFX::op_sub_i() {
int r = regs.sr() - n;
regs.sfr.ov = (regs.sr() ^ n) & (regs.sr() ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0);
regs.sfr.z = ((uint16_t)r == 0);
regs.dr() = r;
regs.reset();
}
//$60-6f(alt3): cmp rN
template<int n> void SuperFX::op_cmp_r() {
int r = regs.sr() - regs.r[n];
regs.sfr.ov = (regs.sr() ^ regs.r[n]) & (regs.sr() ^ r) & 0x8000;
regs.sfr.s = (r & 0x8000);
regs.sfr.cy = (r >= 0);
regs.sfr.z = ((uint16_t)r == 0);
regs.reset();
}
//$70: merge
void SuperFX::op_merge() {
regs.dr() = (regs.r[7] & 0xff00) | (regs.r[8] >> 8);
regs.sfr.ov = (regs.dr() & 0xc0c0);
regs.sfr.s = (regs.dr() & 0x8080);
regs.sfr.cy = (regs.dr() & 0xe0e0);
regs.sfr.z = (regs.dr() & 0xf0f0);
regs.reset();
}
//$71-7f(alt0): and rN
template<int n> void SuperFX::op_and_r() {
regs.dr() = regs.sr() & regs.r[n];
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$71-7f(alt1): bic rN
template<int n> void SuperFX::op_bic_r() {
regs.dr() = regs.sr() & ~regs.r[n];
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$71-7f(alt2): and #N
template<int n> void SuperFX::op_and_i() {
regs.dr() = regs.sr() & n;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$71-7f(alt3): bic #N
template<int n> void SuperFX::op_bic_i() {
regs.dr() = regs.sr() & ~n;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$80-8f(alt0): mult rN
template<int n> void SuperFX::op_mult_r() {
regs.dr() = (int8_t)regs.sr() * (int8_t)regs.r[n];
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
if(!regs.cfgr.ms0) add_clocks(2);
}
//$80-8f(alt1): umult rN
template<int n> void SuperFX::op_umult_r() {
regs.dr() = (uint8_t)regs.sr() * (uint8_t)regs.r[n];
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
if(!regs.cfgr.ms0) add_clocks(2);
}
//$80-8f(alt2): mult #N
template<int n> void SuperFX::op_mult_i() {
regs.dr() = (int8_t)regs.sr() * (int8_t)n;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
if(!regs.cfgr.ms0) add_clocks(2);
}
//$80-8f(alt3): umult #N
template<int n> void SuperFX::op_umult_i() {
regs.dr() = (uint8_t)regs.sr() * (uint8_t)n;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
if(!regs.cfgr.ms0) add_clocks(2);
}
//$90: sbk
void SuperFX::op_sbk() {
rambuffer_write(regs.ramaddr ^ 0, regs.sr() >> 0);
rambuffer_write(regs.ramaddr ^ 1, regs.sr() >> 8);
regs.reset();
}
//$91-94: link #N
template<int n> void SuperFX::op_link() {
regs.r[11] = regs.r[15] + n;
regs.reset();
}
//$95: sex
void SuperFX::op_sex() {
regs.dr() = (int8_t)regs.sr();
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$96(alt0): asr
void SuperFX::op_asr() {
regs.sfr.cy = (regs.sr() & 1);
regs.dr() = (int16_t)regs.sr() >> 1;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$96(alt1): div2
void SuperFX::op_div2() {
regs.sfr.cy = (regs.sr() & 1);
regs.dr() = ((int16_t)regs.sr() >> 1) + ((regs.sr() + 1) >> 16);
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$97: ror
void SuperFX::op_ror() {
bool carry = (regs.sr() & 1);
regs.dr() = (regs.sfr.cy << 15) | (regs.sr() >> 1);
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.cy = carry;
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$98-9d(alt0): jmp rN
template<int n> void SuperFX::op_jmp_r() {
regs.r[15] = regs.r[n];
regs.reset();
}
//$98-9d(alt1): ljmp rN
template<int n> void SuperFX::op_ljmp_r() {
regs.pbr = regs.r[n];
regs.r[15] = regs.sr();
regs.cbr = regs.r[15] & 0xfff0;
cache_flush();
regs.reset();
}
//$9e: lob
void SuperFX::op_lob() {
regs.dr() = regs.sr() & 0xff;
regs.sfr.s = (regs.dr() & 0x80);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$9f(alt0): fmult
void SuperFX::op_fmult() {
uint32_t result = (int16_t)regs.sr() * (int16_t)regs.r[6];
regs.dr() = result >> 16;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.cy = (result & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
add_clocks(4 + (regs.cfgr.ms0 << 2));
}
//$9f(alt1): lmult
void SuperFX::op_lmult() {
uint32_t result = (int16_t)regs.sr() * (int16_t)regs.r[6];
regs.r[4] = result;
regs.dr() = result >> 16;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.cy = (result & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
add_clocks(4 + (regs.cfgr.ms0 << 2));
}
//$a0-af(alt0): ibt rN,#pp
template<int n> void SuperFX::op_ibt_r() {
regs.r[n] = (int8_t)pipe();
regs.reset();
}
//$a0-af(alt1): lms rN,(yy)
template<int n> void SuperFX::op_lms_r() {
regs.ramaddr = pipe() << 1;
uint16_t data;
data = rambuffer_read(regs.ramaddr ^ 0) << 0;
data |= rambuffer_read(regs.ramaddr ^ 1) << 8;
regs.r[n] = data;
regs.reset();
}
//$a0-af(alt2): sms (yy),rN
template<int n> void SuperFX::op_sms_r() {
regs.ramaddr = pipe() << 1;
rambuffer_write(regs.ramaddr ^ 0, regs.r[n] >> 0);
rambuffer_write(regs.ramaddr ^ 1, regs.r[n] >> 8);
regs.reset();
}
//$b0-bf(b0): from rN
//$b0-bf(b1): moves rN
template<int n> void SuperFX::op_from_r() {
if(regs.sfr.b == 0) {
regs.sreg = &regs.r[n];
} else {
regs.dr() = regs.r[n];
regs.sfr.ov = (regs.dr() & 0x80);
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
}
//$c0: hib
void SuperFX::op_hib() {
regs.dr() = regs.sr() >> 8;
regs.sfr.s = (regs.dr() & 0x80);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$c1-cf(alt0): or rN
template<int n> void SuperFX::op_or_r() {
regs.dr() = regs.sr() | regs.r[n];
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$c1-cf(alt1): xor rN
template<int n> void SuperFX::op_xor_r() {
regs.dr() = regs.sr() ^ regs.r[n];
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$c1-cf(alt2): or #N
template<int n> void SuperFX::op_or_i() {
regs.dr() = regs.sr() | n;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$c1-cf(alt3): xor #N
template<int n> void SuperFX::op_xor_i() {
regs.dr() = regs.sr() ^ n;
regs.sfr.s = (regs.dr() & 0x8000);
regs.sfr.z = (regs.dr() == 0);
regs.reset();
}
//$d0-de: inc rN
template<int n> void SuperFX::op_inc_r() {
regs.r[n]++;
regs.sfr.s = (regs.r[n] & 0x8000);
regs.sfr.z = (regs.r[n] == 0);
regs.reset();
}
//$df(alt0): getc
void SuperFX::op_getc() {
regs.colr = color(rombuffer_read());
regs.reset();
}
//$df(alt2): ramb
void SuperFX::op_ramb() {
rambuffer_sync();
regs.rambr = regs.sr();
regs.reset();
}
//$df(alt3): romb
void SuperFX::op_romb() {
rombuffer_sync();
regs.rombr = regs.sr();
regs.reset();
}
//$e0-ee: dec rN
template<int n> void SuperFX::op_dec_r() {
regs.r[n]--;
regs.sfr.s = (regs.r[n] & 0x8000);
regs.sfr.z = (regs.r[n] == 0);
regs.reset();
}
//$ef(alt0): getb
void SuperFX::op_getb() {
regs.dr() = rombuffer_read();
regs.reset();
}
//$ef(alt1): getbh
void SuperFX::op_getbh() {
regs.dr() = (rombuffer_read() << 8) | (regs.sr() & 0x00ff);
regs.reset();
}
//$ef(alt2): getbl
void SuperFX::op_getbl() {
regs.dr() = (regs.sr() & 0xff00) | (rombuffer_read() << 0);
regs.reset();
}
//$ef(alt3): getbs
void SuperFX::op_getbs() {
regs.dr() = (int8_t)rombuffer_read();
regs.reset();
}
//$f0-ff(alt0): iwt rN,#xx
template<int n> void SuperFX::op_iwt_r() {
uint16_t data;
data = pipe() << 0;
data |= pipe() << 8;
regs.r[n] = data;
regs.reset();
}
//$f0-ff(alt1): lm rN,(xx)
template<int n> void SuperFX::op_lm_r() {
regs.ramaddr = pipe() << 0;
regs.ramaddr |= pipe() << 8;
uint16_t data;
data = rambuffer_read(regs.ramaddr ^ 0) << 0;
data |= rambuffer_read(regs.ramaddr ^ 1) << 8;
regs.r[n] = data;
regs.reset();
}
//$f0-ff(alt2): sm (xx),rN
template<int n> void SuperFX::op_sm_r() {
regs.ramaddr = pipe() << 0;
regs.ramaddr |= pipe() << 8;
rambuffer_write(regs.ramaddr ^ 0, regs.r[n] >> 0);
rambuffer_write(regs.ramaddr ^ 1, regs.r[n] >> 8);
regs.reset();
}
#endif

View File

@ -0,0 +1,177 @@
//accepts a callback binding so r14 writes can trigger ROM buffering transparently
struct reg16_t : noncopyable {
uint16_t data;
function<void (uint16_t)> on_modify;
inline operator unsigned() const { return data; }
inline uint16_t assign(uint16_t i) {
if(on_modify) on_modify(i);
else data = i;
return data;
}
inline unsigned operator++() { return assign(data + 1); }
inline unsigned operator--() { return assign(data - 1); }
inline unsigned operator++(int) { unsigned r = data; assign(data + 1); return r; }
inline unsigned operator--(int) { unsigned r = data; assign(data - 1); return r; }
inline unsigned operator = (unsigned i) { return assign(i); }
inline unsigned operator |= (unsigned i) { return assign(data | i); }
inline unsigned operator ^= (unsigned i) { return assign(data ^ i); }
inline unsigned operator &= (unsigned i) { return assign(data & i); }
inline unsigned operator <<= (unsigned i) { return assign(data << i); }
inline unsigned operator >>= (unsigned i) { return assign(data >> i); }
inline unsigned operator += (unsigned i) { return assign(data + i); }
inline unsigned operator -= (unsigned i) { return assign(data - i); }
inline unsigned operator *= (unsigned i) { return assign(data * i); }
inline unsigned operator /= (unsigned i) { return assign(data / i); }
inline unsigned operator %= (unsigned i) { return assign(data % i); }
inline unsigned operator = (const reg16_t& i) { return assign(i); }
reg16_t() : data(0) {}
};
struct sfr_t {
bool irq; //interrupt flag
bool b; //WITH flag
bool ih; //immediate higher 8-bit flag
bool il; //immediate lower 8-bit flag
bool alt2; //ALT2 mode
bool alt1; //ALT2 instruction mode
bool r; //ROM r14 read flag
bool g; //GO flag
bool ov; //overflow flag
bool s; //sign flag
bool cy; //carry flag
bool z; //zero flag
operator uint16_t() const {
return (irq << 15) | (b << 12) | (ih << 11) | (il << 10) | (alt2 << 9) | (alt1 << 8)
| (r << 6) | (g << 5) | (ov << 4) | (s << 3) | (cy << 2) | (z << 1);
}
sfr_t& operator=(uint16_t data) {
irq = data & 0x8000;
b = data & 0x1000;
ih = data & 0x0800;
il = data & 0x0400;
alt2 = data & 0x0200;
alt1 = data & 0x0100;
r = data & 0x0040;
g = data & 0x0020;
ov = data & 0x0010;
s = data & 0x0008;
cy = data & 0x0004;
z = data & 0x0002;
return *this;
}
};
struct scmr_t {
unsigned ht;
bool ron;
bool ran;
unsigned md;
operator uint8_t() const {
return ((ht >> 1) << 5) | (ron << 4) | (ran << 3) | ((ht & 1) << 2) | (md);
}
scmr_t& operator=(uint8_t data) {
ht = (bool)(data & 0x20) << 1;
ht |= (bool)(data & 0x04) << 0;
ron = data & 0x10;
ran = data & 0x08;
md = data & 0x03;
return *this;
}
};
struct por_t {
bool obj;
bool freezehigh;
bool highnibble;
bool dither;
bool transparent;
operator uint8_t() const {
return (obj << 4) | (freezehigh << 3) | (highnibble << 2) | (dither << 1) | (transparent);
}
por_t& operator=(uint8_t data) {
obj = data & 0x10;
freezehigh = data & 0x08;
highnibble = data & 0x04;
dither = data & 0x02;
transparent = data & 0x01;
return *this;
}
};
struct cfgr_t {
bool irq;
bool ms0;
operator uint8_t() const {
return (irq << 7) | (ms0 << 5);
}
cfgr_t& operator=(uint8_t data) {
irq = data & 0x80;
ms0 = data & 0x20;
return *this;
}
};
struct regs_t {
uint8_t pipeline;
uint16_t ramaddr;
reg16_t r[16]; //general purpose registers
sfr_t sfr; //status flag register
uint8_t pbr; //program bank register
uint8_t rombr; //game pack ROM bank register
bool rambr; //game pack RAM bank register
uint16_t cbr; //cache base register
uint8_t scbr; //screen base register
scmr_t scmr; //screen mode register
uint8_t colr; //color register
por_t por; //plot option register
bool bramr; //back-up RAM register
uint8_t vcr; //version code register
cfgr_t cfgr; //config register
bool clsr; //clock select register
unsigned romcl; //clock ticks until romdr is valid
uint8_t romdr; //ROM buffer data register
unsigned ramcl; //clock ticks until ramdr is valid
uint16_t ramar; //RAM buffer address register
uint8_t ramdr; //RAM buffer data register
reg16_t *sreg, *dreg;
reg16_t& sr() { return *sreg; } //source register (from)
reg16_t& dr() { return *dreg; } //destination register (to)
void reset() {
sfr.b = 0;
sfr.alt1 = 0;
sfr.alt2 = 0;
sreg = &r[0];
dreg = &r[0];
}
} regs;
struct cache_t {
uint8_t buffer[512];
bool valid[32];
} cache;
struct pixelcache_t {
uint16_t offset;
uint8_t bitpend;
uint8_t data[8];
} pixelcache[2];

View File

@ -0,0 +1,275 @@
void SuperFX::disassemble_opcode(char *output) {
*output = 0;
if(!regs.sfr.alt2) {
if(!regs.sfr.alt1) {
disassemble_alt0(output);
} else {
disassemble_alt1(output);
}
} else {
if(!regs.sfr.alt1) {
disassemble_alt2(output);
} else {
disassemble_alt3(output);
}
}
unsigned length = strlen(output);
while(length++ < 20) strcat(output, " ");
}
#define case4(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3
#define case6(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5
#define case12(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
case id+ 8: case id+ 9: case id+10: case id+11
#define case15(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
case id+ 8: case id+ 9: case id+10: case id+11: case id+12: case id+13: case id+14
#define case16(id) \
case id+ 0: case id+ 1: case id+ 2: case id+ 3: case id+ 4: case id+ 5: case id+ 6: case id+ 7: \
case id+ 8: case id+ 9: case id+10: case id+11: case id+12: case id+13: case id+14: case id+15
#define op0 regs.pipeline
#define op1 superfxbus.read((regs.pbr << 16) + regs.r[15] + 0)
#define op2 superfxbus.read((regs.pbr << 16) + regs.r[15] + 1)
void SuperFX::disassemble_alt0(char *output) {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
case (0x01): sprintf(t, "nop"); break;
case (0x02): sprintf(t, "cache"); break;
case (0x03): sprintf(t, "lsr"); break;
case (0x04): sprintf(t, "rol"); break;
case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break;
case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break;
case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break;
case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break;
case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break;
case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break;
case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break;
case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break;
case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break;
case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break;
case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break;
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
case12(0x30): sprintf(t, "stw (r%u)", op0 & 15); break;
case (0x3c): sprintf(t, "loop"); break;
case (0x3d): sprintf(t, "alt1"); break;
case (0x3e): sprintf(t, "alt2"); break;
case (0x3f): sprintf(t, "alt3"); break;
case12(0x40): sprintf(t, "ldw (r%u)", op0 & 15); break;
case (0x4c): sprintf(t, "plot"); break;
case (0x4d): sprintf(t, "swap"); break;
case (0x4e): sprintf(t, "color"); break;
case (0x4f): sprintf(t, "not"); break;
case16(0x50): sprintf(t, "add r%u", op0 & 15); break;
case16(0x60): sprintf(t, "sub r%u", op0 & 15); break;
case (0x70): sprintf(t, "merge"); break;
case15(0x71): sprintf(t, "and r%u", op0 & 15); break;
case16(0x80): sprintf(t, "mult r%u", op0 & 15); break;
case (0x90): sprintf(t, "sbk"); break;
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
case (0x95): sprintf(t, "sex"); break;
case (0x96): sprintf(t, "asr"); break;
case (0x97): sprintf(t, "ror"); break;
case6 (0x98): sprintf(t, "jmp r%u", op0 & 15); break;
case (0x9e): sprintf(t, "lob"); break;
case (0x9f): sprintf(t, "fmult"); break;
case16(0xa0): sprintf(t, "ibt r%u,#$%.2x", op0 & 15, op1); break;
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
case (0xc0): sprintf(t, "hib");
case15(0xc1): sprintf(t, "or r%u", op0 & 15); break;
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
case (0xdf): sprintf(t, "getc"); break;
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
case (0xef): sprintf(t, "getb"); break;
case16(0xf0): sprintf(t, "iwt r%u,#$%.2x%.2x", op0 & 15, op2, op1); break;
}
strcat(output, t);
}
void SuperFX::disassemble_alt1(char *output) {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
case (0x01): sprintf(t, "nop"); break;
case (0x02): sprintf(t, "cache"); break;
case (0x03): sprintf(t, "lsr"); break;
case (0x04): sprintf(t, "rol"); break;
case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break;
case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break;
case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break;
case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break;
case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break;
case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break;
case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break;
case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break;
case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break;
case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break;
case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break;
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
case12(0x30): sprintf(t, "stb (r%u)", op0 & 15); break;
case (0x3c): sprintf(t, "loop"); break;
case (0x3d): sprintf(t, "alt1"); break;
case (0x3e): sprintf(t, "alt2"); break;
case (0x3f): sprintf(t, "alt3"); break;
case12(0x40): sprintf(t, "ldb (r%u)", op0 & 15); break;
case (0x4c): sprintf(t, "rpix"); break;
case (0x4d): sprintf(t, "swap"); break;
case (0x4e): sprintf(t, "cmode"); break;
case (0x4f): sprintf(t, "not"); break;
case16(0x50): sprintf(t, "adc r%u", op0 & 15); break;
case16(0x60): sprintf(t, "sbc r%u", op0 & 15); break;
case (0x70): sprintf(t, "merge"); break;
case15(0x71): sprintf(t, "bic r%u", op0 & 15); break;
case16(0x80): sprintf(t, "umult r%u", op0 & 15); break;
case (0x90): sprintf(t, "sbk"); break;
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
case (0x95): sprintf(t, "sex"); break;
case (0x96): sprintf(t, "div2"); break;
case (0x97): sprintf(t, "ror"); break;
case6 (0x98): sprintf(t, "ljmp r%u", op0 & 15); break;
case (0x9e): sprintf(t, "lob"); break;
case (0x9f): sprintf(t, "lmult"); break;
case16(0xa0): sprintf(t, "lms r%u,(#$%.4x)", op0 & 15, op1 << 1); break;
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
case (0xc0): sprintf(t, "hib"); break;
case15(0xc1): sprintf(t, "xor r%u", op0 & 15); break;
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
case (0xdf): sprintf(t, "getc"); break;
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
case (0xef): sprintf(t, "getbh"); break;
case16(0xf0): sprintf(t, "lm r%u", op0 & 15); break;
}
strcat(output, t);
}
void SuperFX::disassemble_alt2(char *output) {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
case (0x01): sprintf(t, "nop"); break;
case (0x02): sprintf(t, "cache"); break;
case (0x03): sprintf(t, "lsr"); break;
case (0x04): sprintf(t, "rol"); break;
case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break;
case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break;
case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break;
case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break;
case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break;
case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break;
case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break;
case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break;
case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break;
case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break;
case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break;
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
case12(0x30): sprintf(t, "stw (r%u)", op0 & 15); break;
case (0x3c): sprintf(t, "loop"); break;
case (0x3d): sprintf(t, "alt1"); break;
case (0x3e): sprintf(t, "alt2"); break;
case (0x3f): sprintf(t, "alt3"); break;
case12(0x40): sprintf(t, "ldw (r%u)", op0 & 15); break;
case (0x4c): sprintf(t, "plot"); break;
case (0x4d): sprintf(t, "swap"); break;
case (0x4e): sprintf(t, "color"); break;
case (0x4f): sprintf(t, "not"); break;
case16(0x50): sprintf(t, "add #%u", op0 & 15); break;
case16(0x60): sprintf(t, "sub #%u", op0 & 15); break;
case (0x70): sprintf(t, "merge"); break;
case15(0x71): sprintf(t, "and #%u", op0 & 15); break;
case16(0x80): sprintf(t, "mult #%u", op0 & 15); break;
case (0x90): sprintf(t, "sbk"); break;
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
case (0x95): sprintf(t, "sex"); break;
case (0x96): sprintf(t, "asr"); break;
case (0x97): sprintf(t, "ror"); break;
case6 (0x98): sprintf(t, "jmp r%u", op0 & 15); break;
case (0x9e): sprintf(t, "lob"); break;
case (0x9f): sprintf(t, "fmult"); break;
case16(0xa0): sprintf(t, "sms r%u,(#$%.4x)", op0 & 15, op1 << 1); break;
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
case (0xc0): sprintf(t, "hib"); break;
case15(0xc1): sprintf(t, "or #%u", op0 & 15); break;
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
case (0xdf): sprintf(t, "ramb"); break;
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
case (0xef): sprintf(t, "getbl"); break;
case16(0xf0): sprintf(t, "sm r%u", op0 & 15); break;
}
strcat(output, t);
}
void SuperFX::disassemble_alt3(char *output) {
char t[256] = "";
switch(op0) {
case (0x00): sprintf(t, "stop"); break;
case (0x01): sprintf(t, "nop"); break;
case (0x02): sprintf(t, "cache"); break;
case (0x03): sprintf(t, "lsr"); break;
case (0x04): sprintf(t, "rol"); break;
case (0x05): sprintf(t, "bra %+d", (int8_t)op1); break;
case (0x06): sprintf(t, "blt %+d", (int8_t)op1); break;
case (0x07): sprintf(t, "bge %+d", (int8_t)op1); break;
case (0x08): sprintf(t, "bne %+d", (int8_t)op1); break;
case (0x09): sprintf(t, "beq %+d", (int8_t)op1); break;
case (0x0a): sprintf(t, "bpl %+d", (int8_t)op1); break;
case (0x0b): sprintf(t, "bmi %+d", (int8_t)op1); break;
case (0x0c): sprintf(t, "bcc %+d", (int8_t)op1); break;
case (0x0d): sprintf(t, "bcs %+d", (int8_t)op1); break;
case (0x0e): sprintf(t, "bvc %+d", (int8_t)op1); break;
case (0x0f): sprintf(t, "bvs %+d", (int8_t)op1); break;
case16(0x10): sprintf(t, "to r%u", op0 & 15); break;
case16(0x20): sprintf(t, "with r%u", op0 & 15); break;
case12(0x30): sprintf(t, "stb (r%u)", op0 & 15); break;
case (0x3c): sprintf(t, "loop"); break;
case (0x3d): sprintf(t, "alt1"); break;
case (0x3e): sprintf(t, "alt2"); break;
case (0x3f): sprintf(t, "alt3"); break;
case12(0x40): sprintf(t, "ldb (r%u)", op0 & 15); break;
case (0x4c): sprintf(t, "rpix"); break;
case (0x4d): sprintf(t, "swap"); break;
case (0x4e): sprintf(t, "cmode"); break;
case (0x4f): sprintf(t, "not"); break;
case16(0x50): sprintf(t, "adc #%u", op0 & 15); break;
case16(0x60): sprintf(t, "cmp r%u", op0 & 15); break;
case (0x70): sprintf(t, "merge"); break;
case15(0x71): sprintf(t, "bic #%u", op0 & 15); break;
case16(0x80): sprintf(t, "umult #%u", op0 & 15); break;
case (0x90): sprintf(t, "sbk"); break;
case4 (0x91): sprintf(t, "link #%u", op0 & 15); break;
case (0x95): sprintf(t, "sex"); break;
case (0x96): sprintf(t, "div2"); break;
case (0x97): sprintf(t, "ror"); break;
case6 (0x98): sprintf(t, "ljmp r%u", op0 & 15); break;
case (0x9e): sprintf(t, "lob"); break;
case (0x9f): sprintf(t, "lmult"); break;
case16(0xa0): sprintf(t, "lms r%u", op0 & 15); break;
case16(0xb0): sprintf(t, "from r%u", op0 & 15); break;
case (0xc0): sprintf(t, "hib"); break;
case15(0xc1): sprintf(t, "xor #%u", op0 & 15); break;
case15(0xd0): sprintf(t, "inc r%u", op0 & 15); break;
case (0xdf): sprintf(t, "romb"); break;
case15(0xe0): sprintf(t, "dec r%u", op0 & 15); break;
case (0xef): sprintf(t, "getbs"); break;
case16(0xf0): sprintf(t, "lm r%u", op0 & 15); break;
}
strcat(output, t);
}
#undef case4
#undef case6
#undef case12
#undef case15
#undef case16
#undef op0
#undef op1
#undef op2

View File

@ -0,0 +1,5 @@
void disassemble_opcode(char *output);
void disassemble_alt0(char *output);
void disassemble_alt1(char *output);
void disassemble_alt2(char *output);
void disassemble_alt3(char *output);

View File

@ -0,0 +1,67 @@
uint8_t SuperFX::op_read(uint16_t addr) {
uint16_t offset = addr - regs.cbr;
if(offset < 512) {
if(cache.valid[offset >> 4] == false) {
unsigned dp = offset & 0xfff0;
unsigned sp = (regs.pbr << 16) + ((regs.cbr + dp) & 0xfff0);
for(unsigned n = 0; n < 16; n++) {
add_clocks(memory_access_speed);
cache.buffer[dp++] = superfxbus.read(sp++);
}
cache.valid[offset >> 4] = true;
} else {
add_clocks(cache_access_speed);
}
return cache.buffer[offset];
}
if(regs.pbr <= 0x5f) {
//$[00-5f]:[0000-ffff] ROM
rombuffer_sync();
add_clocks(memory_access_speed);
return superfxbus.read((regs.pbr << 16) + addr);
} else {
//$[60-7f]:[0000-ffff] RAM
rambuffer_sync();
add_clocks(memory_access_speed);
return superfxbus.read((regs.pbr << 16) + addr);
}
}
uint8_t SuperFX::peekpipe() {
uint8_t result = regs.pipeline;
regs.pipeline = op_read(regs.r[15]);
r15_modified = false;
return result;
}
uint8_t SuperFX::pipe() {
uint8_t result = regs.pipeline;
regs.pipeline = op_read(++regs.r[15]);
r15_modified = false;
return result;
}
void SuperFX::cache_flush() {
for(unsigned n = 0; n < 32; n++) cache.valid[n] = false;
}
uint8_t SuperFX::cache_mmio_read(uint16_t addr) {
addr = (addr + regs.cbr) & 511;
return cache.buffer[addr];
}
void SuperFX::cache_mmio_write(uint16_t addr, uint8_t data) {
addr = (addr + regs.cbr) & 511;
cache.buffer[addr] = data;
if((addr & 15) == 15) cache.valid[addr >> 4] = true;
}
void SuperFX::memory_reset() {
for(unsigned n = 0; n < 512; n++) cache.buffer[n] = 0x00;
for(unsigned n = 0; n < 32; n++) cache.valid[n] = false;
for(unsigned n = 0; n < 2; n++) {
pixelcache[n].offset = ~0;
pixelcache[n].bitpend = 0x00;
}
}

View File

@ -0,0 +1,9 @@
uint8_t op_read(uint16_t addr);
alwaysinline uint8_t peekpipe();
alwaysinline uint8_t pipe();
void cache_flush();
uint8_t cache_mmio_read(uint16_t addr);
void cache_mmio_write(uint16_t addr, uint8_t data);
void memory_reset();

View File

@ -0,0 +1,118 @@
#ifdef SUPERFX_CPP
uint8_t SuperFX::mmio_read(unsigned addr) {
addr &= 0xffff;
if(addr >= 0x3100 && addr <= 0x32ff) {
return cache_mmio_read(addr - 0x3100);
}
if(addr >= 0x3000 && addr <= 0x301f) {
return regs.r[(addr >> 1) & 15] >> ((addr & 1) << 3);
}
switch(addr) {
case 0x3030: {
return regs.sfr >> 0;
}
case 0x3031: {
uint8_t r = regs.sfr >> 8;
regs.sfr.irq = 0;
cpu.regs.irq = 0;
return r;
}
case 0x3034: {
return regs.pbr;
}
case 0x3036: {
return regs.rombr;
}
case 0x303b: {
return regs.vcr;
}
case 0x303c: {
return regs.rambr;
}
case 0x303e: {
return regs.cbr >> 0;
}
case 0x303f: {
return regs.cbr >> 8;
}
}
return 0x00;
}
void SuperFX::mmio_write(unsigned addr, uint8_t data) {
addr &= 0xffff;
if(addr >= 0x3100 && addr <= 0x32ff) {
return cache_mmio_write(addr - 0x3100, data);
}
if(addr >= 0x3000 && addr <= 0x301f) {
unsigned n = (addr >> 1) & 15;
if((addr & 1) == 0) {
regs.r[n] = (regs.r[n] & 0xff00) | data;
} else {
regs.r[n] = (data << 8) | (regs.r[n] & 0xff);
}
if(addr == 0x301f) regs.sfr.g = 1;
return;
}
switch(addr) {
case 0x3030: {
bool g = regs.sfr.g;
regs.sfr = (regs.sfr & 0xff00) | (data << 0);
if(g == 1 && regs.sfr.g == 0) {
regs.cbr = 0x0000;
cache_flush();
}
} break;
case 0x3031: {
regs.sfr = (data << 8) | (regs.sfr & 0x00ff);
} break;
case 0x3033: {
regs.bramr = data;
} break;
case 0x3034: {
regs.pbr = data;
cache_flush();
} break;
case 0x3037: {
regs.cfgr = data;
if(regs.clsr) regs.cfgr.ms0 = 0; //cannot use high-speed multiplication in 21MHz mode
} break;
case 0x3038: {
regs.scbr = data;
} break;
case 0x3039: {
regs.clsr = data;
if(regs.clsr) regs.cfgr.ms0 = 0; //cannot use high-speed multiplication in 21MHz mode
cache_access_speed = (regs.clsr ? config.superfx.fast_cache_speed : config.superfx.slow_cache_speed );
memory_access_speed = (regs.clsr ? config.superfx.fast_memory_speed : config.superfx.slow_memory_speed);
} break;
case 0x303a: {
regs.scmr = data;
} break;
}
}
#endif

View File

@ -0,0 +1,2 @@
uint8_t mmio_read(unsigned addr);
void mmio_write(unsigned addr, uint8_t data);

View File

@ -0,0 +1,61 @@
#include <../base.hpp>
#define SUPERFX_CPP
namespace SNES {
#include "bus/bus.cpp"
#include "core/core.cpp"
#include "memory/memory.cpp"
#include "mmio/mmio.cpp"
#include "timing/timing.cpp"
#include "disasm/disasm.cpp"
SuperFX superfx;
void SuperFX::enter() {
while(true) {
while(regs.sfr.g == 0) add_clocks(2);
exec_opcode();
}
}
void SuperFX::init() {
initialize_opcode_table();
regs.r[14].on_modify = bind(&SuperFX::r14_modify, this);
regs.r[15].on_modify = bind(&SuperFX::r15_modify, this);
}
void SuperFX::enable() {
for(uint16_t i = 0x3000; i <= 0x32ff; i++) memory::mmio.map(i, *this);
}
void SuperFX::power() {
reset();
}
void SuperFX::reset() {
superfxbus.init();
for(unsigned n = 0; n < 16; n++) regs.r[n] = 0x0000;
regs.sfr = 0x0000;
regs.pbr = 0x00;
regs.rombr = 0x00;
regs.rambr = 0;
regs.cbr = 0x0000;
regs.scbr = 0x00;
regs.scmr = 0x00;
regs.colr = 0x00;
regs.por = 0x00;
regs.bramr = 0;
regs.vcr = 0x04;
regs.cfgr = 0x00;
regs.clsr = 0;
regs.pipeline = 0x01; //nop
regs.ramaddr = 0x0000;
regs.reset();
memory_reset();
timing_reset();
}
};

View File

@ -0,0 +1,20 @@
#include "bus/bus.hpp"
class SuperFX : public MMIO {
public:
#include "core/core.hpp"
#include "memory/memory.hpp"
#include "mmio/mmio.hpp"
#include "timing/timing.hpp"
#include "disasm/disasm.hpp"
void enter();
void init();
void enable();
void power();
void reset();
};
extern SuperFX superfx;
extern SuperFXBus superfxbus;

View File

@ -0,0 +1,72 @@
void SuperFX::add_clocks(unsigned clocks) {
if(regs.romcl) {
regs.romcl -= min(clocks, regs.romcl);
if(regs.romcl == 0) {
regs.sfr.r = 0;
regs.romdr = superfxbus.read((regs.rombr << 16) + regs.r[14]);
}
}
if(regs.ramcl) {
regs.ramcl -= min(clocks, regs.ramcl);
if(regs.ramcl == 0) {
superfxbus.write(0x700000 + (regs.rambr << 16) + regs.ramar, regs.ramdr);
}
}
scheduler.addclocks_cop(clocks);
scheduler.sync_copcpu();
}
void SuperFX::rombuffer_sync() {
if(regs.romcl) add_clocks(regs.romcl);
}
void SuperFX::rombuffer_update() {
regs.sfr.r = 1;
regs.romcl = memory_access_speed;
}
uint8_t SuperFX::rombuffer_read() {
rombuffer_sync();
return regs.romdr;
}
void SuperFX::rambuffer_sync() {
if(regs.ramcl) add_clocks(regs.ramcl);
}
uint8_t SuperFX::rambuffer_read(uint16_t addr) {
rambuffer_sync();
return superfxbus.read(0x700000 + (regs.rambr << 16) + addr);
}
void SuperFX::rambuffer_write(uint16_t addr, uint8_t data) {
rambuffer_sync();
regs.ramcl = memory_access_speed;
regs.ramar = addr;
regs.ramdr = data;
}
void SuperFX::r14_modify(uint16_t data) {
regs.r[14].data = data;
rombuffer_update();
}
void SuperFX::r15_modify(uint16_t data) {
regs.r[15].data = data;
r15_modified = true;
}
void SuperFX::timing_reset() {
cache_access_speed = config.superfx.slow_cache_speed;
memory_access_speed = config.superfx.slow_memory_speed;
r15_modified = false;
regs.romcl = 0;
regs.romdr = 0;
regs.ramcl = 0;
regs.ramar = 0;
regs.ramdr = 0;
}

View File

@ -0,0 +1,18 @@
unsigned cache_access_speed;
unsigned memory_access_speed;
bool r15_modified;
void add_clocks(unsigned clocks);
void rombuffer_sync();
void rombuffer_update();
uint8_t rombuffer_read();
void rambuffer_sync();
uint8_t rambuffer_read(uint16_t addr);
void rambuffer_write(uint16_t addr, uint8_t data);
void r14_modify(uint16_t);
void r15_modify(uint16_t);
void timing_reset();

View File

@ -48,4 +48,3 @@ CPUcore::CPUcore() {
} }
}; };

View File

@ -365,5 +365,5 @@ inline void CPUcore::op_tsb_w() {
regs.p.z = (rd.w & regs.a.w) == 0; regs.p.z = (rd.w & regs.a.w) == 0;
rd.w |= regs.a.w; rd.w |= regs.a.w;
} }
#endif
#endif

View File

@ -138,4 +138,3 @@ void CPUcore::update_table() {
} }
#endif #endif

View File

@ -15,5 +15,5 @@ CPU::CPU() {
CPU::~CPU() { CPU::~CPU() {
} }
};
};

View File

@ -270,4 +270,4 @@ void sCPU::dma_reset() {
} }
} }
#endif //ifdef SCPU_CPP #endif

View File

@ -2,29 +2,26 @@
void sCPU::op_io() { void sCPU::op_io() {
status.clock_count = 6; status.clock_count = 6;
precycle_edge();
add_clocks(6);
cycle_edge(); cycle_edge();
add_clocks(6);
} }
uint8 sCPU::op_read(uint32 addr) { uint8 sCPU::op_read(uint32 addr) {
status.clock_count = speed(addr); status.clock_count = speed(addr);
precycle_edge(); cycle_edge();
add_clocks(status.clock_count - 4); add_clocks(status.clock_count - 4);
scheduler.sync_cpucop(); scheduler.sync_cpucop();
regs.mdr = bus.read(addr); regs.mdr = bus.read(addr);
add_clocks(4); add_clocks(4);
cycle_edge();
return regs.mdr; return regs.mdr;
} }
void sCPU::op_write(uint32 addr, uint8 data) { void sCPU::op_write(uint32 addr, uint8 data) {
status.clock_count = speed(addr); status.clock_count = speed(addr);
precycle_edge(); cycle_edge();
add_clocks(status.clock_count); add_clocks(status.clock_count);
scheduler.sync_cpucop(); scheduler.sync_cpucop();
bus.write(addr, regs.mdr = data); bus.write(addr, regs.mdr = data);
cycle_edge();
} }
unsigned sCPU::speed(unsigned addr) const { unsigned sCPU::speed(unsigned addr) const {
@ -38,4 +35,3 @@ unsigned sCPU::speed(unsigned addr) const {
} }
#endif #endif

View File

@ -534,4 +534,4 @@ void sCPU::mmio_write(unsigned addr, uint8 data) {
} }
} }
#endif //ifdef SCPU_CPP #endif

View File

@ -96,5 +96,5 @@ sCPU::sCPU() {
sCPU::~sCPU() { sCPU::~sCPU() {
} }
};
};

View File

@ -9,8 +9,6 @@ public:
#include "mmio/mmio.hpp" #include "mmio/mmio.hpp"
#include "timing/timing.hpp" #include "timing/timing.hpp"
enum DmaState { DmaInactive, DmaRun, DmaCpuSync };
struct { struct {
bool interrupt_pending; bool interrupt_pending;
uint16 interrupt_vector; uint16 interrupt_vector;
@ -36,12 +34,12 @@ public:
bool irq_hold; bool irq_hold;
//DMA //DMA
bool dma_active;
unsigned dma_counter; unsigned dma_counter;
unsigned dma_clocks; unsigned dma_clocks;
bool dma_pending; bool dma_pending;
bool hdma_pending; bool hdma_pending;
bool hdma_mode; //0 = init, 1 = run bool hdma_mode; //0 = init, 1 = run
DmaState dma_state;
//MMIO //MMIO

View File

@ -52,14 +52,6 @@ void sCPU::scanline() {
} }
} }
//used for H/DMA bus synchronization
void sCPU::precycle_edge() {
if(status.dma_state == DmaCpuSync) {
add_clocks(status.clock_count - (status.dma_clocks % status.clock_count));
status.dma_state = DmaInactive;
}
}
//used to test for H/DMA, which can trigger on the edge of every opcode cycle. //used to test for H/DMA, which can trigger on the edge of every opcode cycle.
void sCPU::cycle_edge() { void sCPU::cycle_edge() {
while(cycle_edge_state) { while(cycle_edge_state) {
@ -91,30 +83,34 @@ void sCPU::cycle_edge() {
//.. Run one bus CPU cycle //.. Run one bus CPU cycle
//.. CPU sync //.. CPU sync
if(status.dma_state == DmaRun) { if(status.dma_active == true) {
if(status.hdma_pending) { if(status.hdma_pending) {
status.hdma_pending = false; status.hdma_pending = false;
if(hdma_enabled_channels()) { if(hdma_enabled_channels()) {
dma_add_clocks(8 - dma_counter()); //DMA sync dma_add_clocks(8 - dma_counter());
status.hdma_mode == 0 ? hdma_init() : hdma_run(); status.hdma_mode == 0 ? hdma_init() : hdma_run();
if(!dma_enabled_channels()) status.dma_state = DmaCpuSync; if(!dma_enabled_channels()) {
add_clocks(status.clock_count - (status.dma_clocks % status.clock_count));
status.dma_active = false;
}
} }
} }
if(status.dma_pending) { if(status.dma_pending) {
status.dma_pending = false; status.dma_pending = false;
if(dma_enabled_channels()) { if(dma_enabled_channels()) {
dma_add_clocks(8 - dma_counter()); //DMA sync dma_add_clocks(8 - dma_counter());
dma_run(); dma_run();
status.dma_state = DmaCpuSync; add_clocks(status.clock_count - (status.dma_clocks % status.clock_count));
status.dma_active = false;
} }
} }
} }
if(status.dma_state == DmaInactive) { if(status.dma_active == false) {
if(status.dma_pending || status.hdma_pending) { if(status.dma_pending || status.hdma_pending) {
status.dma_clocks = 0; status.dma_clocks = 0;
status.dma_state = DmaRun; status.dma_active = true;
} }
} }
} }
@ -159,12 +155,12 @@ void sCPU::timing_reset() {
status.irq_pending = false; status.irq_pending = false;
status.irq_hold = false; status.irq_hold = false;
status.dma_active = false;
status.dma_counter = 0; status.dma_counter = 0;
status.dma_clocks = 0; status.dma_clocks = 0;
status.dma_pending = false; status.dma_pending = false;
status.hdma_pending = false; status.hdma_pending = false;
status.hdma_mode = 0; status.hdma_mode = 0;
status.dma_state = DmaInactive;
cycle_edge_state = 0; cycle_edge_state = 0;
} }

View File

@ -18,9 +18,8 @@
void add_clocks(unsigned clocks); void add_clocks(unsigned clocks);
void scanline(); void scanline();
alwaysinline void precycle_edge();
alwaysinline void cycle_edge(); alwaysinline void cycle_edge();
void last_cycle(); alwaysinline void last_cycle();
void timing_power(); void timing_power();
void timing_reset(); void timing_reset();

View File

@ -5,15 +5,19 @@
<h1>bsnes&trade; Usage Documentation</h1><br> <h1>bsnes&trade; Usage Documentation</h1><br>
bsnes is a Super Nintendo / Super Famicom emulator that strives to provide bsnes is a Super Nintendo / Super Famicom emulator that strives to provide the
the most faithful emulation experience possible. It focuses on accuracy and most faithful hardware emulation possible. It focuses on accuracy and clean
clean code; over speed and features. code, rather than speed and special features. It is meant as a reference
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> <hr>
<h2><u>Modes of Operation</u></h2><br> <h2><u>Modes of Operation</u></h2><br>
bsnes is capable of running both in its default multi-user mode, as well as bsnes is capable of running both in its default multi-user mode, as well as in
in single-user mode.<br> single-user mode.<br>
<br> <br>
In multi-user mode, configuration data is stored inside the user's home In multi-user mode, configuration data is stored inside the user's home
@ -39,16 +43,15 @@ configuration data.
<h2><u>Known Limitations</u></h2><br> <h2><u>Known Limitations</u></h2><br>
<b>Cartridge co-processors:</b> certain cartridges contain special co-processor chips to enhance <b>Satellaview BS-X emulation:</b> this hardware is only partially supported.
their functionality. Some of these are either partially or completely unsupported. A message box This is mostly because the satellite network it used (St. GIGA) has been shut
warning will pop up when attempting to load such a cartridge.<br> 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> <br>
<b>Satellaview BS-X emulation:</b> this hardware is only partially supported. As a result, <b>Savestates:</b> due to the internal design of bsnes, it is not plausible to
most BS-X software will not function correctly.<br>
<br>
<b>Savestates:</b> due to the design of bsnes, it is not plausible to
implement support for savestate and/or rewind functionality.<br> implement support for savestate and/or rewind functionality.<br>
<br> <br>
@ -58,6 +61,7 @@ implement support for savestate and/or rewind functionality.<br>
<h2><u>Contributors</u></h2> <h2><u>Contributors</u></h2>
&bull; Andreas Naive<br> &bull; Andreas Naive<br>
&bull; anomie<br> &bull; anomie<br>
&bull; _Demo_<br>
&bull; Derrick Sobodash<br> &bull; Derrick Sobodash<br>
&bull; DMV27<br> &bull; DMV27<br>
&bull; FirebrandX<br> &bull; FirebrandX<br>

View File

@ -591,4 +591,3 @@ aDSP::aDSP() {}
aDSP::~aDSP() {} aDSP::~aDSP() {}
}; };

View File

@ -74,4 +74,4 @@ const int16 aDSP::gaussian_table[512] = {
0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519 0x517, 0x518, 0x518, 0x518, 0x518, 0x518, 0x519, 0x519
}; };
#endif //ifdef ADSP_CPP #endif

View File

@ -59,4 +59,4 @@ void sDSP::brr_decode(voice_t &v) {
} }
} }
#endif //ifdef SDSP_CPP #endif

View File

@ -49,4 +49,4 @@ inline bool sDSP::counter_poll(unsigned rate) {
return (((unsigned)state.counter + counter_offset[rate]) % counter_rate[rate]) == 0; return (((unsigned)state.counter + counter_offset[rate]) % counter_rate[rate]) == 0;
} }
#endif //ifdef SDSP_CPP #endif

View File

@ -132,4 +132,4 @@ void sDSP::echo_30() {
echo_write(1); echo_write(1);
} }
#endif //ifdef SDSP_CPP #endif

View File

@ -59,4 +59,4 @@ void sDSP::envelope_run(voice_t &v) {
if(counter_poll(rate) == true) v.env = env; if(counter_poll(rate) == true) v.env = env;
} }
#endif //ifdef SDSP_CPP #endif

View File

@ -51,4 +51,4 @@ int sDSP::gaussian_interpolate(const voice_t &v) {
return sclamp<16>(output) & ~1; return sclamp<16>(output) & ~1;
} }
#endif //ifdef SDSP_CPP #endif

View File

@ -32,4 +32,4 @@ void sDSP::misc_30() {
} }
} }
#endif //ifdef SDSP_CPP #endif

View File

@ -326,4 +326,3 @@ sDSP::~sDSP() {
} }
}; };

View File

@ -171,4 +171,4 @@ void sDSP::voice_9(voice_t &v) {
VREG(envx) = (uint8)state.envx_buf; VREG(envx) = (uint8)state.envx_buf;
} }
#endif //ifdef SDSP_CPP #endif

View File

@ -28,4 +28,3 @@ namespace SNES {
#include "chip/chip.hpp" #include "chip/chip.hpp"
#include "cartridge/cartridge.hpp" #include "cartridge/cartridge.hpp"
}; };

View File

@ -1,8 +1,13 @@
DirectFilter filter_direct; DirectFilter filter_direct;
void DirectFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height;
}
void DirectFilter::render( void DirectFilter::render(
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height unsigned *line, unsigned width, unsigned height
) { ) {
pitch >>= 1; pitch >>= 1;
outpitch >>= 2; outpitch >>= 2;
@ -24,7 +29,4 @@ void DirectFilter::render(
input += pitch - width; input += pitch - width;
output += outpitch - width; output += outpitch - width;
} }
outwidth = width;
outheight = height;
} }

View File

@ -1,6 +1,7 @@
class DirectFilter : public Filter { class DirectFilter : public Filter {
public: public:
void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned); 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; extern DirectFilter filter_direct;

View File

@ -4,30 +4,26 @@ void FilterInterface::set(FilterInterface::FilterType type) {
active_filter = 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 HQ2x: return filter_hq2x.size(outwidth, outheight, width, height);
case NTSC: return filter_ntsc.size(outwidth, outheight, width, height);
}
}
void FilterInterface::render( void FilterInterface::render(
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height unsigned *line, unsigned width, unsigned height
) { ) {
switch(active_filter) { default: switch(active_filter) { default:
case Direct: { case Direct: return filter_direct.render(output, outpitch, input, pitch, line, width, height);
filter_direct.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height); case Scanline: return filter_scanline.render(output, outpitch, input, pitch, line, width, height);
} break; case Scale2x: return filter_scale2x.render(output, outpitch, input, pitch, line, width, height);
case HQ2x: return filter_hq2x.render(output, outpitch, input, pitch, line, width, height);
case Scanline: { case NTSC: return filter_ntsc.render(output, outpitch, input, pitch, line, width, height);
filter_scanline.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
} break;
case Scale2x: {
filter_scale2x.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
} break;
case HQ2x: {
filter_hq2x.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
} break;
case NTSC: {
filter_ntsc.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height);
} break;
} }
} }

View File

@ -1,8 +1,10 @@
class Filter { class Filter {
public: public:
virtual void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) = 0;
virtual void render( virtual void render(
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height unsigned *line, unsigned width, unsigned height
) = 0; ) = 0;
}; };
@ -18,9 +20,11 @@ public:
void set(FilterType type); void set(FilterType type);
void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render( void render(
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height unsigned *line, unsigned width, unsigned height
); );
FilterInterface(); FilterInterface();

View File

@ -56,12 +56,17 @@ static uint16_t blend10(uint32_t c1, uint32_t c2, uint32_t c3) {
return c1; return c1;
} }
void HQ2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width * 2;
outheight = height * 2;
}
void HQ2xFilter::render( void HQ2xFilter::render(
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height unsigned *line, unsigned width, unsigned height
) { ) {
if(width > 256 || height > 240) { if(width > 256 || height > 240) {
filter_direct.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height); filter_direct.render(output, outpitch, input, pitch, line, width, height);
return; return;
} }
@ -125,9 +130,6 @@ void HQ2xFilter::render(
memset(out0, 0, 2048); memset(out0, 0, 2048);
memset(out1, 0, 2048); memset(out1, 0, 2048);
outwidth = width * 2;
outheight = height * 2;
} }
HQ2xFilter::HQ2xFilter() { HQ2xFilter::HQ2xFilter() {

View File

@ -1,6 +1,7 @@
class HQ2xFilter : public Filter { class HQ2xFilter : public Filter {
public: public:
void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned); void size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height);
void render(uint32_t*, unsigned, uint16_t*, unsigned, unsigned*, unsigned, unsigned);
HQ2xFilter(); HQ2xFilter();
~HQ2xFilter(); ~HQ2xFilter();

View File

@ -11,4 +11,4 @@ namespace libfilter {
#include "scale2x.cpp" #include "scale2x.cpp"
#include "hq2x.cpp" #include "hq2x.cpp"
#include "ntsc.cpp" #include "ntsc.cpp"
} //namespace libfilter }

View File

@ -17,6 +17,6 @@ namespace libfilter {
#include "scale2x.hpp" #include "scale2x.hpp"
#include "hq2x.hpp" #include "hq2x.hpp"
#include "ntsc.hpp" #include "ntsc.hpp"
} //namespace libfilter };
#endif //ifndef LIBFILTER_H #endif

View File

@ -2,37 +2,42 @@
NTSCFilter filter_ntsc; NTSCFilter filter_ntsc;
void NTSCFilter::render( void NTSCFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, outwidth = SNES_NTSC_OUT_WIDTH(256);
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height outheight = height;
) { }
if(!ntsc)return;
int const out_width = outwidth = SNES_NTSC_OUT_WIDTH(256); void NTSCFilter::render(
int const out_height = outheight = height; 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; burst ^= burst_toggle;
//blit multiple scanlines of same width, rather than one at a time pitch >>= 1;
int run_start = 0; outpitch >>= 2;
int run_width = line[0];
int l = 0;
while(1) { unsigned line_burst = burst;
if(run_width != line[l] || l >= out_height) { for(unsigned y = 0; y < height; y++) {
uint16_t const *in = (uint16_t*)((uint8_t*)input + pitch * run_start); uint16_t *in = input + y * pitch;
uint16_t *out = (uint16_t*)((uint8_t*)output + outpitch * run_start); uint32_t *out = output + y * outpitch;
int height = l - run_start;
int line_burst = (burst + run_start) % 3; //render as many lines in one snes_ntsc_blit as possible:
if(run_width == 256) { //do this by determining for how many lines the width stays the same
snes_ntsc_blit(ntsc, in, (pitch >> 1), line_burst, out_width, height, out, outpitch); 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 { } else {
snes_ntsc_blit_hires(ntsc, in, (pitch >> 1), line_burst, out_width, height, out, outpitch); snes_ntsc_blit_hires(ntsc, in, pitch, line_burst, rwidth, rheight, out, outpitch << 2);
} }
if(l >= out_height) break;
run_width = line[l]; line_burst = (line_burst + rheight) % 3;
run_start = l; y += rheight;
}
l++;
} }
} }
@ -54,7 +59,8 @@ void NTSCFilter::adjust(
if(!ntsc) { if(!ntsc) {
ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc); ntsc = (snes_ntsc_t*)malloc(sizeof *ntsc);
if(!ntsc) { if(!ntsc) {
return; //to do: report out of memory error fprintf(stderr, "error: snes_ntsc: out of memory\n");
return;
} }
} }

View File

@ -2,7 +2,8 @@
class NTSCFilter : public Filter { class NTSCFilter : public Filter {
public: public:
void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned); 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); void adjust(float hue, float saturation, float contrast, float brightness, float sharpness, bool merge_fields);
NTSCFilter(); NTSCFilter();

View File

@ -1,11 +1,16 @@
Scale2xFilter filter_scale2x; Scale2xFilter filter_scale2x;
void Scale2xFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width * 2;
outheight = height * 2;
}
void Scale2xFilter::render( void Scale2xFilter::render(
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height unsigned *line, unsigned width, unsigned height
) { ) {
if(width > 256 || height > 240) { if(width > 256 || height > 240) {
filter_direct.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height); filter_direct.render(output, outpitch, input, pitch, line, width, height);
return; return;
} }
@ -41,7 +46,4 @@ void Scale2xFilter::render(
input += pitch - 256; input += pitch - 256;
output += outpitch + outpitch - 512; output += outpitch + outpitch - 512;
} }
outwidth = width * 2;
outheight = height * 2;
} }

View File

@ -1,6 +1,7 @@
class Scale2xFilter : public Filter { class Scale2xFilter : public Filter {
public: public:
void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned); 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; extern Scale2xFilter filter_scale2x;

View File

@ -1,11 +1,16 @@
ScanlineFilter filter_scanline; ScanlineFilter filter_scanline;
void ScanlineFilter::size(unsigned &outwidth, unsigned &outheight, unsigned width, unsigned height) {
outwidth = width;
outheight = height * 2;
}
void ScanlineFilter::render( void ScanlineFilter::render(
uint32_t *output, unsigned outpitch, unsigned &outwidth, unsigned &outheight, uint32_t *output, unsigned outpitch, uint16_t *input, unsigned pitch,
uint16_t *input, unsigned pitch, unsigned *line, unsigned width, unsigned height unsigned *line, unsigned width, unsigned height
) { ) {
if(height > 240) { if(height > 240) {
filter_direct.render(output, outpitch, outwidth, outheight, input, pitch, line, width, height); filter_direct.render(output, outpitch, input, pitch, line, width, height);
return; return;
} }
@ -14,7 +19,7 @@ void ScanlineFilter::render(
for(unsigned y = 0; y < height; y++) { for(unsigned y = 0; y < height; y++) {
uint32_t *out0 = output; uint32_t *out0 = output;
uint32_t *out1 = output + pitch; uint32_t *out1 = output + outpitch;
if(width == 512 && line[y] == 256) { if(width == 512 && line[y] == 256) {
for(unsigned x = 0; x < 256; x++) { for(unsigned x = 0; x < 256; x++) {
uint16_t p = *input++; uint16_t p = *input++;
@ -34,7 +39,4 @@ void ScanlineFilter::render(
input += pitch - width; input += pitch - width;
output += outpitch * 2; output += outpitch * 2;
} }
outwidth = width;
outheight = height * 2;
} }

View File

@ -1,6 +1,7 @@
class ScanlineFilter : public Filter { class ScanlineFilter : public Filter {
public: public:
void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned); 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; extern ScanlineFilter filter_scanline;

54
src/lib/nall/Makefile-qt Normal file
View File

@ -0,0 +1,54 @@
# requires nall/Makefile
# exports the following symbols:
# $(moc) -- meta-object compiler
# $(rcc) -- resource compiler
# $(qtinc) -- includes for compiling
# $(qtlib) -- libraries for linking
ifeq ($(moc),)
moc := moc
endif
ifeq ($(rcc),)
rcc := rcc
endif
ifeq ($(platform),x)
qtinc := `pkg-config --cflags QtCore QtGui`
qtlib := `pkg-config --libs QtCore QtGui`
else ifeq ($(platform),osx)
qtinc := -I/usr/include/QtCore
qtinc += -I/usr/include/QtGui
qtinc += -I/Library/Frameworks/QtCore.framework/Versions/4/Headers
qtinc += -I/Library/Frameworks/QtGui.framework/Versions/4/Headers
qtlib := -L/Library/Frameworks
qtlib += -framework QtCore
qtlib += -framework QtGui
qtlib += -framework Carbon
qtlib += -framework Cocoa
qtlib += -framework AppKit
qtlib += -framework ApplicationServices
else ifeq ($(platform),win)
ifeq ($(qtpath),)
# find Qt install directory from PATH environment variable
qtpath := $(foreach path,$(subst ;, ,$(PATH)),$(if $(wildcard $(path)/$(moc).exe),$(path)))
qtpath := $(strip $(qtpath))
qtpath := $(subst \,/,$(qtpath))
qtpath := $(patsubst %/bin,%,$(qtpath))
endif
qtinc := -I$(qtpath)/include
qtinc += -I$(qtpath)/include/QtCore
qtinc += -I$(qtpath)/include/QtGui
qtlib := -L$(qtpath)/lib
qtlib += -L$(qtpath)/plugins/imageformats
qtlib += -lmingw32 -lqtmain -lQtGui -lcomdlg32 -loleaut32 -limm32 -lwinmm
qtlib += -lwinspool -lmsimg32 -lQtCore -lole32 -ladvapi32 -lws2_32 -luuid -lgdi32
# optional image-file support:
# qtlib += -lqjpeg -lqmng
endif

View File

@ -1,24 +0,0 @@
#ifndef NALL_STRING_CPP
#define NALL_STRING_CPP
#include <math.h>
#include <nall/algorithm.hpp>
#include <nall/static.hpp>
#include <nall/utf8.hpp>
#include <nall/string.hpp>
#include <nall/string/compare.cpp>
#include <nall/string/convert.cpp>
#include <nall/string/match.cpp>
#include <nall/string/math.cpp>
#include <nall/string/strl.cpp>
#include <nall/string/trim.cpp>
#include <nall/string/utility.cpp>
namespace nall {
#include <nall/string/core.cpp>
#include <nall/string/replace.cpp>
#include <nall/string/split.cpp>
}
#endif

View File

@ -1,175 +1,17 @@
#ifndef NALL_STRING_HPP #ifndef NALL_STRING_HPP
#define NALL_STRING_HPP #define NALL_STRING_HPP
#include <stdio.h> #include <nall/string/base.hpp>
#include <stdlib.h> #include <nall/string/core.hpp>
#include <string.h> #include <nall/string/cast.hpp>
#include <nall/stdint.hpp> #include <nall/string/compare.hpp>
#include <nall/vector.hpp> #include <nall/string/convert.hpp>
#include <nall/string/match.hpp>
//=============== #include <nall/string/math.hpp>
//libc extensions #include <nall/string/strl.hpp>
//=============== #include <nall/string/trim.hpp>
#include <nall/string/replace.hpp>
//compare.cpp #include <nall/string/split.hpp>
char chrlower(char c); #include <nall/string/utility.hpp>
char chrupper(char c);
int stricmp(const char *dest, const char *src);
int strpos (const char *str, const char *key);
int qstrpos(const char *str, const char *key);
bool strbegin (const char *str, const char *key);
bool stribegin(const char *str, const char *key);
bool strend (const char *str, const char *key);
bool striend(const char *str, const char *key);
//convert.cpp
char* strlower(char *str);
char* strupper(char *str);
char* strtr(char *dest, const char *before, const char *after);
uintmax_t strhex (const char *str);
intmax_t strsigned (const char *str);
uintmax_t strunsigned(const char *str);
uintmax_t strbin (const char *str);
double strdouble (const char *str);
size_t strhex (char *str, uintmax_t value, size_t length = 0);
size_t strsigned (char *str, intmax_t value, size_t length = 0);
size_t strunsigned(char *str, uintmax_t value, size_t length = 0);
size_t strbin (char *str, uintmax_t value, size_t length = 0);
size_t strdouble (char *str, double value, size_t length = 0);
//match.cpp
bool match(const char *pattern, const char *str);
//math.cpp
bool strint (const char *str, int &result);
bool strmath(const char *str, int &result);
//strl.cpp
size_t strlcpy(char *dest, const char *src, size_t length);
size_t strlcat(char *dest, const char *src, size_t length);
//trim.cpp
char* ltrim(char *str, const char *key = " ");
char* rtrim(char *str, const char *key = " ");
char* trim (char *str, const char *key = " ");
char* ltrim_once(char *str, const char *key = " ");
char* rtrim_once(char *str, const char *key = " ");
char* trim_once (char *str, const char *key = " ");
//================
//string + lstring
//================
namespace nall {
class string;
template<typename T> inline string to_string(T);
class string {
public:
void reserve(size_t);
unsigned length() const;
string& assign(const char*);
string& append(const char*);
template<typename T> string& operator= (T value) { return assign(to_string<T>(value)); }
template<typename T> string& operator<<(T value) { return append(to_string<T>(value)); }
operator const char*() const;
char* operator()();
char& operator[](int);
bool operator==(const char*) const;
bool operator!=(const char*) const;
bool operator< (const char*) const;
bool operator<=(const char*) const;
bool operator> (const char*) const;
bool operator>=(const char*) const;
string();
string(const char*);
string(const string&);
string& operator=(const string&);
~string();
//core.cpp
bool readfile(const char*);
//replace.cpp
string& replace (const char*, const char*);
string& qreplace(const char*, const char*);
protected:
char *data;
size_t size;
};
class lstring : public vector<string> {
public:
template<typename T> lstring& operator<<(T value) {
operator[](size()).assign(to_string<T>(value));
return *this;
}
//core.cpp
int find(const char*);
//split.cpp
void split (const char*, const char*, unsigned = 0);
void qsplit(const char*, const char*, unsigned = 0);
};
}
//=====================
//string<>libc wrappers
//=====================
size_t strlcpy(nall::string &dest, const char *src, size_t length);
size_t strlcat(nall::string &dest, const char *src, size_t length);
nall::string& strlower(nall::string &str);
nall::string& strupper(nall::string &str);
nall::string& strtr(nall::string &dest, const char *before, const char *after);
nall::string& ltrim(nall::string &str, const char *key = " ");
nall::string& rtrim(nall::string &str, const char *key = " ");
nall::string& trim (nall::string &str, const char *key = " ");
nall::string& ltrim_once(nall::string &str, const char *key = " ");
nall::string& rtrim_once(nall::string &str, const char *key = " ");
nall::string& trim_once (nall::string &str, const char *key = " ");
//==============
//misc functions
//==============
nall::string substr(const char *src, size_t start = 0, size_t length = 0);
nall::string strhex (uintmax_t value);
nall::string strsigned (intmax_t value);
nall::string strunsigned(uintmax_t value);
nall::string strbin (uintmax_t value);
nall::string strdouble (double value);
namespace nall {
//this is needed, as C++98 does not support explicit template specialization inside classes;
//redundant memory allocation should hopefully be avoided via compiler optimizations.
template<> inline string to_string<bool> (bool v) { return v ? "true" : "false"; }
template<> inline string to_string<signed int> (signed int v) { return strsigned(v); }
template<> inline string to_string<unsigned int> (unsigned int v) { return strunsigned(v); }
template<> inline string to_string<double> (double v) { return strdouble(v); }
template<> inline string to_string<char*> (char *v) { return v; }
template<> inline string to_string<const char*> (const char *v) { return v; }
template<> inline string to_string<string> (string v) { return v; }
template<> inline string to_string<const string&>(const string &v) { return v; }
}
#endif #endif

View File

@ -0,0 +1,114 @@
#ifndef NALL_STRING_BASE_HPP
#define NALL_STRING_BASE_HPP
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <nall/stdint.hpp>
#include <nall/utf8.hpp>
#include <nall/vector.hpp>
inline char chrlower(char c);
inline char chrupper(char c);
inline int stricmp(const char *dest, const char *src);
inline int strpos (const char *str, const char *key);
inline int qstrpos(const char *str, const char *key);
inline bool strbegin (const char *str, const char *key);
inline bool stribegin(const char *str, const char *key);
inline bool strend (const char *str, const char *key);
inline bool striend(const char *str, const char *key);
inline char* strlower(char *str);
inline char* strupper(char *str);
inline char* strtr(char *dest, const char *before, const char *after);
inline uintmax_t strhex (const char *str);
inline intmax_t strsigned (const char *str);
inline uintmax_t strunsigned(const char *str);
inline uintmax_t strbin (const char *str);
inline double strdouble (const char *str);
inline size_t strhex (char *str, uintmax_t value, size_t length = 0);
inline size_t strsigned (char *str, intmax_t value, size_t length = 0);
inline size_t strunsigned(char *str, uintmax_t value, size_t length = 0);
inline size_t strbin (char *str, uintmax_t value, size_t length = 0);
inline size_t strdouble (char *str, double value, size_t length = 0);
inline bool match(const char *pattern, const char *str);
inline bool strint (const char *str, int &result);
inline bool strmath(const char *str, int &result);
inline size_t strlcpy(char *dest, const char *src, size_t length);
inline size_t strlcat(char *dest, const char *src, size_t length);
inline char* ltrim(char *str, const char *key = " ");
inline char* rtrim(char *str, const char *key = " ");
inline char* trim (char *str, const char *key = " ");
inline char* ltrim_once(char *str, const char *key = " ");
inline char* rtrim_once(char *str, const char *key = " ");
inline char* trim_once (char *str, const char *key = " ");
namespace nall {
class string;
template<typename T> inline string to_string(T);
class string {
public:
inline void reserve(size_t);
inline unsigned length() const;
inline string& assign(const char*);
inline string& append(const char*);
template<typename T> inline string& operator= (T value);
template<typename T> inline string& operator<<(T value);
inline operator const char*() const;
inline char* operator()();
inline char& operator[](int);
inline bool operator==(const char*) const;
inline bool operator!=(const char*) const;
inline bool operator< (const char*) const;
inline bool operator<=(const char*) const;
inline bool operator> (const char*) const;
inline bool operator>=(const char*) const;
inline string();
inline string(const char*);
inline string(const string&);
inline string& operator=(const string&);
inline ~string();
inline bool readfile(const char*);
inline string& replace (const char*, const char*);
inline string& qreplace(const char*, const char*);
protected:
char *data;
size_t size;
};
class lstring : public vector<string> {
public:
template<typename T> inline lstring& operator<<(T value);
inline int find(const char*);
inline void split (const char*, const char*, unsigned = 0);
inline void qsplit(const char*, const char*, unsigned = 0);
};
};
inline size_t strlcpy(nall::string &dest, const char *src, size_t length);
inline size_t strlcat(nall::string &dest, const char *src, size_t length);
inline nall::string& strlower(nall::string &str);
inline nall::string& strupper(nall::string &str);
inline nall::string& strtr(nall::string &dest, const char *before, const char *after);
inline nall::string& ltrim(nall::string &str, const char *key = " ");
inline nall::string& rtrim(nall::string &str, const char *key = " ");
inline nall::string& trim (nall::string &str, const char *key = " ");
inline nall::string& ltrim_once(nall::string &str, const char *key = " ");
inline nall::string& rtrim_once(nall::string &str, const char *key = " ");
inline nall::string& trim_once (nall::string &str, const char *key = " ");
inline nall::string substr(const char *src, size_t start = 0, size_t length = 0);
inline nall::string strhex (uintmax_t value);
inline nall::string strsigned (intmax_t value);
inline nall::string strunsigned(uintmax_t value);
inline nall::string strbin (uintmax_t value);
inline nall::string strdouble (double value);
#endif

View File

@ -0,0 +1,25 @@
#ifndef NALL_STRING_CAST_HPP
#define NALL_STRING_CAST_HPP
namespace nall {
//this is needed, as C++98 does not support explicit template specialization inside classes;
//redundant memory allocation should hopefully be avoided via compiler optimizations.
template<> inline string to_string<bool> (bool v) { return v ? "true" : "false"; }
template<> inline string to_string<signed int> (signed int v) { return strsigned(v); }
template<> inline string to_string<unsigned int> (unsigned int v) { return strunsigned(v); }
template<> inline string to_string<double> (double v) { return strdouble(v); }
template<> inline string to_string<char*> (char *v) { return v; }
template<> inline string to_string<const char*> (const char *v) { return v; }
template<> inline string to_string<string> (string v) { return v; }
template<> inline string to_string<const string&>(const string &v) { return v; }
template<typename T> string& string::operator= (T value) { return assign(to_string<T>(value)); }
template<typename T> string& string::operator<<(T value) { return append(to_string<T>(value)); }
template<typename T> lstring& lstring::operator<<(T value) {
operator[](size()).assign(to_string<T>(value));
return *this;
}
};
#endif

View File

@ -1,4 +1,5 @@
#ifdef NALL_STRING_CPP #ifndef NALL_STRING_COMPARE_HPP
#define NALL_STRING_COMPARE_HPP
char chrlower(char c) { char chrlower(char c) {
return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c; return (c >= 'A' && c <= 'Z') ? c + ('a' - 'A') : c;

View File

@ -1,4 +1,5 @@
#ifdef NALL_STRING_CPP #ifndef NALL_STRING_CONVERT_HPP
#define NALL_STRING_CONVERT_HPP
char* strlower(char *str) { char* strlower(char *str) {
if(!str) return 0; if(!str) return 0;

View File

@ -1,4 +1,7 @@
#ifdef NALL_STRING_CPP #ifndef NALL_STRING_CORE_HPP
#define NALL_STRING_CORE_HPP
namespace nall {
void string::reserve(size_t size_) { void string::reserve(size_t size_) {
if(size_ > size) { if(size_ > size) {
@ -64,6 +67,7 @@ string::string(const string &value) {
string& string::operator=(const string &value) { string& string::operator=(const string &value) {
assign(value); assign(value);
return *this;
} }
string::~string() { string::~string() {
@ -100,4 +104,6 @@ int lstring::find(const char *key) {
return -1; return -1;
} }
};
#endif #endif

View File

@ -1,4 +1,5 @@
#ifdef NALL_STRING_CPP #ifndef NALL_STRING_MATCH_HPP
#define NALL_STRING_MATCH_HPP
bool match(const char *p, const char *s) { bool match(const char *p, const char *s) {
const char *p_ = 0, *s_ = 0; const char *p_ = 0, *s_ = 0;

View File

@ -1,4 +1,5 @@
#ifdef NALL_STRING_CPP #ifndef NALL_STRING_MATH_HPP
#define NALL_STRING_MATH_HPP
static int eval_integer(const char *&s) { static int eval_integer(const char *&s) {
if(!*s) throw "unrecognized_integer"; if(!*s) throw "unrecognized_integer";

View File

@ -1,4 +1,7 @@
#ifdef NALL_STRING_CPP #ifndef NALL_STRING_REPLACE_HPP
#define NALL_STRING_REPLACE_HPP
namespace nall {
string& string::replace(const char *key, const char *token) { string& string::replace(const char *key, const char *token) {
int i, z, ksl = strlen(key), tsl = strlen(token), ssl = length(); int i, z, ksl = strlen(key), tsl = strlen(token), ssl = length();
@ -95,4 +98,6 @@ string& string::qreplace(const char *key, const char *token) {
return *this; return *this;
} }
};
#endif #endif

View File

@ -1,4 +1,7 @@
#ifdef NALL_STRING_CPP #ifndef NALL_STRING_SPLIT_HPP
#define NALL_STRING_SPLIT_HPP
namespace nall {
void lstring::split(const char *key, const char *src, unsigned limit) { void lstring::split(const char *key, const char *src, unsigned limit) {
reset(); reset();
@ -48,4 +51,6 @@ void lstring::qsplit(const char *key, const char *src, unsigned limit) {
operator[](split_count++) = src + lp; operator[](split_count++) = src + lp;
} }
};
#endif #endif

View File

@ -1,4 +1,5 @@
#ifdef NALL_STRING_CPP #ifndef NALL_STRING_STRL_HPP
#define NALL_STRING_STRL_HPP
//strlcpy, strlcat based on OpenBSD implementation by Todd C. Miller //strlcpy, strlcat based on OpenBSD implementation by Todd C. Miller

View File

@ -1,4 +1,5 @@
#ifdef NALL_STRING_CPP #ifndef NALL_STRING_TRIM_HPP
#define NALL_STRING_TRIM_HPP
char* ltrim(char *str, const char *key) { char* ltrim(char *str, const char *key) {
if(!key || !*key) return str; if(!key || !*key) return str;

View File

@ -1,4 +1,5 @@
#ifdef NALL_STRING_CPP #ifndef NALL_STRING_UTILITY_HPP
#define NALL_STRING_UTILITY_HPP
size_t strlcpy(nall::string &dest, const char *src, size_t length) { size_t strlcpy(nall::string &dest, const char *src, size_t length) {
dest.reserve(length); dest.reserve(length);

View File

@ -8,6 +8,8 @@
#if defined(_WIN32) #if defined(_WIN32)
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#undef NOMINMAX #undef NOMINMAX
#define NOMINMAX #define NOMINMAX
#include <windows.h> #include <windows.h>

View File

@ -1,22 +1,17 @@
class Audio { class Audio {
public: public:
enum Setting { static const char *Volume;
//AudioInterface settings static const char *Resample;
Volume, static const char *ResampleRatio;
Resample,
ResampleOutputFrequency,
ResampleInputFrequency,
//Audio settings static const char *Handle;
Handle, static const char *Synchronize;
Synchronize, static const char *Frequency;
Frequency, static const char *Latency;
Latency,
};
virtual bool cap(Setting) { return false; } virtual bool cap(const nall::string& name) { return false; }
virtual uintptr_t get(Setting) { return false; } virtual nall::any get(const nall::string& name) { return false; }
virtual bool set(Setting, uintptr_t) { return false; } virtual bool set(const nall::string& name, const nall::any& value) { return false; }
virtual void sample(uint16_t left, uint16_t right) {} virtual void sample(uint16_t left, uint16_t right) {}
virtual void clear() {} virtual void clear() {}

View File

@ -1,13 +1,14 @@
/*
audio.alsa (2008-08-12)
authors: Nach, RedDwarf
*/
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
namespace ruby { namespace ruby {
#include "alsa.hpp"
class pAudioALSA { class pAudioALSA {
public: public:
AudioALSA &self;
struct { struct {
snd_pcm_t *handle; snd_pcm_t *handle;
snd_pcm_format_t format; snd_pcm_format_t format;
@ -28,50 +29,41 @@ public:
unsigned latency; unsigned latency;
} settings; } settings;
bool cap(Audio::Setting setting) { bool cap(const string& name) {
if(setting == Audio::Synchronize) return true; if(name == Audio::Synchronize) return true;
if(setting == Audio::Frequency) return true; if(name == Audio::Frequency) return true;
if(setting == Audio::Latency) return true; if(name == Audio::Latency) return true;
return false; return false;
} }
uintptr_t get(Audio::Setting setting) { any get(const string& name) {
if(setting == Audio::Synchronize) return settings.synchronize; if(name == Audio::Synchronize) return settings.synchronize;
if(setting == Audio::Frequency) return settings.frequency; if(name == Audio::Frequency) return settings.frequency;
if(setting == Audio::Latency) return settings.latency; if(name == Audio::Latency) return settings.latency;
return false; return false;
} }
bool set(Audio::Setting setting, uintptr_t param) { bool set(const string& name, const any& value) {
if(setting == Audio::Synchronize) { if(name == Audio::Synchronize) {
if(settings.synchronize != param) { if(settings.synchronize != any_cast<bool>(value)) {
settings.synchronize = param; settings.synchronize = any_cast<bool>(value);
if(device.handle) { if(device.handle) init();
term();
init();
}
} }
return true; return true;
} }
if(setting == Audio::Frequency) { if(name == Audio::Frequency) {
if(settings.frequency != param) { if(settings.frequency != any_cast<unsigned>(value)) {
settings.frequency = param; settings.frequency = any_cast<unsigned>(value);
if(device.handle) { if(device.handle) init();
term();
init();
}
} }
return true; return true;
} }
if(setting == Audio::Latency) { if(name == Audio::Latency) {
if(settings.latency != param) { if(settings.latency != any_cast<unsigned>(value)) {
settings.latency = param; settings.latency = any_cast<unsigned>(value);
if(device.handle) { if(device.handle) init();
term();
init();
}
} }
return true; return true;
} }
@ -86,12 +78,8 @@ public:
if(buffer.length < device.period_size) return; if(buffer.length < device.period_size) return;
if(settings.synchronize == false) { if(settings.synchronize == false) {
snd_pcm_avail_update(device.handle); snd_pcm_sframes_t avail = snd_pcm_avail_update(device.handle);
snd_pcm_sframes_t delay; if(avail < device.period_size) {
snd_pcm_delay(device.handle, &delay);
if(delay < 0) {
snd_pcm_prepare(device.handle);
} else if(delay > device.buffer_size - device.period_size) {
buffer.length = 0; buffer.length = 0;
return; return;
} }
@ -120,7 +108,12 @@ public:
} }
} }
void clear() {
}
bool init() { bool init() {
term();
if(snd_pcm_open(&device.handle, device.name, SND_PCM_STREAM_PLAYBACK, 0) < 0) { if(snd_pcm_open(&device.handle, device.name, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
term(); term();
return false; return false;
@ -128,21 +121,21 @@ public:
/* //below code will not work with 24khz frequency rate (ALSA library bug) /* //below code will not work with 24khz frequency rate (ALSA library bug)
if(snd_pcm_set_params(device.handle, device.format, SND_PCM_ACCESS_RW_INTERLEAVED, if(snd_pcm_set_params(device.handle, device.format, SND_PCM_ACCESS_RW_INTERLEAVED,
device.channels, settings.frequency, 1, settings.latency * 100) < 0) { device.channels, settings.frequency, 1, settings.latency * 1000) < 0) {
//failed to set device parameters //failed to set device parameters
term(); term();
return false; return false;
} }
if(snd_pcm_get_params(device.handle, &device.buffer_size, &device.period_size) < 0) { if(snd_pcm_get_params(device.handle, &device.buffer_size, &device.period_size) < 0) {
device.period_size = settings.latency * 100 * 1e-6 * settings.frequency / 4; device.period_size = settings.latency * 1000 * 1e-6 * settings.frequency / 4;
}*/ }*/
snd_pcm_hw_params_t *hwparams; snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams; snd_pcm_sw_params_t *swparams;
unsigned rate = settings.frequency; unsigned rate = settings.frequency;
unsigned buffer_time = settings.latency * 100; unsigned buffer_time = settings.latency * 1000;
unsigned period_time = settings.latency * 100 / 4; unsigned period_time = settings.latency * 1000 / 4;
snd_pcm_hw_params_alloca(&hwparams); snd_pcm_hw_params_alloca(&hwparams);
if(snd_pcm_hw_params_any(device.handle, hwparams) < 0) { if(snd_pcm_hw_params_any(device.handle, hwparams) < 0) {
@ -206,7 +199,7 @@ public:
} }
} }
pAudioALSA(AudioALSA &self_) : self(self_) { pAudioALSA() {
device.handle = 0; device.handle = 0;
device.format = SND_PCM_FORMAT_S16_LE; device.format = SND_PCM_FORMAT_S16_LE;
device.channels = 2; device.channels = 2;
@ -225,13 +218,6 @@ public:
} }
}; };
bool AudioALSA::cap(Setting setting) { return p.cap(setting); } DeclareAudio(ALSA)
uintptr_t AudioALSA::get(Setting setting) { return p.get(setting); }
bool AudioALSA::set(Setting setting, uintptr_t param) { return p.set(setting, param); }
void AudioALSA::sample(uint16_t left, uint16_t right) { p.sample(left, right); }
bool AudioALSA::init() { return p.init(); }
void AudioALSA::term() { p.term(); }
AudioALSA::AudioALSA() : p(*new pAudioALSA(*this)) {}
AudioALSA::~AudioALSA() { delete &p; }
} //namespace ruby };

View File

@ -1,23 +0,0 @@
/*
audio.alsa (2008-08-12)
authors: Nach, RedDwarf
*/
class pAudioALSA;
class AudioALSA : public Audio {
public:
bool cap(Setting);
uintptr_t get(Setting);
bool set(Setting, uintptr_t);
void sample(uint16_t left, uint16_t right);
bool init();
void term();
AudioALSA();
~AudioALSA();
private:
pAudioALSA &p;
};

View File

@ -1,13 +1,14 @@
/*
audio.ao (2008-06-01)
authors: Nach, RedDwarf
*/
#include <ao/ao.h> #include <ao/ao.h>
namespace ruby { namespace ruby {
#include "ao.hpp"
class pAudioAO { class pAudioAO {
public: public:
AudioAO &self;
int driver_id; int driver_id;
ao_sample_format driver_format; ao_sample_format driver_format;
ao_device *audio_device; ao_device *audio_device;
@ -16,25 +17,23 @@ public:
unsigned frequency; unsigned frequency;
} settings; } settings;
bool cap(Audio::Setting setting) { bool cap(const string& name) {
if(setting == Audio::Frequency) return true; if(name == Audio::Frequency) return true;
return false; return false;
} }
uintptr_t get(Audio::Setting setting) { any get(const string& name) {
if(setting == Audio::Frequency) return settings.frequency; if(name == Audio::Frequency) return settings.frequency;
return false; return false;
} }
bool set(Audio::Setting setting, uintptr_t param) { bool set(const string& name, const any& value) {
if(setting == Audio::Frequency) { if(name == Audio::Frequency) {
settings.frequency = param; settings.frequency = any_cast<unsigned>(value);
if(audio_device) { if(audio_device) init();
term();
init();
}
return true; return true;
} }
return false; return false;
} }
@ -43,7 +42,12 @@ public:
ao_play(audio_device, (char*)&samp, 4); //This may need to be byte swapped for Big Endian ao_play(audio_device, (char*)&samp, 4); //This may need to be byte swapped for Big Endian
} }
void clear() {
}
bool init() { bool init() {
term();
driver_id = ao_default_driver_id(); //ao_driver_id((const char*)driver) driver_id = ao_default_driver_id(); //ao_driver_id((const char*)driver)
if(driver_id < 0) return false; if(driver_id < 0) return false;
@ -72,7 +76,7 @@ public:
} }
} }
pAudioAO(AudioAO &self_) : self(self_) { pAudioAO() {
audio_device = 0; audio_device = 0;
ao_initialize(); ao_initialize();
@ -85,13 +89,6 @@ public:
} }
}; };
bool AudioAO::cap(Setting setting) { return p.cap(setting); } DeclareAudio(AO)
uintptr_t AudioAO::get(Setting setting) { return p.get(setting); }
bool AudioAO::set(Setting setting, uintptr_t param) { return p.set(setting, param); }
void AudioAO::sample(uint16_t l_sample, uint16_t r_sample) { p.sample(l_sample, r_sample); }
bool AudioAO::init() { return p.init(); }
void AudioAO::term() { p.term(); }
AudioAO::AudioAO() : p(*new pAudioAO(*this)) {}
AudioAO::~AudioAO() { delete &p; }
} //namespace ruby };

View File

@ -1,23 +0,0 @@
/*
audio.ao (2008-06-01)
authors: Nach, RedDwarf
*/
class pAudioAO;
class AudioAO : public Audio {
public:
bool cap(Setting);
uintptr_t get(Setting);
bool set(Setting, uintptr_t);
void sample(uint16_t left, uint16_t right);
bool init();
void term();
AudioAO();
~AudioAO();
private:
pAudioAO &p;
};

View File

@ -1,14 +1,14 @@
#include <windows.h> /*
audio.directsound (2007-12-26)
author: byuu
*/
#include <dsound.h> #include <dsound.h>
namespace ruby { namespace ruby {
#include "directsound.hpp"
class pAudioDS { class pAudioDS {
public: public:
AudioDS &self;
LPDIRECTSOUND ds; LPDIRECTSOUND ds;
LPDIRECTSOUNDBUFFER dsb_p, dsb_b; LPDIRECTSOUNDBUFFER dsb_p, dsb_b;
DSBUFFERDESC dsbd; DSBUFFERDESC dsbd;
@ -33,42 +33,42 @@ public:
unsigned latency; unsigned latency;
} settings; } settings;
bool cap(Audio::Setting setting) { bool cap(const string& name) {
if(setting == Audio::Handle) return true; if(name == Audio::Handle) return true;
if(setting == Audio::Synchronize) return true; if(name == Audio::Synchronize) return true;
if(setting == Audio::Frequency) return true; if(name == Audio::Frequency) return true;
if(setting == Audio::Latency) return true; if(name == Audio::Latency) return true;
return false; return false;
} }
uintptr_t get(Audio::Setting setting) { any get(const string& name) {
if(setting == Audio::Handle) return (uintptr_t)settings.handle; if(name == Audio::Handle) return (uintptr_t)settings.handle;
if(setting == Audio::Synchronize) return settings.synchronize; if(name == Audio::Synchronize) return settings.synchronize;
if(setting == Audio::Frequency) return settings.frequency; if(name == Audio::Frequency) return settings.frequency;
if(setting == Audio::Latency) return settings.latency; if(name == Audio::Latency) return settings.latency;
return false; return false;
} }
bool set(Audio::Setting setting, uintptr_t param) { bool set(const string& name, const any& value) {
if(setting == Audio::Handle) { if(name == Audio::Handle) {
settings.handle = (HWND)param; settings.handle = (HWND)any_cast<uintptr_t>(value);
return true; return true;
} }
if(setting == Audio::Synchronize) { if(name == Audio::Synchronize) {
settings.synchronize = param; settings.synchronize = any_cast<bool>(value);
if(ds) clear(); if(ds) clear();
return true; return true;
} }
if(setting == Audio::Frequency) { if(name == Audio::Frequency) {
settings.frequency = param; settings.frequency = any_cast<unsigned>(value);
if(ds) init(); if(ds) init();
return true; return true;
} }
if(setting == Audio::Latency) { if(name == Audio::Latency) {
settings.latency = param; settings.latency = any_cast<unsigned>(value);
if(ds) init(); if(ds) init();
return true; return true;
} }
@ -90,7 +90,7 @@ public:
dsb_b->GetCurrentPosition(&pos, 0); dsb_b->GetCurrentPosition(&pos, 0);
unsigned activering = pos / (device.latency * 4); unsigned activering = pos / (device.latency * 4);
if(activering == device.readring) { if(activering == device.readring) {
if(video.get(Video::Synchronize) == false) Sleep(1); if(settings.synchronize == false) Sleep(1);
continue; continue;
} }
@ -189,7 +189,7 @@ public:
if(ds) { ds->Release(); ds = 0; } if(ds) { ds->Release(); ds = 0; }
} }
pAudioDS(AudioDS &self_) : self(self_) { pAudioDS() {
ds = 0; ds = 0;
dsb_p = 0; dsb_p = 0;
dsb_b = 0; dsb_b = 0;
@ -207,14 +207,6 @@ public:
} }
}; };
bool AudioDS::cap(Setting setting) { return p.cap(setting); } DeclareAudio(DS)
uintptr_t AudioDS::get(Setting setting) { return p.get(setting); }
bool AudioDS::set(Setting setting, uintptr_t param) { return p.set(setting, param); }
void AudioDS::sample(uint16_t left, uint16_t right) { p.sample(left, right); }
void AudioDS::clear() { p.clear(); }
bool AudioDS::init() { return p.init(); }
void AudioDS::term() { p.term(); }
AudioDS::AudioDS() : p(*new pAudioDS(*this)) {}
AudioDS::~AudioDS() { delete &p; }
} //namespace ruby };

View File

@ -1,24 +0,0 @@
/*
audio.directsound (2007-12-26)
author: byuu
*/
class pAudioDS;
class AudioDS : public Audio {
public:
bool cap(Setting);
uintptr_t get(Setting);
bool set(Setting, uintptr_t);
void sample(uint16_t left, uint16_t right);
void clear();
bool init();
void term();
AudioDS();
~AudioDS();
private:
pAudioDS &p;
};

View File

@ -1,14 +1,21 @@
#include <AL/al.h> /*
#include <AL/alc.h> audio.openal (2007-12-26)
author: Nach
contributors: byuu, wertigon, _willow_
*/
#if defined(PLATFORM_OSX)
#include <OpenAL/al.h>
#include <OpenAL/alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#endif
namespace ruby { namespace ruby {
#include "openal.hpp"
class pAudioOpenAL { class pAudioOpenAL {
public: public:
AudioOpenAL &self;
struct { struct {
ALCdevice *handle; ALCdevice *handle;
ALCcontext *context; ALCcontext *context;
@ -30,34 +37,34 @@ public:
unsigned latency; unsigned latency;
} settings; } settings;
bool cap(Audio::Setting setting) { bool cap(const string& name) {
if(setting == Audio::Synchronize) return true; if(name == Audio::Synchronize) return true;
if(setting == Audio::Frequency) return true; if(name == Audio::Frequency) return true;
if(setting == Audio::Latency) return true; if(name == Audio::Latency) return true;
return false; return false;
} }
uintptr_t get(Audio::Setting setting) { any get(const string& name) {
if(setting == Audio::Synchronize) return settings.synchronize; if(name == Audio::Synchronize) return settings.synchronize;
if(setting == Audio::Frequency) return settings.frequency; if(name == Audio::Frequency) return settings.frequency;
if(setting == Audio::Latency) return settings.latency; if(name == Audio::Latency) return settings.latency;
return false; return false;
} }
bool set(Audio::Setting setting, uintptr_t param) { bool set(const string& name, const any& value) {
if(setting == Audio::Synchronize) { if(name == Audio::Synchronize) {
settings.synchronize = param; settings.synchronize = any_cast<bool>(value);
return true; return true;
} }
if(setting == Audio::Frequency) { if(name == Audio::Frequency) {
settings.frequency = param; settings.frequency = any_cast<unsigned>(value);
return true; return true;
} }
if(setting == Audio::Latency) { if(name == Audio::Latency) {
if(settings.latency != param) { if(settings.latency != any_cast<unsigned>(value)) {
settings.latency = param; settings.latency = any_cast<unsigned>(value);
update_latency(); update_latency();
} }
return true; return true;
@ -96,6 +103,9 @@ public:
buffer.length = 0; buffer.length = 0;
} }
void clear() {
}
void update_latency() { void update_latency() {
if(buffer.data) delete[] buffer.data; if(buffer.data) delete[] buffer.data;
buffer.size = settings.frequency * settings.latency / 1000.0 + 0.5; buffer.size = settings.frequency * settings.latency / 1000.0 + 0.5;
@ -174,7 +184,7 @@ public:
} }
} }
pAudioOpenAL(AudioOpenAL &self_) : self(self_) { pAudioOpenAL() {
device.source = 0; device.source = 0;
device.handle = 0; device.handle = 0;
device.context = 0; device.context = 0;
@ -195,13 +205,6 @@ public:
} }
}; };
bool AudioOpenAL::cap(Setting setting) { return p.cap(setting); } DeclareAudio(OpenAL)
uintptr_t AudioOpenAL::get(Setting setting) { return p.get(setting); }
bool AudioOpenAL::set(Setting setting, uintptr_t param) { return p.set(setting, param); }
void AudioOpenAL::sample(uint16_t sl, uint16_t sr) { p.sample(sl, sr); }
bool AudioOpenAL::init() { return p.init(); }
void AudioOpenAL::term() { p.term(); }
AudioOpenAL::AudioOpenAL() : p(*new pAudioOpenAL(*this)) {}
AudioOpenAL::~AudioOpenAL() { delete &p; }
} //namespace ruby };

View File

@ -1,24 +0,0 @@
/*
audio.openal (2007-12-26)
author: Nach
contributors: byuu, wertigon, _willow_
*/
class pAudioOpenAL;
class AudioOpenAL : public Audio {
public:
bool cap(Setting);
uintptr_t get(Setting);
bool set(Setting, uintptr_t);
void sample(uint16_t sl, uint16_t sr);
bool init();
void term();
AudioOpenAL();
~AudioOpenAL();
private:
pAudioOpenAL &p;
};

View File

@ -1,3 +1,8 @@
/*
audio.oss (2007-12-26)
author: Nach
*/
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -20,12 +25,8 @@
namespace ruby { namespace ruby {
#include "oss.hpp"
class pAudioOSS { class pAudioOSS {
public: public:
AudioOSS &self;
struct { struct {
int fd; int fd;
int format; int format;
@ -37,25 +38,23 @@ public:
unsigned frequency; unsigned frequency;
} settings; } settings;
bool cap(Audio::Setting setting) { bool cap(const string& name) {
if(setting == Audio::Frequency) return true; if(name == Audio::Frequency) return true;
return false; return false;
} }
uintptr_t get(Audio::Setting setting) { any get(const string& name) {
if(setting == Audio::Frequency) return settings.frequency; if(name == Audio::Frequency) return settings.frequency;
return false; return false;
} }
bool set(Audio::Setting setting, uintptr_t param) { bool set(const string& name, const any& value) {
if(setting == Audio::Frequency) { if(name == Audio::Frequency) {
settings.frequency = param; settings.frequency = any_cast<unsigned>(value);
if(device.fd > 0) { if(device.fd > 0) init();
term();
init();
}
return true; return true;
} }
return false; return false;
} }
@ -64,7 +63,12 @@ public:
unsigned unused = write(device.fd, &sample, 4); unsigned unused = write(device.fd, &sample, 4);
} }
void clear() {
}
bool init() { bool init() {
term();
device.fd = open(device.name, O_WRONLY, O_NONBLOCK); device.fd = open(device.name, O_WRONLY, O_NONBLOCK);
if(device.fd < 0) return false; if(device.fd < 0) return false;
@ -90,7 +94,7 @@ public:
} }
} }
pAudioOSS(AudioOSS &self_) : self(self_) { pAudioOSS() {
device.fd = -1; device.fd = -1;
device.format = AFMT_S16_LE; device.format = AFMT_S16_LE;
device.channels = 2; device.channels = 2;
@ -104,13 +108,6 @@ public:
} }
}; };
bool AudioOSS::cap(Setting setting) { return p.cap(setting); } DeclareAudio(OSS)
uintptr_t AudioOSS::get(Setting setting) { return p.get(setting); }
bool AudioOSS::set(Setting setting, uintptr_t param) { return p.set(setting, param); }
void AudioOSS::sample(uint16_t sl, uint16_t sr) { p.sample(sl, sr); }
bool AudioOSS::init() { return p.init(); }
void AudioOSS::term() { p.term(); }
AudioOSS::AudioOSS() : p(*new pAudioOSS(*this)) {}
AudioOSS::~AudioOSS() { delete &p; }
} //namespace ruby };

View File

@ -1,23 +0,0 @@
/*
audio.oss (2007-12-26)
author: Nach
*/
class pAudioOSS;
class AudioOSS : public Audio {
public:
bool cap(Setting);
uintptr_t get(Setting);
bool set(Setting, uintptr_t);
void sample(uint16_t sl, uint16_t sr);
bool init();
void term();
AudioOSS();
~AudioOSS();
private:
pAudioOSS &p;
};

View File

@ -1,10 +1,13 @@
/*
audio.pulseaudio (2008-10-31)
author: byuu
*/
#include <pulse/simple.h> #include <pulse/simple.h>
#include <pulse/error.h> #include <pulse/error.h>
namespace ruby { namespace ruby {
#include "pulseaudio.hpp"
class pAudioPulseAudio { class pAudioPulseAudio {
public: public:
struct { struct {
@ -21,25 +24,20 @@ public:
unsigned frequency; unsigned frequency;
} settings; } settings;
AudioPulseAudio &self; bool cap(const string& name) {
if(name == Audio::Frequency) return true;
bool cap(Audio::Setting setting) {
if(setting == Audio::Frequency) return true;
return false; return false;
} }
uintptr_t get(Audio::Setting setting) { any get(const string& name) {
if(setting == Audio::Frequency) return settings.frequency; if(name == Audio::Frequency) return settings.frequency;
return false; return false;
} }
bool set(Audio::Setting setting, uintptr_t param) { bool set(const string& name, const any& value) {
if(setting == Audio::Frequency) { if(name == Audio::Frequency) {
settings.frequency = param; settings.frequency = any_cast<unsigned>(value);
if(device.handle) { if(device.handle) init();
term();
init();
}
return true; return true;
} }
@ -57,7 +55,12 @@ public:
} }
} }
void clear() {
}
bool init() { bool init() {
term();
device.spec.format = PA_SAMPLE_S16LE; device.spec.format = PA_SAMPLE_S16LE;
device.spec.channels = 2; device.spec.channels = 2;
device.spec.rate = settings.frequency; device.spec.rate = settings.frequency;
@ -98,7 +101,7 @@ public:
} }
} }
pAudioPulseAudio(AudioPulseAudio &self_) : self(self_) { pAudioPulseAudio() {
device.handle = 0; device.handle = 0;
buffer.data = 0; buffer.data = 0;
settings.frequency = 22050; settings.frequency = 22050;
@ -109,13 +112,6 @@ public:
} }
}; };
bool AudioPulseAudio::cap(Setting setting) { return p.cap(setting); } DeclareAudio(PulseAudio)
uintptr_t AudioPulseAudio::get(Setting setting) { return p.get(setting); }
bool AudioPulseAudio::set(Setting setting, uintptr_t param) { return p.set(setting, param); }
void AudioPulseAudio::sample(uint16_t left, uint16_t right) { return p.sample(left, right); }
bool AudioPulseAudio::init() { return p.init(); }
void AudioPulseAudio::term() { p.term(); }
AudioPulseAudio::AudioPulseAudio() : p(*new pAudioPulseAudio(*this)) {}
AudioPulseAudio::~AudioPulseAudio() { delete &p; }
} //namespace ruby };

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