mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-26 18:19:12 +02:00
Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
7b0e484c18 |
53
src/Makefile
53
src/Makefile
@@ -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 ""
|
||||||
|
|
||||||
|
@@ -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"
|
||||||
|
|
||||||
|
@@ -30,6 +30,7 @@ public:
|
|||||||
HiROM,
|
HiROM,
|
||||||
ExLoROM,
|
ExLoROM,
|
||||||
ExHiROM,
|
ExHiROM,
|
||||||
|
SuperFXROM,
|
||||||
SA1ROM,
|
SA1ROM,
|
||||||
SPC7110ROM,
|
SPC7110ROM,
|
||||||
BSCLoROM,
|
BSCLoROM,
|
||||||
|
@@ -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);
|
if(info.ram_size == 1024) info.ram_size = 0; //no RAM present, eg RamSize == 0
|
||||||
} else {
|
|
||||||
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)) {
|
||||||
|
@@ -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
|
||||||
|
@@ -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"
|
||||||
|
@@ -36,5 +36,5 @@ void DSP3::write(unsigned addr, uint8 data) {
|
|||||||
DSP3i::dsp3_byte = data;
|
DSP3i::dsp3_byte = data;
|
||||||
DSP3i::DSP3SetByte();
|
DSP3i::DSP3SetByte();
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
};
|
||||||
|
@@ -56,5 +56,5 @@ void DSP4::write(unsigned addr, uint8 data) {
|
|||||||
DSP4i::DSP4SetByte();
|
DSP4i::DSP4SetByte();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
};
|
||||||
|
@@ -75,4 +75,3 @@ OBC1::OBC1() {}
|
|||||||
OBC1::~OBC1() {}
|
OBC1::~OBC1() {}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
|
||||||
}
|
|
||||||
|
@@ -315,4 +315,3 @@ SA1::SA1() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -158,5 +158,5 @@ SDD1::SDD1() {
|
|||||||
SDD1::~SDD1() {
|
SDD1::~SDD1() {
|
||||||
delete[] buffer.data;
|
delete[] buffer.data;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
};
|
||||||
|
@@ -63,4 +63,3 @@ void SuperGameBoy::reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -25,4 +25,3 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern SuperGameBoy sgb;
|
extern SuperGameBoy sgb;
|
||||||
|
|
||||||
|
@@ -674,4 +674,3 @@ SPC7110::SPC7110() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -229,4 +229,3 @@ SRTC::SRTC() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -88,5 +88,5 @@ void ST010::write(unsigned addr, uint8 data) {
|
|||||||
ram[0x0021] &= ~0x80;
|
ram[0x0021] &= ~0x80;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
};
|
||||||
|
92
src/chip/superfx/bus/bus.cpp
Normal file
92
src/chip/superfx/bus/bus.cpp
Normal 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
|
27
src/chip/superfx/bus/bus.hpp
Normal file
27
src/chip/superfx/bus/bus.hpp
Normal 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);
|
||||||
|
};
|
121
src/chip/superfx/core/core.cpp
Normal file
121
src/chip/superfx/core/core.cpp
Normal 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
|
93
src/chip/superfx/core/core.hpp
Normal file
93
src/chip/superfx/core/core.hpp
Normal 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();
|
270
src/chip/superfx/core/opcode_table.cpp
Normal file
270
src/chip/superfx/core/opcode_table.cpp
Normal 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
|
661
src/chip/superfx/core/opcodes.cpp
Normal file
661
src/chip/superfx/core/opcodes.cpp
Normal 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 = ®s.r[n];
|
||||||
|
} else {
|
||||||
|
regs.r[n] = regs.sr();
|
||||||
|
regs.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//$20-2f: with rN
|
||||||
|
template<int n> void SuperFX::op_with_r() {
|
||||||
|
regs.sreg = ®s.r[n];
|
||||||
|
regs.dreg = ®s.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 = ®s.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
|
177
src/chip/superfx/core/registers.hpp
Normal file
177
src/chip/superfx/core/registers.hpp
Normal 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];
|
275
src/chip/superfx/disasm/disasm.cpp
Normal file
275
src/chip/superfx/disasm/disasm.cpp
Normal 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
|
5
src/chip/superfx/disasm/disasm.hpp
Normal file
5
src/chip/superfx/disasm/disasm.hpp
Normal 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);
|
67
src/chip/superfx/memory/memory.cpp
Normal file
67
src/chip/superfx/memory/memory.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
9
src/chip/superfx/memory/memory.hpp
Normal file
9
src/chip/superfx/memory/memory.hpp
Normal 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();
|
118
src/chip/superfx/mmio/mmio.cpp
Normal file
118
src/chip/superfx/mmio/mmio.cpp
Normal 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
|
2
src/chip/superfx/mmio/mmio.hpp
Normal file
2
src/chip/superfx/mmio/mmio.hpp
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
uint8_t mmio_read(unsigned addr);
|
||||||
|
void mmio_write(unsigned addr, uint8_t data);
|
61
src/chip/superfx/superfx.cpp
Normal file
61
src/chip/superfx/superfx.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
20
src/chip/superfx/superfx.hpp
Normal file
20
src/chip/superfx/superfx.hpp
Normal 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;
|
72
src/chip/superfx/timing/timing.cpp
Normal file
72
src/chip/superfx/timing/timing.cpp
Normal 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;
|
||||||
|
}
|
18
src/chip/superfx/timing/timing.hpp
Normal file
18
src/chip/superfx/timing/timing.hpp
Normal 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();
|
@@ -48,4 +48,3 @@ CPUcore::CPUcore() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -138,4 +138,3 @@ void CPUcore::update_table() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -15,5 +15,5 @@ CPU::CPU() {
|
|||||||
|
|
||||||
CPU::~CPU() {
|
CPU::~CPU() {
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
};
|
||||||
|
@@ -270,4 +270,4 @@ void sCPU::dma_reset() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //ifdef SCPU_CPP
|
#endif
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
@@ -534,4 +534,4 @@ void sCPU::mmio_write(unsigned addr, uint8 data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //ifdef SCPU_CPP
|
#endif
|
||||||
|
@@ -96,5 +96,5 @@ sCPU::sCPU() {
|
|||||||
|
|
||||||
sCPU::~sCPU() {
|
sCPU::~sCPU() {
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
};
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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();
|
||||||
|
@@ -5,15 +5,19 @@
|
|||||||
|
|
||||||
<h1>bsnes™ Usage Documentation</h1><br>
|
<h1>bsnes™ 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>
|
||||||
• Andreas Naive<br>
|
• Andreas Naive<br>
|
||||||
• anomie<br>
|
• anomie<br>
|
||||||
|
• _Demo_<br>
|
||||||
• Derrick Sobodash<br>
|
• Derrick Sobodash<br>
|
||||||
• DMV27<br>
|
• DMV27<br>
|
||||||
• FirebrandX<br>
|
• FirebrandX<br>
|
||||||
|
@@ -591,4 +591,3 @@ aDSP::aDSP() {}
|
|||||||
aDSP::~aDSP() {}
|
aDSP::~aDSP() {}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -59,4 +59,4 @@ void sDSP::brr_decode(voice_t &v) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //ifdef SDSP_CPP
|
#endif
|
||||||
|
@@ -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
|
||||||
|
@@ -132,4 +132,4 @@ void sDSP::echo_30() {
|
|||||||
echo_write(1);
|
echo_write(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //ifdef SDSP_CPP
|
#endif
|
||||||
|
@@ -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
|
||||||
|
@@ -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
|
||||||
|
@@ -32,4 +32,4 @@ void sDSP::misc_30() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //ifdef SDSP_CPP
|
#endif
|
||||||
|
@@ -326,4 +326,3 @@ sDSP::~sDSP() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
@@ -28,4 +28,3 @@ namespace SNES {
|
|||||||
#include "chip/chip.hpp"
|
#include "chip/chip.hpp"
|
||||||
#include "cartridge/cartridge.hpp"
|
#include "cartridge/cartridge.hpp"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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();
|
||||||
|
@@ -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() {
|
||||||
|
@@ -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();
|
||||||
|
@@ -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
|
}
|
||||||
|
@@ -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
|
||||||
|
@@ -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;
|
||||||
} else {
|
unsigned rwidth = line[y];
|
||||||
snes_ntsc_blit_hires(ntsc, in, (pitch >> 1), line_burst, out_width, height, out, outpitch);
|
while(y + rheight < height && rwidth == line[y + rheight]) rheight++;
|
||||||
}
|
|
||||||
if(l >= out_height) break;
|
if(rwidth == 256) {
|
||||||
run_width = line[l];
|
snes_ntsc_blit (ntsc, in, pitch, line_burst, rwidth, rheight, out, outpitch << 2);
|
||||||
run_start = l;
|
} else {
|
||||||
|
snes_ntsc_blit_hires(ntsc, in, pitch, line_burst, rwidth, rheight, out, outpitch << 2);
|
||||||
}
|
}
|
||||||
l++;
|
|
||||||
|
line_burst = (line_burst + rheight) % 3;
|
||||||
|
y += rheight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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();
|
||||||
|
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
@@ -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;
|
||||||
|
@@ -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;
|
|
||||||
}
|
}
|
||||||
|
@@ -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
54
src/lib/nall/Makefile-qt
Normal 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
|
@@ -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
|
|
@@ -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
|
||||||
|
114
src/lib/nall/string/base.hpp
Normal file
114
src/lib/nall/string/base.hpp
Normal 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
|
25
src/lib/nall/string/cast.hpp
Normal file
25
src/lib/nall/string/cast.hpp
Normal 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
|
@@ -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;
|
@@ -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;
|
@@ -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
|
@@ -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;
|
@@ -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";
|
@@ -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
|
@@ -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
|
@@ -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
|
||||||
|
|
@@ -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;
|
@@ -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);
|
@@ -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>
|
||||||
|
@@ -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() {}
|
||||||
|
@@ -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
|
};
|
||||||
|
@@ -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;
|
|
||||||
};
|
|
@@ -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
|
};
|
||||||
|
@@ -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;
|
|
||||||
};
|
|
@@ -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
|
};
|
||||||
|
@@ -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;
|
|
||||||
};
|
|
@@ -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
|
};
|
||||||
|
@@ -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;
|
|
||||||
};
|
|
@@ -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
|
};
|
||||||
|
@@ -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;
|
|
||||||
};
|
|
@@ -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
Reference in New Issue
Block a user