mirror of
https://github.com/bsnes-emu/bsnes.git
synced 2025-09-26 09:39:07 +02:00
Compare commits
12 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
9133129209 | ||
|
7d83cde40a | ||
|
bbc77a6cf2 | ||
|
ebb9367c68 | ||
|
96fe8f760d | ||
|
8abd1b2dfe | ||
|
f6efcbe6fd | ||
|
36859ea52c | ||
|
64589148d4 | ||
|
89ae1101ee | ||
|
340d86845a | ||
|
b895f29bed |
@@ -66,7 +66,8 @@ such software.
|
||||
libco, author: byuu
|
||||
libui, author: byuu
|
||||
OBC-1 emu, author: byuu
|
||||
S-DD1 emu, author: Andreas Naive
|
||||
S-DD1 decompressor, author: Andreas Naive
|
||||
SPC7110 decompressor, author: neviksti
|
||||
S-RTC emu, author: byuu
|
||||
|
||||
Any software listed above as exemptions may be relicensed individually from
|
||||
|
52
readme.txt
52
readme.txt
@@ -1,10 +1,10 @@
|
||||
bsnes
|
||||
Version: 0.031
|
||||
Version: 0.033
|
||||
Author: byuu
|
||||
|
||||
--------
|
||||
========
|
||||
General:
|
||||
--------
|
||||
========
|
||||
bsnes is a Super Nintendo / Super Famicom emulator that began on
|
||||
October 14th, 2004.
|
||||
|
||||
@@ -13,9 +13,32 @@ http://byuu.org/
|
||||
|
||||
Please see license.txt for important licensing information.
|
||||
|
||||
------------------
|
||||
==============
|
||||
Configuration:
|
||||
==============
|
||||
bsnes has two configuration files: bsnes.cfg, for program settings; and
|
||||
locale.cfg, for localization.
|
||||
|
||||
For each file, bsnes will start by looking inside the same folder where the
|
||||
bsnes executable is located. If said file is not found, it will then check your
|
||||
user profile folder. On Windows, this is located at "%APPDATA%/.bsnes". On all
|
||||
other operating systems, this is located at "~/.bsnes". If said file is still
|
||||
not found, it will automatically be created in your user profile folder.
|
||||
|
||||
If you wish to use bsnes in single-user mode, be sure that both files exist
|
||||
inside the same folder as the bsnes executable. If they do not, you can simply
|
||||
create new blank files and bsnes will use them in the future.
|
||||
|
||||
If you wish to use bsnes in multi-user mode, simply delete these two files from
|
||||
the bsnes executable directory if they exist.
|
||||
|
||||
If you wish to have multiple configuration profiles for the same user, you will
|
||||
need to make copies of the bsnes executable, and use each one in single-user
|
||||
mode.
|
||||
|
||||
==================
|
||||
Known Limitations:
|
||||
------------------
|
||||
==================
|
||||
S-CPU
|
||||
- Multiply / divide register delays not implemented
|
||||
|
||||
@@ -33,9 +56,9 @@ Hardware Bugs
|
||||
- S-CPU.r1 HDMA crashing bug not emulated
|
||||
- S-CPU<>S-SMP communication bus conflicts not emulated
|
||||
|
||||
---------------------
|
||||
=====================
|
||||
Unsupported Hardware:
|
||||
---------------------
|
||||
=====================
|
||||
SA-1
|
||||
Coprocessor used in many popular games, including:
|
||||
- Dragon Ball Z Hyper Dimension
|
||||
@@ -52,25 +75,18 @@ Coprocessor used in many popular games, including:
|
||||
- Star Fox 2 (unreleased beta)
|
||||
- Super Mario World 2: Yoshi's Island
|
||||
|
||||
SPC7110
|
||||
Coprocessor used only by the following games:
|
||||
- Far East of Eden Zero
|
||||
- Far East of Eden Zero: Shounen Jump no Shou
|
||||
- Momotarou Densetsu Happy
|
||||
- Super Power League 4
|
||||
|
||||
ST-011
|
||||
SETA DSP used only by Quick-move Shogi Match with Nidan Rank-holder Morita
|
||||
SETA DSP used by Quick-move Shogi Match with Nidan Rank-holder Morita
|
||||
|
||||
ST-018
|
||||
SETA RISC CPU used only by Quick-move Shogi Match with Nidan Rank-holder Morita 2
|
||||
SETA RISC CPU used by Quick-move Shogi Match with Nidan Rank-holder Morita 2
|
||||
|
||||
Super Gameboy
|
||||
Cartridge passthrough used for playing Gameboy games
|
||||
|
||||
------------------------
|
||||
========================
|
||||
Unsupported Controllers:
|
||||
------------------------
|
||||
========================
|
||||
Mouse
|
||||
Super Scope
|
||||
Justifier
|
||||
|
10
src/Makefile
10
src/Makefile
@@ -11,7 +11,7 @@ ifneq ($(findstring gcc,$(compiler)),) # GCC family
|
||||
cpp = $(subst cc,++,$(compiler)) $(flags)
|
||||
obj = o
|
||||
rule = -c $< -o $@
|
||||
link =
|
||||
link = -s
|
||||
mkbin = -o$1
|
||||
mkdef = -D$1
|
||||
mklib = -l$1
|
||||
@@ -34,7 +34,7 @@ endif
|
||||
##########
|
||||
|
||||
ifeq ($(platform),x) # X11
|
||||
ruby = video.glx video.xv video.sdl audio.openal audio.oss audio.ao input.sdl input.x
|
||||
ruby = video.glx video.xv video.sdl audio.openal audio.oss audio.alsa audio.ao input.sdl input.x
|
||||
link += `pkg-config --libs gtk+-2.0`
|
||||
link += $(call mklib,Xtst)
|
||||
delete = rm -f $1
|
||||
@@ -66,6 +66,7 @@ link += $(if $(findstring video.directdraw,$(ruby)),$(call mklib,ddraw))
|
||||
link += $(if $(findstring video.glx,$(ruby)),$(call mklib,GL))
|
||||
link += $(if $(findstring video.wgl,$(ruby)),$(call mklib,opengl32))
|
||||
link += $(if $(findstring video.xv,$(ruby)),$(call mklib,Xv))
|
||||
link += $(if $(findstring audio.alsa,$(ruby)),$(call mklib,asound))
|
||||
link += $(if $(findstring audio.ao,$(ruby)),$(call mklib,ao))
|
||||
link += $(if $(findstring audio.directsound,$(ruby)),$(call mklib,dsound))
|
||||
link += $(if $(findstring audio.openal,$(ruby)),$(if $(call streq,$(platform),x),$(call mklib,openal),$(call mklib,openal32)))
|
||||
@@ -78,7 +79,7 @@ link += $(if $(findstring input.sdl,$(ruby)),`sdl-config --libs`)
|
||||
|
||||
objects = main libco hiro ruby libfilter string reader cart cheat \
|
||||
memory smemory cpu scpu smp ssmp sdsp ppu bppu snes \
|
||||
bsx srtc sdd1 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010
|
||||
bsx srtc sdd1 spc7110 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010
|
||||
|
||||
ifeq ($(enable_gzip),true)
|
||||
objects += adler32 compress crc32 deflate gzio inffast inflate inftrees ioapi trees unzip zip zutil
|
||||
@@ -198,13 +199,14 @@ obj/snes.$(obj): snes/snes.cpp snes/* snes/scheduler/* snes/video/* snes/audio/*
|
||||
obj/bsx.$(obj) : chip/bsx/bsx.cpp chip/bsx/*
|
||||
obj/srtc.$(obj) : chip/srtc/srtc.cpp chip/srtc/*
|
||||
obj/sdd1.$(obj) : chip/sdd1/sdd1.cpp chip/sdd1/*
|
||||
obj/spc7110.$(obj): chip/spc7110/spc7110.cpp chip/spc7110/*
|
||||
obj/cx4.$(obj) : chip/cx4/cx4.cpp chip/cx4/*
|
||||
obj/dsp1.$(obj) : chip/dsp1/dsp1.cpp chip/dsp1/*
|
||||
obj/dsp2.$(obj) : chip/dsp2/dsp2.cpp chip/dsp2/*
|
||||
obj/dsp3.$(obj) : chip/dsp3/dsp3.cpp chip/dsp3/*
|
||||
obj/dsp4.$(obj) : chip/dsp4/dsp4.cpp chip/dsp4/*
|
||||
obj/obc1.$(obj) : chip/obc1/obc1.cpp chip/obc1/*
|
||||
obj/st010.$(obj): chip/st010/st010.cpp chip/st010/*
|
||||
obj/st010.$(obj) : chip/st010/st010.cpp chip/st010/*
|
||||
|
||||
############
|
||||
### zlib ###
|
||||
|
@@ -1,4 +1,4 @@
|
||||
#define BSNES_VERSION "0.031"
|
||||
#define BSNES_VERSION "0.033"
|
||||
#define BSNES_TITLE "bsnes v" BSNES_VERSION
|
||||
|
||||
#define BUSCORE sBus
|
||||
|
@@ -13,7 +13,7 @@
|
||||
#include "cart_header.cpp"
|
||||
|
||||
namespace memory {
|
||||
MappedRAM cartrom, cartram;
|
||||
MappedRAM cartrom, cartram, cartrtc;
|
||||
MappedRAM bscram;
|
||||
MappedRAM stArom, stAram;
|
||||
MappedRAM stBrom, stBram;
|
||||
@@ -27,12 +27,12 @@ Cartridge::Region Cartridge::region() { return info.region; }
|
||||
bool Cartridge::loaded() { return cart.loaded; }
|
||||
|
||||
void Cartridge::load_begin(CartridgeType cart_type) {
|
||||
cart.rom = cart.ram = 0;
|
||||
cart.rom = cart.ram = cart.rtc = 0;
|
||||
bs.ram = 0;
|
||||
stA.rom = stA.ram = 0;
|
||||
stB.rom = stB.ram = 0;
|
||||
|
||||
cart.rom_size = cart.ram_size = 0;
|
||||
cart.rom_size = cart.ram_size = cart.rtc_size = 0;
|
||||
bs.ram_size = 0;
|
||||
stA.rom_size = stA.ram_size = 0;
|
||||
stB.rom_size = stB.ram_size = 0;
|
||||
@@ -46,9 +46,10 @@ void Cartridge::load_begin(CartridgeType cart_type) {
|
||||
|
||||
info.superfx = false;
|
||||
info.sa1 = false;
|
||||
info.spc7110 = false;
|
||||
info.srtc = false;
|
||||
info.sdd1 = false;
|
||||
info.spc7110 = false;
|
||||
info.spc7110rtc = false;
|
||||
info.cx4 = false;
|
||||
info.dsp1 = false;
|
||||
info.dsp2 = false;
|
||||
@@ -73,6 +74,7 @@ void Cartridge::load_begin(CartridgeType cart_type) {
|
||||
void Cartridge::load_end() {
|
||||
memory::cartrom.map(cart.rom, cart.rom_size);
|
||||
memory::cartram.map(cart.ram, cart.ram_size);
|
||||
memory::cartrtc.map(cart.rtc, cart.rtc_size);
|
||||
memory::bscram.map(bs.ram, bs.ram_size);
|
||||
memory::stArom.map(stA.rom, stA.rom_size);
|
||||
memory::stAram.map(stA.ram, stA.ram_size);
|
||||
@@ -108,13 +110,14 @@ bool Cartridge::unload() {
|
||||
case CartridgeSufamiTurbo: unload_cart_st(); break;
|
||||
}
|
||||
|
||||
safe_free(cart.rom);
|
||||
safe_free(cart.ram);
|
||||
safe_free(bs.ram);
|
||||
safe_free(stA.rom);
|
||||
safe_free(stA.ram);
|
||||
safe_free(stB.rom);
|
||||
safe_free(stB.ram);
|
||||
if(cart.rom) { delete[] cart.rom; cart.rom = 0; }
|
||||
if(cart.ram) { delete[] cart.ram; cart.ram = 0; }
|
||||
if(cart.rtc) { delete[] cart.rtc; cart.rtc = 0; }
|
||||
if(bs.ram) { delete[] bs.ram; bs.ram = 0; }
|
||||
if(stA.rom) { delete[] stA.rom; stA.rom = 0; }
|
||||
if(stA.ram) { delete[] stA.ram; stA.ram = 0; }
|
||||
if(stB.rom) { delete[] stB.rom; stB.rom = 0; }
|
||||
if(stB.ram) { delete[] stB.ram; stB.ram = 0; }
|
||||
|
||||
char fn[PATH_MAX];
|
||||
strcpy(fn, cart.fn);
|
||||
|
@@ -32,6 +32,7 @@ public:
|
||||
HiROM,
|
||||
ExLoROM,
|
||||
ExHiROM,
|
||||
SPC7110ROM,
|
||||
BSXROM,
|
||||
BSCLoROM,
|
||||
BSCHiROM,
|
||||
@@ -48,8 +49,8 @@ public:
|
||||
struct {
|
||||
bool loaded;
|
||||
char fn[PATH_MAX];
|
||||
uint8 *rom, *ram;
|
||||
uint rom_size, ram_size;
|
||||
uint8 *rom, *ram, *rtc;
|
||||
uint rom_size, ram_size, rtc_size;
|
||||
} cart;
|
||||
|
||||
struct {
|
||||
@@ -85,6 +86,7 @@ public:
|
||||
bool srtc;
|
||||
bool sdd1;
|
||||
bool spc7110;
|
||||
bool spc7110rtc;
|
||||
bool cx4;
|
||||
bool dsp1;
|
||||
bool dsp2;
|
||||
@@ -143,11 +145,12 @@ public:
|
||||
private:
|
||||
char patchfn[PATH_MAX];
|
||||
char savefn[PATH_MAX];
|
||||
char rtcfn[PATH_MAX];
|
||||
char cheatfn[PATH_MAX];
|
||||
};
|
||||
|
||||
namespace memory {
|
||||
extern MappedRAM cartrom, cartram;
|
||||
extern MappedRAM cartrom, cartram, cartrtc;
|
||||
extern MappedRAM bscram;
|
||||
extern MappedRAM stArom, stAram;
|
||||
extern MappedRAM stBrom, stBram;
|
||||
|
@@ -14,7 +14,7 @@ void Cartridge::load_cart_bsc(const char *base, const char *slot) {
|
||||
|
||||
if(load_file(get_patch_filename(cart.fn, "ups"), data, size, CompressionInspect) == true) {
|
||||
apply_patch(data, size, cart.rom, cart.rom_size);
|
||||
if(data) { free(data); data = 0; }
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
if(*bs.fn) {
|
||||
@@ -23,7 +23,7 @@ void Cartridge::load_cart_bsc(const char *base, const char *slot) {
|
||||
bs.ram = data, bs.ram_size = size;
|
||||
if(load_file(get_patch_filename(bs.fn, "ups"), data, size, CompressionInspect) == true) {
|
||||
apply_patch(data, size, bs.ram, bs.ram_size);
|
||||
if(data) { free(data); data = 0; }
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,12 +35,12 @@ void Cartridge::load_cart_bsc(const char *base, const char *slot) {
|
||||
info.region = NTSC;
|
||||
|
||||
if(info.ram_size > 0) {
|
||||
cart.ram = (uint8*)malloc(cart.ram_size = info.ram_size);
|
||||
cart.ram = new uint8_t[cart.ram_size = info.ram_size];
|
||||
memset(cart.ram, 0xff, cart.ram_size);
|
||||
|
||||
if(load_file(get_save_filename(cart.fn, "srm"), data, size, CompressionNone) == true) {
|
||||
memcpy(cart.ram, data, min(size, cart.ram_size));
|
||||
safe_free(data);
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,7 @@ void Cartridge::load_cart_bsx(const char *base, const char *slot) {
|
||||
|
||||
if(load_file(get_patch_filename(cart.fn, "ups"), data, size, CompressionInspect) == true) {
|
||||
apply_patch(data, size, cart.rom, cart.rom_size);
|
||||
if(data) { free(data); data = 0; }
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
memset(bsxcart.sram.handle (), 0x00, bsxcart.sram.size ());
|
||||
@@ -28,12 +28,12 @@ void Cartridge::load_cart_bsx(const char *base, const char *slot) {
|
||||
|
||||
if(load_file(get_save_filename(cart.fn, "srm"), data, size, CompressionNone) == true) {
|
||||
memcpy(bsxcart.sram.handle (), data, min(bsxcart.sram.size (), size));
|
||||
safe_free(data);
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
if(load_file(get_save_filename(cart.fn, "psr"), data, size, CompressionNone) == true) {
|
||||
memcpy(bsxcart.psram.handle(), data, min(bsxcart.psram.size(), size));
|
||||
safe_free(data);
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
if(*bs.fn) {
|
||||
@@ -42,7 +42,7 @@ void Cartridge::load_cart_bsx(const char *base, const char *slot) {
|
||||
bs.ram = data, bs.ram_size = size;
|
||||
if(load_file(get_patch_filename(bs.fn, "ups"), data, size, CompressionInspect) == true) {
|
||||
apply_patch(data, size, bs.ram, bs.ram_size);
|
||||
if(data) { free(data); data = 0; }
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -158,8 +158,8 @@ bool Cartridge::apply_patch(const uint8_t *pdata, const unsigned psize, uint8_t
|
||||
}
|
||||
|
||||
if(apply == true) {
|
||||
free(data);
|
||||
data = (uint8_t*)malloc(size = outsize);
|
||||
delete[] data;
|
||||
data = new uint8_t[size = outsize];
|
||||
memcpy(data, outdata, outsize);
|
||||
} else {
|
||||
dprintf("* Warning: patch application failed!");
|
||||
@@ -169,9 +169,10 @@ bool Cartridge::apply_patch(const uint8_t *pdata, const unsigned psize, uint8_t
|
||||
}
|
||||
|
||||
bool Cartridge::save_file(const char *fn, uint8 *data, uint size) {
|
||||
FileWriter ff(fn);
|
||||
if(!ff.ready())return false;
|
||||
ff.write(data, size);
|
||||
FILE *fp = fopen(fn, "wb");
|
||||
if(!fp) return false;
|
||||
fwrite(data, 1, size, fp);
|
||||
fclose(fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -52,8 +52,9 @@ void Cartridge::read_header() {
|
||||
}
|
||||
|
||||
if(mapper == 0x3a && (rom_type == 0xf5 || rom_type == 0xf9)) {
|
||||
//rom_type: 0xf5 = no S-RTC, 0xf9 = S-RTC
|
||||
info.spc7110 = true;
|
||||
info.spc7110rtc = (rom_type == 0xf9);
|
||||
info.mapper = SPC7110ROM;
|
||||
}
|
||||
|
||||
if(mapper == 0x20 && rom_type == 0xf3) {
|
||||
@@ -179,7 +180,7 @@ void Cartridge::find_header() {
|
||||
score_ex = 0;
|
||||
} else {
|
||||
if(rom[0x7fc0 + MAPPER] == 0x32) score_lo++;
|
||||
else score_ex += 16;
|
||||
else score_ex += 12;
|
||||
}
|
||||
|
||||
if(score_lo >= score_hi && score_lo >= score_ex) {
|
||||
|
@@ -12,17 +12,17 @@ void Cartridge::load_cart_normal(const char *filename) {
|
||||
|
||||
//load ROM data, ignore 512-byte header if detected
|
||||
if((size & 0x7fff) != 512) {
|
||||
cart.rom = (uint8*)malloc(cart.rom_size = size);
|
||||
cart.rom = new uint8_t[cart.rom_size = size];
|
||||
memcpy(cart.rom, data, size);
|
||||
} else {
|
||||
cart.rom = (uint8*)malloc(cart.rom_size = size - 512);
|
||||
cart.rom = new uint8_t[cart.rom_size = size - 512];
|
||||
memcpy(cart.rom, data + 512, size - 512);
|
||||
}
|
||||
safe_free(data);
|
||||
delete[] data;
|
||||
|
||||
if(load_file(get_patch_filename(cart.fn, "ups"), data, size, CompressionInspect) == true) {
|
||||
apply_patch(data, size, cart.rom, cart.rom_size);
|
||||
if(data) { free(data); data = 0; }
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
info.crc32 = crc32_calculate(cart.rom, cart.rom_size);
|
||||
@@ -31,12 +31,20 @@ void Cartridge::load_cart_normal(const char *filename) {
|
||||
read_header();
|
||||
|
||||
if(info.ram_size > 0) {
|
||||
cart.ram = (uint8*)malloc(cart.ram_size = info.ram_size);
|
||||
cart.ram = new uint8_t[cart.ram_size = info.ram_size];
|
||||
memset(cart.ram, 0xff, cart.ram_size);
|
||||
|
||||
if(load_file(get_save_filename(cart.fn, "srm"), data, size, CompressionNone) == true) {
|
||||
memcpy(cart.ram, data, min(size, cart.ram_size));
|
||||
safe_free(data);
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
|
||||
if(info.srtc || info.spc7110rtc) {
|
||||
cart.rtc = new(zeromemory) uint8_t[cart.rtc_size = 20];
|
||||
if(load_file(get_save_filename(cart.fn, "rtc"), data, size, CompressionNone) == true) {
|
||||
memcpy(cart.rtc, data, min(size, cart.rtc_size));
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +57,7 @@ void Cartridge::load_cart_normal(const char *filename) {
|
||||
|
||||
void Cartridge::unload_cart_normal() {
|
||||
if(cart.ram) save_file(get_save_filename(cart.fn, "srm"), cart.ram, cart.ram_size);
|
||||
if(cart.rtc) save_file(get_save_filename(cart.fn, "rtc"), cart.rtc, cart.rtc_size);
|
||||
}
|
||||
|
||||
#endif //ifdef CART_CPP
|
||||
|
@@ -15,51 +15,51 @@ void Cartridge::load_cart_st(const char *base, const char *slotA, const char *sl
|
||||
uint8_t *data = 0;
|
||||
unsigned size;
|
||||
if(load_file(cart.fn, data, size, CompressionAuto) == true) {
|
||||
cart.rom = (uint8*)malloc(cart.rom_size = 0x040000);
|
||||
cart.rom = new(zeromemory) uint8_t[cart.rom_size = 0x040000];
|
||||
memcpy(cart.rom, data, min(size, cart.rom_size));
|
||||
safe_free(data);
|
||||
delete[] data;
|
||||
if(load_file(get_patch_filename(cart.fn, "ups"), data, size, CompressionInspect) == true) {
|
||||
apply_patch(data, size, cart.rom, cart.rom_size);
|
||||
if(data) { free(data); data = 0; }
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
|
||||
if(*stA.fn) {
|
||||
if(load_file(stA.fn, data, size, CompressionAuto) == true) {
|
||||
stA.rom = (uint8*)malloc(stA.rom_size = 0x100000);
|
||||
stA.rom = new(zeromemory) uint8_t[stA.rom_size = 0x100000];
|
||||
memcpy(stA.rom, data, min(size, stA.rom_size));
|
||||
safe_free(data);
|
||||
delete[] data;
|
||||
if(load_file(get_patch_filename(stA.fn, "ups"), data, size, CompressionInspect) == true) {
|
||||
apply_patch(data, size, stA.rom, stA.rom_size);
|
||||
if(data) { free(data); data = 0; }
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
stA.ram = (uint8*)malloc(stA.ram_size = 0x020000);
|
||||
stA.ram = new uint8_t[stA.ram_size = 0x020000];
|
||||
memset(stA.ram, 0xff, stA.ram_size);
|
||||
|
||||
if(load_file(get_save_filename(stA.fn, "srm"), data, size, CompressionNone) == true) {
|
||||
memcpy(stA.ram, data, min(size, 0x020000U));
|
||||
safe_free(data);
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(*stB.fn) {
|
||||
if(load_file(stB.fn, data, size, CompressionAuto) == true) {
|
||||
stB.rom = (uint8*)malloc(stB.rom_size = 0x100000);
|
||||
stB.rom = new(zeromemory) uint8_t[stB.rom_size = 0x100000];
|
||||
memcpy(stB.rom, data, min(size, stB.rom_size));
|
||||
safe_free(data);
|
||||
delete[] data;
|
||||
if(load_file(get_patch_filename(stB.fn, "ups"), data, size, CompressionInspect) == true) {
|
||||
apply_patch(data, size, stB.rom, stB.rom_size);
|
||||
if(data) { free(data); data = 0; }
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
stB.ram = (uint8*)malloc(stB.ram_size = 0x020000);
|
||||
stB.ram = new uint8_t[stB.ram_size = 0x020000];
|
||||
memset(stB.ram, 0xff, stB.ram_size);
|
||||
|
||||
if(load_file(get_save_filename(stB.fn, "srm"), data, size, CompressionNone) == true) {
|
||||
memcpy(stB.ram, data, min(size, 0x020000U));
|
||||
safe_free(data);
|
||||
delete[] data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@ void BSXCart::reset() {
|
||||
}
|
||||
|
||||
void BSXCart::update_memory_map() {
|
||||
Memory &cart = (regs.r[0x01] & 0x80) == 0x00 ? (Memory&)bsxflash : (Memory&)psram;
|
||||
Memory &cart = (regs.r[0x01] & 0x80) == 0x00 ? (Memory&)bsxflash : (Memory&)psram;
|
||||
|
||||
if((regs.r[0x02] & 0x80) == 0x00) { //LoROM mapping
|
||||
bus.map(Bus::MapLinear, 0x00, 0x7d, 0x8000, 0xffff, cart);
|
||||
@@ -84,16 +84,16 @@ void BSXCart::mmio_write(uint addr, uint8 data) {
|
||||
}
|
||||
|
||||
BSXCart::BSXCart() {
|
||||
sram_data = (uint8*)malloc( 32 * 1024);
|
||||
psram_data = (uint8*)malloc(512 * 1024);
|
||||
sram_data = new uint8_t[ 32 * 1024];
|
||||
psram_data = new uint8_t[512 * 1024];
|
||||
|
||||
sram.map (sram_data, 32 * 1024);
|
||||
psram.map(psram_data, 512 * 1024);
|
||||
}
|
||||
|
||||
BSXCart::~BSXCart() {
|
||||
safe_free(sram_data);
|
||||
safe_free(psram_data);
|
||||
delete[] sram_data;
|
||||
delete[] psram_data;
|
||||
}
|
||||
|
||||
#endif //ifdef BSX_CPP
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#include "bsx/bsx.h"
|
||||
#include "srtc/srtc.h"
|
||||
#include "sdd1/sdd1.h"
|
||||
#include "spc7110/spc7110.h"
|
||||
#include "cx4/cx4.h"
|
||||
#include "dsp1/dsp1.h"
|
||||
#include "dsp2/dsp2.h"
|
||||
|
697
src/chip/spc7110/codec.cpp
Normal file
697
src/chip/spc7110/codec.cpp
Normal file
@@ -0,0 +1,697 @@
|
||||
const uint8_t SPC7110Codec::EvolutionTable[53][4] = {
|
||||
//prob, nextlps, nextmps, toggle invert
|
||||
{0x5a, 1, 1,1}, //0 l,m
|
||||
{0x25, 6, 2,0}, //1 l,m
|
||||
{0x11, 8, 3,0}, //2 l,m
|
||||
{0x08, 10, 4,0}, //3 ,m
|
||||
{0x03, 12, 5,0}, //4 ,m
|
||||
{0x01, 15, 5,0}, //5 ,m
|
||||
|
||||
{0x5a, 7, 7,1}, //6 l,
|
||||
{0x3f, 19, 8,0}, //7 l,m
|
||||
{0x2c, 21, 9,0}, //8 l,m
|
||||
{0x20, 22, 10,0}, //9 ,m
|
||||
{0x17, 23, 11,0}, //10 ,m
|
||||
{0x11, 25, 12,0}, //11 ,m
|
||||
{0x0c, 26, 13,0}, //12 ,m
|
||||
{0x09, 28, 14,0}, //13 ,m
|
||||
{0x07, 29, 15,0}, //14 ,m
|
||||
{0x05, 31, 16,0}, //15 ,m
|
||||
{0x04, 32, 17,0}, //16 ,m
|
||||
{0x03, 34, 18,0}, //17 ,m
|
||||
{0x02, 35, 5,0}, //18 ,m
|
||||
|
||||
{0x5a, 20, 20,1}, //19 l,m
|
||||
{0x48, 39, 21,0}, //20 l,m
|
||||
{0x3a, 40, 22,0}, //21 l,m
|
||||
{0x2e, 42, 23,0}, //22 l,m
|
||||
{0x26, 44, 24,0}, //23 l,m
|
||||
{0x1f, 45, 25,0}, //24 l,m
|
||||
{0x19, 46, 26,0}, //25 l,m
|
||||
{0x15, 25, 27,0}, //26 l,m
|
||||
{0x11, 26, 28,0}, //27 l,m
|
||||
{0x0e, 26, 29,0}, //28 l,m
|
||||
{0x0b, 27, 30,0}, //29 ,m
|
||||
{0x09, 28, 31,0}, //30 ,m
|
||||
{0x08, 29, 32,0}, //31 l,m
|
||||
{0x07, 30, 33,0}, //32 l,m
|
||||
{0x05, 31, 34,0}, //33 l,m <--- changed lps
|
||||
{0x04, 33, 35,0}, //34 ,m ... this is NOT skipped
|
||||
{0x04, 33, 36,0}, //35 ,m
|
||||
{0x03, 34, 37,0}, //36 ,m
|
||||
{0x02, 35, 38,0}, //37 ,m ... this is NOT skipped
|
||||
{0x02, 36, 5,0}, //38 ,m
|
||||
|
||||
{0x58, 39, 40,1}, //39 l,m
|
||||
{0x4d, 47, 41,0}, //40 l,m
|
||||
{0x43, 48, 42,0}, //41 ,m
|
||||
{0x3b, 49, 43,0}, //42 ,m
|
||||
{0x34, 50, 44,0}, //43 l,m
|
||||
{0x2e, 51, 45,0}, //44 l,m
|
||||
{0x29, 44, 46,0}, //45 l,m
|
||||
{0x25, 45, 24,0}, //46 ,m
|
||||
|
||||
{0x56, 47, 48,1}, //47 l,m
|
||||
{0x4f, 47, 49,0}, //48 l,m
|
||||
{0x47, 48, 50,0}, //49 l,m
|
||||
{0x41, 49, 51,0}, //50 l,m
|
||||
{0x3c, 50, 52,0}, //51 l,m
|
||||
{0x37, 51, 43,0} //52 ,m
|
||||
};
|
||||
|
||||
const uint8_t SPC7110Codec::Mode2ContextTable[32][4] = {
|
||||
// "bit" = (lps^invert)
|
||||
//next_0, use ref pixel, next_1, use ref pixel
|
||||
// if use ref pixel, then add on the 0-4 bell number grouping
|
||||
{1, 0, 2, 0}, //0
|
||||
|
||||
{3, 1, 8, 1}, //1 prev bit 0
|
||||
{13,0, 14,0}, //2 prev bit 1
|
||||
|
||||
{15,0, 16,0}, //3 prev bit 00
|
||||
{17,0, 18,0}, //4
|
||||
{19,0, 20,0}, //5
|
||||
{21,0, 22,0}, //6
|
||||
{23,0, 24,0}, //7
|
||||
{25,0, 26,0}, //8 prev bit 01
|
||||
{25,0, 26,0}, //9
|
||||
{25,0, 26,0}, //10
|
||||
{25,0, 26,0}, //11
|
||||
{25,0, 26,0}, //12
|
||||
{27,0, 28,0}, //13 prev bit 10
|
||||
{29,0, 30,0}, //14 prev bit 11
|
||||
|
||||
{31,0, 31,0}, //15 000 ref group 0
|
||||
{31,0, 31,0}, //16 001 ref group 0
|
||||
{31,0, 31,0}, //17 000 ref group 1
|
||||
{31,0, 31,0}, //18 001 ref group 1
|
||||
{31,0, 31,0}, //19 000 ref group 2
|
||||
{31,0, 31,0}, //20 001 ref group 2
|
||||
{31,0, 31,0}, //21 000 ref group 3
|
||||
{31,0, 31,0}, //22 001 ref group 3
|
||||
{31,0, 31,0}, //23 000 ref group 4
|
||||
{31,0, 31,0}, //24 001 ref group 4
|
||||
{31,0, 31,0}, //25 010
|
||||
{31,0, 31,0}, //26 011
|
||||
{31,0, 31,0}, //27 100
|
||||
{31,0, 31,0}, //28 101
|
||||
{31,0, 31,0}, //29 110
|
||||
{31,0, 31,0}, //30 111
|
||||
|
||||
{31,0, 31,0} //31 -- used as a trap for testing purposes --
|
||||
};
|
||||
|
||||
#define PROB(x) EvolutionTable[Contexts[x].index][0]
|
||||
#define NEXT_LPS(x) EvolutionTable[Contexts[x].index][1]
|
||||
#define NEXT_MPS(x) EvolutionTable[Contexts[x].index][2]
|
||||
#define TOGGLE_INVERT(x) EvolutionTable[Contexts[x].index][3]
|
||||
#define BIT(x,y) ((x>>y)&1)
|
||||
|
||||
void SPC7110Codec::decomp_mode0(int len) {
|
||||
uint8_t *datain = buffer;
|
||||
uint8_t *dataout = output;
|
||||
static const unsigned NUM_CONTEXTS = 30;
|
||||
|
||||
uint8 top,val;
|
||||
uint8 con,mps,prob;
|
||||
uint8 flag_lps,shift,mask;
|
||||
|
||||
int out=0;
|
||||
int inverts=0;
|
||||
int lps=0;
|
||||
|
||||
unsigned char in;
|
||||
int in_count;
|
||||
|
||||
int i,bit;
|
||||
|
||||
//setup
|
||||
top=0xFF;
|
||||
|
||||
val=*datain;
|
||||
datain++;
|
||||
|
||||
in=*datain;
|
||||
datain++;
|
||||
in_count=8;
|
||||
|
||||
//reset context states
|
||||
for(i=0;i<NUM_CONTEXTS;i++)
|
||||
{
|
||||
Contexts[i].index=0;
|
||||
Contexts[i].invert=0;
|
||||
}
|
||||
|
||||
for(i=0;i<len;i++)
|
||||
{
|
||||
if(i==-1800)
|
||||
{
|
||||
int k;
|
||||
printf("\nEvolution table:\n");
|
||||
//for(k=0;k<53;k++)
|
||||
//printf(" %d,%d //%d\n",SeenEvolution[k][0],SeenEvolution[k][1],k);
|
||||
}
|
||||
|
||||
|
||||
for(bit=0;bit<8;bit++)
|
||||
{
|
||||
//get context
|
||||
mask = (1<<(bit&3)) - 1;
|
||||
con = mask + ((inverts&mask)^(lps&mask));
|
||||
if(bit>3)
|
||||
con+=15;
|
||||
|
||||
//get PROB and MPS
|
||||
prob = PROB(con);
|
||||
mps = (BIT(out,15) ^ Contexts[con].invert);
|
||||
|
||||
if(i>=15 && i<=18 && 0)
|
||||
printf("byte %d bit %d: val=%.2X top=%.2X prob=%.2X mps=%d con=%d state=%d\n",
|
||||
i,bit,val,top,prob,mps,con,Contexts[con].index);
|
||||
|
||||
//get bit
|
||||
if (val <= top-prob)
|
||||
{
|
||||
//mps
|
||||
top = top - prob;
|
||||
out = (out << 1) + mps;
|
||||
|
||||
flag_lps=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//lps
|
||||
val = val - (top - (prob - 1));
|
||||
top = prob - 1;
|
||||
out = (out << 1) + 1-mps;
|
||||
|
||||
flag_lps=1;
|
||||
}
|
||||
|
||||
// renormalize
|
||||
shift=0;
|
||||
while(top<0x7F) // NOTE: not 0x80, it's a strange border case
|
||||
{
|
||||
shift++;
|
||||
|
||||
top = (top<<1)+1;
|
||||
val = (val<<1)+(in>>7);
|
||||
|
||||
in = (in<<1);
|
||||
if(--in_count==0)
|
||||
{
|
||||
in=*datain;
|
||||
datain++;
|
||||
in_count=8;
|
||||
}
|
||||
}
|
||||
|
||||
//update processing info
|
||||
lps = (lps<<1) + flag_lps;
|
||||
inverts = (inverts<<1) + Contexts[con].invert;
|
||||
|
||||
//update context state
|
||||
if(flag_lps & TOGGLE_INVERT(con))
|
||||
Contexts[con].invert ^= 1;
|
||||
|
||||
if(flag_lps)
|
||||
{
|
||||
//SeenEvolution[Contexts[con].index][0]=1;
|
||||
Contexts[con].index = NEXT_LPS(con);
|
||||
}
|
||||
else if(shift)
|
||||
{
|
||||
//SeenEvolution[Contexts[con].index][1]=1;
|
||||
Contexts[con].index = NEXT_MPS(con);
|
||||
}
|
||||
}
|
||||
|
||||
//save byte
|
||||
*dataout = (out & 0xFF);
|
||||
dataout++;
|
||||
}
|
||||
}
|
||||
|
||||
void SPC7110Codec::decomp_mode1(int len) {
|
||||
uint8_t *datain = buffer;
|
||||
uint8_t *dataout = output;
|
||||
static const unsigned NUM_CONTEXTS = 15;
|
||||
|
||||
int pixelorder[4]={0,1,2,3};
|
||||
int realorder[4];
|
||||
int a,b,c;
|
||||
int m,n;
|
||||
|
||||
uint8 top,val;
|
||||
uint8 con,prob;
|
||||
uint8 flag_lps,shift;
|
||||
|
||||
int out=0;
|
||||
int inverts=0;
|
||||
int lps=0;
|
||||
|
||||
unsigned char in;
|
||||
int in_count;
|
||||
int in_len=0;
|
||||
|
||||
int i,j,pixel;
|
||||
|
||||
//setup
|
||||
top=0xFF;
|
||||
|
||||
val=datain[in_len++];
|
||||
|
||||
in=datain[in_len++];
|
||||
in_count=8;
|
||||
|
||||
//reset context states
|
||||
for(i=0;i<NUM_CONTEXTS;i++)
|
||||
{
|
||||
Contexts[i].index=0;
|
||||
Contexts[i].invert=0;
|
||||
}
|
||||
|
||||
for(i=0;i<len;i+=2)
|
||||
{
|
||||
if(i!=0)
|
||||
{
|
||||
//turn pixel data into bitplanes
|
||||
//and save as output
|
||||
*dataout = (BIT(out,15)<<7) + (BIT(out,13)<<6) + (BIT(out,11)<<5) + (BIT(out,9)<<4)
|
||||
+ (BIT(out,7)<<3) + (BIT(out,5)<<2) + (BIT(out,3)<<1) + BIT(out,1);
|
||||
dataout++;
|
||||
*dataout = (BIT(out,14)<<7) + (BIT(out,12)<<6) + (BIT(out,10)<<5) + (BIT(out,8)<<4)
|
||||
+ (BIT(out,6)<<3) + (BIT(out,4)<<2) + (BIT(out,2)<<1) + BIT(out,0);
|
||||
dataout++;
|
||||
}
|
||||
|
||||
for(pixel=0;pixel<8;pixel++)
|
||||
{
|
||||
//get first symbol context
|
||||
a = ((out >> (1*2)) & 0x3);
|
||||
b = ((out >> (7*2)) & 0x3);
|
||||
c = ((out >> (8*2)) & 0x3);
|
||||
if(a==b && b==c)
|
||||
con=0;
|
||||
else if (a==b && b!=c)
|
||||
con=1;
|
||||
else if (a!=b && b==c)
|
||||
con=2;
|
||||
else if (a==c && b!=c)
|
||||
con=3;
|
||||
else
|
||||
con=4;
|
||||
|
||||
//update pixel order
|
||||
for(m=0;m<4;m++)
|
||||
if(pixelorder[m]==a)
|
||||
break;
|
||||
for(n=m;n>0;n--)
|
||||
{
|
||||
j=pixelorder[n-1];
|
||||
pixelorder[n-1]=pixelorder[n];
|
||||
pixelorder[n]=j;
|
||||
}
|
||||
|
||||
|
||||
//get PROB
|
||||
prob = PROB(con);
|
||||
|
||||
//get symbol
|
||||
if (val <= top-prob)
|
||||
{
|
||||
//mps
|
||||
top = top - prob;
|
||||
flag_lps=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//lps
|
||||
val = val - (top - (prob - 1));
|
||||
top = prob - 1;
|
||||
flag_lps=1;
|
||||
}
|
||||
|
||||
// renormalize
|
||||
shift=0;
|
||||
while(top<0x7F)
|
||||
{
|
||||
shift++;
|
||||
|
||||
top = (top<<1)+1;
|
||||
val = (val<<1)+(in>>7);
|
||||
|
||||
in = (in<<1);
|
||||
if(--in_count==0)
|
||||
{
|
||||
in=datain[in_len++];
|
||||
in_count=8;
|
||||
}
|
||||
}
|
||||
|
||||
//update processing info
|
||||
lps = (lps<<1) + flag_lps;
|
||||
inverts = (inverts<<1) + Contexts[con].invert;
|
||||
|
||||
//update context state
|
||||
if(flag_lps & TOGGLE_INVERT(con))
|
||||
Contexts[con].invert ^= 1;
|
||||
if(flag_lps)
|
||||
Contexts[con].index = NEXT_LPS(con);
|
||||
else if(shift)
|
||||
Contexts[con].index = NEXT_MPS(con);
|
||||
|
||||
//get context of second symbol
|
||||
con = 5 + con*2 + ((lps^inverts)&1);
|
||||
|
||||
//get PROB
|
||||
prob = PROB(con);
|
||||
|
||||
//get symbol
|
||||
if (val <= top-prob)
|
||||
{
|
||||
//mps
|
||||
top = top - prob;
|
||||
flag_lps=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//lps
|
||||
val = val - (top - (prob - 1));
|
||||
top = prob - 1;
|
||||
flag_lps=1;
|
||||
}
|
||||
|
||||
// renormalize
|
||||
shift=0;
|
||||
while(top<0x7F)
|
||||
{
|
||||
shift++;
|
||||
|
||||
top = (top<<1)+1;
|
||||
val = (val<<1)+(in>>7);
|
||||
|
||||
in = (in<<1);
|
||||
if(--in_count==0)
|
||||
{
|
||||
in=datain[in_len++];
|
||||
in_count=8;
|
||||
}
|
||||
}
|
||||
|
||||
//calculate the real pixel order
|
||||
for(m=0;m<4;m++)
|
||||
realorder[m]=pixelorder[m];
|
||||
//shift refence pixel c value to top
|
||||
for(m=0;m<4;m++)
|
||||
if(realorder[m]==c)
|
||||
break;
|
||||
for(n=m;n>0;n--)
|
||||
{
|
||||
j=realorder[n-1];
|
||||
realorder[n-1]=realorder[n];
|
||||
realorder[n]=j;
|
||||
}
|
||||
//shift refence pixel b value to top
|
||||
for(m=0;m<4;m++)
|
||||
if(realorder[m]==b)
|
||||
break;
|
||||
for(n=m;n>0;n--)
|
||||
{
|
||||
j=realorder[n-1];
|
||||
realorder[n-1]=realorder[n];
|
||||
realorder[n]=j;
|
||||
}
|
||||
//shift refence pixel a value to top
|
||||
for(m=0;m<4;m++)
|
||||
if(realorder[m]==a)
|
||||
break;
|
||||
for(n=m;n>0;n--)
|
||||
{
|
||||
j=realorder[n-1];
|
||||
realorder[n-1]=realorder[n];
|
||||
realorder[n]=j;
|
||||
}
|
||||
|
||||
|
||||
//update processing info
|
||||
lps = (lps<<1) + flag_lps;
|
||||
inverts = (inverts<<1) + Contexts[con].invert;
|
||||
|
||||
//update context state
|
||||
if(flag_lps & TOGGLE_INVERT(con))
|
||||
Contexts[con].invert ^= 1;
|
||||
if(flag_lps)
|
||||
Contexts[con].index = NEXT_LPS(con);
|
||||
else if(shift)
|
||||
Contexts[con].index = NEXT_MPS(con);
|
||||
|
||||
//get pixel
|
||||
b=realorder[(lps^inverts)&3];
|
||||
out = (out<<2) + b;
|
||||
}
|
||||
}
|
||||
|
||||
//turn pixel data into bitplanes
|
||||
//and save as output.. BUT don't save second byte unless asked to
|
||||
*dataout = (BIT(out,15)<<7) + (BIT(out,13)<<6) + (BIT(out,11)<<5) + (BIT(out,9)<<4)
|
||||
+ (BIT(out,7)<<3) + (BIT(out,5)<<2) + (BIT(out,3)<<1) + BIT(out,1);
|
||||
dataout++;
|
||||
if((len&1)==0)
|
||||
{
|
||||
*dataout = (BIT(out,14)<<7) + (BIT(out,12)<<6) + (BIT(out,10)<<5) + (BIT(out,8)<<4)
|
||||
+ (BIT(out,6)<<3) + (BIT(out,4)<<2) + (BIT(out,2)<<1) + BIT(out,0);
|
||||
dataout++;
|
||||
}
|
||||
|
||||
if(in_count==8)
|
||||
in_len--;
|
||||
//printf("Used %d bytes of input.\n",in_len);
|
||||
//return in_len;
|
||||
}
|
||||
|
||||
void SPC7110Codec::decomp_mode2(int len) {
|
||||
uint8_t *datain = buffer;
|
||||
uint8_t *dataout = output;
|
||||
static const unsigned NUM_CONTEXTS = 32;
|
||||
|
||||
int pixelorder[16]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
|
||||
int realorder[16];
|
||||
int a,b,c;
|
||||
int m,n;
|
||||
|
||||
uint8 bitplanebuffer[16];
|
||||
uint8 buf_idx=0;
|
||||
|
||||
uint8 top,val,prob;
|
||||
uint8 con,refcon;
|
||||
uint8 flag_lps,invertbit,shift;
|
||||
|
||||
int out=0;
|
||||
int out2=0;
|
||||
int inverts=0;
|
||||
int lps=0;
|
||||
|
||||
unsigned char in;
|
||||
int in_count;
|
||||
int in_len=0;
|
||||
|
||||
int i,j,pixel,bit;
|
||||
|
||||
//setup
|
||||
top=0xFF;
|
||||
|
||||
val=datain[in_len++];
|
||||
|
||||
in=datain[in_len++];
|
||||
in_count=8;
|
||||
|
||||
//reset context states
|
||||
for(i=0;i<NUM_CONTEXTS;i++)
|
||||
{
|
||||
Contexts[i].index=0;
|
||||
Contexts[i].invert=0;
|
||||
}
|
||||
|
||||
for(i=0;i<len;i+=2)
|
||||
{
|
||||
for(pixel=0;pixel<8;pixel++)
|
||||
{
|
||||
//get first symbol context
|
||||
a = ((out >> (0*4)) & 0x0F);
|
||||
b = ((out >> (7*4)) & 0x0F);
|
||||
c = ((out2>> (0*4)) & 0x0F);
|
||||
if(a==b && b==c)
|
||||
refcon=0;
|
||||
else if (a==b && b!=c)
|
||||
refcon=1;
|
||||
else if (a!=b && b==c)
|
||||
refcon=2;
|
||||
else if (a==c && b!=c)
|
||||
refcon=3;
|
||||
else
|
||||
refcon=4;
|
||||
|
||||
con=0;
|
||||
|
||||
//update pixel order
|
||||
for(m=0;m<16;m++)
|
||||
if(pixelorder[m]==a)
|
||||
break;
|
||||
for(n=m;n>0;n--)
|
||||
{
|
||||
j=pixelorder[n-1];
|
||||
pixelorder[n-1]=pixelorder[n];
|
||||
pixelorder[n]=j;
|
||||
}
|
||||
|
||||
//calculate the real pixel order
|
||||
for(m=0;m<16;m++)
|
||||
realorder[m]=pixelorder[m];
|
||||
//shift refence pixel c value to top
|
||||
for(m=0;m<16;m++)
|
||||
if(realorder[m]==c)
|
||||
break;
|
||||
for(n=m;n>0;n--)
|
||||
{
|
||||
j=realorder[n-1];
|
||||
realorder[n-1]=realorder[n];
|
||||
realorder[n]=j;
|
||||
}
|
||||
//shift refence pixel b value to top
|
||||
for(m=0;m<16;m++)
|
||||
if(realorder[m]==b)
|
||||
break;
|
||||
for(n=m;n>0;n--)
|
||||
{
|
||||
j=realorder[n-1];
|
||||
realorder[n-1]=realorder[n];
|
||||
realorder[n]=j;
|
||||
}
|
||||
//shift refence pixel a value to top
|
||||
for(m=0;m<16;m++)
|
||||
if(realorder[m]==a)
|
||||
break;
|
||||
for(n=m;n>0;n--)
|
||||
{
|
||||
j=realorder[n-1];
|
||||
realorder[n-1]=realorder[n];
|
||||
realorder[n]=j;
|
||||
}
|
||||
|
||||
//get 4 symbols
|
||||
for(bit=0;bit<4;bit++)
|
||||
{
|
||||
//get PROB
|
||||
prob = PROB(con);
|
||||
|
||||
//get symbol
|
||||
if (val <= top-prob)
|
||||
{
|
||||
//mps
|
||||
top = top - prob;
|
||||
flag_lps=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//lps
|
||||
val = val - (top - (prob - 1));
|
||||
top = prob - 1;
|
||||
flag_lps=1;
|
||||
}
|
||||
|
||||
// renormalize
|
||||
shift=0;
|
||||
while(top<0x7F)
|
||||
{
|
||||
shift++;
|
||||
|
||||
top = (top<<1)+1;
|
||||
val = (val<<1)+(in>>7);
|
||||
|
||||
in = (in<<1);
|
||||
if(--in_count==0)
|
||||
{
|
||||
in=datain[in_len++];
|
||||
in_count=8;
|
||||
}
|
||||
}
|
||||
|
||||
//update processing info
|
||||
lps = (lps<<1) + flag_lps;
|
||||
invertbit = Contexts[con].invert;
|
||||
inverts = (inverts<<1) + Contexts[con].invert;
|
||||
|
||||
//update context state
|
||||
if(flag_lps & TOGGLE_INVERT(con))
|
||||
Contexts[con].invert ^= 1;
|
||||
if(flag_lps)
|
||||
Contexts[con].index = NEXT_LPS(con);
|
||||
else if(shift)
|
||||
Contexts[con].index = NEXT_MPS(con);
|
||||
|
||||
//get next context
|
||||
if(Mode2ContextTable[con][2*(flag_lps^invertbit)+1])
|
||||
con=Mode2ContextTable[con][2*(flag_lps^invertbit)]+refcon;
|
||||
else
|
||||
con=Mode2ContextTable[con][2*(flag_lps^invertbit)];
|
||||
}
|
||||
|
||||
//get pixel
|
||||
b=realorder[(lps^inverts)&0x0F];
|
||||
out2 = (out2<<4) + ((out>>28)&0x0F);
|
||||
out = (out<<4) + b;
|
||||
}
|
||||
|
||||
//cludge to convert pixel data into bitplanes and respect len parameter for output buf
|
||||
*dataout = (BIT(out,31)<<7) + (BIT(out,27)<<6) + (BIT(out,23)<<5) + (BIT(out,19)<<4)
|
||||
+ (BIT(out,15)<<3) + (BIT(out,11)<<2) + (BIT(out,7)<<1) + BIT(out,3);
|
||||
dataout++;
|
||||
|
||||
if((i+1)<len)
|
||||
{
|
||||
*dataout = (BIT(out,30)<<7) + (BIT(out,26)<<6) + (BIT(out,22)<<5) + (BIT(out,18)<<4)
|
||||
+ (BIT(out,14)<<3) + (BIT(out,10)<<2) + (BIT(out,6)<<1) + BIT(out,2);
|
||||
dataout++;
|
||||
}
|
||||
|
||||
bitplanebuffer[buf_idx++] =
|
||||
(BIT(out,29)<<7) + (BIT(out,25)<<6) + (BIT(out,21)<<5) + (BIT(out,17)<<4)
|
||||
+ (BIT(out,13)<<3) + (BIT(out,9)<<2) + (BIT(out,5)<<1) + BIT(out,1);
|
||||
bitplanebuffer[buf_idx++] =
|
||||
(BIT(out,28)<<7) + (BIT(out,24)<<6) + (BIT(out,20)<<5) + (BIT(out,16)<<4)
|
||||
+ (BIT(out,12)<<3) + (BIT(out,8)<<2) + (BIT(out,4)<<1) + BIT(out,0);
|
||||
|
||||
if(buf_idx==16)
|
||||
{
|
||||
for(m=0;m<16 && i+2<len;m++,i++)
|
||||
{
|
||||
*dataout = bitplanebuffer[m];
|
||||
dataout++;
|
||||
}
|
||||
|
||||
buf_idx=0;
|
||||
}
|
||||
}
|
||||
|
||||
if(in_count==8)
|
||||
in_len--;
|
||||
//printf("Used %d bytes of input.\n",in_len);
|
||||
//return in_len;
|
||||
}
|
||||
|
||||
#undef PROB
|
||||
#undef NEXT_LPS
|
||||
#undef NEXT_MPS
|
||||
#undef TOGGLE_INVERT
|
||||
#undef BIT
|
||||
|
||||
SPC7110Codec::SPC7110Codec() {
|
||||
buffer = new(zeromemory) uint8_t[65536];
|
||||
output = new(zeromemory) uint8_t[65536];
|
||||
}
|
||||
|
||||
SPC7110Codec::~SPC7110Codec() {
|
||||
delete[] buffer;
|
||||
delete[] output;
|
||||
}
|
20
src/chip/spc7110/codec.h
Normal file
20
src/chip/spc7110/codec.h
Normal file
@@ -0,0 +1,20 @@
|
||||
class SPC7110Codec {
|
||||
public:
|
||||
uint8_t *buffer;
|
||||
uint8_t *output;
|
||||
|
||||
void decomp_mode0(int len);
|
||||
void decomp_mode1(int len);
|
||||
void decomp_mode2(int len);
|
||||
|
||||
SPC7110Codec();
|
||||
~SPC7110Codec();
|
||||
|
||||
private:
|
||||
static const uint8_t EvolutionTable[53][4];
|
||||
static const uint8_t Mode2ContextTable[32][4];
|
||||
struct ContextState {
|
||||
uint8_t index;
|
||||
uint8_t invert;
|
||||
} Contexts[32];
|
||||
};
|
690
src/chip/spc7110/spc7110.cpp
Normal file
690
src/chip/spc7110/spc7110.cpp
Normal file
@@ -0,0 +1,690 @@
|
||||
#include "../../base.h"
|
||||
#define SPC7110_CPP
|
||||
|
||||
#include "codec.cpp"
|
||||
|
||||
const unsigned SPC7110::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
void SPC7110::init() {}
|
||||
|
||||
void SPC7110::enable() {
|
||||
uint16_t limit = (cartridge.info.spc7110rtc ? 0x4842 : 0x483f);
|
||||
for(uint16_t i = 0x4800; i <= limit; i++) memory::mmio.map(i, *this);
|
||||
}
|
||||
|
||||
void SPC7110::power() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void SPC7110::reset() {
|
||||
r4801 = 0x00;
|
||||
r4802 = 0x00;
|
||||
r4803 = 0x00;
|
||||
r4804 = 0x00;
|
||||
r4805 = 0x00;
|
||||
r4806 = 0x00;
|
||||
r4807 = 0x00;
|
||||
r4808 = 0x00;
|
||||
r4809 = 0x00;
|
||||
r480a = 0x00;
|
||||
r480b = 0x00;
|
||||
r480c = 0x00;
|
||||
|
||||
memset(codec.output, 0, 65536);
|
||||
memset(codec.buffer, 0, 65536);
|
||||
decomp_offset = 0;
|
||||
|
||||
r4811 = 0x00;
|
||||
r4812 = 0x00;
|
||||
r4813 = 0x00;
|
||||
r4814 = 0x00;
|
||||
r4815 = 0x00;
|
||||
r4816 = 0x00;
|
||||
r4817 = 0x00;
|
||||
r4818 = 0x00;
|
||||
|
||||
r481x = 0x00;
|
||||
r4814_latch = false;
|
||||
r4815_latch = false;
|
||||
|
||||
r4820 = 0x00;
|
||||
r4821 = 0x00;
|
||||
r4822 = 0x00;
|
||||
r4823 = 0x00;
|
||||
r4824 = 0x00;
|
||||
r4825 = 0x00;
|
||||
r4826 = 0x00;
|
||||
r4827 = 0x00;
|
||||
r4828 = 0x00;
|
||||
r4829 = 0x00;
|
||||
r482a = 0x00;
|
||||
r482b = 0x00;
|
||||
r482c = 0x00;
|
||||
r482d = 0x00;
|
||||
r482e = 0x00;
|
||||
r482f = 0x00;
|
||||
|
||||
r4830 = 0x00;
|
||||
mmio_write(0x4831, 0);
|
||||
mmio_write(0x4832, 1);
|
||||
mmio_write(0x4833, 2);
|
||||
r4834 = 0x00;
|
||||
|
||||
r4840 = 0x00;
|
||||
r4841 = 0x00;
|
||||
r4842 = 0x00;
|
||||
|
||||
if(cartridge.info.spc7110rtc) {
|
||||
rtc_state = RTCS_Inactive;
|
||||
rtc_mode = RTCM_Linear;
|
||||
rtc_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned SPC7110::datarom_addr(unsigned addr) {
|
||||
unsigned size = memory::cartrom.size() - 0x100000;
|
||||
while(addr >= size) addr -= size;
|
||||
return addr + 0x100000;
|
||||
}
|
||||
|
||||
unsigned SPC7110::data_pointer() { return r4811 + (r4812 << 8) + (r4813 << 16); }
|
||||
unsigned SPC7110::data_adjust() { return r4814 + (r4815 << 8); }
|
||||
unsigned SPC7110::data_increment() { return r4816 + (r4817 << 8); }
|
||||
void SPC7110::set_data_pointer(unsigned addr) { r4811 = addr; r4812 = addr >> 8; r4813 = addr >> 16; }
|
||||
void SPC7110::set_data_adjust(unsigned addr) { r4814 = addr; r4815 = addr >> 8; }
|
||||
|
||||
void SPC7110::update_time(int offset) {
|
||||
time_t rtc_time;
|
||||
rtc_time = memory::cartrtc.read(16);
|
||||
rtc_time |= memory::cartrtc.read(17) << 8;
|
||||
rtc_time |= memory::cartrtc.read(18) << 16;
|
||||
rtc_time |= memory::cartrtc.read(19) << 24;
|
||||
|
||||
bool update = true;
|
||||
if(memory::cartrtc.read(13) & 1) update = false; //do not update if CR0 timer disable flag is set
|
||||
if(memory::cartrtc.read(15) & 3) update = false; //do not update if CR2 timer disable flags are set
|
||||
|
||||
time_t current_time = time(0) - offset;
|
||||
if(update && current_time > rtc_time) {
|
||||
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
|
||||
unsigned minute = memory::cartrtc.read( 2) + memory::cartrtc.read( 3) * 10;
|
||||
unsigned hour = memory::cartrtc.read( 4) + memory::cartrtc.read( 5) * 10;
|
||||
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
|
||||
unsigned month = memory::cartrtc.read( 8) + memory::cartrtc.read( 9) * 10;
|
||||
unsigned year = memory::cartrtc.read(10) + memory::cartrtc.read(11) * 10;
|
||||
unsigned weekday = memory::cartrtc.read(12);
|
||||
|
||||
day--;
|
||||
month--;
|
||||
year += (year >= 90) ? 1900 : 2000; //range = 1990-2089
|
||||
|
||||
second += (unsigned)(current_time - rtc_time);
|
||||
while(second >= 60) {
|
||||
second -= 60;
|
||||
|
||||
minute++;
|
||||
if(minute < 60) continue;
|
||||
minute = 0;
|
||||
|
||||
hour++;
|
||||
if(hour < 24) continue;
|
||||
hour = 0;
|
||||
|
||||
day++;
|
||||
weekday = (weekday + 1) % 7;
|
||||
unsigned days = months[month % 12];
|
||||
if(days == 28) {
|
||||
bool leapyear = false;
|
||||
if((year % 4) == 0) {
|
||||
leapyear = true;
|
||||
if((year % 100) == 0 && (year % 400) != 0) leapyear = false;
|
||||
}
|
||||
if(leapyear) days++;
|
||||
}
|
||||
if(day < days) continue;
|
||||
day = 0;
|
||||
|
||||
month++;
|
||||
if(month < 12) continue;
|
||||
month = 0;
|
||||
|
||||
year++;
|
||||
}
|
||||
|
||||
day++;
|
||||
month++;
|
||||
year %= 100;
|
||||
|
||||
memory::cartrtc.write( 0, second % 10);
|
||||
memory::cartrtc.write( 1, second / 10);
|
||||
memory::cartrtc.write( 2, minute % 10);
|
||||
memory::cartrtc.write( 3, minute / 10);
|
||||
memory::cartrtc.write( 4, hour % 10);
|
||||
memory::cartrtc.write( 5, hour / 10);
|
||||
memory::cartrtc.write( 6, day % 10);
|
||||
memory::cartrtc.write( 7, day / 10);
|
||||
memory::cartrtc.write( 8, month % 10);
|
||||
memory::cartrtc.write( 9, month / 10);
|
||||
memory::cartrtc.write(10, year % 10);
|
||||
memory::cartrtc.write(11, (year / 10) % 10);
|
||||
memory::cartrtc.write(12, weekday % 7);
|
||||
}
|
||||
|
||||
memory::cartrtc.write(16, current_time);
|
||||
memory::cartrtc.write(17, current_time >> 8);
|
||||
memory::cartrtc.write(18, current_time >> 16);
|
||||
memory::cartrtc.write(19, current_time >> 24);
|
||||
}
|
||||
|
||||
uint8 SPC7110::mmio_read(uint addr) {
|
||||
addr &= 0xffff;
|
||||
|
||||
switch(addr) {
|
||||
//==================
|
||||
//decompression unit
|
||||
//==================
|
||||
|
||||
case 0x4800: {
|
||||
uint16 counter = (r4809 + (r480a << 8));
|
||||
counter--;
|
||||
r4809 = counter;
|
||||
r480a = counter >> 8;
|
||||
return codec.output[(decomp_offset++) & 0xffff];
|
||||
}
|
||||
case 0x4801: return r4801;
|
||||
case 0x4802: return r4802;
|
||||
case 0x4803: return r4803;
|
||||
case 0x4804: return r4804;
|
||||
case 0x4805: return r4805;
|
||||
case 0x4806: return r4806;
|
||||
case 0x4807: return r4807;
|
||||
case 0x4808: return r4808;
|
||||
case 0x4809: return r4809;
|
||||
case 0x480a: return r480a;
|
||||
case 0x480b: return r480b;
|
||||
case 0x480c: {
|
||||
uint8 status = r480c;
|
||||
r480c &= 0x7f;
|
||||
return status;
|
||||
}
|
||||
|
||||
//==============
|
||||
//data port unit
|
||||
//==============
|
||||
|
||||
case 0x4810: {
|
||||
if(r481x != 0x1f) return 0x00;
|
||||
|
||||
unsigned addr = data_pointer();
|
||||
unsigned adjust = data_adjust();
|
||||
if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend
|
||||
|
||||
unsigned adjustaddr = addr;
|
||||
if(r4818 & 2) {
|
||||
adjustaddr += adjust;
|
||||
set_data_adjust(adjust + 1);
|
||||
}
|
||||
|
||||
uint8 data = memory::cartrom.read(datarom_addr(adjustaddr));
|
||||
if(!(r4818 & 2)) {
|
||||
unsigned increment = (r4818 & 1) ? data_increment() : 1;
|
||||
if(r4818 & 4) increment = (int16)increment; //16-bit sign extend
|
||||
|
||||
if((r4818 & 16) == 0) {
|
||||
set_data_pointer(addr + increment);
|
||||
} else {
|
||||
set_data_adjust(adjust + increment);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
case 0x4811: return r4811;
|
||||
case 0x4812: return r4812;
|
||||
case 0x4813: return r4813;
|
||||
case 0x4814: return r4814;
|
||||
case 0x4815: return r4815;
|
||||
case 0x4816: return r4816;
|
||||
case 0x4817: return r4817;
|
||||
case 0x4818: return r4818;
|
||||
case 0x481a: {
|
||||
if(r481x != 0x1f) return 0x00;
|
||||
|
||||
unsigned addr = data_pointer();
|
||||
unsigned adjust = data_adjust();
|
||||
if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend
|
||||
|
||||
uint8 data = memory::cartrom.read(datarom_addr(addr + adjust));
|
||||
if((r4818 & 0x60) == 0x60) {
|
||||
if((r4818 & 16) == 0) {
|
||||
set_data_pointer(addr + adjust);
|
||||
} else {
|
||||
set_data_adjust(adjust + adjust);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
//=========
|
||||
//math unit
|
||||
//=========
|
||||
|
||||
case 0x4820: return r4820;
|
||||
case 0x4821: return r4821;
|
||||
case 0x4822: return r4822;
|
||||
case 0x4823: return r4823;
|
||||
case 0x4824: return r4824;
|
||||
case 0x4825: return r4825;
|
||||
case 0x4826: return r4826;
|
||||
case 0x4827: return r4827;
|
||||
case 0x4828: return r4828;
|
||||
case 0x4829: return r4829;
|
||||
case 0x482a: return r482a;
|
||||
case 0x482b: return r482b;
|
||||
case 0x482c: return r482c;
|
||||
case 0x482d: return r482d;
|
||||
case 0x482e: return r482e;
|
||||
case 0x482f: {
|
||||
uint8 status = r482f;
|
||||
r482f &= 0x7f;
|
||||
return status;
|
||||
}
|
||||
|
||||
//===================
|
||||
//memory mapping unit
|
||||
//===================
|
||||
|
||||
case 0x4830: return r4830;
|
||||
case 0x4831: return r4831;
|
||||
case 0x4832: return r4832;
|
||||
case 0x4833: return r4833;
|
||||
case 0x4834: return r4834;
|
||||
|
||||
//====================
|
||||
//real-time clock unit
|
||||
//====================
|
||||
|
||||
case 0x4840: return r4840;
|
||||
case 0x4841: {
|
||||
if(rtc_state == RTCS_Inactive || rtc_state == RTCS_ModeSelect) return 0x00;
|
||||
|
||||
r4842 = 0x80;
|
||||
uint8 data = memory::cartrtc.read(rtc_index);
|
||||
rtc_index = (rtc_index + 1) & 15;
|
||||
return data;
|
||||
}
|
||||
case 0x4842: {
|
||||
uint8 status = r4842;
|
||||
r4842 &= 0x7f;
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
void SPC7110::mmio_write(uint addr, uint8 data) {
|
||||
addr &= 0xffff;
|
||||
|
||||
switch(addr) {
|
||||
//==================
|
||||
//decompression unit
|
||||
//==================
|
||||
|
||||
case 0x4801: r4801 = data; break;
|
||||
case 0x4802: r4802 = data; break;
|
||||
case 0x4803: r4803 = data; break;
|
||||
case 0x4804: r4804 = data; break;
|
||||
case 0x4805: r4805 = data; break;
|
||||
case 0x4806: {
|
||||
r4806 = data;
|
||||
|
||||
unsigned table = (r4801 + (r4802 << 8) + (r4803 << 16));
|
||||
unsigned index = (r4804 << 2);
|
||||
unsigned length = (r4809 + (r480a << 8));
|
||||
unsigned addr = datarom_addr(table + index);
|
||||
unsigned mode = (memory::cartrom.read(addr + 0));
|
||||
unsigned offset = (memory::cartrom.read(addr + 1) << 16)
|
||||
+ (memory::cartrom.read(addr + 2) << 8)
|
||||
+ (memory::cartrom.read(addr + 3) << 0);
|
||||
|
||||
//this can technically be 65536, but it has never been observed higher than 32768 ...
|
||||
//really need a way to determine both compressed and decompressed lengths, though.
|
||||
static const unsigned max_length = 32768;
|
||||
|
||||
offset = datarom_addr(offset);
|
||||
for(unsigned i = 0; i < max_length; i++) codec.buffer[i] = memory::cartrom.read(offset + i);
|
||||
|
||||
#if 0
|
||||
printf("decompression: 4805=$%0.2x,4806=$%0.2x,4807=$%0.2x,4808=$%0.2x,480b=$%0.2x\n",
|
||||
r4805, r4806, r4807, r4808, r480b);
|
||||
printf("table=$%0.6x,index=%3d,length=%5d,mode=%d,offset=$%0.6x\n",
|
||||
table, r4804, length, mode, offset);
|
||||
#endif
|
||||
|
||||
switch(mode) {
|
||||
case 0: codec.decomp_mode0(max_length); break;
|
||||
case 1: codec.decomp_mode1(max_length); break;
|
||||
case 2: codec.decomp_mode2(max_length); break;
|
||||
}
|
||||
|
||||
decomp_offset = (r4805 + (r4806 << 8)) << mode;
|
||||
r480c = 0x80;
|
||||
} break;
|
||||
|
||||
case 0x4807: r4807 = data; break;
|
||||
case 0x4808: r4808 = data; break;
|
||||
case 0x4809: r4809 = data; break;
|
||||
case 0x480a: r480a = data; break;
|
||||
case 0x480b: r480b = data; break;
|
||||
|
||||
//==============
|
||||
//data port unit
|
||||
//==============
|
||||
|
||||
case 0x4811: r4811 = data; r481x |= 0x01; break;
|
||||
case 0x4812: r4812 = data; r481x |= 0x02; break;
|
||||
case 0x4813: r4813 = data; r481x |= 0x04; break;
|
||||
case 0x4814: {
|
||||
r4814 = data;
|
||||
r481x |= 0x08;
|
||||
r4814_latch = true;
|
||||
if(!r4815_latch) break;
|
||||
if(!(r4818 & 2)) break;
|
||||
if(r4818 & 0x10) break;
|
||||
|
||||
if((r4818 & 0x60) == 0x20) {
|
||||
unsigned increment = data_adjust() & 0xff;
|
||||
if(r4818 & 8) increment = (int8)increment; //8-bit sign extend
|
||||
set_data_pointer(data_pointer() + increment);
|
||||
} else if((r4818 & 0x60) == 0x40) {
|
||||
unsigned increment = data_adjust();
|
||||
if(r4818 & 8) increment = (int16)increment; //16-bit sign extend
|
||||
set_data_pointer(data_pointer() + increment);
|
||||
}
|
||||
} break;
|
||||
case 0x4815: {
|
||||
r4815 = data;
|
||||
r481x |= 0x10;
|
||||
r4815_latch = true;
|
||||
if(!r4814_latch) break;
|
||||
if(!(r4818 & 2)) break;
|
||||
if(r4818 & 0x10) break;
|
||||
|
||||
if((r4818 & 0x60) == 0x20) {
|
||||
unsigned increment = data_adjust() & 0xff;
|
||||
if(r4818 & 8) increment = (int8)increment; //8-bit sign extend
|
||||
set_data_pointer(data_pointer() + increment);
|
||||
} else if((r4818 & 0x60) == 0x40) {
|
||||
unsigned increment = data_adjust();
|
||||
if(r4818 & 8) increment = (int16)increment; //16-bit sign extend
|
||||
set_data_pointer(data_pointer() + increment);
|
||||
}
|
||||
} break;
|
||||
case 0x4816: r4816 = data; break;
|
||||
case 0x4817: r4817 = data; break;
|
||||
case 0x4818: {
|
||||
if(r481x != 0x1f) break;
|
||||
|
||||
r4818 = data;
|
||||
r4814_latch = r4815_latch = false;
|
||||
} break;
|
||||
|
||||
//=========
|
||||
//math unit
|
||||
//=========
|
||||
|
||||
case 0x4820: r4820 = data; break;
|
||||
case 0x4821: r4821 = data; break;
|
||||
case 0x4822: r4822 = data; break;
|
||||
case 0x4823: r4823 = data; break;
|
||||
case 0x4824: r4824 = data; break;
|
||||
case 0x4825: {
|
||||
r4825 = data;
|
||||
|
||||
if(r482e & 1) {
|
||||
//signed 16-bit x 16-bit multiplication
|
||||
int16 r0 = (int16)(r4824 + (r4825 << 8));
|
||||
int16 r1 = (int16)(r4820 + (r4821 << 8));
|
||||
|
||||
signed result = r0 * r1;
|
||||
r4828 = result;
|
||||
r4829 = result >> 8;
|
||||
r482a = result >> 16;
|
||||
r482b = result >> 24;
|
||||
} else {
|
||||
//unsigned 16-bit x 16-bit multiplication
|
||||
uint16 r0 = (uint16)(r4824 + (r4825 << 8));
|
||||
uint16 r1 = (uint16)(r4820 + (r4821 << 8));
|
||||
|
||||
unsigned result = r0 * r1;
|
||||
r4828 = result;
|
||||
r4829 = result >> 8;
|
||||
r482a = result >> 16;
|
||||
r482b = result >> 24;
|
||||
}
|
||||
|
||||
r482f = 0x80;
|
||||
} break;
|
||||
case 0x4826: r4826 = data; break;
|
||||
case 0x4827: {
|
||||
r4827 = data;
|
||||
|
||||
if(r482e & 1) {
|
||||
//signed 32-bit x 16-bit division
|
||||
int32 dividend = (int32)(r4820 + (r4821 << 8) + (r4822 << 16) + (r4823 << 24));
|
||||
int16 divisor = (int16)(r4826 + (r4827 << 8));
|
||||
|
||||
int32 quotient;
|
||||
int16 remainder;
|
||||
|
||||
if(divisor) {
|
||||
quotient = (int32)(dividend / divisor);
|
||||
remainder = (int32)(dividend % divisor);
|
||||
} else {
|
||||
//illegal division by zero
|
||||
quotient = 0;
|
||||
remainder = dividend & 0xffff;
|
||||
}
|
||||
|
||||
r4828 = quotient;
|
||||
r4829 = quotient >> 8;
|
||||
r482a = quotient >> 16;
|
||||
r482b = quotient >> 24;
|
||||
|
||||
r482c = remainder;
|
||||
r482d = remainder >> 8;
|
||||
} else {
|
||||
//unsigned 32-bit x 16-bit division
|
||||
uint32 dividend = (uint32)(r4820 + (r4821 << 8) + (r4822 << 16) + (r4823 << 24));
|
||||
uint16 divisor = (uint16)(r4826 + (r4827 << 8));
|
||||
|
||||
uint32 quotient;
|
||||
uint16 remainder;
|
||||
|
||||
if(divisor) {
|
||||
quotient = (uint32)(dividend / divisor);
|
||||
remainder = (uint16)(dividend % divisor);
|
||||
} else {
|
||||
//illegal division by zero
|
||||
quotient = 0;
|
||||
remainder = dividend & 0xffff;
|
||||
}
|
||||
|
||||
r4828 = quotient;
|
||||
r4829 = quotient >> 8;
|
||||
r482a = quotient >> 16;
|
||||
r482b = quotient >> 24;
|
||||
|
||||
r482c = remainder;
|
||||
r482d = remainder >> 8;
|
||||
}
|
||||
|
||||
r482f = 0x80;
|
||||
} break;
|
||||
|
||||
case 0x482e: {
|
||||
//reset math unit
|
||||
r4820 = r4821 = r4822 = r4823 = 0;
|
||||
r4824 = r4825 = r4826 = r4827 = 0;
|
||||
r4828 = r4829 = r482a = r482b = 0;
|
||||
r482c = r482d = 0;
|
||||
|
||||
r482e = data;
|
||||
} break;
|
||||
|
||||
//===================
|
||||
//memory mapping unit
|
||||
//===================
|
||||
|
||||
case 0x4830: r4830 = data; break;
|
||||
|
||||
case 0x4831: {
|
||||
r4831 = data;
|
||||
dx_offset = datarom_addr((data & 7) * 0x100000);
|
||||
} break;
|
||||
|
||||
case 0x4832: {
|
||||
r4832 = data;
|
||||
ex_offset = datarom_addr((data & 7) * 0x100000);
|
||||
} break;
|
||||
|
||||
case 0x4833: {
|
||||
r4833 = data;
|
||||
fx_offset = datarom_addr((data & 7) * 0x100000);
|
||||
} break;
|
||||
|
||||
case 0x4834: r4834 = data; break;
|
||||
|
||||
//====================
|
||||
//real-time clock unit
|
||||
//====================
|
||||
|
||||
case 0x4840: {
|
||||
r4840 = data;
|
||||
if(!(r4840 & 1)) {
|
||||
//disable RTC
|
||||
rtc_state = RTCS_Inactive;
|
||||
update_time();
|
||||
} else {
|
||||
//enable RTC
|
||||
r4842 = 0x80;
|
||||
rtc_state = RTCS_ModeSelect;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 0x4841: {
|
||||
r4841 = data;
|
||||
|
||||
switch(rtc_state) {
|
||||
case RTCS_ModeSelect: {
|
||||
if(data == RTCM_Linear || data == RTCM_Indexed) {
|
||||
r4842 = 0x80;
|
||||
rtc_state = RTCS_IndexSelect;
|
||||
rtc_mode = (RTC_Mode)data;
|
||||
rtc_index = 0;
|
||||
}
|
||||
} break;
|
||||
|
||||
case RTCS_IndexSelect: {
|
||||
r4842 = 0x80;
|
||||
rtc_index = data & 15;
|
||||
if(rtc_mode == RTCM_Linear) rtc_state = RTCS_Write;
|
||||
} break;
|
||||
|
||||
case RTCS_Write: {
|
||||
r4842 = 0x80;
|
||||
|
||||
//control register 0
|
||||
if(rtc_index == 13) {
|
||||
//increment second counter
|
||||
if(data & 2) update_time(+1);
|
||||
|
||||
//round minute counter
|
||||
if(data & 8) {
|
||||
update_time();
|
||||
|
||||
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
|
||||
//clear seconds
|
||||
memory::cartrtc.write(0, 0);
|
||||
memory::cartrtc.write(1, 0);
|
||||
|
||||
if(second >= 30) update_time(+60);
|
||||
}
|
||||
}
|
||||
|
||||
//control register 2
|
||||
if(rtc_index == 15) {
|
||||
//disable timer and clear second counter
|
||||
if((data & 1) && !(memory::cartrtc.read(15) & 1)) {
|
||||
update_time();
|
||||
|
||||
//clear seconds
|
||||
memory::cartrtc.write(0, 0);
|
||||
memory::cartrtc.write(1, 0);
|
||||
}
|
||||
|
||||
//disable timer
|
||||
if((data & 2) && !(memory::cartrtc.read(15) & 2)) {
|
||||
update_time();
|
||||
}
|
||||
}
|
||||
|
||||
memory::cartrtc.write(rtc_index, data & 15);
|
||||
rtc_index = (rtc_index + 1) & 15;
|
||||
} break;
|
||||
} //switch(rtc_state)
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 SPC7110::read(uint addr) {
|
||||
if((addr & 0xffe000) == 0x006000 || (addr & 0xffe000) == 0x306000) {
|
||||
//$[00|30]:[6000-7fff]
|
||||
return memory::cartram.read(addr & 0x1fff);
|
||||
}
|
||||
|
||||
if((addr & 0x708000) == 0x008000) {
|
||||
//$[00-0f|80-8f]:[8000-ffff]
|
||||
return memory::cartrom.read(addr & 0x0fffff);
|
||||
}
|
||||
|
||||
if((addr & 0xff0000) == 0x500000) {
|
||||
//$[50]:[0000-ffff]
|
||||
return mmio_read(0x4800);
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0xc00000) {
|
||||
//$[c0-cf]:[0000-ffff]
|
||||
return memory::cartrom.read(addr & 0x0fffff);
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0xd00000) {
|
||||
//$[d0-df]:[0000-ffff]
|
||||
return memory::cartrom.read(dx_offset + (addr & 0x0fffff));
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0xe00000) {
|
||||
//$[e0-ef]:[0000-ffff]
|
||||
return memory::cartrom.read(ex_offset + (addr & 0x0fffff));
|
||||
}
|
||||
|
||||
if((addr & 0xf00000) == 0xf00000) {
|
||||
//$[f0-ff]:[0000-ffff]
|
||||
return memory::cartrom.read(fx_offset + (addr & 0x0fffff));
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
void SPC7110::write(uint addr, uint8 data) {
|
||||
if((addr & 0xffe000) == 0x006000 || (addr & 0xffe000) == 0x306000) {
|
||||
//$[00|30]:[6000-7fff]
|
||||
if(r4830 & 0x80) memory::cartram.write(addr & 0x1fff, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
SPC7110::SPC7110() {
|
||||
}
|
130
src/chip/spc7110/spc7110.h
Normal file
130
src/chip/spc7110/spc7110.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*****
|
||||
* SPC7110 emulator - version 0.1 (2008-07-19)
|
||||
* Copyright (c) 2008, byuu and neviksti
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* The software is provided "as is" and the author disclaims all warranties
|
||||
* with regard to this software including all implied warranties of
|
||||
* merchantibility and fitness, in no event shall the author be liable for
|
||||
* any special, direct, indirect, or consequential damages or any damages
|
||||
* whatsoever resulting from loss of use, data or profits, whether in an
|
||||
* action of contract, negligence or other tortious action, arising out of
|
||||
* or in connection with the use or performance of this software.
|
||||
*****/
|
||||
|
||||
#include "codec.h"
|
||||
|
||||
class SPC7110 : public MMIO, public Memory {
|
||||
public:
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
void reset();
|
||||
|
||||
unsigned datarom_addr(unsigned addr);
|
||||
|
||||
unsigned data_pointer();
|
||||
unsigned data_adjust();
|
||||
unsigned data_increment();
|
||||
void set_data_pointer(unsigned addr);
|
||||
void set_data_adjust(unsigned addr);
|
||||
|
||||
void update_time(int offset = 0);
|
||||
time_t create_time();
|
||||
|
||||
uint8 mmio_read (uint addr);
|
||||
void mmio_write(uint addr, uint8 data);
|
||||
|
||||
uint8 read (uint addr);
|
||||
void write(uint addr, uint8 data);
|
||||
|
||||
SPC7110();
|
||||
|
||||
private:
|
||||
//==================
|
||||
//decompression unit
|
||||
//==================
|
||||
uint8 r4801; //compression table low
|
||||
uint8 r4802; //compression table high
|
||||
uint8 r4803; //compression table bank
|
||||
uint8 r4804; //compression table index
|
||||
uint8 r4805; //decompression buffer index low
|
||||
uint8 r4806; //decompression buffer index high
|
||||
uint8 r4807; //???
|
||||
uint8 r4808; //???
|
||||
uint8 r4809; //compression length low
|
||||
uint8 r480a; //compression length high
|
||||
uint8 r480b; //decompression control register
|
||||
uint8 r480c; //decompression status
|
||||
|
||||
SPC7110Codec codec;
|
||||
uint16 decomp_offset;
|
||||
|
||||
//==============
|
||||
//data port unit
|
||||
//==============
|
||||
uint8 r4811; //data pointer low
|
||||
uint8 r4812; //data pointer high
|
||||
uint8 r4813; //data pointer bank
|
||||
uint8 r4814; //data adjust low
|
||||
uint8 r4815; //data adjust high
|
||||
uint8 r4816; //data increment low
|
||||
uint8 r4817; //data increment high
|
||||
uint8 r4818; //data port control register
|
||||
|
||||
uint8 r481x;
|
||||
|
||||
bool r4814_latch;
|
||||
bool r4815_latch;
|
||||
|
||||
//=========
|
||||
//math unit
|
||||
//=========
|
||||
uint8 r4820; //16-bit multiplicand B0, 32-bit dividend B0
|
||||
uint8 r4821; //16-bit multiplicand B1, 32-bit dividend B1
|
||||
uint8 r4822; //32-bit dividend B2
|
||||
uint8 r4823; //32-bit dividend B3
|
||||
uint8 r4824; //16-bit multiplier B0
|
||||
uint8 r4825; //16-bit multiplier B1
|
||||
uint8 r4826; //16-bit divisor B0
|
||||
uint8 r4827; //16-bit divisor B1
|
||||
uint8 r4828; //32-bit product B0, 32-bit quotient B0
|
||||
uint8 r4829; //32-bit product B1, 32-bit quotient B1
|
||||
uint8 r482a; //32-bit product B2, 32-bit quotient B2
|
||||
uint8 r482b; //32-bit product B3, 32-bit quotient B3
|
||||
uint8 r482c; //16-bit remainder B0
|
||||
uint8 r482d; //16-bit remainder B1
|
||||
uint8 r482e; //math control register
|
||||
uint8 r482f; //math status
|
||||
|
||||
//===================
|
||||
//memory mapping unit
|
||||
//===================
|
||||
uint8 r4830; //SRAM write enable
|
||||
uint8 r4831; //$[d0-df]:[0000-ffff] mapping
|
||||
uint8 r4832; //$[e0-ef]:[0000-ffff] mapping
|
||||
uint8 r4833; //$[f0-ff]:[0000-ffff] mapping
|
||||
uint8 r4834; //???
|
||||
|
||||
unsigned dx_offset;
|
||||
unsigned ex_offset;
|
||||
unsigned fx_offset;
|
||||
|
||||
//====================
|
||||
//real-time clock unit
|
||||
//====================
|
||||
uint8 r4840; //RTC latch
|
||||
uint8 r4841; //RTC index/data port
|
||||
uint8 r4842; //RTC status
|
||||
|
||||
enum RTC_State { RTCS_Inactive, RTCS_ModeSelect, RTCS_IndexSelect, RTCS_Write } rtc_state;
|
||||
enum RTC_Mode { RTCM_Linear = 0x03, RTCM_Indexed = 0x0c } rtc_mode;
|
||||
unsigned rtc_index;
|
||||
|
||||
static const unsigned months[12];
|
||||
};
|
||||
|
||||
extern SPC7110 spc7110;
|
@@ -1,189 +1,213 @@
|
||||
/*
|
||||
S-RTC chip emulation
|
||||
Used by Hudson Soft in Dai Kaijuu Monogatari II and Far East of Eden Zero.
|
||||
Currently, only the former is supported by bsnes.
|
||||
|
||||
Original S-RTC emulation code via John Weidman/SNES9x
|
||||
Rewritten for compatibility with bsnes via byuu
|
||||
|
||||
The S-RTC is a real-time clock chip that was added to the above two carts
|
||||
to allow the games to maintain the current time, even when the game was not
|
||||
powered on. Thus allowing special events at certain times, and on certain
|
||||
dates. Hudson Soft called this the PLG (Player's Life Gameplay System).
|
||||
|
||||
This chip is a special case to the term 'emulation' itself.
|
||||
There are a few different ways to go about emulating this chip, and each
|
||||
result in a different style of emulation.
|
||||
|
||||
The first is to simply return the current PC system time when the S-RTC is
|
||||
read from. This emulates the original S-RTC in the sense that it always
|
||||
returns the true current time, ignoring the speed that the SNES itself is
|
||||
running at. The downside to this method is that you lose the ability to set
|
||||
the time to whatever you choose inside the game itself. It will always return
|
||||
the true time, regardless. This can be overcome by changing the PC system time,
|
||||
which actually adds a greater degree of control over event timing, very useful
|
||||
for emulation. It also has a timeshifting flaw discussed below.
|
||||
|
||||
The second is to run the S-RTC relative to the SNES speed. This means that
|
||||
if the emulator is sped up (via fast forward key, frameskipping, etc), or
|
||||
slowed down (via slowdown key, system bottlenecking, etc); the time increments
|
||||
slower, thus ~60 frames on the SNES equal one second. Without this, timeshifting
|
||||
will occur between the S-RTC and the real SNES.
|
||||
|
||||
The third and final method is to save a copy of the local system time when the
|
||||
S-RTC is initially set, and compare the current system time against this value
|
||||
when setting the S-RTC time. This overcomes the first methods' shortcoming of
|
||||
not allowing the player to set the time in-game, however a new problem arises.
|
||||
You now have to save the time when the RTC was initially set to both savestates
|
||||
and to save-game data. This would require an extra file, or the breaking of
|
||||
perhaps the only standard format (.srm savegame backups) in the entire SNES
|
||||
emulation scene. You also give up the control of being able to override the
|
||||
RTC clock at will via the PC system time outside of emulation.
|
||||
The first method has another advantage over the third: Dai Kaijuu Monogatari II
|
||||
only allows dates in the range of the years 1996-2199. The first method gets
|
||||
around this limitation. But who knows, maybe it will break something in the
|
||||
game if the date exceeds 2199... I guess we'll worry about that in two hundred
|
||||
years from now.
|
||||
|
||||
For my implementation, I chose to go with the first method. Both for simplicity
|
||||
and because I did not wish to create a new method for saving the system time
|
||||
whenever the RTC is set.
|
||||
*/
|
||||
|
||||
#include "../../base.h"
|
||||
|
||||
void SRTC::set_time() {
|
||||
time_t rawtime;
|
||||
tm *t;
|
||||
::time(&rawtime);
|
||||
t = localtime(&rawtime);
|
||||
const unsigned SRTC::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
|
||||
|
||||
//see srtc.h for format of srtc.data[]
|
||||
srtc.data[0] = t->tm_sec % 10;
|
||||
srtc.data[1] = t->tm_sec / 10;
|
||||
srtc.data[2] = t->tm_min % 10;
|
||||
srtc.data[3] = t->tm_min / 10;
|
||||
srtc.data[4] = t->tm_hour % 10;
|
||||
srtc.data[5] = t->tm_hour / 10;
|
||||
srtc.data[6] = t->tm_mday % 10;
|
||||
srtc.data[7] = t->tm_mday / 10;
|
||||
srtc.data[8] = t->tm_mon + 1;
|
||||
srtc.data[9] = t->tm_year % 10;
|
||||
srtc.data[10] = (t->tm_year / 10) % 10;
|
||||
srtc.data[11] = 9 + (t->tm_year / 100);
|
||||
srtc.data[12] = t->tm_wday;
|
||||
void SRTC::init() {
|
||||
}
|
||||
|
||||
void SRTC::init() {}
|
||||
|
||||
void SRTC::enable() {
|
||||
memory::mmio.map(0x2800, *this);
|
||||
memory::mmio.map(0x2801, *this);
|
||||
}
|
||||
|
||||
void SRTC::power() {
|
||||
memset(&srtc, 0, sizeof(srtc));
|
||||
reset();
|
||||
}
|
||||
|
||||
void SRTC::reset() {
|
||||
srtc.index = -1;
|
||||
srtc.mode = SRTC_READ;
|
||||
rtc_mode = RTCM_Read;
|
||||
rtc_index = -1;
|
||||
update_time();
|
||||
}
|
||||
|
||||
void SRTC::update_time() {
|
||||
time_t rtc_time;
|
||||
rtc_time = memory::cartrtc.read(16);
|
||||
rtc_time |= memory::cartrtc.read(17) << 8;
|
||||
rtc_time |= memory::cartrtc.read(18) << 16;
|
||||
rtc_time |= memory::cartrtc.read(19) << 24;
|
||||
|
||||
time_t current_time = time(0);
|
||||
if(current_time > rtc_time) {
|
||||
unsigned second = memory::cartrtc.read( 0) + memory::cartrtc.read( 1) * 10;
|
||||
unsigned minute = memory::cartrtc.read( 2) + memory::cartrtc.read( 3) * 10;
|
||||
unsigned hour = memory::cartrtc.read( 4) + memory::cartrtc.read( 5) * 10;
|
||||
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
|
||||
unsigned month = memory::cartrtc.read( 8);
|
||||
unsigned year = memory::cartrtc.read( 9) + memory::cartrtc.read(10) * 10 + memory::cartrtc.read(11) * 100;
|
||||
unsigned weekday = memory::cartrtc.read(12);
|
||||
|
||||
day--;
|
||||
month--;
|
||||
year += 1000;
|
||||
|
||||
second += (unsigned)(current_time - rtc_time);
|
||||
|
||||
while(second >= 60) {
|
||||
second -= 60;
|
||||
|
||||
minute++;
|
||||
if(minute < 60) continue;
|
||||
minute = 0;
|
||||
|
||||
hour++;
|
||||
if(hour < 24) continue;
|
||||
hour = 0;
|
||||
|
||||
day++;
|
||||
weekday = (weekday + 1) % 7;
|
||||
unsigned days = months[month % 12];
|
||||
if(days == 28) {
|
||||
bool leapyear = false;
|
||||
if((year % 4) == 0) {
|
||||
leapyear = true;
|
||||
if((year % 100) == 0 && (year % 400) != 0) leapyear = false;
|
||||
}
|
||||
if(leapyear) days++;
|
||||
}
|
||||
if(day < days) continue;
|
||||
day = 0;
|
||||
|
||||
month++;
|
||||
if(month < 12) continue;
|
||||
month = 0;
|
||||
|
||||
year++;
|
||||
}
|
||||
|
||||
day++;
|
||||
month++;
|
||||
year -= 1000;
|
||||
|
||||
memory::cartrtc.write( 0, second % 10);
|
||||
memory::cartrtc.write( 1, second / 10);
|
||||
memory::cartrtc.write( 2, minute % 10);
|
||||
memory::cartrtc.write( 3, minute / 10);
|
||||
memory::cartrtc.write( 4, hour % 10);
|
||||
memory::cartrtc.write( 5, hour / 10);
|
||||
memory::cartrtc.write( 6, day % 10);
|
||||
memory::cartrtc.write( 7, day / 10);
|
||||
memory::cartrtc.write( 8, month);
|
||||
memory::cartrtc.write( 9, year % 10);
|
||||
memory::cartrtc.write(10, (year / 10) % 10);
|
||||
memory::cartrtc.write(11, year / 100);
|
||||
memory::cartrtc.write(12, weekday % 7);
|
||||
}
|
||||
|
||||
memory::cartrtc.write(16, current_time);
|
||||
memory::cartrtc.write(17, current_time >> 8);
|
||||
memory::cartrtc.write(18, current_time >> 16);
|
||||
memory::cartrtc.write(19, current_time >> 24);
|
||||
}
|
||||
|
||||
//returns day of week for specified date
|
||||
//eg 0 = Sunday, 1 = Monday, ... 6 = Saturday
|
||||
//usage: weekday(2008, 1, 1) returns weekday of January 1st, 2008
|
||||
unsigned SRTC::weekday(unsigned year, unsigned month, unsigned day) {
|
||||
unsigned y = 1900, m = 1; //epoch is 1900-01-01
|
||||
unsigned sum = 0; //number of days passed since epoch
|
||||
|
||||
year = max(1900, year);
|
||||
month = max(1, min(12, month));
|
||||
day = max(1, min(31, day));
|
||||
|
||||
while(y < year) {
|
||||
bool leapyear = false;
|
||||
if((y % 4) == 0) {
|
||||
leapyear = true;
|
||||
if((y % 100) == 0 && (y % 400) != 0) leapyear = false;
|
||||
}
|
||||
sum += leapyear ? 366 : 365;
|
||||
y++;
|
||||
}
|
||||
|
||||
while(m < month) {
|
||||
unsigned days = months[m - 1];
|
||||
if(days == 28) {
|
||||
bool leapyear = false;
|
||||
if((y % 4) == 0) {
|
||||
leapyear = true;
|
||||
if((y % 100) == 0 && (y % 400) != 0) leapyear = false;
|
||||
}
|
||||
if(leapyear) days++;
|
||||
}
|
||||
sum += days;
|
||||
m++;
|
||||
}
|
||||
|
||||
sum += day - 1;
|
||||
return (sum + 1) % 7; //1900-01-01 was a Monday
|
||||
}
|
||||
|
||||
uint8 SRTC::mmio_read(uint addr) {
|
||||
switch(addr & 0xffff) {
|
||||
addr &= 0xffff;
|
||||
|
||||
case 0x2800: {
|
||||
if(srtc.mode == SRTC_READ) {
|
||||
if(srtc.index < 0) {
|
||||
set_time();
|
||||
srtc.index++;
|
||||
return 0x0f; //send start message
|
||||
} else if(srtc.index > MAX_SRTC_INDEX) {
|
||||
srtc.index = -1;
|
||||
return 0x0f; //send finished message
|
||||
if(addr == 0x2800) {
|
||||
if(rtc_mode != RTCM_Read) return 0x00;
|
||||
|
||||
if(rtc_index < 0) {
|
||||
update_time();
|
||||
rtc_index++;
|
||||
return 0x0f;
|
||||
} else if(rtc_index > 12) {
|
||||
rtc_index = -1;
|
||||
return 0x0f;
|
||||
} else {
|
||||
return srtc.data[srtc.index++];
|
||||
return memory::cartrtc.read(rtc_index++);
|
||||
}
|
||||
} else {
|
||||
return 0x00;
|
||||
}
|
||||
} break;
|
||||
|
||||
case 0x2801: {
|
||||
} break;
|
||||
|
||||
}
|
||||
|
||||
return cpu.regs.mdr;
|
||||
}
|
||||
|
||||
//Please see notes above about the implementation of the S-RTC
|
||||
//Writes are stored the srtc.data[] array, but they are ignored
|
||||
//as reads will refresh the data array with the current system
|
||||
//time. The write method is only here for the sake of faux
|
||||
//emulation of the real hardware.
|
||||
void SRTC::mmio_write(uint addr, uint8 data) {
|
||||
switch(addr & 0xffff) {
|
||||
addr &= 0xffff;
|
||||
|
||||
case 0x2800: {
|
||||
} break;
|
||||
|
||||
case 0x2801: {
|
||||
if(addr == 0x2801) {
|
||||
data &= 0x0f; //only the low four bits are used
|
||||
|
||||
if(data >= 0x0d) {
|
||||
switch(data) {
|
||||
case 0x0d:
|
||||
srtc.mode = SRTC_READ;
|
||||
srtc.index = -1;
|
||||
break;
|
||||
case 0x0e:
|
||||
srtc.mode = SRTC_COMMAND;
|
||||
break;
|
||||
case 0x0f:
|
||||
//unknown behaviour
|
||||
break;
|
||||
}
|
||||
if(data == 0x0d) {
|
||||
rtc_mode = RTCM_Read;
|
||||
rtc_index = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if(srtc.mode == SRTC_WRITE) {
|
||||
if(srtc.index >= 0 && srtc.index < MAX_SRTC_INDEX) {
|
||||
srtc.data[srtc.index++] = data;
|
||||
if(data == 0x0e) {
|
||||
rtc_mode = RTCM_Command;
|
||||
return;
|
||||
}
|
||||
|
||||
if(srtc.index == MAX_SRTC_INDEX) {
|
||||
//all S-RTC data has been loaded by program
|
||||
srtc.data[srtc.index++] = 0x00; //day_of_week
|
||||
if(data == 0x0f) return; //unknown behavior
|
||||
|
||||
if(rtc_mode == RTCM_Write) {
|
||||
if(rtc_index >= 0 && rtc_index < 12) {
|
||||
memory::cartrtc.write(rtc_index++, data);
|
||||
|
||||
if(rtc_index == 12) {
|
||||
//day of week is automatically calculated and written
|
||||
unsigned day = memory::cartrtc.read( 6) + memory::cartrtc.read( 7) * 10;
|
||||
unsigned month = memory::cartrtc.read( 8);
|
||||
unsigned year = memory::cartrtc.read( 9) + memory::cartrtc.read(10) * 10 + memory::cartrtc.read(11) * 100;
|
||||
year += 1000;
|
||||
|
||||
memory::cartrtc.write(rtc_index++, weekday(year, month, day));
|
||||
}
|
||||
}
|
||||
} else if(srtc.mode == SRTC_COMMAND) {
|
||||
switch(data) {
|
||||
case SRTC_COMMAND_CLEAR:
|
||||
memset(srtc.data, 0, MAX_SRTC_INDEX + 1);
|
||||
srtc.index = -1;
|
||||
srtc.mode = SRTC_READY;
|
||||
break;
|
||||
case SRTC_COMMAND_WRITE:
|
||||
srtc.index = 0;
|
||||
srtc.mode = SRTC_WRITE;
|
||||
break;
|
||||
default:
|
||||
//unknown behaviour
|
||||
srtc.mode = SRTC_READY;
|
||||
break;
|
||||
}
|
||||
} else if(rtc_mode == RTCM_Command) {
|
||||
if(data == 0) {
|
||||
rtc_mode = RTCM_Write;
|
||||
rtc_index = 0;
|
||||
} else if(data == 4) {
|
||||
rtc_mode = RTCM_Ready;
|
||||
rtc_index = -1;
|
||||
for(unsigned i = 0; i < 13; i++) memory::cartrtc.write(i, 0);
|
||||
} else {
|
||||
if(srtc.mode == SRTC_READ) {
|
||||
//ignore writes while in read mode
|
||||
} else if(srtc.mode == SRTC_READY) {
|
||||
//unknown behaviour
|
||||
//unknown behavior
|
||||
rtc_mode = RTCM_Ready;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
SRTC::SRTC() {}
|
||||
SRTC::SRTC() {
|
||||
}
|
||||
|
@@ -1,43 +1,8 @@
|
||||
class SRTC : public MMIO {
|
||||
public:
|
||||
enum { MAX_SRTC_INDEX = 0x0c };
|
||||
void update_time();
|
||||
unsigned weekday(unsigned year, unsigned month, unsigned day);
|
||||
|
||||
enum {
|
||||
SRTC_READ = 0,
|
||||
SRTC_WRITE,
|
||||
SRTC_COMMAND,
|
||||
SRTC_READY
|
||||
};
|
||||
|
||||
enum {
|
||||
SRTC_COMMAND_WRITE = 0,
|
||||
SRTC_COMMAND_CLEAR = 4
|
||||
};
|
||||
|
||||
/******************************
|
||||
[srtc.data structure]
|
||||
Index Description Range
|
||||
----- ----------- -----
|
||||
0 Seconds low 0-9
|
||||
1 Seconds high 0-5
|
||||
2 Minutes low 0-9
|
||||
3 Minutes high 0-5
|
||||
4 Hour low 0-9
|
||||
5 Hour high 0-2
|
||||
6 Day low 0-9
|
||||
7 Day high 0-3
|
||||
8 Month 1-12
|
||||
9 Year ones 0-9
|
||||
10 Year tens 0-9
|
||||
11 Year hundreds 9-11 (9=19xx, 10=20xx, 11=21xx)
|
||||
12 Day of week 0-6 (0=Sunday, ...)
|
||||
******************************/
|
||||
struct {
|
||||
int8 index;
|
||||
uint8 mode;
|
||||
uint8 data[MAX_SRTC_INDEX + 1];
|
||||
} srtc;
|
||||
void set_time();
|
||||
void init();
|
||||
void enable();
|
||||
void power();
|
||||
@@ -47,6 +12,11 @@ struct {
|
||||
void mmio_write(uint addr, uint8 data);
|
||||
|
||||
SRTC();
|
||||
|
||||
private:
|
||||
static const unsigned months[12];
|
||||
enum RTC_Mode { RTCM_Ready, RTCM_Command, RTCM_Read, RTCM_Write } rtc_mode;
|
||||
signed rtc_index;
|
||||
};
|
||||
|
||||
extern SRTC srtc;
|
||||
|
@@ -44,8 +44,9 @@ string file_updatepath(const char *req_file, const char *req_path) {
|
||||
return path;
|
||||
}
|
||||
|
||||
string_setting Path::base("path.base",
|
||||
"Path that bsnes resides in", "");
|
||||
string_setting Path::base("path.base", "Path that bsnes resides in", "");
|
||||
string_setting Path::user("path.user", "Path to user folder", "");
|
||||
|
||||
string_setting Path::rom(config(), "path.rom",
|
||||
"Default path to look for ROM files in (\"\" = use default directory)", "");
|
||||
string_setting Path::patch(config(), "path.patch",
|
||||
|
@@ -10,7 +10,7 @@ extern struct File {
|
||||
} file;
|
||||
|
||||
extern struct Path {
|
||||
static string_setting base, rom, patch, save, cheat;
|
||||
static string_setting base, user, rom, patch, save, cheat;
|
||||
static string_setting bsx, st;
|
||||
} path;
|
||||
|
||||
|
@@ -1,19 +1,32 @@
|
||||
template<int mask>
|
||||
struct CPUFlag {
|
||||
uint8 &data;
|
||||
|
||||
inline operator bool() const { return data & mask; }
|
||||
inline CPUFlag& operator=(bool i) { data = (data & ~mask) | (-i & mask); return *this; }
|
||||
|
||||
CPUFlag(uint8 &data_) : data(data_) {}
|
||||
};
|
||||
|
||||
class CPURegFlags {
|
||||
public:
|
||||
union {
|
||||
uint8 data;
|
||||
struct {
|
||||
bool order_msb8(n:1, v:1, m:1, x:1, d:1, i:1, z:1, c:1);
|
||||
};
|
||||
};
|
||||
CPUFlag<0x80> n;
|
||||
CPUFlag<0x40> v;
|
||||
CPUFlag<0x20> m;
|
||||
CPUFlag<0x10> x;
|
||||
CPUFlag<0x08> d;
|
||||
CPUFlag<0x04> i;
|
||||
CPUFlag<0x02> z;
|
||||
CPUFlag<0x01> c;
|
||||
|
||||
inline operator unsigned() const { return data; }
|
||||
template<typename T> inline unsigned operator = (const T i) { data = i; return data; }
|
||||
template<typename T> inline unsigned operator |= (const T i) { data |= i; return data; }
|
||||
template<typename T> inline unsigned operator ^= (const T i) { data ^= i; return data; }
|
||||
template<typename T> inline unsigned operator &= (const T i) { data &= i; return data; }
|
||||
inline unsigned operator = (unsigned i) { data = i; return data; }
|
||||
inline unsigned operator |= (unsigned i) { data |= i; return data; }
|
||||
inline unsigned operator ^= (unsigned i) { data ^= i; return data; }
|
||||
inline unsigned operator &= (unsigned i) { data &= i; return data; }
|
||||
|
||||
CPURegFlags() : data(0) {}
|
||||
CPURegFlags() : data(0), n(data), v(data), m(data), x(data), d(data), i(data), z(data), c(data) {}
|
||||
};
|
||||
|
||||
class CPUReg16 {
|
||||
@@ -24,17 +37,17 @@ public:
|
||||
};
|
||||
|
||||
inline operator unsigned() const { return w; }
|
||||
template<typename T> inline unsigned operator = (const T i) { w = i; return w; }
|
||||
template<typename T> inline unsigned operator |= (const T i) { w |= i; return w; }
|
||||
template<typename T> inline unsigned operator ^= (const T i) { w ^= i; return w; }
|
||||
template<typename T> inline unsigned operator &= (const T i) { w &= i; return w; }
|
||||
template<typename T> inline unsigned operator <<= (const T i) { w <<= i; return w; }
|
||||
template<typename T> inline unsigned operator >>= (const T i) { w >>= i; return w; }
|
||||
template<typename T> inline unsigned operator += (const T i) { w += i; return w; }
|
||||
template<typename T> inline unsigned operator -= (const T i) { w -= i; return w; }
|
||||
template<typename T> inline unsigned operator *= (const T i) { w *= i; return w; }
|
||||
template<typename T> inline unsigned operator /= (const T i) { w /= i; return w; }
|
||||
template<typename T> inline unsigned operator %= (const T i) { w %= i; return w; }
|
||||
inline unsigned operator = (unsigned i) { w = i; return w; }
|
||||
inline unsigned operator |= (unsigned i) { w |= i; return w; }
|
||||
inline unsigned operator ^= (unsigned i) { w ^= i; return w; }
|
||||
inline unsigned operator &= (unsigned i) { w &= i; return w; }
|
||||
inline unsigned operator <<= (unsigned i) { w <<= i; return w; }
|
||||
inline unsigned operator >>= (unsigned i) { w >>= i; return w; }
|
||||
inline unsigned operator += (unsigned i) { w += i; return w; }
|
||||
inline unsigned operator -= (unsigned i) { w -= i; return w; }
|
||||
inline unsigned operator *= (unsigned i) { w *= i; return w; }
|
||||
inline unsigned operator /= (unsigned i) { w /= i; return w; }
|
||||
inline unsigned operator %= (unsigned i) { w %= i; return w; }
|
||||
|
||||
CPUReg16() : w(0) {}
|
||||
};
|
||||
@@ -48,17 +61,17 @@ public:
|
||||
};
|
||||
|
||||
inline operator unsigned() const { return d; }
|
||||
template<typename T> inline unsigned operator = (const T i) { d = uclip<24>(i); return d; }
|
||||
template<typename T> inline unsigned operator |= (const T i) { d = uclip<24>(d | i); return d; }
|
||||
template<typename T> inline unsigned operator ^= (const T i) { d = uclip<24>(d ^ i); return d; }
|
||||
template<typename T> inline unsigned operator &= (const T i) { d = uclip<24>(d & i); return d; }
|
||||
template<typename T> inline unsigned operator <<= (const T i) { d = uclip<24>(d << i); return d; }
|
||||
template<typename T> inline unsigned operator >>= (const T i) { d = uclip<24>(d >> i); return d; }
|
||||
template<typename T> inline unsigned operator += (const T i) { d = uclip<24>(d + i); return d; }
|
||||
template<typename T> inline unsigned operator -= (const T i) { d = uclip<24>(d - i); return d; }
|
||||
template<typename T> inline unsigned operator *= (const T i) { d = uclip<24>(d * i); return d; }
|
||||
template<typename T> inline unsigned operator /= (const T i) { d = uclip<24>(d / i); return d; }
|
||||
template<typename T> inline unsigned operator %= (const T i) { d = uclip<24>(d % i); return d; }
|
||||
inline unsigned operator = (unsigned i) { d = uclip<24>(i); return d; }
|
||||
inline unsigned operator |= (unsigned i) { d = uclip<24>(d | i); return d; }
|
||||
inline unsigned operator ^= (unsigned i) { d = uclip<24>(d ^ i); return d; }
|
||||
inline unsigned operator &= (unsigned i) { d = uclip<24>(d & i); return d; }
|
||||
inline unsigned operator <<= (unsigned i) { d = uclip<24>(d << i); return d; }
|
||||
inline unsigned operator >>= (unsigned i) { d = uclip<24>(d >> i); return d; }
|
||||
inline unsigned operator += (unsigned i) { d = uclip<24>(d + i); return d; }
|
||||
inline unsigned operator -= (unsigned i) { d = uclip<24>(d - i); return d; }
|
||||
inline unsigned operator *= (unsigned i) { d = uclip<24>(d * i); return d; }
|
||||
inline unsigned operator /= (unsigned i) { d = uclip<24>(d / i); return d; }
|
||||
inline unsigned operator %= (unsigned i) { d = uclip<24>(d % i); return d; }
|
||||
|
||||
CPUReg24() : d(0) {}
|
||||
};
|
||||
@@ -71,5 +84,5 @@ public:
|
||||
uint8 db;
|
||||
uint8 mdr;
|
||||
bool e;
|
||||
CPURegs() : db(0), mdr(0x00), e(false) {}
|
||||
CPURegs() : db(0), mdr(0), e(false) {}
|
||||
};
|
||||
|
@@ -2,207 +2,201 @@
|
||||
|
||||
//op_read
|
||||
inline void sCPU::op_adc_b() {
|
||||
int32 r = regs.a.l + rd.l + regs.p.c;
|
||||
int r;
|
||||
if(regs.p.d) {
|
||||
uint8 n0 = (regs.a.l ) & 15;
|
||||
uint8 n1 = (regs.a.l >> 4) & 15;
|
||||
n0 += ((rd.l) & 15) + regs.p.c;
|
||||
n0 += (rd.l & 15) + regs.p.c;
|
||||
if(n0 > 9) {
|
||||
n0 -= 10;
|
||||
n0 &= 15;
|
||||
n0 = (n0 - 10) & 15;
|
||||
n1++;
|
||||
}
|
||||
n1 += ((rd.l >> 4) & 15);
|
||||
if(n1 > 9) {
|
||||
n1 -= 10;
|
||||
n1 &= 15;
|
||||
n1 = (n1 - 10) & 15;
|
||||
regs.p.c = 1;
|
||||
} else {
|
||||
regs.p.c = 0;
|
||||
}
|
||||
r = (n1 << 4) | (n0);
|
||||
r = (n1 << 4) | n0;
|
||||
} else {
|
||||
r = regs.a.l + rd.l + regs.p.c;
|
||||
regs.p.c = (r > 0xff);
|
||||
regs.p.c = r > 0xff;
|
||||
}
|
||||
regs.p.n = !!(r & 0x80);
|
||||
regs.p.v = !!(~(regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.v = ~(regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80;
|
||||
regs.p.z = (uint8)r == 0;
|
||||
regs.a.l = r;
|
||||
}
|
||||
|
||||
inline void sCPU::op_adc_w() {
|
||||
int32 r;
|
||||
int r;
|
||||
if(regs.p.d) {
|
||||
uint8 n0 = (regs.a.w ) & 15;
|
||||
uint8 n1 = (regs.a.w >> 4) & 15;
|
||||
uint8 n2 = (regs.a.w >> 8) & 15;
|
||||
uint8 n3 = (regs.a.w >> 12) & 15;
|
||||
n0 += ((rd.w) & 15) + regs.p.c;
|
||||
n0 += (rd.w & 15) + regs.p.c;
|
||||
if(n0 > 9) {
|
||||
n0 -= 10;
|
||||
n0 &= 15;
|
||||
n0 = (n0 - 10) & 15;
|
||||
n1++;
|
||||
}
|
||||
n1 += ((rd.w >> 4) & 15);
|
||||
if(n1 > 9) {
|
||||
n1 -= 10;
|
||||
n1 &= 15;
|
||||
n1 = (n1 - 10) & 15;
|
||||
n2++;
|
||||
}
|
||||
n2 += ((rd.w >> 8) & 15);
|
||||
if(n2 > 9) {
|
||||
n2 -= 10;
|
||||
n2 &= 15;
|
||||
n2 = (n2 - 10) & 15;
|
||||
n3++;
|
||||
}
|
||||
n3 += ((rd.w >> 12) & 15);
|
||||
if(n3 > 9) {
|
||||
n3 -= 10;
|
||||
n3 &= 15;
|
||||
n3 = (n3 - 10) & 15;
|
||||
regs.p.c = 1;
|
||||
} else {
|
||||
regs.p.c = 0;
|
||||
}
|
||||
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
|
||||
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | n0;
|
||||
} else {
|
||||
r = regs.a.w + rd.w + regs.p.c;
|
||||
regs.p.c = (r > 0xffff);
|
||||
regs.p.c = r > 0xffff;
|
||||
}
|
||||
regs.p.n = !!(r & 0x8000);
|
||||
regs.p.v = !!(~(regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
regs.p.n = r & 0x8000;
|
||||
regs.p.v = ~(regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000;
|
||||
regs.p.z = (uint16)r == 0;
|
||||
regs.a.w = r;
|
||||
}
|
||||
|
||||
inline void sCPU::op_and_b() {
|
||||
regs.a.l &= rd.l;
|
||||
regs.p.n = !!(regs.a.l & 0x80);
|
||||
regs.p.z = (regs.a.l == 0);
|
||||
regs.p.n = regs.a.l & 0x80;
|
||||
regs.p.z = regs.a.l == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_and_w() {
|
||||
regs.a.w &= rd.w;
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
regs.p.n = regs.a.w & 0x8000;
|
||||
regs.p.z = regs.a.w == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_bit_b() {
|
||||
regs.p.n = !!(rd.l & 0x80);
|
||||
regs.p.v = !!(rd.l & 0x40);
|
||||
regs.p.z = ((rd.l & regs.a.l) == 0);
|
||||
regs.p.n = rd.l & 0x80;
|
||||
regs.p.v = rd.l & 0x40;
|
||||
regs.p.z = (rd.l & regs.a.l) == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_bit_w() {
|
||||
regs.p.n = !!(rd.w & 0x8000);
|
||||
regs.p.v = !!(rd.w & 0x4000);
|
||||
regs.p.z = ((rd.w & regs.a.w) == 0);
|
||||
regs.p.n = rd.w & 0x8000;
|
||||
regs.p.v = rd.w & 0x4000;
|
||||
regs.p.z = (rd.w & regs.a.w) == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_cmp_b() {
|
||||
int32 r = regs.a.l - rd.l;
|
||||
regs.p.n = !!(r & 0x80);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
int r = regs.a.l - rd.l;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.z = (uint8)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_cmp_w() {
|
||||
int32 r = regs.a.w - rd.w;
|
||||
regs.p.n = !!(r & 0x8000);
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
int r = regs.a.w - rd.w;
|
||||
regs.p.n = r & 0x8000;
|
||||
regs.p.z = (uint16)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_cpx_b() {
|
||||
int32 r = regs.x.l - rd.l;
|
||||
regs.p.n = !!(r & 0x80);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
int r = regs.x.l - rd.l;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.z = (uint8)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_cpx_w() {
|
||||
int32 r = regs.x.w - rd.w;
|
||||
regs.p.n = !!(r & 0x8000);
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
int r = regs.x.w - rd.w;
|
||||
regs.p.n = r & 0x8000;
|
||||
regs.p.z = (uint16)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_cpy_b() {
|
||||
int32 r = regs.y.l - rd.l;
|
||||
regs.p.n = !!(r & 0x80);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
int r = regs.y.l - rd.l;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.z = (uint8)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_cpy_w() {
|
||||
int32 r = regs.y.w - rd.w;
|
||||
regs.p.n = !!(r & 0x8000);
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
int r = regs.y.w - rd.w;
|
||||
regs.p.n = r & 0x8000;
|
||||
regs.p.z = (uint16)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_eor_b() {
|
||||
regs.a.l ^= rd.l;
|
||||
regs.p.n = !!(regs.a.l & 0x80);
|
||||
regs.p.z = (regs.a.l == 0);
|
||||
regs.p.n = regs.a.l & 0x80;
|
||||
regs.p.z = regs.a.l == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_eor_w() {
|
||||
regs.a.w ^= rd.w;
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
regs.p.n = regs.a.w & 0x8000;
|
||||
regs.p.z = regs.a.w == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_lda_b() {
|
||||
regs.a.l = rd.l;
|
||||
regs.p.n = !!(regs.a.l & 0x80);
|
||||
regs.p.z = (regs.a.l == 0);
|
||||
regs.p.n = regs.a.l & 0x80;
|
||||
regs.p.z = regs.a.l == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_lda_w() {
|
||||
regs.a.w = rd.w;
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
regs.p.n = regs.a.w & 0x8000;
|
||||
regs.p.z = regs.a.w == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_ldx_b() {
|
||||
regs.x.l = rd.l;
|
||||
regs.p.n = !!(regs.x.l & 0x80);
|
||||
regs.p.z = (regs.x.l == 0);
|
||||
regs.p.n = regs.x.l & 0x80;
|
||||
regs.p.z = regs.x.l == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_ldx_w() {
|
||||
regs.x.w = rd.w;
|
||||
regs.p.n = !!(regs.x.w & 0x8000);
|
||||
regs.p.z = (regs.x.w == 0);
|
||||
regs.p.n = regs.x.w & 0x8000;
|
||||
regs.p.z = regs.x.w == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_ldy_b() {
|
||||
regs.y.l = rd.l;
|
||||
regs.p.n = !!(regs.y.l & 0x80);
|
||||
regs.p.z = (regs.y.l == 0);
|
||||
regs.p.n = regs.y.l & 0x80;
|
||||
regs.p.z = regs.y.l == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_ldy_w() {
|
||||
regs.y.w = rd.w;
|
||||
regs.p.n = !!(regs.y.w & 0x8000);
|
||||
regs.p.z = (regs.y.w == 0);
|
||||
regs.p.n = regs.y.w & 0x8000;
|
||||
regs.p.z = regs.y.w == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_ora_b() {
|
||||
regs.a.l |= rd.l;
|
||||
regs.p.n = !!(regs.a.l & 0x80);
|
||||
regs.p.z = (regs.a.l == 0);
|
||||
regs.p.n = regs.a.l & 0x80;
|
||||
regs.p.z = regs.a.l == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_ora_w() {
|
||||
regs.a.w |= rd.w;
|
||||
regs.p.n = !!(regs.a.w & 0x8000);
|
||||
regs.p.z = (regs.a.w == 0);
|
||||
regs.p.n = regs.a.w & 0x8000;
|
||||
regs.p.z = regs.a.w == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_sbc_b() {
|
||||
int32 r;
|
||||
int r;
|
||||
if(regs.p.d) {
|
||||
uint8 n0 = (regs.a.l ) & 15;
|
||||
uint8 n1 = (regs.a.l >> 4) & 15;
|
||||
@@ -221,16 +215,16 @@ int32 r;
|
||||
r = (n1 << 4) | (n0);
|
||||
} else {
|
||||
r = regs.a.l - rd.l - !regs.p.c;
|
||||
regs.p.c = (r >= 0);
|
||||
regs.p.c = r >= 0;
|
||||
}
|
||||
regs.p.n = !!(r & 0x80);
|
||||
regs.p.v = !!((regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.v = (regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80;
|
||||
regs.p.z = (uint8)r == 0;
|
||||
regs.a.l = r;
|
||||
}
|
||||
|
||||
inline void sCPU::op_sbc_w() {
|
||||
int32 r;
|
||||
int r;
|
||||
if(regs.p.d) {
|
||||
uint8 n0 = (regs.a.w ) & 15;
|
||||
uint8 n1 = (regs.a.w >> 4) & 15;
|
||||
@@ -261,116 +255,116 @@ int32 r;
|
||||
r = (n3 << 12) | (n2 << 8) | (n1 << 4) | (n0);
|
||||
} else {
|
||||
r = regs.a.w - rd.w - !regs.p.c;
|
||||
regs.p.c = (r >= 0);
|
||||
regs.p.c = r >= 0;
|
||||
}
|
||||
regs.p.n = !!(r & 0x8000);
|
||||
regs.p.v = !!((regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
regs.p.n = r & 0x8000;
|
||||
regs.p.v = (regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000;
|
||||
regs.p.z = (uint16)r == 0;
|
||||
regs.a.w = r;
|
||||
}
|
||||
|
||||
//op_rmw
|
||||
inline void sCPU::op_inc_b() {
|
||||
rd.l++;
|
||||
regs.p.n = !!(rd.l & 0x80);
|
||||
regs.p.z = (rd.l == 0);
|
||||
regs.p.n = rd.l & 0x80;
|
||||
regs.p.z = rd.l == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_inc_w() {
|
||||
rd.w++;
|
||||
regs.p.n = !!(rd.w & 0x8000);
|
||||
regs.p.z = (rd.w == 0);
|
||||
regs.p.n = rd.w & 0x8000;
|
||||
regs.p.z = rd.w == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_dec_b() {
|
||||
rd.l--;
|
||||
regs.p.n = !!(rd.l & 0x80);
|
||||
regs.p.z = (rd.l == 0);
|
||||
regs.p.n = rd.l & 0x80;
|
||||
regs.p.z = rd.l == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_dec_w() {
|
||||
rd.w--;
|
||||
regs.p.n = !!(rd.w & 0x8000);
|
||||
regs.p.z = (rd.w == 0);
|
||||
regs.p.n = rd.w & 0x8000;
|
||||
regs.p.z = rd.w == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_asl_b() {
|
||||
regs.p.c = !!(rd.l & 0x80);
|
||||
regs.p.c = rd.l & 0x80;
|
||||
rd.l <<= 1;
|
||||
regs.p.n = !!(rd.l & 0x80);
|
||||
regs.p.z = (rd.l == 0);
|
||||
regs.p.n = rd.l & 0x80;
|
||||
regs.p.z = rd.l == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_asl_w() {
|
||||
regs.p.c = !!(rd.w & 0x8000);
|
||||
regs.p.c = rd.w & 0x8000;
|
||||
rd.w <<= 1;
|
||||
regs.p.n = !!(rd.w & 0x8000);
|
||||
regs.p.z = (rd.w == 0);
|
||||
regs.p.n = rd.w & 0x8000;
|
||||
regs.p.z = rd.w == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_lsr_b() {
|
||||
regs.p.c = rd.l & 1;
|
||||
rd.l >>= 1;
|
||||
regs.p.n = !!(rd.l & 0x80);
|
||||
regs.p.z = (rd.l == 0);
|
||||
regs.p.n = rd.l & 0x80;
|
||||
regs.p.z = rd.l == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_lsr_w() {
|
||||
regs.p.c = rd.w & 1;
|
||||
rd.w >>= 1;
|
||||
regs.p.n = !!(rd.w & 0x8000);
|
||||
regs.p.z = (rd.w == 0);
|
||||
regs.p.n = rd.w & 0x8000;
|
||||
regs.p.z = rd.w == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_rol_b() {
|
||||
uint16 carry = (uint16)regs.p.c;
|
||||
regs.p.c = !!(rd.l & 0x80);
|
||||
unsigned carry = (unsigned)regs.p.c;
|
||||
regs.p.c = rd.l & 0x80;
|
||||
rd.l = (rd.l << 1) | carry;
|
||||
regs.p.n = !!(rd.l & 0x80);
|
||||
regs.p.z = (rd.l == 0);
|
||||
regs.p.n = rd.l & 0x80;
|
||||
regs.p.z = rd.l == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_rol_w() {
|
||||
uint16 carry = (uint16)regs.p.c;
|
||||
regs.p.c = !!(rd.w & 0x8000);
|
||||
unsigned carry = (unsigned)regs.p.c;
|
||||
regs.p.c = rd.w & 0x8000;
|
||||
rd.w = (rd.w << 1) | carry;
|
||||
regs.p.n = !!(rd.w & 0x8000);
|
||||
regs.p.z = (rd.w == 0);
|
||||
regs.p.n = rd.w & 0x8000;
|
||||
regs.p.z = rd.w == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_ror_b() {
|
||||
uint16 carry = (uint16)regs.p.c << 7;
|
||||
unsigned carry = (unsigned)regs.p.c << 7;
|
||||
regs.p.c = rd.l & 1;
|
||||
rd.l = carry | (rd.l >> 1);
|
||||
regs.p.n = !!(rd.l & 0x80);
|
||||
regs.p.z = (rd.l == 0);
|
||||
regs.p.n = rd.l & 0x80;
|
||||
regs.p.z = rd.l == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_ror_w() {
|
||||
uint16 carry = (uint16)regs.p.c << 15;
|
||||
unsigned carry = (unsigned)regs.p.c << 15;
|
||||
regs.p.c = rd.w & 1;
|
||||
rd.w = carry | (rd.w >> 1);
|
||||
regs.p.n = !!(rd.w & 0x8000);
|
||||
regs.p.z = (rd.w == 0);
|
||||
regs.p.n = rd.w & 0x8000;
|
||||
regs.p.z = rd.w == 0;
|
||||
}
|
||||
|
||||
inline void sCPU::op_trb_b() {
|
||||
regs.p.z = ((rd.l & regs.a.l) == 0);
|
||||
regs.p.z = (rd.l & regs.a.l) == 0;
|
||||
rd.l &= ~regs.a.l;
|
||||
}
|
||||
|
||||
inline void sCPU::op_trb_w() {
|
||||
regs.p.z = ((rd.w & regs.a.w) == 0);
|
||||
regs.p.z = (rd.w & regs.a.w) == 0;
|
||||
rd.w &= ~regs.a.w;
|
||||
}
|
||||
|
||||
inline void sCPU::op_tsb_b() {
|
||||
regs.p.z = ((rd.l & regs.a.l) == 0);
|
||||
regs.p.z = (rd.l & regs.a.l) == 0;
|
||||
rd.l |= regs.a.l;
|
||||
}
|
||||
|
||||
inline void sCPU::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;
|
||||
}
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.3 KiB |
@@ -2,39 +2,40 @@ static char enc_icon48[] = {
|
||||
"_gAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHw"
|
||||
"AfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB"
|
||||
"8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHw"
|
||||
"AfAB8AHwAfD_AfAB8AHwAfAB8AHwAfABgFD_oRYPBAA1BABWVQQAWwQAQQQAGgQA"
|
||||
"Av8u8AHwAfAB8AHwAfAB8AHwVbSAAQQALQQAsAQA9FUEAP8EwPsEAM4EAFP9BAAE"
|
||||
"QvAB8AHwAfAB8AHwqwHwvOAEBACFBAD5uPDVBOD-BAC9BAAUSvAB8L8B8AHwAfAB"
|
||||
"8AHwvGADBACuoqjwBPAEwNsEABZS8H8B8AHwAfAB8AHwAfDAIHuvnPAE8ATwBCDH"
|
||||
"BAAFVvC_AfAB8AHwAfAB8LzAIAQA3vaY8ATwBPAEYGZa8AHw3wHwAfAB8AHwwMCX"
|
||||
"kPAE8OsE8ASg3wQABl7wAfAB8K8B8AHwAfC8QAYEAOeQ8PcE8ATw0OMvYvAB8AHw"
|
||||
"AfDXAfAB8MBAHAQA_JDwBPALBPAE4GRi8AAAPz9U_wEEAA0EAB0EAB59BAAPBABE"
|
||||
"9gHwAfDA8BVVBABxBAB3BAChUET9p5zwBPAE8BaGuMALBACqbAQAzgQA9AQA-wQA"
|
||||
"qvwEAPYEANYEAHoEAL4SlvAB8AHwAfAEhjIEAF68FEKo8ATwBFCBcIFHtQQA5AQA"
|
||||
"_wTwBKDuBAB-XDQQjvAB8AHwAfAQhmhHzPYE8ARgpQ5YwEBor2xBsPAE8AQQ_QQA"
|
||||
"hFTyfwHwAfAB8MjA-Bgg8wTQowAQ-_-rACMuNrz_SrzwBPAE8MQgZ4LwbwHwAfAB"
|
||||
"8BDJkbTwBMCnAAfLfV-0ETU6fP_mnPAE8ATwBCAkExxfhvAB8AHwAfDEgBEEAO0D"
|
||||
"uPAEQKQO_f-tAIBCLDX_cTw-mPA3BPAE8ASAlYLwAUDNAKoBBAAFBAAUBAAiBAB-"
|
||||
"JQhAEBAYEETz5PYE8KgABZxKRfIENju8_9eQ8ATwBPAEoOq0wKoDBAAsBACGBADM"
|
||||
"BADq7AQA_AQA_gSAEBAYEOrKBACDBAAqBABMo6gAFkC88AQgrvgCBy83wP8VPj7_"
|
||||
"-JDwBPCvBPAIs7yAuBDEoED_BPBXBPAEQDAQwAQAKcCAHRf8S7hQMBl_uFk4O_--"
|
||||
"KYzwBPAE8ATwvEBhBABe95zwBPAE8ARg9gQAW1HAIJ8XFKwA8uhIkFUEAB-sxhkE"
|
||||
"AH0EAJL1BADDBADznPAE8ATwwADozQBIBAD5kPAE8ATwAQTg-ADQACn_nrwYAshD"
|
||||
"pPUB8NAQEQQA3nGgRqjwBPDAkOKI8ATw9wTwBPAEIM8UAwHwAfAB8HvIEPQYzKjw"
|
||||
"BPAEQDQS0t-I8ATwBPAE8ARAeprwAfB3AfDEYLAZyqzwBPAEAMX1cAAvBADxiPAE"
|
||||
"8ATwBOB68AQAGZbwAfAB8MSgHK0EAPGw8ASg_gQAScBDvj4URZTwBPAE8AQw6gQA"
|
||||
"RjwN9mwJ__8IBAAT_QQAGgRADBAUEET2xHDgE6u48ARwuwQAA0CFGQQAup0EAPOc"
|
||||
"8ATwBIDyBACgmADLABe0gAkEAKpFBACaBADSBADsBABa-QQA-wRADBDtBADTVQQA"
|
||||
"nQQASAQACsDAGK0EAPW48AQg3QQAFfbwVcggEQQAUwQAoRxD6b0EAPRcJNwwEBAY"
|
||||
"EJ8EAKpRBAAQuIAGBABuBAC66AQA_wTwBPAEgOoEAEpzBAAHSxBBOFgryF-88BQg"
|
||||
"LHEB8NDQBgQAC10EAA0IQLj-vDAQBADFr5jwBPAE8ASgywQAFMRA6pm4gOcEAHAE"
|
||||
"AOAgAfCvAfAB8AHwvEACBAC1jPAvBPAE8ATwBAC_VBBDMtT_TrAAeQQAPAQAYKLf"
|
||||
"AfAB8AHwAfDAQBnYQozw1wTwBPAE8P0EAB1p8AHwrwHwAfAB8MDgGAQA-ojw7wTw"
|
||||
"BPAE8AQA_AQA3PsB8N8B8AHwAfDA8CQVsYjwBPD3BPAE8AQAulz1AfAB8AHw1wHw"
|
||||
"AfDEQA0EAL2M8ATw9wTwBKAEFBFh8AHwAfAB8FcB8AHwxIAFBABoBADjXQQA_pzw"
|
||||
"BPAEgOUEAG3_hCUB8AHwAfAB8AHwAfAB8KvIEFwXPQQAkgQAz8BGXveYQwQQDBAU"
|
||||
"ENAEAJT9BABB9CYB8AHwAfAB8AHwrwHwAfAB8NBwBAQADtgl_QQwDxRA5PIB8AHw"
|
||||
"AfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB"
|
||||
"8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHw"
|
||||
"AfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHwfwHwAfAB8AHwAfAB8AGA"
|
||||
"AfAB8AHwAfD_AfAB8AHwAfAB8AHwAfABAAD_qgAD_p8VOwD_oRaI_qEWthD-oBbL"
|
||||
"CADE_qEAFaP_oBZm_p38GBU28AHwAfAB8AHwAfBfAfAB8AFQuBCoAMe0AP4twAD_"
|
||||
"BPAEIPAkAIX_-JkZCkLwAfAB8AHwAfBHAfAB8HSB_wABtABvPQQA-7DwBPAEECwA"
|
||||
"0P74oBIbTvAB8AHwAfAB8EcB8AHweEGgFWwkAv0HqPAE8MSwFdX-oRr-E1LwAfAB"
|
||||
"8AHwAfAB8Lzg6KEUMRAC96DwBPAE8P3EIKXAEVrwAfAB8AHwAfDzAfDAsBa3mPAE"
|
||||
"8ATwwED_uAE4E1rwAfAB8AHwAfAB8PG8YKIVJDjyBPAE8ATA-KAWoF7wAfAB8AHw"
|
||||
"AfB7AfD4gmmQ8ATwBPDM4-Z_XvAB8AHwAfAB8AHwwICPH_wSePQE8ATwBMClDxEB"
|
||||
"YNBERP8PPz_-oEw-Pv56CACMCACCgggAXT8__yD2BA808wHwAfDAkKMSDv6AmxwS"
|
||||
"_qQYH8QC6kjIAJTUAOug8ATwhOFDRABYUDw8_hWsAI9QPj7_8KwA_wTw_oL6BAC1"
|
||||
"PT3-MpbwjwHwAfAB8AxmpRkUFAOOkxjzBPAEoJ8PEEAQdZQAOrwA47TwBPAoAPh9"
|
||||
"yAB0hvAB8AHwAfBcsha6XFwC-KzwBPDsAOQ0EHWQAD0EAPSs8ATwBMCAn4LwAfAB"
|
||||
"8AHwXLUVakz4gwTwKACbQkL-F0wBTuac8ATwiPH-_AQATh-C8AHwAfAB8ExifwAC"
|
||||
"DcAAtbTwfKT8_qETejSAAJOc8ATwBPAUY9p9CAAIhvAB8AHwAfCEYZ4MGDWE8YCn"
|
||||
"nEs8_3oRgAD1lPAE8ATwBKBVh4LwAQAUCwDNACQEAKBNAMwAaggAewgAoH8AywBz"
|
||||
"CABbCABgNwDIAA458Nxp2IO88Hwhzf-ZEQ-0A15XjPAE8ATwhOGlfaDOVAA1oACY"
|
||||
"sADhCAD9jQgA_wTwBEDMAPQEAHq7NABjCAAcq2QRvPAW9sUMXHwAiIzwBPAE8MDg"
|
||||
"otZxIMsAGYQArQQATv6s8ATwzPAA4wQAUVcKAGQmYAR9MILpBAB3sP-qKgbgUPwC"
|
||||
"mwQAevuAAP6U8ATwBPDAYO3QANEAHIQA3JjwBPCrBPAEoPwEAGyAQVRwAeCV_qIX"
|
||||
"WPQWZNJ8AKoQgAQbSAI2hABtzAC6xAgA_aDwBPCIxOc4Ab6mjPAE8ATwBPAEAPYE"
|
||||
"AK9YZwHwAfA2QwLAAEgEAK7dqPAE8MCAx8AA5Ijw_wTwBPAE8ExCFPQB8AHwAQDQ"
|
||||
"Q0P-E5QAw6zwBPD1wECLcAC2iPAE8ATwBPD1BAD70AMqmvAB8AHwATDQODj-EpgA"
|
||||
"1LDwxPbFBAAxcCDNAOyM8ATwewTwBOCGkvAB8AHwIOM8t-AzuPC8g66UasQwyJDw"
|
||||
"VwTwBPAEIPHEBG4KAAJBDcYKAP7-LAQAT1UEAGUEAHAEAGoEAFd1BAA5BAASJAAY"
|
||||
"-8Qg_gaytPB8Yeg7O_8eUTGgvwAEyABUUAK3XZAA9aTw6OJsFdgIAIOQAM8AG_11"
|
||||
"_guUAKpgCAC1BADvDAD_BPAxBED-_vgIAEoA_nzDBAD4o0BA_lO88Lwgjuy4FPLw"
|
||||
"AYDPABCYAKpCoABtBACKBACbEACKngQAk4wnzQBXoCd3qBe5plgh4azwBPDM8P76"
|
||||
"9QQAiwwA1CjgGeQSvMD6yAQAKbHwAfAB8AHwvMC9RBH-nPAE8ATwBKDAxCFVVDXu"
|
||||
"sADzCAC9dEgEX3nwAfAB8AHwvMAxBAD8X4zwBPAE8ATwTAB-3Ewh_bQADHHwAfAB"
|
||||
"8AHwAfDAYL50iPAE8ATwBPDAQMRl8L8B8AHwAfAB8AHwcABMiPDvBPAE8ATwwECc"
|
||||
"ZfAB8AHwrwHwAfAB8HQAAnQAsIzw9wTwBPC84OQIABy1AfAB8O8B8AHwAfDs1ZUI"
|
||||
"8wTwBPD1vGDHBAAkXfAB8AHwAfCnAfAB8Mjw_zCEAJ8EAK7rpPAE8CgA9wQAvAQA"
|
||||
"_lQQAJC1AfAB8AHwAfAB8FcB8MjwkBE6BABsBACPVQQApAQArwQAqQQAl_UgAHgI"
|
||||
"AEsEANQsAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB"
|
||||
"8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_"
|
||||
"AfAB8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHw"
|
||||
"AfD_AfAB8AHwAfAB8AHwAfAB8A8B8AHwAfABsA"
|
||||
};
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
bbase : version 0.13 ~byuu (2008-04-02)
|
||||
bbase : version 0.14 ~byuu (2008-04-16)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
@@ -99,37 +99,12 @@ static char *userpath(char *output) {
|
||||
#else
|
||||
static char *userpath(char *output) {
|
||||
strcpy(output, "."); //failsafe
|
||||
struct passwd *userinfo = getpwuid(getuid());
|
||||
struct passwd *userinfo = getpwuid(getuid());
|
||||
if(userinfo) { strcpy(output, userinfo->pw_dir); }
|
||||
return output;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****
|
||||
* template functions
|
||||
*****/
|
||||
|
||||
template<typename T> inline void safe_free(T &handle) {
|
||||
if(handle) {
|
||||
free(handle);
|
||||
handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> inline void safe_delete(T &handle) {
|
||||
if(handle) {
|
||||
delete handle;
|
||||
handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T> inline void safe_release(T &handle) {
|
||||
if(handle) {
|
||||
handle->Release();
|
||||
handle = 0;
|
||||
}
|
||||
}
|
||||
|
||||
template<int min, int max, typename T> inline T minmax(const T x) {
|
||||
return (x < (T)min) ? (T)min : (x > (T)max) ? (T)max : x;
|
||||
}
|
||||
@@ -177,47 +152,47 @@ template<int min, int max, typename T> inline T minmax(const T x) {
|
||||
*****/
|
||||
|
||||
//pseudo-random number generator
|
||||
static uint prng() {
|
||||
static uint n = 0;
|
||||
static unsigned prng() {
|
||||
static unsigned n = 0;
|
||||
return n = (n >> 1) ^ (((n & 1) - 1) & 0xedb88320);
|
||||
}
|
||||
|
||||
static uint64 fget(FILE *fp, uint length = 1) {
|
||||
uint64 data = 0;
|
||||
for(uint i = 0; i < length; i++) {
|
||||
static uint64 fget(FILE *fp, unsigned length = 1) {
|
||||
uint64 data = 0;
|
||||
for(unsigned i = 0; i < length; i++) {
|
||||
data |= fgetc(fp) << (i << 3);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
static void fput(FILE *fp, uint64 data, uint length = 1) {
|
||||
for(uint i = 0; i < length; i++) {
|
||||
static void fput(FILE *fp, uint64 data, unsigned length = 1) {
|
||||
for(unsigned i = 0; i < length; i++) {
|
||||
fputc(data >> (i << 3), fp);
|
||||
}
|
||||
}
|
||||
|
||||
static bool fexists(const char *fn) {
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp)return false;
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp) return false;
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32 fsize(FILE *fp) {
|
||||
if(!fp)return 0;
|
||||
uint32 pos = ftell(fp);
|
||||
static unsigned fsize(FILE *fp) {
|
||||
if(!fp) return 0;
|
||||
unsigned pos = ftell(fp);
|
||||
fseek(fp, 0, SEEK_END);
|
||||
uint32 size = ftell(fp);
|
||||
unsigned size = ftell(fp);
|
||||
fseek(fp, pos, SEEK_SET);
|
||||
return size;
|
||||
}
|
||||
|
||||
static uint32 fsize(const char *fn) {
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp)return 0;
|
||||
static unsigned fsize(const char *fn) {
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp) return 0;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
uint32 size = ftell(fp);
|
||||
unsigned size = ftell(fp);
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
return size;
|
||||
|
6
src/lib/hiro/cc.bat
Normal file
6
src/lib/hiro/cc.bat
Normal file
@@ -0,0 +1,6 @@
|
||||
mingw32-g++ -c test/test.cpp -I. -I../
|
||||
mingw32-g++ -c hiro.cpp -I. -I../
|
||||
mingw32-g++ -c ../nall/string.cpp -I. -I../
|
||||
mingw32-g++ test.o hiro.o string.o -o test_app.exe -lkernel32 -luser32 -lgdi32 -ladvapi32 -lcomctl32 -lcomdlg32
|
||||
@pause
|
||||
@del *.o
|
6
src/lib/hiro/cc.sh
Normal file
6
src/lib/hiro/cc.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
clear
|
||||
g++ -c test/test.cpp -I. -I../
|
||||
g++ -c hiro.cpp `pkg-config --cflags gtk+-2.0` -I. -I../
|
||||
g++ -c ../nall/string.cpp -I. -I../
|
||||
g++ test.o hiro.o string.o -o test_app `pkg-config --libs gtk+-2.0` -lXtst
|
||||
rm *.o
|
@@ -4,6 +4,7 @@ void hiro_pbutton_tick(pButton *p) {
|
||||
|
||||
void pButton::create(uint style, uint width, uint height, const char *text) {
|
||||
button = gtk_button_new_with_label(text ? text : "");
|
||||
set_default_font(button);
|
||||
gtk_widget_set_size_request(button, width, height);
|
||||
gtk_widget_show(button);
|
||||
g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(hiro_pbutton_tick), (gpointer)this);
|
||||
|
@@ -1,9 +1,10 @@
|
||||
void hiro_pcheckbox_tick(pCheckbox *p) {
|
||||
if(p->self.on_tick) p->self.on_tick(Event(Event::Tick, p->checked(), &p->self));
|
||||
if(!p->locked && p->self.on_tick) p->self.on_tick(Event(Event::Tick, p->checked(), &p->self));
|
||||
}
|
||||
|
||||
void pCheckbox::create(uint style, uint width, uint height, const char *text) {
|
||||
checkbox = gtk_check_button_new_with_label(text ? text : "");
|
||||
set_default_font(checkbox);
|
||||
gtk_widget_set_size_request(checkbox, width, height);
|
||||
gtk_widget_show(checkbox);
|
||||
g_signal_connect_swapped(G_OBJECT(checkbox), "toggled", G_CALLBACK(hiro_pcheckbox_tick), (gpointer)this);
|
||||
@@ -15,7 +16,9 @@ void pCheckbox::set_text(const char *text) {
|
||||
}
|
||||
|
||||
void pCheckbox::check(bool state) {
|
||||
locked = true;
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox), state ? TRUE : FALSE);
|
||||
locked = false;
|
||||
}
|
||||
|
||||
void pCheckbox::uncheck() {
|
||||
@@ -28,6 +31,7 @@ bool pCheckbox::checked() {
|
||||
|
||||
pCheckbox::pCheckbox(Checkbox &self_) : pFormControl(self_), self(self_) {
|
||||
checkbox = 0;
|
||||
locked = false;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
@@ -10,6 +10,7 @@ public:
|
||||
pCheckbox(Checkbox&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *checkbox;
|
||||
GtkWidget* gtk_handle();
|
||||
GtkWidget *checkbox;
|
||||
bool locked;
|
||||
};
|
||||
|
@@ -4,6 +4,7 @@ void hiro_pcombobox_change(pCombobox *p) {
|
||||
|
||||
void pCombobox::create(uint style, uint width, uint height, const char *text) {
|
||||
combobox = gtk_combo_box_new_text();
|
||||
set_default_font(combobox);
|
||||
gtk_widget_set_size_request(combobox, width, height);
|
||||
gtk_widget_show(combobox);
|
||||
|
||||
|
@@ -26,6 +26,8 @@ void pEditbox::create(uint style, uint width, uint height, const char *text) {
|
||||
gtk_widget_show(editbox);
|
||||
gtk_widget_show(scrollbox);
|
||||
}
|
||||
|
||||
set_default_font(editbox);
|
||||
}
|
||||
|
||||
void pEditbox::set_text(const char *text) {
|
||||
|
@@ -1,5 +1,6 @@
|
||||
void pFrame::create(uint style, uint width, uint height, const char *text) {
|
||||
frame = gtk_frame_new(text ? text : "");
|
||||
set_default_font(frame);
|
||||
gtk_widget_set_size_request(frame, width, height);
|
||||
gtk_widget_show(frame);
|
||||
}
|
||||
|
@@ -6,6 +6,17 @@ using nall::max;
|
||||
|
||||
namespace libhiro {
|
||||
|
||||
static void set_font(GtkWidget *widget, gpointer font) {
|
||||
gtk_widget_modify_font(widget, (PangoFontDescription*)font);
|
||||
if(GTK_IS_CONTAINER(widget)) {
|
||||
gtk_container_foreach(GTK_CONTAINER(widget), (GtkCallback)set_font, font);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_default_font(GtkWidget *widget) {
|
||||
set_font(widget, phiro().font);
|
||||
}
|
||||
|
||||
#include "keymap.cpp"
|
||||
#include "widget.cpp"
|
||||
#include "window.cpp"
|
||||
@@ -49,9 +60,15 @@ void pHiro::init() {
|
||||
} else {
|
||||
colormap = gdk_screen_get_rgb_colormap(screen);
|
||||
}
|
||||
|
||||
font = pango_font_description_new();
|
||||
pango_font_description_set_family(font, "Sans");
|
||||
pango_font_description_set_absolute_size(font, 11.0 * PANGO_SCALE);
|
||||
pango_font_description_set_style(font, PANGO_STYLE_NORMAL);
|
||||
}
|
||||
|
||||
void pHiro::term() {
|
||||
pango_font_description_free(font);
|
||||
enable_screensaver();
|
||||
}
|
||||
|
||||
|
@@ -55,6 +55,7 @@ public:
|
||||
/* internal */
|
||||
GdkScreen *screen;
|
||||
GdkColormap *colormap;
|
||||
PangoFontDescription *font;
|
||||
bool is_composited;
|
||||
char default_path[PATH_MAX];
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
void pLabel::create(uint style, uint width, uint height, const char *text) {
|
||||
label = gtk_label_new(text ? text : "");
|
||||
set_default_font(label);
|
||||
gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.0);
|
||||
gtk_widget_set_size_request(label, width, height);
|
||||
gtk_widget_show(label);
|
||||
|
@@ -8,11 +8,11 @@ void hiro_plistbox_activate(pListbox *p) {
|
||||
}
|
||||
|
||||
void pListbox::create(uint style, uint width, uint height, const char *columns, const char *text) {
|
||||
bool header = style & Listbox::Header;
|
||||
GtkPolicyType hscroll = (style & Listbox::HorizontalScrollAlways) ? GTK_POLICY_ALWAYS :
|
||||
bool header = style & Listbox::Header;
|
||||
GtkPolicyType hscroll = (style & Listbox::HorizontalScrollAlways) ? GTK_POLICY_ALWAYS :
|
||||
(style & Listbox::HorizontalScrollNever) ? GTK_POLICY_NEVER :
|
||||
GTK_POLICY_AUTOMATIC;
|
||||
GtkPolicyType vscroll = (style & Listbox::VerticalScrollAlways) ? GTK_POLICY_ALWAYS :
|
||||
GtkPolicyType vscroll = (style & Listbox::VerticalScrollAlways) ? GTK_POLICY_ALWAYS :
|
||||
(style & Listbox::VerticalScrollNever) ? GTK_POLICY_NEVER :
|
||||
GTK_POLICY_AUTOMATIC;
|
||||
|
||||
@@ -20,10 +20,10 @@ GtkPolicyType vscroll = (style & Listbox::VerticalScrollAlways) ? GTK_POLICY_ALW
|
||||
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollbox), hscroll, vscroll);
|
||||
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrollbox), GTK_SHADOW_ETCHED_IN);
|
||||
|
||||
lstring list;
|
||||
lstring list;
|
||||
split(list, "\t", columns);
|
||||
|
||||
GType *v = (GType*)malloc(count(list) * sizeof(GType));
|
||||
GType *v = (GType*)malloc(count(list) * sizeof(GType));
|
||||
for(uint i = 0; i < count(list); i++) v[i] = G_TYPE_STRING;
|
||||
store = gtk_list_store_newv(count(list), v);
|
||||
free(v);
|
||||
@@ -35,7 +35,7 @@ GType *v = (GType*)malloc(count(list) * sizeof(GType));
|
||||
gtk_widget_show(listbox);
|
||||
gtk_widget_show(scrollbox);
|
||||
|
||||
//alternate colors for each listbox entry if there are multiple columns ...
|
||||
//alternate colors for each listbox entry if there are multiple columns ...
|
||||
gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(listbox), count(list) >= 2 ? true : false);
|
||||
for(uint i = 0; i < count(list); i++) {
|
||||
renderer = gtk_cell_renderer_text_new();
|
||||
@@ -54,6 +54,8 @@ GType *v = (GType*)malloc(count(list) * sizeof(GType));
|
||||
|
||||
g_signal_connect_swapped(G_OBJECT(listbox), "cursor-changed", G_CALLBACK(hiro_plistbox_change), (gpointer)this);
|
||||
g_signal_connect_swapped(G_OBJECT(listbox), "row-activated", G_CALLBACK(hiro_plistbox_activate), (gpointer)this);
|
||||
|
||||
set_default_font(listbox);
|
||||
}
|
||||
|
||||
void pListbox::autosize_columns() {
|
||||
|
@@ -1,15 +1,18 @@
|
||||
void hiro_pmenucheckitem_tick(pMenuCheckItem *p) {
|
||||
if(p->self.on_tick) p->self.on_tick(Event(Event::Tick, p->checked(), &p->self));
|
||||
if(!p->locked && p->self.on_tick) p->self.on_tick(Event(Event::Tick, p->checked(), &p->self));
|
||||
}
|
||||
|
||||
void pMenuCheckItem::create(const char *text) {
|
||||
item = gtk_check_menu_item_new_with_label(text ? text : "?");
|
||||
set_default_font(item);
|
||||
gtk_widget_show(item);
|
||||
g_signal_connect_swapped(G_OBJECT(item), "toggled", G_CALLBACK(hiro_pmenucheckitem_tick), (gpointer)this);
|
||||
}
|
||||
|
||||
void pMenuCheckItem::check(bool state) {
|
||||
locked = true;
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), state ? TRUE : FALSE);
|
||||
locked = false;
|
||||
}
|
||||
|
||||
void pMenuCheckItem::uncheck() {
|
||||
@@ -22,6 +25,7 @@ bool pMenuCheckItem::checked() {
|
||||
|
||||
pMenuCheckItem::pMenuCheckItem(MenuCheckItem &self_) : pMenuControl(self_), self(self_) {
|
||||
item = 0;
|
||||
locked = true;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
@@ -9,6 +9,7 @@ public:
|
||||
pMenuCheckItem(MenuCheckItem&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *item;
|
||||
GtkWidget* gtk_handle();
|
||||
GtkWidget *item;
|
||||
bool locked;
|
||||
};
|
||||
|
@@ -1,6 +1,7 @@
|
||||
void pMenuGroup::create(const char *text) {
|
||||
group = gtk_menu_new();
|
||||
item = gtk_menu_item_new_with_label(text ? text : "");
|
||||
set_default_font(item);
|
||||
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), group);
|
||||
gtk_widget_show(item);
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ void hiro_pmenuitem_tick(pMenuItem *p) {
|
||||
|
||||
void pMenuItem::create(const char *text) {
|
||||
item = gtk_menu_item_new_with_label(text ? text : "");
|
||||
set_default_font(item);
|
||||
g_signal_connect_swapped(G_OBJECT(item), "activate", G_CALLBACK(hiro_pmenuitem_tick), (gpointer)this);
|
||||
gtk_widget_show(item);
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
void hiro_pmenuradioitem_tick(pMenuRadioItem *p) {
|
||||
//GTK+ sends two messages: one for the activated radio item,
|
||||
//and one for the deactivated radio item. ignore the latter.
|
||||
if(p->checked() && p->self.on_tick) p->self.on_tick(Event(Event::Tick, 0, &p->self));
|
||||
//GTK+ sends two messages: one for the activated radio item,
|
||||
//and one for the deactivated radio item. ignore the latter.
|
||||
if(!p->locked && p->checked() && p->self.on_tick) p->self.on_tick(Event(Event::Tick, 0, &p->self));
|
||||
}
|
||||
|
||||
void pMenuRadioItem::create(MenuRadioItemGroup &group, const char *text) {
|
||||
@@ -10,12 +10,15 @@ void pMenuRadioItem::create(MenuRadioItemGroup &group, const char *text) {
|
||||
} else {
|
||||
item = gtk_radio_menu_item_new_with_label_from_widget(GTK_RADIO_MENU_ITEM(group[0]->p.gtk_handle()), text ? text : "");
|
||||
}
|
||||
set_default_font(item);
|
||||
gtk_widget_show(item);
|
||||
g_signal_connect_swapped(G_OBJECT(item), "toggled", G_CALLBACK(hiro_pmenuradioitem_tick), (gpointer)this);
|
||||
}
|
||||
|
||||
void pMenuRadioItem::check() {
|
||||
locked = true;
|
||||
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), TRUE);
|
||||
locked = false;
|
||||
}
|
||||
|
||||
bool pMenuRadioItem::checked() {
|
||||
@@ -24,6 +27,7 @@ bool pMenuRadioItem::checked() {
|
||||
|
||||
pMenuRadioItem::pMenuRadioItem(MenuRadioItem &self_) : pMenuControl(self_), self(self_) {
|
||||
item = 0;
|
||||
locked = false;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
@@ -8,6 +8,7 @@ public:
|
||||
pMenuRadioItem(MenuRadioItem&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *item;
|
||||
GtkWidget* gtk_handle();
|
||||
GtkWidget *item;
|
||||
bool locked;
|
||||
};
|
||||
|
@@ -1,7 +1,7 @@
|
||||
void hiro_pradiobox_tick(pRadiobox *p) {
|
||||
//GTK+ sends two messages: one for the activated radiobox,
|
||||
//and one for the deactivated radiobox. ignore the latter.
|
||||
if(p->checked() && p->self.on_tick) p->self.on_tick(Event(Event::Tick, 0, &p->self));
|
||||
//GTK+ sends two messages: one for the activated radiobox,
|
||||
//and one for the deactivated radiobox. ignore the latter.
|
||||
if(!p->locked && p->checked() && p->self.on_tick) p->self.on_tick(Event(Event::Tick, 0, &p->self));
|
||||
}
|
||||
|
||||
void pRadiobox::create(RadioboxGroup &group, uint style, uint width, uint height, const char *text) {
|
||||
@@ -10,6 +10,7 @@ void pRadiobox::create(RadioboxGroup &group, uint style, uint width, uint height
|
||||
} else {
|
||||
radiobox = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(group[0]->p.gtk_handle()), text ? text : "");
|
||||
}
|
||||
set_default_font(radiobox);
|
||||
gtk_widget_set_size_request(radiobox, width, height);
|
||||
gtk_widget_show(radiobox);
|
||||
g_signal_connect_swapped(G_OBJECT(radiobox), "toggled", G_CALLBACK(hiro_pradiobox_tick), (gpointer)this);
|
||||
@@ -21,7 +22,9 @@ void pRadiobox::set_text(const char *text) {
|
||||
}
|
||||
|
||||
void pRadiobox::check() {
|
||||
locked = true;
|
||||
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radiobox), TRUE);
|
||||
locked = false;
|
||||
}
|
||||
|
||||
bool pRadiobox::checked() {
|
||||
@@ -30,6 +33,7 @@ bool pRadiobox::checked() {
|
||||
|
||||
pRadiobox::pRadiobox(Radiobox &self_) : pFormControl(self), self(self_) {
|
||||
radiobox = 0;
|
||||
locked = false;
|
||||
}
|
||||
|
||||
/* internal */
|
||||
|
@@ -9,6 +9,7 @@ public:
|
||||
pRadiobox(Radiobox&);
|
||||
|
||||
/* internal */
|
||||
GtkWidget *radiobox;
|
||||
GtkWidget* gtk_handle();
|
||||
GtkWidget *radiobox;
|
||||
bool locked;
|
||||
};
|
||||
|
@@ -65,6 +65,7 @@ void pWindow::create(uint style, uint width, uint height, const char *text) {
|
||||
//without affecting the statusbar color
|
||||
statuscontainer = gtk_event_box_new();
|
||||
statusbar = gtk_statusbar_new();
|
||||
set_default_font(statusbar);
|
||||
gtk_container_add(GTK_CONTAINER(statuscontainer), statusbar);
|
||||
gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(statusbar), false);
|
||||
gtk_box_pack_start(GTK_BOX(menucontainer), statuscontainer, false, false, 0);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
hiro
|
||||
version: 0.003 (2008-04-06)
|
||||
version: 0.005 (2008-05-25)
|
||||
author: byuu
|
||||
license: public domain
|
||||
*/
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/function.hpp>
|
||||
#include <nall/input.hpp>
|
||||
#include <nall/new.hpp>
|
||||
#include <nall/stdint.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
237
src/lib/hiro/test/test.cpp
Normal file
237
src/lib/hiro/test/test.cpp
Normal file
@@ -0,0 +1,237 @@
|
||||
#include "../hiro.h"
|
||||
using namespace libhiro;
|
||||
|
||||
#include <nall/algorithm.hpp>
|
||||
using nall::min;
|
||||
using nall::max;
|
||||
|
||||
bool kill_ = false;
|
||||
|
||||
uint32_t windowicon[16 * 16] = {
|
||||
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
|
||||
};
|
||||
|
||||
class SubWindow : public Window {
|
||||
public:
|
||||
Button button;
|
||||
|
||||
uintptr_t tick(Event) {
|
||||
hide();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
create(0, 595, 80);
|
||||
|
||||
button.create(0, 595, 80, "SubWindow (click to hide)");
|
||||
button.on_tick = bind(&SubWindow::tick, this);
|
||||
attach(button, 0, 0);
|
||||
}
|
||||
} subwindow;
|
||||
|
||||
class MainWindow : public Window {
|
||||
public:
|
||||
MenuGroup menu_file;
|
||||
MenuGroup menu_file_disk;
|
||||
MenuItem menu_file_disk_load;
|
||||
MenuItem menu_file_disk_save;
|
||||
MenuSeparator menu_file_separator;
|
||||
MenuItem menu_file_exit;
|
||||
MenuGroup menu_help;
|
||||
MenuCheckItem menu_help_check1, menu_help_check2;
|
||||
MenuSeparator menu_help_separator1;
|
||||
MenuRadioItem menu_help_radio1, menu_help_radio2, menu_help_radio3;
|
||||
MenuSeparator menu_help_separator2;
|
||||
MenuItem menu_help_about;
|
||||
Label label;
|
||||
Editbox editbox, editbox_multi;
|
||||
Button button_ok;
|
||||
Button button_exit;
|
||||
Checkbox check1, check2;
|
||||
Radiobox radio1, radio2;
|
||||
Progressbar progress;
|
||||
Combobox combobox;
|
||||
Listbox listbox;
|
||||
Slider hslider, vslider;
|
||||
Frame frame;
|
||||
Canvas canvas;
|
||||
|
||||
uintptr_t change(Event e) {
|
||||
printf("change(%d)\n", (uint)e.param);
|
||||
}
|
||||
|
||||
uintptr_t activate(Event e) {
|
||||
printf("activate(%d)\n", (uint)e.param);
|
||||
}
|
||||
|
||||
uintptr_t tick(Event e) {
|
||||
printf("tick(%d)\n", e.param);
|
||||
if(e.widget == &button_ok) {
|
||||
char t[4096];
|
||||
editbox.get_text(t, 4096);
|
||||
printf("'%s'\n", t);
|
||||
}
|
||||
if(e.widget == &menu_file_disk_load) {
|
||||
char t[4096] = "";
|
||||
hiro().file_open(0, t, "", "Source files\t*.cpp,*.h\nAll Files\t*.*");
|
||||
printf("'%s'\n", t);
|
||||
}
|
||||
if(e.widget == &menu_file_disk_save) {
|
||||
char t[4096] = "";
|
||||
hiro().file_save(0, t, "", "Source files\t*.cpp,*.h\nAll Files\t*.*");
|
||||
printf("'%s'\n", t);
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t keydown(Event e) {
|
||||
static bool fs = false;
|
||||
if(e.param == nall::keyboard::f11) {
|
||||
fs = !fs;
|
||||
fs ? fullscreen() : unfullscreen();
|
||||
printf("%d -> %4d, %4d\n", fs, get_width(), get_height());
|
||||
} else if(e.param == nall::keyboard::escape) {
|
||||
menu.show(!menu.visible());
|
||||
}
|
||||
}
|
||||
|
||||
uintptr_t close(Event) {
|
||||
printf("close()\n");
|
||||
return kill_ = true;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
create(Window::AutoCenter, 605, 320, "hiro test application");
|
||||
//set_opacity(224);
|
||||
//set_background_color(0, 0, 0);
|
||||
set_icon(16, 16, windowicon);
|
||||
|
||||
attach(menu_file.create("File"));
|
||||
menu_file.attach(menu_file_disk.create("Disk"));
|
||||
menu_file_disk.attach(menu_file_disk_load.create("Load ..."));
|
||||
menu_file_disk.attach(menu_file_disk_save.create("Save ..."));
|
||||
menu_file.attach(menu_file_separator.create());
|
||||
menu_file.attach(menu_file_exit.create("Exit"));
|
||||
attach(menu_help.create("Help"));
|
||||
menu_help.attach(menu_help_check1.create("Check 1"));
|
||||
menu_help.attach(menu_help_check2.create("Check 2"));
|
||||
menu_help.attach(menu_help_separator1.create());
|
||||
{ MenuRadioItemGroup group;
|
||||
group.add(&menu_help_radio1);
|
||||
group.add(&menu_help_radio2);
|
||||
group.add(&menu_help_radio3);
|
||||
menu_help.attach(menu_help_radio1.create(group, "Radio 1"));
|
||||
menu_help.attach(menu_help_radio2.create(group, "Radio 2"));
|
||||
menu_help.attach(menu_help_radio3.create(group, "Radio 3"));
|
||||
} menu_help.attach(menu_help_separator2.create());
|
||||
menu_help.attach(menu_help_about.create("About ..."));
|
||||
menu_help_about.disable();
|
||||
label.create(0, 200, 35, "hiro test application\n~ byuu");
|
||||
editbox.create(0, 200, 25);
|
||||
button_ok.create(0, 100, 30, "Ok");
|
||||
button_exit.create(0, 100, 30, "Exit");
|
||||
editbox_multi.create(Editbox::Multiline | Editbox::VerticalScrollAlways, 200, 95);
|
||||
check1.create(0, 100, 20, "Check 1");
|
||||
check2.create(0, 100, 20, "Check 2");
|
||||
{ RadioboxGroup group;
|
||||
group.add(&radio1);
|
||||
group.add(&radio2);
|
||||
radio1.create(group, 0, 100, 20, "Radio 1");
|
||||
radio2.create(group, 0, 100, 20, "Radio 2");
|
||||
} progress.create(0, 200, 30);
|
||||
progress.set_progress(50);
|
||||
combobox.create(0, 200, 30);
|
||||
combobox.add_item("Option 1");
|
||||
combobox.add_item("Option 2");
|
||||
combobox.add_item("Option 3");
|
||||
listbox.create(Listbox::Header | Listbox::VerticalScrollAlways, 200, 100, "Name\tValue");
|
||||
listbox.add_item("a\ttrue");
|
||||
listbox.add_item("b\tfalse");
|
||||
hslider.create(Slider::Horizontal, 425, 25, 10);
|
||||
vslider.create(Slider::Vertical, 25, 200, 10);
|
||||
frame.create(0, 155, 225, "Canvas:");
|
||||
|
||||
canvas.create(0, 135, 195);
|
||||
for(uint y = 0; y < 195; y++) {
|
||||
uint32_t *p = canvas.buffer() + y * 135;
|
||||
for(uint x = 0; x < 135; x++) {
|
||||
double dx = 128.0 / 135.0 * double(x);
|
||||
double dy = 128.0 / 195.0 * double(y);
|
||||
uint32_t c = uint32_t(dx) + uint32_t(dy);
|
||||
*p++ = (max(0U, min(c, 255U)) ^ 0xff) << 16;
|
||||
}
|
||||
}
|
||||
|
||||
status.show();
|
||||
status.set_text("Statusbar");
|
||||
|
||||
on_close = bind(&MainWindow::close, this);
|
||||
on_keydown = bind(&MainWindow::keydown, this);
|
||||
|
||||
menu_file_disk_load.on_tick =
|
||||
menu_file_disk_save.on_tick = bind(&MainWindow::tick, this);
|
||||
menu_file_exit.on_tick = on_close;
|
||||
menu_help_check1.on_tick = menu_help_check2.on_tick =
|
||||
menu_help_radio1.on_tick = menu_help_radio2.on_tick =
|
||||
menu_help_radio3.on_tick = bind(&MainWindow::tick, this);
|
||||
menu_help_about.on_tick = bind(&MainWindow::tick, this);
|
||||
button_ok.on_tick = bind(&MainWindow::tick, this);
|
||||
button_exit.on_tick = bind(&MainWindow::close, this);
|
||||
check1.on_tick = check2.on_tick =
|
||||
radio1.on_tick = radio2.on_tick = bind(&MainWindow::tick, this);
|
||||
combobox.on_change = bind(&MainWindow::change, this);
|
||||
listbox.on_change = bind(&MainWindow::change, this);
|
||||
listbox.on_activate = bind(&MainWindow::activate, this);
|
||||
hslider.on_change = bind(&MainWindow::change, this);
|
||||
vslider.on_change = bind(&MainWindow::change, this);
|
||||
|
||||
attach(label, 5, 5);
|
||||
attach(editbox, 5, 40);
|
||||
attach(button_ok, 5, 70);
|
||||
attach(button_exit, 105, 70);
|
||||
attach(editbox_multi, 210, 5);
|
||||
attach(check1, 5, 105);
|
||||
attach(check2, 105, 105);
|
||||
attach(radio1, 5, 125);
|
||||
attach(radio2, 105, 125);
|
||||
attach(progress, 5, 145);
|
||||
attach(combobox, 5, 175);
|
||||
attach(listbox, 210, 105);
|
||||
attach(hslider, 5, 205);
|
||||
attach(vslider, 415, 5);
|
||||
|
||||
attach(frame, 445, 5);
|
||||
attach(canvas, 455, 25);
|
||||
|
||||
attach(subwindow, 5, 235);
|
||||
}
|
||||
} window;
|
||||
|
||||
int main() {
|
||||
hiro().init();
|
||||
hiro().disable_screensaver();
|
||||
|
||||
subwindow.setup();
|
||||
window.setup();
|
||||
window.show();
|
||||
|
||||
window.check1.check();
|
||||
|
||||
while(kill_ == false) hiro().run();
|
||||
|
||||
hiro().term();
|
||||
return 0;
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
void pButton::create(uint style, uint width, uint height, const char *text) {
|
||||
hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_TABSTOP | WS_VISIBLE,
|
||||
hwnd = CreateWindow(L"BUTTON", utf16(text), WS_CHILD | WS_TABSTOP | WS_VISIBLE,
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
|
||||
@@ -7,7 +7,7 @@ void pButton::create(uint style, uint width, uint height, const char *text) {
|
||||
}
|
||||
|
||||
void pButton::set_text(const char *text) {
|
||||
SetWindowText(hwnd, text ? text : "");
|
||||
SetWindowText(hwnd, utf16(text));
|
||||
}
|
||||
|
||||
pButton::pButton(Button &self_) : pFormControl(self_), self(self_) {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
void pCanvas::create(uint style, uint width, uint height) {
|
||||
hwnd = CreateWindow("hiro_window", "", WS_CHILD,
|
||||
hwnd = CreateWindow(L"hiro_window", L"", WS_CHILD,
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
|
||||
@@ -8,6 +8,11 @@ void pCanvas::create(uint style, uint width, uint height) {
|
||||
}
|
||||
|
||||
void pCanvas::redraw() {
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(hwnd, &ps);
|
||||
SetDIBitsToDevice(ps.hdc, 0, 0, iwidth, iheight, 0, 0, 0, iheight, (void*)ibuffer, &bmi, DIB_RGB_COLORS);
|
||||
EndPaint(hwnd, &ps);
|
||||
InvalidateRect(hwnd, 0, FALSE);
|
||||
}
|
||||
|
||||
uint32_t* pCanvas::buffer() {
|
||||
@@ -30,13 +35,6 @@ pCanvas::~pCanvas() {
|
||||
|
||||
/* internal */
|
||||
|
||||
void pCanvas::blit() {
|
||||
PAINTSTRUCT ps;
|
||||
BeginPaint(hwnd, &ps);
|
||||
SetDIBitsToDevice(ps.hdc, 0, 0, iwidth, iheight, 0, 0, 0, iheight, (void*)ibuffer, &bmi, DIB_RGB_COLORS);
|
||||
EndPaint(hwnd, &ps);
|
||||
}
|
||||
|
||||
void pCanvas::resize(uint width, uint height) {
|
||||
if(ibuffer) free(ibuffer);
|
||||
|
||||
|
@@ -12,6 +12,5 @@ public:
|
||||
BITMAPINFO bmi;
|
||||
uint32_t *ibuffer;
|
||||
uint ipitch, iwidth, iheight;
|
||||
void blit();
|
||||
void resize(uint width, uint height);
|
||||
};
|
||||
|
@@ -1,20 +1,16 @@
|
||||
void pCheckbox::create(uint style, uint width, uint height, const char *text) {
|
||||
hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_CHECKBOX,
|
||||
hwnd = CreateWindow(L"BUTTON", utf16(text), WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_CHECKBOX,
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
|
||||
}
|
||||
|
||||
void pCheckbox::set_text(const char *text) {
|
||||
SetWindowText(hwnd, text ? text : "");
|
||||
SetWindowText(hwnd, utf16(text));
|
||||
}
|
||||
|
||||
void pCheckbox::check(bool state) {
|
||||
bool prev = checked();
|
||||
SendMessage(hwnd, BM_SETCHECK, (WPARAM)(state ? TRUE : FALSE), 0);
|
||||
if(prev != state) {
|
||||
if(self.on_tick) self.on_tick(Event(Event::Tick, state, &self));
|
||||
}
|
||||
}
|
||||
|
||||
void pCheckbox::uncheck() {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
void pCombobox::create(uint style, uint width, uint height, const char *text) {
|
||||
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "COMBOBOX", "",
|
||||
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, L"COMBOBOX", L"",
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE | CBS_DROPDOWNLIST | CBS_HASSTRINGS,
|
||||
0, 0, width, 200,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
@@ -17,7 +17,7 @@ void pCombobox::create(uint style, uint width, uint height, const char *text) {
|
||||
}
|
||||
|
||||
void pCombobox::add_item(const char *text) {
|
||||
SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)text);
|
||||
SendMessage(hwnd, CB_ADDSTRING, 0, (LPARAM)(wchar_t*)utf16(text));
|
||||
if(SendMessage(hwnd, CB_GETCOUNT, 0, 0) == 1) set_selection(0);
|
||||
}
|
||||
|
||||
|
@@ -8,7 +8,7 @@ void pEditbox::create(uint style, uint width, uint height, const char *text) {
|
||||
(style & Editbox::HorizontalScrollNever) ? 0 :
|
||||
ES_AUTOHSCROLL;
|
||||
|
||||
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "",
|
||||
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
|
||||
WS_CHILD | WS_VISIBLE | vscroll | hscroll |
|
||||
(multiline == true ? ES_MULTILINE | ES_WANTRETURN : WS_TABSTOP) |
|
||||
(readonly == true ? ES_READONLY : 0),
|
||||
@@ -22,14 +22,15 @@ void pEditbox::set_text(const char *text) {
|
||||
string temp = text ? text : "";
|
||||
replace(temp, "\r", "");
|
||||
replace(temp, "\n", "\r\n");
|
||||
SetWindowText(hwnd, temp);
|
||||
SetWindowText(hwnd, utf16(temp));
|
||||
}
|
||||
|
||||
uint pEditbox::get_text(char *text, uint length) {
|
||||
GetWindowText(hwnd, text, length);
|
||||
string temp = text;
|
||||
wchar_t buffer[length * 2 + 1];
|
||||
GetWindowText(hwnd, buffer, length * 2);
|
||||
string temp = (const char*)utf8(buffer);
|
||||
replace(temp, "\r", "");
|
||||
strcpy(text, temp);
|
||||
strlcpy(text, temp, length);
|
||||
return strlen(text);
|
||||
}
|
||||
|
||||
|
@@ -1,12 +1,12 @@
|
||||
void pFrame::create(uint style, uint width, uint height, const char *text) {
|
||||
hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
|
||||
hwnd = CreateWindow(L"BUTTON", utf16(text), WS_CHILD | WS_VISIBLE | BS_GROUPBOX,
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
|
||||
}
|
||||
|
||||
void pFrame::set_text(const char *text) {
|
||||
SetWindowText(hwnd, text ? text : "");
|
||||
SetWindowText(hwnd, utf16(text));
|
||||
}
|
||||
|
||||
pFrame::pFrame(Frame &self_) : pFormControl(self_), self(self_) {
|
||||
|
@@ -8,6 +8,7 @@ namespace libhiro {
|
||||
|
||||
LRESULT CALLBACK phiro_wndproc(HWND, UINT, WPARAM, LPARAM);
|
||||
|
||||
#include "utf.cpp"
|
||||
#include "keymap.cpp"
|
||||
#include "widget.cpp"
|
||||
#include "window.cpp"
|
||||
@@ -43,14 +44,14 @@ void pHiro::init() {
|
||||
wc.hIcon = LoadIcon(0, IDI_APPLICATION);
|
||||
wc.hInstance = GetModuleHandle(0);
|
||||
wc.lpfnWndProc = phiro_wndproc;
|
||||
wc.lpszClassName = "hiro_window";
|
||||
wc.lpszClassName = L"hiro_window";
|
||||
wc.lpszMenuName = 0;
|
||||
wc.style = CS_HREDRAW | CS_VREDRAW;
|
||||
RegisterClass(&wc);
|
||||
|
||||
InitCommonControls();
|
||||
default_hwnd = CreateWindow("hiro_window", "", WS_POPUP, 0, 0, 640, 480, 0, 0, GetModuleHandle(0), 0);
|
||||
default_font = create_font("Tahoma", 9);
|
||||
default_hwnd = CreateWindow(L"hiro_window", L"", WS_POPUP, 0, 0, 640, 480, 0, 0, GetModuleHandle(0), 0);
|
||||
default_font = create_font("Tahoma", 8);
|
||||
black_brush = CreateSolidBrush(RGB(0, 0, 0));
|
||||
}
|
||||
|
||||
@@ -76,12 +77,13 @@ bool pHiro::pending() {
|
||||
}
|
||||
|
||||
bool pHiro::folder_select(Window *focus, char *filename, const char *path) {
|
||||
wchar_t wfilename[_MAX_PATH] = L"";
|
||||
strcpy(filename, "");
|
||||
BROWSEINFO bi;
|
||||
bi.hwndOwner = focus ? focus->p.hwnd : 0;
|
||||
bi.pidlRoot = NULL;
|
||||
bi.pszDisplayName = filename;
|
||||
bi.lpszTitle = "Select Folder";
|
||||
bi.pszDisplayName = wfilename;
|
||||
bi.lpszTitle = L"";
|
||||
bi.ulFlags = BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS;
|
||||
bi.lpfn = NULL;
|
||||
bi.lParam = 0;
|
||||
@@ -89,7 +91,7 @@ bool pHiro::folder_select(Window *focus, char *filename, const char *path) {
|
||||
bool result = false;
|
||||
LPITEMIDLIST pidl = SHBrowseForFolder(&bi);
|
||||
if(pidl) {
|
||||
if(SHGetPathFromIDList(pidl, filename)) {
|
||||
if(SHGetPathFromIDList(pidl, wfilename)) {
|
||||
result = true;
|
||||
IMalloc *imalloc = 0;
|
||||
if(SUCCEEDED(SHGetMalloc(&imalloc))) {
|
||||
@@ -98,6 +100,7 @@ bool pHiro::folder_select(Window *focus, char *filename, const char *path) {
|
||||
}
|
||||
}
|
||||
}
|
||||
strcpy(filename, utf8(wfilename));
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -108,23 +111,28 @@ bool pHiro::file_open(Window *focus, char *filename, const char *path, const cha
|
||||
|
||||
lstring type, part;
|
||||
strcpy(f, "");
|
||||
split(type, "|", filter);
|
||||
split(type, "\n", filter);
|
||||
for(int i = 0; i < count(type); i++) {
|
||||
split(part, ";", type[i]);
|
||||
if(count(part) != 2)continue;
|
||||
split(part, "\t", type[i]);
|
||||
if(count(part) != 2) continue;
|
||||
|
||||
strcat(f, part[0]);
|
||||
strcat(f, " (");
|
||||
strcat(f, part[1]);
|
||||
strcat(f, ")|");
|
||||
strcat(f, ")\t");
|
||||
replace(part[1], ",", ";");
|
||||
strcat(f, part[1]);
|
||||
strcat(f, "|");
|
||||
strcat(f, "\t");
|
||||
}
|
||||
|
||||
char *pf = f();
|
||||
for(int i = strlen(pf) - 1; i >= 0; i--) {
|
||||
if(pf[i] == '|') pf[i] = '\0';
|
||||
utf16 wfilter(f);
|
||||
utf16 wdir(dir);
|
||||
wchar_t wfilename[_MAX_PATH] = L"";
|
||||
|
||||
wchar_t *p = wfilter;
|
||||
while(*p != L'\0') {
|
||||
if(*p == L'\t') *p = L'\0';
|
||||
p++;
|
||||
}
|
||||
|
||||
OPENFILENAME ofn;
|
||||
@@ -132,14 +140,16 @@ bool pHiro::file_open(Window *focus, char *filename, const char *path, const cha
|
||||
memset(&ofn, 0, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = focus ? focus->p.hwnd : 0;
|
||||
ofn.lpstrFilter = pf;
|
||||
ofn.lpstrInitialDir = dir;
|
||||
ofn.lpstrFile = filename;
|
||||
ofn.lpstrFilter = wfilter;
|
||||
ofn.lpstrInitialDir = wdir;
|
||||
ofn.lpstrFile = wfilename;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
|
||||
ofn.lpstrDefExt = "";
|
||||
ofn.lpstrDefExt = L"";
|
||||
|
||||
return GetOpenFileName(&ofn);
|
||||
bool result = GetOpenFileName(&ofn);
|
||||
strcpy(filename, utf8(wfilename));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool pHiro::file_save(Window *focus, char *filename, const char *path, const char *filter) {
|
||||
@@ -149,23 +159,28 @@ bool pHiro::file_save(Window *focus, char *filename, const char *path, const cha
|
||||
|
||||
lstring type, part;
|
||||
strcpy(f, "");
|
||||
split(type, "|", filter);
|
||||
split(type, "\n", filter);
|
||||
for(int i = 0; i < count(type); i++) {
|
||||
split(part, ";", type[i]);
|
||||
if(count(part) != 2)continue;
|
||||
split(part, "\t", type[i]);
|
||||
if(count(part) != 2) continue;
|
||||
|
||||
strcat(f, part[0]);
|
||||
strcat(f, " (");
|
||||
strcat(f, part[1]);
|
||||
strcat(f, ")|");
|
||||
strcat(f, ")\t");
|
||||
replace(part[1], ",", ";");
|
||||
strcat(f, part[1]);
|
||||
strcat(f, "|");
|
||||
strcat(f, "\t");
|
||||
}
|
||||
|
||||
char *pf = f();
|
||||
for(int i = strlen(pf) - 1; i >= 0; i--) {
|
||||
if(pf[i] == '|') pf[i] = '\0';
|
||||
utf16 wfilter(f);
|
||||
utf16 wdir(dir);
|
||||
wchar_t wfilename[_MAX_PATH] = L"";
|
||||
|
||||
wchar_t *p = wfilter;
|
||||
while(*p != L'\0') {
|
||||
if(*p == L'\t') *p = L'\0';
|
||||
p++;
|
||||
}
|
||||
|
||||
OPENFILENAME ofn;
|
||||
@@ -173,14 +188,16 @@ bool pHiro::file_save(Window *focus, char *filename, const char *path, const cha
|
||||
memset(&ofn, 0, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = focus ? focus->p.hwnd : 0;
|
||||
ofn.lpstrFilter = pf;
|
||||
ofn.lpstrInitialDir = dir;
|
||||
ofn.lpstrFile = filename;
|
||||
ofn.lpstrFilter = wfilter;
|
||||
ofn.lpstrInitialDir = wdir;
|
||||
ofn.lpstrFile = wfilename;
|
||||
ofn.nMaxFile = MAX_PATH;
|
||||
ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
|
||||
ofn.lpstrDefExt = "";
|
||||
ofn.lpstrDefExt = L"";
|
||||
|
||||
return GetSaveFileName(&ofn);
|
||||
bool result = GetSaveFileName(&ofn);
|
||||
strcpy(filename, utf8(wfilename));
|
||||
return result;
|
||||
}
|
||||
|
||||
uint pHiro::screen_width() {
|
||||
@@ -214,11 +231,11 @@ pHiro& phiro() {
|
||||
/* internal */
|
||||
|
||||
HFONT pHiro::create_font(const char *name, uint size) {
|
||||
HDC hdc = GetDC(0);
|
||||
HFONT font = CreateFont(-MulDiv(size, GetDeviceCaps(hdc, LOGPIXELSY), 72),
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, name);
|
||||
ReleaseDC(0, hdc);
|
||||
return font;
|
||||
return CreateFont(
|
||||
-(size * 96.0 / 72.0 + 0.5), //96 = DPI
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
utf16(name)
|
||||
);
|
||||
}
|
||||
|
||||
Widget* pHiro::get_widget(uint instance) {
|
||||
@@ -295,7 +312,7 @@ LRESULT pHiro::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
} break;
|
||||
|
||||
case WM_PAINT: {
|
||||
if(p && p->self.type == Widget::CanvasType) ((pCanvas*)p)->blit();
|
||||
if(p && p->self.type == Widget::CanvasType) ((pCanvas*)p)->redraw();
|
||||
} break;
|
||||
|
||||
case WM_COMMAND: {
|
||||
@@ -310,10 +327,13 @@ LRESULT pHiro::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
case Widget::MenuCheckItemType: {
|
||||
MenuCheckItem &w = (MenuCheckItem&)*widget;
|
||||
w.check(!w.checked()); //invert check state
|
||||
if(w.on_tick) w.on_tick(Event(Event::Tick, w.checked(), &w));
|
||||
} break;
|
||||
case Widget::MenuRadioItemType: {
|
||||
MenuRadioItem &w = (MenuRadioItem&)*widget;
|
||||
bool checked = w.checked();
|
||||
w.check();
|
||||
if(!checked && w.on_tick) w.on_tick(Event(Event::Tick, w.checked(), &w));
|
||||
} break;
|
||||
case Widget::ButtonType: {
|
||||
Button &w = (Button&)*widget;
|
||||
@@ -322,10 +342,13 @@ LRESULT pHiro::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
|
||||
case Widget::CheckboxType: {
|
||||
Checkbox &w = (Checkbox&)*widget;
|
||||
w.check(!w.checked()); //invert check state
|
||||
if(w.on_tick) w.on_tick(Event(Event::Tick, w.checked(), &w));
|
||||
} break;
|
||||
case Widget::RadioboxType: {
|
||||
Radiobox &w = (Radiobox&)*widget;
|
||||
bool checked = w.checked();
|
||||
w.check();
|
||||
if(!checked && w.on_tick) w.on_tick(Event(Event::Tick, w.checked(), &w));
|
||||
} break;
|
||||
case Widget::ComboboxType: {
|
||||
Combobox &combobox = (Combobox&)*widget;
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#define _WIN32_IE 0x0600
|
||||
#define NOMINMAX
|
||||
|
||||
#define UNICODE
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include <shlobj.h>
|
||||
|
@@ -30,6 +30,13 @@ uint16_t pHiro::translate_key(uint key) {
|
||||
case '8': return keyboard::num_8;
|
||||
case '9': return keyboard::num_9;
|
||||
|
||||
case VK_INSERT: return keyboard::insert;
|
||||
case VK_DELETE: return keyboard::delete_;
|
||||
case VK_HOME: return keyboard::home;
|
||||
case VK_END: return keyboard::end;
|
||||
case VK_PRIOR: return keyboard::page_up;
|
||||
case VK_NEXT: return keyboard::page_down;
|
||||
|
||||
case 'A': return keyboard::a;
|
||||
case 'B': return keyboard::b;
|
||||
case 'C': return keyboard::c;
|
||||
|
@@ -1,12 +1,12 @@
|
||||
void pLabel::create(uint style, uint width, uint height, const char *text) {
|
||||
hwnd = CreateWindow("STATIC", text ? text : "", WS_CHILD | WS_VISIBLE,
|
||||
hwnd = CreateWindow(L"STATIC", utf16(text), WS_CHILD | WS_VISIBLE,
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
|
||||
}
|
||||
|
||||
void pLabel::set_text(const char *text) {
|
||||
SetWindowText(hwnd, text ? text : "");
|
||||
SetWindowText(hwnd, utf16(text));
|
||||
}
|
||||
|
||||
pLabel::pLabel(Label &self_) : pFormControl(self_), self(self_) {
|
||||
|
@@ -1,12 +1,12 @@
|
||||
void pListbox::create(uint style, uint width, uint height, const char *columns, const char *text) {
|
||||
bool header = style & Listbox::Header;
|
||||
uint hscroll = (style & Listbox::HorizontalScrollAlways) ? WS_HSCROLL :
|
||||
bool header = style & Listbox::Header;
|
||||
unsigned hscroll = (style & Listbox::HorizontalScrollAlways) ? WS_HSCROLL :
|
||||
(style & Listbox::HorizontalScrollNever) ? 0 :
|
||||
0;
|
||||
uint vscroll = (style & Listbox::VerticalScrollAlways) ? WS_VSCROLL :
|
||||
unsigned vscroll = (style & Listbox::VerticalScrollAlways) ? WS_VSCROLL :
|
||||
(style & Listbox::VerticalScrollNever) ? 0 :
|
||||
0;
|
||||
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, "",
|
||||
hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, WC_LISTVIEW, L"",
|
||||
WS_CHILD | WS_TABSTOP | WS_VISIBLE |
|
||||
LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | vscroll | hscroll |
|
||||
(header ? 0 : LVS_NOCOLUMNHEADER),
|
||||
@@ -15,27 +15,28 @@ uint vscroll = (style & Listbox::VerticalScrollAlways) ? WS_VSCROLL :
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
|
||||
ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT);
|
||||
|
||||
lstring list;
|
||||
lstring list;
|
||||
split(list, "\t", columns ? columns : "");
|
||||
column_count = count(list);
|
||||
for(uint i = 0; i < count(list); i++) {
|
||||
for(unsigned i = 0; i < count(list); i++) {
|
||||
LVCOLUMN column;
|
||||
column.mask = LVCF_FMT | LVCF_TEXT | LVCF_SUBITEM;
|
||||
column.fmt = LVCFMT_LEFT;
|
||||
column.iSubItem = count(list);
|
||||
column.pszText = (LPSTR)list[i]();
|
||||
utf16 ulist(list[i]);
|
||||
column.pszText = ulist;
|
||||
ListView_InsertColumn(hwnd, i, &column);
|
||||
}
|
||||
|
||||
if(text && *text) {
|
||||
split(list, "\n", text);
|
||||
for(uint i = 0; i < count(list); i++) add_item(list[i]);
|
||||
for(unsigned i = 0; i < count(list); i++) add_item(list[i]);
|
||||
}
|
||||
autosize_columns();
|
||||
}
|
||||
|
||||
void pListbox::autosize_columns() {
|
||||
for(uint i = 0; i < column_count; i++) {
|
||||
for(unsigned i = 0; i < column_count; i++) {
|
||||
ListView_SetColumnWidth(hwnd, i, LVSCW_AUTOSIZE_USEHEADER);
|
||||
}
|
||||
}
|
||||
@@ -45,40 +46,43 @@ void pListbox::set_column_width(uint column, uint width) {
|
||||
}
|
||||
|
||||
void pListbox::add_item(const char *text) {
|
||||
lstring list;
|
||||
lstring list;
|
||||
split(list, "\t", text ? text : "");
|
||||
LVITEM item;
|
||||
uint pos = ListView_GetItemCount(hwnd);
|
||||
LVITEM item;
|
||||
unsigned pos = ListView_GetItemCount(hwnd);
|
||||
item.mask = LVIF_TEXT;
|
||||
item.iItem = pos;
|
||||
item.iSubItem = 0;
|
||||
item.pszText = (LPSTR)list[0]();
|
||||
utf16 wtext(list[0]);
|
||||
item.pszText = wtext;
|
||||
ListView_InsertItem(hwnd, &item);
|
||||
|
||||
for(uint i = 1; i < count(list); i++) {
|
||||
ListView_SetItemText(hwnd, pos, i, (LPSTR)list[i]());
|
||||
for(unsigned i = 1; i < count(list); i++) {
|
||||
utf16 wtext(list[i]);
|
||||
ListView_SetItemText(hwnd, pos, i, wtext);
|
||||
}
|
||||
}
|
||||
|
||||
void pListbox::set_item(uint index, const char *text) {
|
||||
lstring list;
|
||||
lstring list;
|
||||
split(list, "\t", text ? text : "");
|
||||
for(uint i = 0; i < count(list); i++) {
|
||||
ListView_SetItemText(hwnd, index, i, list[i]());
|
||||
for(unsigned i = 0; i < count(list); i++) {
|
||||
utf16 wtext(list[i]);
|
||||
ListView_SetItemText(hwnd, index, i, wtext);
|
||||
}
|
||||
}
|
||||
|
||||
int pListbox::get_selection() {
|
||||
uint count = ListView_GetItemCount(hwnd);
|
||||
for(uint i = 0; i < count; i++) {
|
||||
unsigned count = ListView_GetItemCount(hwnd);
|
||||
for(unsigned i = 0; i < count; i++) {
|
||||
if(ListView_GetItemState(hwnd, i, LVIS_SELECTED)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void pListbox::set_selection(int index) {
|
||||
uint count = ListView_GetItemCount(hwnd);
|
||||
for(uint i = 0; i < count; i++) {
|
||||
unsigned count = ListView_GetItemCount(hwnd);
|
||||
for(unsigned i = 0; i < count; i++) {
|
||||
ListView_SetItemState(hwnd, i, LVIS_FOCUSED, (i == index) ? LVIS_FOCUSED : 0);
|
||||
ListView_SetItemState(hwnd, i, LVIS_SELECTED, (i == index) ? LVIS_SELECTED : 0);
|
||||
}
|
||||
|
@@ -3,11 +3,7 @@ void pMenuCheckItem::create(const char *text_) {
|
||||
}
|
||||
|
||||
void pMenuCheckItem::check(bool state) {
|
||||
bool prev = checked();
|
||||
CheckMenuItem(parent, instance, state ? MF_CHECKED : MF_UNCHECKED);
|
||||
if(prev != state) {
|
||||
if(self.on_tick) self.on_tick(Event(Event::Tick, state, &self));
|
||||
}
|
||||
}
|
||||
|
||||
void pMenuCheckItem::uncheck() {
|
||||
@@ -15,7 +11,7 @@ void pMenuCheckItem::uncheck() {
|
||||
}
|
||||
|
||||
bool pMenuCheckItem::checked() {
|
||||
MENUITEMINFO info;
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof info);
|
||||
info.cbSize = sizeof info;
|
||||
info.fMask = MIIM_STATE;
|
||||
|
@@ -6,20 +6,20 @@ void pMenuGroup::create(const char *text_) {
|
||||
void pMenuGroup::attach(MenuControl &menucontrol) {
|
||||
switch(menucontrol.type) {
|
||||
case Widget::MenuGroupType: {
|
||||
AppendMenu(group, MF_STRING | MF_POPUP, (uint)((MenuGroup&)menucontrol).p.group, menucontrol.p.text);
|
||||
AppendMenu(group, MF_STRING | MF_POPUP, (uint)((MenuGroup&)menucontrol).p.group, utf16(menucontrol.p.text));
|
||||
} break;
|
||||
|
||||
case Widget::MenuItemType:
|
||||
case Widget::MenuCheckItemType:
|
||||
case Widget::MenuRadioItemType: {
|
||||
AppendMenu(group, MF_STRING, menucontrol.p.instance, menucontrol.p.text);
|
||||
AppendMenu(group, MF_STRING, menucontrol.p.instance, utf16(menucontrol.p.text));
|
||||
if(menucontrol.type == Widget::MenuRadioItemType && ((MenuRadioItem&)menucontrol).p.create_checked) {
|
||||
CheckMenuItem(group, menucontrol.p.instance, MF_CHECKED);
|
||||
}
|
||||
} break;
|
||||
|
||||
case Widget::MenuSeparatorType: {
|
||||
AppendMenu(group, MF_SEPARATOR, menucontrol.p.instance, "");
|
||||
AppendMenu(group, MF_SEPARATOR, menucontrol.p.instance, L"");
|
||||
} break;
|
||||
}
|
||||
|
||||
|
@@ -5,15 +5,13 @@ void pMenuRadioItem::create(MenuRadioItemGroup &group_, const char *text_) {
|
||||
}
|
||||
|
||||
void pMenuRadioItem::check() {
|
||||
bool prev = checked();
|
||||
for(uint i = 0; i < group.size(); i++) {
|
||||
CheckMenuItem(parent, group[i]->p.instance, (group[i] == &self) ? MF_CHECKED : MF_UNCHECKED);
|
||||
}
|
||||
if(prev == false && self.on_tick) self.on_tick(Event(Event::Tick, 0, &self));
|
||||
}
|
||||
|
||||
bool pMenuRadioItem::checked() {
|
||||
MENUITEMINFO info;
|
||||
MENUITEMINFO info;
|
||||
memset(&info, 0, sizeof info);
|
||||
info.cbSize = sizeof info;
|
||||
info.fMask = MIIM_STATE;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
void pProgressbar::create(uint style, uint width, uint height) {
|
||||
hwnd = CreateWindow(PROGRESS_CLASS, "", WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
|
||||
hwnd = CreateWindow(PROGRESS_CLASS, L"", WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
|
||||
0, 0, width, height,
|
||||
phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
|
||||
|
@@ -1,21 +1,19 @@
|
||||
void pRadiobox::create(RadioboxGroup &group_, uint style, uint width, uint height, const char *text) {
|
||||
group = group_;
|
||||
hwnd = CreateWindow("BUTTON", text ? text : "", WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_RADIOBUTTON,
|
||||
hwnd = CreateWindow(L"BUTTON", utf16(text), WS_CHILD | WS_TABSTOP | WS_VISIBLE | BS_RADIOBUTTON,
|
||||
0, 0, width, height, phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0);
|
||||
SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0);
|
||||
if(group[0] == &self) check();
|
||||
}
|
||||
|
||||
void pRadiobox::set_text(const char *text) {
|
||||
SetWindowText(hwnd, text);
|
||||
SetWindowText(hwnd, utf16(text));
|
||||
}
|
||||
|
||||
void pRadiobox::check() {
|
||||
bool prev = checked();
|
||||
for(uint i = 0; i < group.size(); i++) {
|
||||
SendMessage(group[i]->p.hwnd, BM_SETCHECK, (WPARAM)(group[i] == &self), 0);
|
||||
}
|
||||
if(prev == false && self.on_tick) self.on_tick(Event(Event::Tick, 0, &self));
|
||||
}
|
||||
|
||||
bool pRadiobox::checked() {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
void pSlider::create(uint style, uint width, uint height, uint length) {
|
||||
if(length < 1) length = 1;
|
||||
|
||||
hwnd = CreateWindow(TRACKBAR_CLASS, "",
|
||||
hwnd = CreateWindow(TRACKBAR_CLASS, L"",
|
||||
WS_CHILD | WS_VISIBLE | WS_TABSTOP | TBS_NOTICKS | TBS_BOTH |
|
||||
(style & Slider::Vertical ? TBS_VERT : TBS_HORZ),
|
||||
0, 0, width, height,
|
||||
|
55
src/lib/hiro/win/utf.cpp
Normal file
55
src/lib/hiro/win/utf.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
/*****
|
||||
* UTF-8 to UTF-16
|
||||
*****/
|
||||
class utf16 {
|
||||
public:
|
||||
operator wchar_t*() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
operator const wchar_t*() const {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
utf16(const char *s = "") {
|
||||
if(!s) s = "";
|
||||
unsigned length = MultiByteToWideChar(CP_UTF8, 0, s, -1, 0, 0);
|
||||
buffer = new(zeromemory) wchar_t[length + 1];
|
||||
MultiByteToWideChar(CP_UTF8, 0, s, -1, buffer, length);
|
||||
}
|
||||
|
||||
~utf16() {
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
wchar_t *buffer;
|
||||
};
|
||||
|
||||
/*****
|
||||
* UTF-16 to UTF-8
|
||||
*****/
|
||||
class utf8 {
|
||||
public:
|
||||
operator char*() {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
operator const char*() const {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
utf8(const wchar_t *s = L"") {
|
||||
if(!s) s = L"";
|
||||
unsigned length = WideCharToMultiByte(CP_UTF8, 0, s, -1, 0, 0, (const char*)0, (BOOL*)0);
|
||||
buffer = new(zeromemory) char[length + 1];
|
||||
WideCharToMultiByte(CP_UTF8, 0, s, -1, buffer, length, (const char*)0, (BOOL*)0);
|
||||
}
|
||||
|
||||
~utf8() {
|
||||
delete[] buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
char *buffer;
|
||||
};
|
@@ -4,16 +4,16 @@ void pWindow::create(uint style, uint width_, uint height_, const char *text) {
|
||||
RECT rc;
|
||||
SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0);
|
||||
|
||||
hwnd = CreateWindowEx(0, "hiro_window", text ? text : "",
|
||||
hwnd = CreateWindowEx(0, L"hiro_window", utf16(text),
|
||||
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
|
||||
rc.left, rc.top, width_, height_,
|
||||
0, 0, GetModuleHandle(0), 0);
|
||||
hwndr = CreateWindowEx(0, "hiro_window", text ? text : "",
|
||||
hwndr = CreateWindowEx(0, L"hiro_window", utf16(text),
|
||||
WS_POPUP | WS_SYSMENU | WS_CAPTION | WS_MINIMIZEBOX,
|
||||
rc.left, rc.top, width_, height_,
|
||||
0, 0, GetModuleHandle(0), 0);
|
||||
hmenu = CreateMenu();
|
||||
hstatus = CreateWindowEx(0, STATUSCLASSNAME, "",
|
||||
hstatus = CreateWindowEx(0, STATUSCLASSNAME, L"",
|
||||
WS_CHILD, 0, 0, 0, 0, hwnd, 0, GetModuleHandle(0), 0);
|
||||
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
|
||||
|
||||
@@ -194,7 +194,7 @@ void pWindow::set_icon(unsigned width, unsigned height, const uint32_t *data) {
|
||||
}
|
||||
|
||||
void pWindow::set_text(const char *text) {
|
||||
SetWindowText(hwnd, text);
|
||||
SetWindowText(hwnd, utf16(text));
|
||||
}
|
||||
|
||||
void pWindow::attach(Window &window, uint x, uint y) {
|
||||
@@ -214,7 +214,7 @@ void pWindow::attach(Window &window, uint x, uint y) {
|
||||
}
|
||||
|
||||
void pWindow::attach(MenuGroup &menugroup) {
|
||||
AppendMenu(hmenu, MF_STRING | MF_POPUP, (uint)menugroup.p.group, menugroup.p.text);
|
||||
AppendMenu(hmenu, MF_STRING | MF_POPUP, (uint)menugroup.p.group, utf16(menugroup.p.text));
|
||||
if(menu_visible() == false) menu_show();
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ bool pWindow::menu_visible() {
|
||||
}
|
||||
|
||||
void pWindow::status_set_text(const char *text) {
|
||||
SendMessage(hstatus, SB_SETTEXT, 0, (LPARAM)text);
|
||||
SendMessage(hstatus, SB_SETTEXT, 0, (LPARAM)(wchar_t*)utf16(text));
|
||||
}
|
||||
|
||||
void pWindow::status_show(bool state) {
|
||||
|
@@ -71,15 +71,15 @@ void HQ2xFilter::render(
|
||||
uint32_t *out0 = output;
|
||||
uint32_t *out1 = output + outpitch;
|
||||
|
||||
#define W1 input[-1 - pitch]
|
||||
#define W2 input[ 0 - pitch]
|
||||
#define W3 input[+1 - pitch]
|
||||
#define W1 input[-1 - (int)pitch]
|
||||
#define W2 input[ 0 - (int)pitch]
|
||||
#define W3 input[+1 - (int)pitch]
|
||||
#define W4 input[-1]
|
||||
#define W5 input[ 0]
|
||||
#define W6 input[+1]
|
||||
#define W7 input[-1 + pitch]
|
||||
#define W8 input[ 0 + pitch]
|
||||
#define W9 input[+1 + pitch]
|
||||
#define W7 input[-1 + (int)pitch]
|
||||
#define W8 input[ 0 + (int)pitch]
|
||||
#define W9 input[+1 + (int)pitch]
|
||||
|
||||
input += pitch;
|
||||
memset(out0, 0, 2048); out0 += outpitch << 1;
|
||||
|
66
src/lib/nall/dictionary.hpp
Normal file
66
src/lib/nall/dictionary.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
#ifndef NALL_DICTIONARY_HPP
|
||||
#define NALL_DICTIONARY_HPP
|
||||
|
||||
#include <nall/array.hpp>
|
||||
#include <nall/string.hpp>
|
||||
#include <nall/utility.hpp>
|
||||
|
||||
namespace nall {
|
||||
|
||||
class dictionary : noncopyable {
|
||||
public:
|
||||
const char* operator[](const char *input) const {
|
||||
for(unsigned i = 0; i < index_input.size(); i++) {
|
||||
if(!strcmp(input, index_input[i])) return index_output[i];
|
||||
}
|
||||
return input; //no match, return input rather than null string
|
||||
}
|
||||
|
||||
bool import(const char *filename) {
|
||||
string data;
|
||||
if(fread(data, filename) == false) return false;
|
||||
replace(data, "\r", "");
|
||||
|
||||
lstring line;
|
||||
split(line, "\n", data);
|
||||
for(unsigned i = 0; i < count(line); i++) {
|
||||
lstring part;
|
||||
//format: "Input" = "Output"
|
||||
qsplit(part, "=", line[i]);
|
||||
if(count(part) != 2) continue;
|
||||
|
||||
//remove whitespace
|
||||
trim(part[0]);
|
||||
trim(part[1]);
|
||||
|
||||
//remove quotes
|
||||
trim_once(part[0], "\"");
|
||||
trim_once(part[1], "\"");
|
||||
|
||||
unsigned i = index_input.size();
|
||||
index_input[i] = strdup(part[0]);
|
||||
index_output[i] = strdup(part[1]);
|
||||
}
|
||||
}
|
||||
|
||||
void reset() {
|
||||
for(unsigned i = 0; i < index_input.size(); i++) {
|
||||
free(index_input[i]);
|
||||
free(index_output[i]);
|
||||
}
|
||||
index_input.reset();
|
||||
index_output.reset();
|
||||
}
|
||||
|
||||
~dictionary() {
|
||||
reset();
|
||||
}
|
||||
|
||||
private:
|
||||
array<char*> index_input;
|
||||
array<char*> index_output;
|
||||
};
|
||||
|
||||
} //namespace nall
|
||||
|
||||
#endif //ifndef NALL_DICTIONARY_HPP
|
138
src/lib/ruby/audio/alsa.cpp
Normal file
138
src/lib/ruby/audio/alsa.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
#include <alsa/asoundlib.h>
|
||||
|
||||
#include <ruby/ruby.h>
|
||||
|
||||
namespace ruby {
|
||||
|
||||
#include "alsa.h"
|
||||
|
||||
class pAudioALSA {
|
||||
public:
|
||||
AudioALSA &self;
|
||||
|
||||
struct {
|
||||
snd_pcm_t *handle;
|
||||
snd_pcm_format_t format;
|
||||
snd_pcm_uframes_t buffer_size;
|
||||
snd_pcm_uframes_t period_size;
|
||||
int channels;
|
||||
const char *name;
|
||||
unsigned latency;
|
||||
} device;
|
||||
|
||||
struct {
|
||||
uint32_t *data;
|
||||
unsigned length;
|
||||
} buffer;
|
||||
|
||||
struct {
|
||||
unsigned frequency;
|
||||
} settings;
|
||||
|
||||
bool cap(Audio::Setting setting) {
|
||||
if(setting == Audio::Frequency) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
uintptr_t get(Audio::Setting setting) {
|
||||
if(setting == Audio::Frequency) return settings.frequency;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool set(Audio::Setting setting, uintptr_t param) {
|
||||
if(setting == Audio::Frequency) {
|
||||
settings.frequency = param;
|
||||
if(device.handle) {
|
||||
term();
|
||||
init();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void sample(uint16_t left, uint16_t right) {
|
||||
if(!device.handle) return;
|
||||
|
||||
buffer.data[buffer.length++] = left + (right << 16);
|
||||
if(buffer.length < device.period_size) return;
|
||||
uint32_t *buffer_ptr = buffer.data;
|
||||
do {
|
||||
snd_pcm_sframes_t written = snd_pcm_writei(device.handle, buffer_ptr, buffer.length);
|
||||
if(written < 0) {
|
||||
//no samples written
|
||||
snd_pcm_recover(device.handle, written, 1);
|
||||
} else if(written < buffer.length) {
|
||||
//only some samples written
|
||||
buffer.length -= written;
|
||||
buffer_ptr += written;
|
||||
} else {
|
||||
//all samples written
|
||||
buffer.length = 0;
|
||||
}
|
||||
} while(buffer.length > 0);
|
||||
}
|
||||
|
||||
bool init() {
|
||||
if(snd_pcm_open(&device.handle, device.name, SND_PCM_STREAM_PLAYBACK, 0) < 0) {
|
||||
//failed to initialize
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(snd_pcm_set_params(device.handle, device.format, SND_PCM_ACCESS_RW_INTERLEAVED,
|
||||
device.channels, settings.frequency, 1, device.latency) < 0) {
|
||||
//failed to set device parameters
|
||||
term();
|
||||
return false;
|
||||
}
|
||||
|
||||
if(snd_pcm_get_params(device.handle, &device.buffer_size, &device.period_size) < 0) {
|
||||
device.period_size = device.latency * 1e-6 * settings.frequency / 4;
|
||||
}
|
||||
|
||||
buffer.data = new uint32_t[device.period_size];
|
||||
return true;
|
||||
}
|
||||
|
||||
void term() {
|
||||
if(device.handle) {
|
||||
snd_pcm_drain(device.handle);
|
||||
snd_pcm_close(device.handle);
|
||||
device.handle = 0;
|
||||
}
|
||||
|
||||
if(buffer.data) {
|
||||
delete[] buffer.data;
|
||||
buffer.data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pAudioALSA(AudioALSA &self_) : self(self_) {
|
||||
device.handle = 0;
|
||||
device.format = SND_PCM_FORMAT_S16_LE;
|
||||
device.channels = 2;
|
||||
device.name = "default";
|
||||
device.latency = 100000;
|
||||
|
||||
buffer.data = 0;
|
||||
buffer.length = 0;
|
||||
|
||||
settings.frequency = 22050;
|
||||
}
|
||||
|
||||
~pAudioALSA() {
|
||||
term();
|
||||
}
|
||||
};
|
||||
|
||||
bool AudioALSA::cap(Setting setting) { return p.cap(setting); }
|
||||
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
|
23
src/lib/ruby/audio/alsa.h
Normal file
23
src/lib/ruby/audio/alsa.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
audio.alsa (2008-06-01)
|
||||
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;
|
||||
};
|
@@ -47,16 +47,23 @@ public:
|
||||
|
||||
bool init() {
|
||||
driver_id = ao_default_driver_id(); //ao_driver_id((const char*)driver)
|
||||
if(driver_id < 0) driver_id = ao_default_driver_id(); //fallback on default if driver doesn't exist
|
||||
if(driver_id < 0) return false;
|
||||
|
||||
driver_format.bits = 16;
|
||||
driver_format.channels = 2;
|
||||
driver_format.rate = settings.frequency;
|
||||
driver_format.byte_format = AO_FMT_LITTLE;
|
||||
|
||||
audio_device = ao_open_live(driver_id, &driver_format, 0);
|
||||
ao_option *options = 0;
|
||||
ao_info *di = ao_driver_info(driver_id);
|
||||
if(!di) return false;
|
||||
if(!strcmp(di->short_name, "alsa")) {
|
||||
ao_append_option(&options, "buffer_time", "100000"); //100ms latency (default was 500ms)
|
||||
}
|
||||
|
||||
audio_device = ao_open_live(driver_id, &driver_format, options);
|
||||
if(!audio_device) return false;
|
||||
|
||||
ao_info *di = ao_driver_info(driver_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
audio.ao (2007-12-26)
|
||||
author: Nach
|
||||
audio.ao (2008-06-01)
|
||||
authors: Nach, RedDwarf
|
||||
*/
|
||||
|
||||
class pAudioAO;
|
||||
|
@@ -92,6 +92,10 @@ void AudioInterface::driver(const char *driver) {
|
||||
|
||||
if(!strcmp(driver, "none")) p = new Audio();
|
||||
|
||||
#ifdef AUDIO_ALSA
|
||||
else if(!strcmp(driver, "alsa")) p = new AudioALSA();
|
||||
#endif
|
||||
|
||||
#ifdef AUDIO_AO
|
||||
else if(!strcmp(driver, "ao")) p = new AudioAO();
|
||||
#endif
|
||||
@@ -114,6 +118,8 @@ void AudioInterface::driver(const char *driver) {
|
||||
p = new AudioDS();
|
||||
#elif defined(AUDIO_AO)
|
||||
p = new AudioAO();
|
||||
#elif defined(AUDIO_ALSA)
|
||||
p = new AudioALSA();
|
||||
#elif defined(AUDIO_OPENAL)
|
||||
p = new AudioOpenAL();
|
||||
#elif defined(AUDIO_OSS)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
ruby
|
||||
version: 0.02 (2008-04-06)
|
||||
version: 0.03 (2008-05-04)
|
||||
license: public domain
|
||||
*/
|
||||
|
||||
|
@@ -30,6 +30,10 @@
|
||||
|
||||
/* Audio */
|
||||
|
||||
#ifdef AUDIO_ALSA
|
||||
#include <ruby/audio/alsa.cpp>
|
||||
#endif
|
||||
|
||||
#ifdef AUDIO_AO
|
||||
#include <ruby/audio/ao.cpp>
|
||||
#endif
|
||||
|
6
src/lib/sync.sh
Normal file
6
src/lib/sync.sh
Normal file
@@ -0,0 +1,6 @@
|
||||
rm -r nall
|
||||
rm -r hiro
|
||||
rm -r ruby
|
||||
cp -r ../../../nall ./nall
|
||||
cp -r ../../../hiro ./hiro
|
||||
cp -r ../../../ruby ./ruby
|
@@ -32,6 +32,15 @@ void sBus::map_generic() {
|
||||
map_generic_sram();
|
||||
} break;
|
||||
|
||||
case Cartridge::SPC7110ROM: {
|
||||
map(MapDirect, 0x00, 0x00, 0x6000, 0x7fff, spc7110);
|
||||
map(MapDirect, 0x00, 0x0f, 0x8000, 0xffff, spc7110);
|
||||
map(MapDirect, 0x30, 0x30, 0x6000, 0x7fff, spc7110);
|
||||
map(MapDirect, 0x50, 0x50, 0x0000, 0xffff, spc7110);
|
||||
map(MapDirect, 0x80, 0x8f, 0x8000, 0xffff, spc7110);
|
||||
map(MapDirect, 0xc0, 0xff, 0x0000, 0xffff, spc7110);
|
||||
} break;
|
||||
|
||||
case Cartridge::BSXROM: {
|
||||
//full map is dynamically mapped by:
|
||||
//src/chip/bsx/bsx_cart.cpp : BSXCart::update_memory_map();
|
||||
|
@@ -330,12 +330,9 @@ void bPPU::cgram_write(uint16 addr, uint8 value) {
|
||||
}
|
||||
|
||||
bPPU::bPPU() {
|
||||
vram = (uint8*)malloc(65536);
|
||||
oam = (uint8*)malloc( 544);
|
||||
cgram = (uint8*)malloc( 512);
|
||||
memset(vram, 0, 65536);
|
||||
memset(oam, 0, 544);
|
||||
memset(cgram, 0, 512);
|
||||
vram = new(zeromemory) uint8_t[65536];
|
||||
oam = new(zeromemory) uint8_t[ 544];
|
||||
cgram = new(zeromemory) uint8_t[ 512];
|
||||
|
||||
init_tiledata_cache();
|
||||
|
||||
@@ -359,7 +356,7 @@ bPPU::bPPU() {
|
||||
}
|
||||
|
||||
bPPU::~bPPU() {
|
||||
free(vram);
|
||||
free(oam);
|
||||
free(cgram);
|
||||
delete[] vram;
|
||||
delete[] oam;
|
||||
delete[] cgram;
|
||||
}
|
||||
|
@@ -15,19 +15,16 @@ uint8_t* FileReader::read(unsigned length) {
|
||||
|
||||
if(length == 0) {
|
||||
//read the entire file into RAM
|
||||
data = (uint8*)malloc(filesize);
|
||||
memset(data, 0, filesize);
|
||||
data = new(zeromemory) uint8_t[filesize];
|
||||
if(fp) fread(data, 1, filesize, fp);
|
||||
} else if(length > filesize) {
|
||||
//read the entire file into RAM, pad the rest with 0x00s
|
||||
data = (uint8*)malloc(length);
|
||||
memset(data, 0, length);
|
||||
if(fp)fread(data, 1, filesize, fp);
|
||||
data = new(zeromemory) uint8_t[length];
|
||||
if(fp) fread(data, 1, filesize, fp);
|
||||
} else { //filesize >= length
|
||||
//read only what was requested
|
||||
data = (uint8*)malloc(length);
|
||||
memset(data, 0, length);
|
||||
if(fp)fread(data, 1, length, fp);
|
||||
data = new(zeromemory) uint8_t[length];
|
||||
if(fp) fread(data, 1, length, fp);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
@@ -58,24 +55,4 @@ FileReader::~FileReader() {
|
||||
}
|
||||
}
|
||||
|
||||
void FileWriter::write(uint8_t *buffer, unsigned length) {
|
||||
if(!fp) return;
|
||||
fwrite(buffer, 1, length, fp);
|
||||
}
|
||||
|
||||
bool FileWriter::ready() {
|
||||
return (fp != 0);
|
||||
}
|
||||
|
||||
FileWriter::FileWriter(const char *fn) {
|
||||
fp = fopen(fn, "wb");
|
||||
}
|
||||
|
||||
FileWriter::~FileWriter() {
|
||||
if(fp) {
|
||||
fclose(fp);
|
||||
fp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif //ifdef READER_CPP
|
||||
|
@@ -1,8 +1,4 @@
|
||||
class FileReader : public Reader {
|
||||
private:
|
||||
FILE *fp;
|
||||
unsigned filesize;
|
||||
|
||||
public:
|
||||
unsigned size();
|
||||
uint8_t* read(unsigned length = 0);
|
||||
@@ -10,16 +6,8 @@ public:
|
||||
|
||||
FileReader(const char *fn);
|
||||
~FileReader();
|
||||
};
|
||||
|
||||
class FileWriter : public Writer {
|
||||
private:
|
||||
FILE *fp;
|
||||
|
||||
public:
|
||||
void write(uint8_t *buffer, unsigned length);
|
||||
bool ready();
|
||||
|
||||
FileWriter(const char *fn);
|
||||
~FileWriter();
|
||||
unsigned filesize;
|
||||
};
|
||||
|
@@ -15,19 +15,16 @@ uint8_t* GZReader::read(unsigned length) {
|
||||
|
||||
if(length == 0) {
|
||||
//read the entire file into RAM
|
||||
data = (uint8*)malloc(filesize);
|
||||
memset(data, 0, filesize);
|
||||
if(gp)gzread(gp, data, filesize);
|
||||
data = new(zeromemory) uint8_t[filesize];
|
||||
if(gp) gzread(gp, data, filesize);
|
||||
} else if(length > filesize) {
|
||||
//read the entire file into RAM, pad the rest with 0x00s
|
||||
data = (uint8*)malloc(length);
|
||||
memset(data, 0, length);
|
||||
if(gp)gzread(gp, data, filesize);
|
||||
data = new(zeromemory) uint8_t[length];
|
||||
if(gp) gzread(gp, data, filesize);
|
||||
} else { //filesize >= length
|
||||
//read only what was requested
|
||||
data = (uint8*)malloc(length);
|
||||
memset(data, 0, length);
|
||||
if(gp)gzread(gp, data, length);
|
||||
data = new(zeromemory) uint8_t[length];
|
||||
if(gp) gzread(gp, data, length);
|
||||
}
|
||||
|
||||
return data;
|
||||
@@ -40,7 +37,7 @@ bool GZReader::ready() {
|
||||
GZReader::GZReader(const char *fn) {
|
||||
gp = 0;
|
||||
FILE *fp = fopen(fn, "rb");
|
||||
if(!fp)return;
|
||||
if(!fp) return;
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
filesize = ftell(fp);
|
||||
@@ -62,7 +59,7 @@ uint32 gzsize;
|
||||
fp = 0;
|
||||
|
||||
gp = gzopen(fn, "rb");
|
||||
if(!gp)return;
|
||||
if(!gp) return;
|
||||
|
||||
if(!gzdirect(gp)) {
|
||||
filesize = gzsize;
|
||||
|
@@ -15,12 +15,11 @@ uint8_t* JMAReader::read(unsigned length) {
|
||||
|
||||
if(length <= filesize) {
|
||||
//read the entire file into RAM
|
||||
data = (uint8_t*)malloc(filesize);
|
||||
data = new(zeromemory) uint8_t[filesize];
|
||||
JMAFile.extract_file(cname, data);
|
||||
} else if(length > filesize) {
|
||||
//read the entire file into RAM, pad the rest with 0x00s
|
||||
data = (uint8_t*)malloc(length);
|
||||
memset(data, 0, length);
|
||||
data = new(zeromemory) uint8_t[length];
|
||||
JMAFile.extract_file(cname, data);
|
||||
}
|
||||
|
||||
|
@@ -13,9 +13,3 @@ public:
|
||||
virtual uint8_t* read(unsigned length = 0) = 0;
|
||||
virtual bool ready() { return true; } //can only call read() when ready() returns true
|
||||
};
|
||||
|
||||
class Writer {
|
||||
public:
|
||||
virtual void write(uint8_t *buffer, uint32 length) = 0;
|
||||
virtual bool ready() { return true; }
|
||||
};
|
||||
|
@@ -15,12 +15,11 @@ uint8_t* ZipReader::read(unsigned length) {
|
||||
|
||||
if(length <= filesize) {
|
||||
//read the entire file into RAM
|
||||
data = (uint8_t*)malloc(filesize);
|
||||
data = new(zeromemory) uint8_t[filesize];
|
||||
unzReadCurrentFile(zipfile, data, filesize);
|
||||
} else if(length > filesize) {
|
||||
//read the entire file into RAM, pad the rest with 0x00s
|
||||
data = (uint8_t*)malloc(length);
|
||||
memset(data, 0, length);
|
||||
data = new(zeromemory) uint8_t[length];
|
||||
unzReadCurrentFile(zipfile, data, filesize);
|
||||
}
|
||||
|
||||
|
@@ -1,19 +1,32 @@
|
||||
template<int mask>
|
||||
struct SMPFlag {
|
||||
uint8 &data;
|
||||
|
||||
inline operator bool() const { return data & mask; }
|
||||
inline SMPFlag& operator=(bool i) { data = (data & ~mask) | (-i & mask); return *this; }
|
||||
|
||||
SMPFlag(uint8 &data_) : data(data_) {}
|
||||
};
|
||||
|
||||
class SMPRegFlags {
|
||||
public:
|
||||
union {
|
||||
uint8 data;
|
||||
struct {
|
||||
bool order_msb8(n:1, v:1, p:1, b:1, h:1, i:1, z:1, c:1);
|
||||
};
|
||||
};
|
||||
SMPFlag<0x80> n;
|
||||
SMPFlag<0x40> v;
|
||||
SMPFlag<0x20> p;
|
||||
SMPFlag<0x10> b;
|
||||
SMPFlag<0x08> h;
|
||||
SMPFlag<0x04> i;
|
||||
SMPFlag<0x02> z;
|
||||
SMPFlag<0x01> c;
|
||||
|
||||
inline operator unsigned() const { return data; }
|
||||
template<typename T> inline unsigned operator = (const T i) { data = i; return data; }
|
||||
template<typename T> inline unsigned operator |= (const T i) { data |= i; return data; }
|
||||
template<typename T> inline unsigned operator ^= (const T i) { data ^= i; return data; }
|
||||
template<typename T> inline unsigned operator &= (const T i) { data &= i; return data; }
|
||||
inline unsigned operator = (unsigned i) { data = i; return data; }
|
||||
inline unsigned operator |= (unsigned i) { data |= i; return data; }
|
||||
inline unsigned operator ^= (unsigned i) { data ^= i; return data; }
|
||||
inline unsigned operator &= (unsigned i) { data &= i; return data; }
|
||||
|
||||
SMPRegFlags() : data(0) {}
|
||||
SMPRegFlags() : data(0), n(data), v(data), p(data), b(data), h(data), i(data), z(data), c(data) {}
|
||||
};
|
||||
|
||||
class SMPRegs {
|
||||
@@ -25,4 +38,5 @@ public:
|
||||
};
|
||||
uint8 x, sp;
|
||||
SMPRegFlags p;
|
||||
SMPRegs() : pc(0), ya(0), x(0), sp(0) {}
|
||||
};
|
||||
|
@@ -64,7 +64,7 @@ clrv(0xe0) {
|
||||
notc(0xed) {
|
||||
1:op_io();
|
||||
2:op_io();
|
||||
regs.p.c ^= 1;
|
||||
regs.p.c = !regs.p.c;
|
||||
}
|
||||
|
||||
ei(0xa0, 1),
|
||||
|
@@ -93,7 +93,7 @@ case 0xe0: {
|
||||
case 0xed: {
|
||||
op_io();
|
||||
op_io();
|
||||
regs.p.c ^= 1;
|
||||
regs.p.c = !regs.p.c;
|
||||
} break;
|
||||
|
||||
//ei
|
||||
|
@@ -1,125 +1,125 @@
|
||||
#ifdef SSMP_CPP
|
||||
|
||||
uint8 sSMP::op_adc(uint8 x, uint8 y) {
|
||||
int16 r = x + y + regs.p.c;
|
||||
regs.p.n = !!(r & 0x80);
|
||||
regs.p.v = !!(~(x ^ y) & (y ^ (uint8)r) & 0x80);
|
||||
regs.p.h = !!((x ^ y ^ (uint8)r) & 0x10);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.c = (r > 0xff);
|
||||
int r = x + y + regs.p.c;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.v = ~(x ^ y) & (x ^ r) & 0x80;
|
||||
regs.p.h = (x ^ y ^ r) & 0x10;
|
||||
regs.p.z = (uint8)r == 0;
|
||||
regs.p.c = r > 0xff;
|
||||
return r;
|
||||
}
|
||||
|
||||
uint16 sSMP::op_addw(uint16 x, uint16 y) {
|
||||
uint16 r;
|
||||
uint16 r;
|
||||
regs.p.c = 0;
|
||||
r = op_adc(x, y);
|
||||
r |= op_adc(x >> 8, y >> 8) << 8;
|
||||
regs.p.z = (r == 0);
|
||||
regs.p.z = r == 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
uint8 sSMP::op_and(uint8 x, uint8 y) {
|
||||
x &= y;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sSMP::op_cmp(uint8 x, uint8 y) {
|
||||
int16 r = x - y;
|
||||
regs.p.n = !!(r & 0x80);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
int r = x - y;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.z = (uint8)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint16 sSMP::op_cmpw(uint16 x, uint16 y) {
|
||||
int32 r = x - y;
|
||||
regs.p.n = !!(r & 0x8000);
|
||||
regs.p.z = ((uint16)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
int r = x - y;
|
||||
regs.p.n = r & 0x8000;
|
||||
regs.p.z = (uint16)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sSMP::op_eor(uint8 x, uint8 y) {
|
||||
x ^= y;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sSMP::op_or(uint8 x, uint8 y) {
|
||||
x |= y;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sSMP::op_sbc(uint8 x, uint8 y) {
|
||||
int16 r = x - y - !regs.p.c;
|
||||
regs.p.n = !!(r & 0x80);
|
||||
regs.p.v = !!((x ^ y) & (x ^ (uint8)r) & 0x80);
|
||||
regs.p.h = !((x ^ y ^ (uint8)r) & 0x10);
|
||||
regs.p.z = ((uint8)r == 0);
|
||||
regs.p.c = (r >= 0);
|
||||
int r = x - y - !regs.p.c;
|
||||
regs.p.n = r & 0x80;
|
||||
regs.p.v = (x ^ y) & (x ^ r) & 0x80;
|
||||
regs.p.h = !((x ^ y ^ r) & 0x10);
|
||||
regs.p.z = (uint8)r == 0;
|
||||
regs.p.c = r >= 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
uint16 sSMP::op_subw(uint16 x, uint16 y) {
|
||||
uint16 r;
|
||||
uint16 r;
|
||||
regs.p.c = 1;
|
||||
r = op_sbc(x, y);
|
||||
r |= op_sbc(x >> 8, y >> 8) << 8;
|
||||
regs.p.z = (r == 0);
|
||||
regs.p.z = r == 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
uint8 sSMP::op_inc(uint8 x) {
|
||||
x++;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sSMP::op_dec(uint8 x) {
|
||||
x--;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sSMP::op_asl(uint8 x) {
|
||||
regs.p.c = !!(x & 0x80);
|
||||
regs.p.c = x & 0x80;
|
||||
x <<= 1;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sSMP::op_lsr(uint8 x) {
|
||||
regs.p.c = !!(x & 0x01);
|
||||
regs.p.c = x & 0x01;
|
||||
x >>= 1;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sSMP::op_rol(uint8 x) {
|
||||
uint8 carry = (uint8)regs.p.c;
|
||||
regs.p.c = !!(x & 0x80);
|
||||
unsigned carry = (unsigned)regs.p.c;
|
||||
regs.p.c = x & 0x80;
|
||||
x = (x << 1) | carry;
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
uint8 sSMP::op_ror(uint8 x) {
|
||||
uint8 carry = (uint8)regs.p.c << 7;
|
||||
regs.p.c = !!(x & 0x01);
|
||||
unsigned carry = (unsigned)regs.p.c << 7;
|
||||
regs.p.c = x & 0x01;
|
||||
x = carry | (x >> 1);
|
||||
regs.p.n = !!(x & 0x80);
|
||||
regs.p.z = (x == 0);
|
||||
regs.p.n = x & 0x80;
|
||||
regs.p.z = x == 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
@@ -7,6 +7,7 @@ BSXCart bsxcart;
|
||||
BSXFlash bsxflash;
|
||||
SRTC srtc;
|
||||
SDD1 sdd1;
|
||||
SPC7110 spc7110;
|
||||
Cx4 cx4;
|
||||
DSP1 dsp1;
|
||||
DSP2 dsp2;
|
||||
@@ -34,6 +35,7 @@ void SNES::init() {
|
||||
bsxflash.init();
|
||||
srtc.init();
|
||||
sdd1.init();
|
||||
spc7110.init();
|
||||
cx4.init();
|
||||
dsp1.init();
|
||||
dsp2.init();
|
||||
@@ -67,6 +69,7 @@ void SNES::power() {
|
||||
if(cartridge.info.bsxflash) bsxflash.power();
|
||||
if(cartridge.info.srtc) srtc.power();
|
||||
if(cartridge.info.sdd1) sdd1.power();
|
||||
if(cartridge.info.spc7110) spc7110.power();
|
||||
if(cartridge.info.cx4) cx4.power();
|
||||
if(cartridge.info.dsp1) dsp1.power();
|
||||
if(cartridge.info.dsp2) dsp2.power();
|
||||
@@ -87,6 +90,7 @@ void SNES::power() {
|
||||
if(cartridge.info.bsxflash) bsxflash.enable();
|
||||
if(cartridge.info.srtc) srtc.enable();
|
||||
if(cartridge.info.sdd1) sdd1.enable();
|
||||
if(cartridge.info.spc7110) spc7110.enable();
|
||||
if(cartridge.info.cx4) cx4.enable();
|
||||
if(cartridge.info.dsp1) dsp1.enable();
|
||||
if(cartridge.info.dsp2) dsp2.enable();
|
||||
@@ -112,6 +116,7 @@ void SNES::reset() {
|
||||
if(cartridge.info.bsxflash) bsxflash.reset();
|
||||
if(cartridge.info.srtc) srtc.reset();
|
||||
if(cartridge.info.sdd1) sdd1.reset();
|
||||
if(cartridge.info.spc7110) spc7110.reset();
|
||||
if(cartridge.info.cx4) cx4.reset();
|
||||
if(cartridge.info.dsp1) dsp1.reset();
|
||||
if(cartridge.info.dsp2) dsp2.reset();
|
||||
|
@@ -58,10 +58,9 @@ void Tracer::enable(bool en) {
|
||||
|
||||
void Tracer::cpuopmask_enable(bool en) {
|
||||
if(en == true && cpuopmask_enabled() == false) {
|
||||
settings.cpuopmasktbl = (uint8*)malloc(0x200000);
|
||||
memset(settings.cpuopmasktbl, 0x00, 0x200000);
|
||||
settings.cpuopmasktbl = new(zeromemory) uint8_t[0x200000];
|
||||
} else if(en == false && cpuopmask_enabled() == true) {
|
||||
safe_free(settings.cpuopmasktbl);
|
||||
delete[] settings.cpuopmasktbl;
|
||||
}
|
||||
|
||||
settings.cpuopmask = en;
|
||||
@@ -69,10 +68,9 @@ void Tracer::cpuopmask_enable(bool en) {
|
||||
|
||||
void Tracer::smpopmask_enable(bool en) {
|
||||
if(en == true && smpopmask_enabled() == false) {
|
||||
settings.smpopmasktbl = (uint8*)malloc(0x2000);
|
||||
memset(settings.smpopmasktbl, 0x00, 0x2000);
|
||||
settings.smpopmasktbl = new(zeromemory) uint8_t[0x2000];
|
||||
} else if(en == false && smpopmask_enabled() == true) {
|
||||
safe_free(settings.smpopmasktbl);
|
||||
delete[] settings.smpopmasktbl;
|
||||
}
|
||||
|
||||
settings.smpopmask = en;
|
||||
|
@@ -1,25 +1,25 @@
|
||||
const char AboutWindow::about_text[1024] = ""
|
||||
"bsnes -- version " BSNES_VERSION "\n"
|
||||
"Author: byuu\n"
|
||||
"Project began: October 14th, 2004";
|
||||
|
||||
const char AboutWindow::contributors_text[1024] =
|
||||
"Contributors:\n"
|
||||
" anomie, blargg, DMV27, GIGO, kode54, Nach,\n"
|
||||
" Overload, Richard Bannister, TRAC, zones";
|
||||
|
||||
uintptr_t AboutWindow::close(Event) {
|
||||
hide();
|
||||
return false;
|
||||
}
|
||||
|
||||
void AboutWindow::setup() {
|
||||
create(Window::AutoCenter, 350, 125, "About bsnes ...");
|
||||
create(Window::AutoCenter, 360, 135, translate["About bsnes ..."]);
|
||||
set_icon(48, 48, (uint32_t*)resource::icon48);
|
||||
|
||||
icon.create(0, 48, 48);
|
||||
about.create(0, 287, 48, about_text);
|
||||
contributors.create(0, 340, 48, contributors_text);
|
||||
about.create(0, 225, 48, string()
|
||||
<< "bsnes -- " << translate["Version"] << " " << BSNES_VERSION "\n"
|
||||
<< translate["Author"] << ": byuu\n"
|
||||
<< translate["Project began: October 14th, 2004"]
|
||||
);
|
||||
contributors.create(0, 350, 75, string()
|
||||
<< translate["Contributors:"] << "\n"
|
||||
<< " Andreas Naive, anomie, blargg, DMV27, GIGO, kode54,\n"
|
||||
<< " neviksti, Nach, Overload, Richard Bannister, TRAC, zones\n"
|
||||
<< "\n"
|
||||
<< translate["Localization by: byuu"]
|
||||
);
|
||||
|
||||
attach(icon, 5, 5);
|
||||
attach(about, 58, 5);
|
||||
|
@@ -8,13 +8,7 @@ bool MainWindow::input_ready() {
|
||||
}
|
||||
|
||||
uintptr_t MainWindow::close(Event) {
|
||||
app.term = true;
|
||||
window_about.hide();
|
||||
window_message.hide();
|
||||
window_settings.hide();
|
||||
window_bsxloader.hide();
|
||||
window_stloader.hide();
|
||||
hide();
|
||||
event::quit();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -26,14 +20,14 @@ uintptr_t MainWindow::event(Event e) {
|
||||
|
||||
if(e.widget == &menu_file_load_bsx) {
|
||||
window_bsxloader.mode = BSXLoaderWindow::ModeBSX;
|
||||
window_bsxloader.set_text("Load BS-X Cartridge");
|
||||
window_bsxloader.set_text(translate["Load BS-X Cartridge"]);
|
||||
window_bsxloader.tbase.set_text(config::path.bsx);
|
||||
window_bsxloader.focus();
|
||||
}
|
||||
|
||||
if(e.widget == &menu_file_load_bsc) {
|
||||
window_bsxloader.mode = BSXLoaderWindow::ModeBSC;
|
||||
window_bsxloader.set_text("Load BS-X Slotted Cartridge");
|
||||
window_bsxloader.set_text(translate["Load BS-X Slotted Cartridge"]);
|
||||
window_bsxloader.tbase.set_text("");
|
||||
window_bsxloader.focus();
|
||||
}
|
||||
@@ -59,8 +53,6 @@ uintptr_t MainWindow::event(Event e) {
|
||||
event(Event(Event::Close));
|
||||
}
|
||||
|
||||
if(locked == false) {
|
||||
//set locked to true to update below menu item check statuses without triggering events
|
||||
if(e.widget == &menu_settings_videomode_1x) { event::update_multiplier(1); }
|
||||
if(e.widget == &menu_settings_videomode_2x) { event::update_multiplier(2); }
|
||||
if(e.widget == &menu_settings_videomode_3x) { event::update_multiplier(3); }
|
||||
@@ -83,28 +75,27 @@ uintptr_t MainWindow::event(Event e) {
|
||||
if(e.widget == &menu_settings_videofilter_swhq2x) { event::update_software_filter(3); }
|
||||
if(e.widget == &menu_settings_videofilter_swntsc) { event::update_software_filter(4); }
|
||||
|
||||
if(e.widget == &menu_settings_videoframeskip_0) { config::video.frameskip = 0; }
|
||||
if(e.widget == &menu_settings_videoframeskip_1) { config::video.frameskip = 1; }
|
||||
if(e.widget == &menu_settings_videoframeskip_2) { config::video.frameskip = 2; }
|
||||
if(e.widget == &menu_settings_videoframeskip_3) { config::video.frameskip = 3; }
|
||||
if(e.widget == &menu_settings_videoframeskip_4) { config::video.frameskip = 4; }
|
||||
if(e.widget == &menu_settings_videoframeskip_5) { config::video.frameskip = 5; }
|
||||
if(e.widget == &menu_settings_videoframeskip_6) { config::video.frameskip = 6; }
|
||||
if(e.widget == &menu_settings_videoframeskip_7) { config::video.frameskip = 7; }
|
||||
if(e.widget == &menu_settings_videoframeskip_8) { config::video.frameskip = 8; }
|
||||
if(e.widget == &menu_settings_videoframeskip_9) { config::video.frameskip = 9; }
|
||||
if(e.widget == &menu_settings_videoframeskip_0) { event::update_frameskip(0); }
|
||||
if(e.widget == &menu_settings_videoframeskip_1) { event::update_frameskip(1); }
|
||||
if(e.widget == &menu_settings_videoframeskip_2) { event::update_frameskip(2); }
|
||||
if(e.widget == &menu_settings_videoframeskip_3) { event::update_frameskip(3); }
|
||||
if(e.widget == &menu_settings_videoframeskip_4) { event::update_frameskip(4); }
|
||||
if(e.widget == &menu_settings_videoframeskip_5) { event::update_frameskip(5); }
|
||||
if(e.widget == &menu_settings_videoframeskip_6) { event::update_frameskip(6); }
|
||||
if(e.widget == &menu_settings_videoframeskip_7) { event::update_frameskip(7); }
|
||||
if(e.widget == &menu_settings_videoframeskip_8) { event::update_frameskip(8); }
|
||||
if(e.widget == &menu_settings_videoframeskip_9) { event::update_frameskip(9); }
|
||||
|
||||
if(e.widget == &menu_settings_mute) {
|
||||
config::audio.mute = menu_settings_mute.checked();
|
||||
}
|
||||
|
||||
if(e.widget == &menu_settings_speedreg_disabled) { event::update_speed_regulation(0); }
|
||||
if(e.widget == &menu_settings_speedreg_slowest) { event::update_speed_regulation(1); }
|
||||
if(e.widget == &menu_settings_speedreg_slow) { event::update_speed_regulation(2); }
|
||||
if(e.widget == &menu_settings_speedreg_normal) { event::update_speed_regulation(3); }
|
||||
if(e.widget == &menu_settings_speedreg_fast) { event::update_speed_regulation(4); }
|
||||
if(e.widget == &menu_settings_speedreg_fastest) { event::update_speed_regulation(5); }
|
||||
}
|
||||
if(e.widget == &menu_settings_emuspeed_slowest) { event::update_emulation_speed(0); }
|
||||
if(e.widget == &menu_settings_emuspeed_slow) { event::update_emulation_speed(1); }
|
||||
if(e.widget == &menu_settings_emuspeed_normal) { event::update_emulation_speed(2); }
|
||||
if(e.widget == &menu_settings_emuspeed_fast) { event::update_emulation_speed(3); }
|
||||
if(e.widget == &menu_settings_emuspeed_fastest) { event::update_emulation_speed(4); }
|
||||
if(e.widget == &menu_settings_emuspeed_disabled) { event::update_emulation_speed(5); }
|
||||
|
||||
if(e.widget == &menu_settings_config) { window_settings.show(); }
|
||||
|
||||
@@ -130,53 +121,52 @@ uintptr_t MainWindow::block(Event) {
|
||||
}
|
||||
|
||||
void MainWindow::setup() {
|
||||
locked = true;
|
||||
|
||||
create(Window::AutoCenter, 256, 224, BSNES_TITLE);
|
||||
set_background_color(0, 0, 0);
|
||||
set_icon(48, 48, (uint32_t*)resource::icon48);
|
||||
|
||||
MenuRadioItemGroup group;
|
||||
attach(menu_file.create("File"));
|
||||
menu_file.attach(menu_file_load.create("Load Cartridge ..."));
|
||||
menu_file.attach(menu_file_load_special.create("Load Special"));
|
||||
menu_file_load_special.attach(menu_file_load_bsx.create("Load BS-X Cartridge ..."));
|
||||
menu_file_load_special.attach(menu_file_load_bsc.create("Load BS-X Slotted Cartridge ..."));
|
||||
menu_file_load_special.attach(menu_file_load_st.create("Load ST Cartridge ..."));
|
||||
menu_file.attach(menu_file_unload.create("Unload Cartridge"));
|
||||
MenuRadioItemGroup group;
|
||||
attach(menu_file.create(translate["System"]));
|
||||
menu_file.attach(menu_file_load.create(string() << translate["Load Cartridge"] << " ..."));
|
||||
menu_file.attach(menu_file_load_special.create(translate["Load Special"]));
|
||||
menu_file_load_special.attach(menu_file_load_bsx.create(string() << translate["Load BS-X Cartridge"] << " ..."));
|
||||
menu_file_load_special.attach(menu_file_load_bsc.create(string() << translate["Load BS-X Slotted Cartridge"] << " ..."));
|
||||
menu_file_load_special.attach(menu_file_load_st.create(string() << translate["Load Sufami Turbo Cartridge"] << " ..."));
|
||||
menu_file.attach(menu_file_unload.create(translate["Unload Cartridge"]));
|
||||
menu_file.attach(menu_file_sep1.create());
|
||||
menu_file.attach(menu_file_reset.create("Reset System"));
|
||||
menu_file.attach(menu_file_power.create("Power Cycle System"));
|
||||
menu_file.attach(menu_file_reset.create(translate["Reset"]));
|
||||
menu_file_power.create(translate["Power Cycle"]);
|
||||
if(config::advanced.enable) menu_file.attach(menu_file_power);
|
||||
menu_file.attach(menu_file_sep2.create());
|
||||
menu_file.attach(menu_file_exit.create("Exit"));
|
||||
menu_file.attach(menu_file_exit.create(translate["Exit"]));
|
||||
|
||||
attach(menu_settings.create("Settings"));
|
||||
menu_settings.attach(menu_settings_videomode.create("Video Mode"));
|
||||
attach(menu_settings.create(translate["Settings"]));
|
||||
menu_settings.attach(menu_settings_videomode.create(translate["Video Mode"]));
|
||||
group.add(&menu_settings_videomode_1x);
|
||||
group.add(&menu_settings_videomode_2x);
|
||||
group.add(&menu_settings_videomode_3x);
|
||||
group.add(&menu_settings_videomode_4x);
|
||||
group.add(&menu_settings_videomode_5x);
|
||||
menu_settings_videomode.attach(menu_settings_videomode_1x.create(group, "Scale 1x"));
|
||||
menu_settings_videomode.attach(menu_settings_videomode_2x.create(group, "Scale 2x"));
|
||||
menu_settings_videomode.attach(menu_settings_videomode_3x.create(group, "Scale 3x"));
|
||||
menu_settings_videomode.attach(menu_settings_videomode_4x.create(group, "Scale 4x"));
|
||||
menu_settings_videomode.attach(menu_settings_videomode_5x.create(group, "Scale 5x"));
|
||||
menu_settings_videomode.attach(menu_settings_videomode_1x.create(group, translate["Scale 1x"]));
|
||||
menu_settings_videomode.attach(menu_settings_videomode_2x.create(group, translate["Scale 2x"]));
|
||||
menu_settings_videomode.attach(menu_settings_videomode_3x.create(group, translate["Scale 3x"]));
|
||||
menu_settings_videomode.attach(menu_settings_videomode_4x.create(group, translate["Scale 4x"]));
|
||||
menu_settings_videomode.attach(menu_settings_videomode_5x.create(group, translate["Scale 5x"]));
|
||||
group.reset();
|
||||
menu_settings_videomode.attach(menu_settings_videomode_sep1.create());
|
||||
menu_settings_videomode.attach(menu_settings_videomode_aspect_correction.create("Correct Aspect Ratio"));
|
||||
menu_settings_videomode.attach(menu_settings_videomode_aspect_correction.create(translate["Correct Aspect Ratio"]));
|
||||
menu_settings_videomode.attach(menu_settings_videomode_sep2.create());
|
||||
group.add(&menu_settings_videomode_ntsc);
|
||||
group.add(&menu_settings_videomode_pal);
|
||||
menu_settings_videomode.attach(menu_settings_videomode_ntsc.create(group, "NTSC"));
|
||||
menu_settings_videomode.attach(menu_settings_videomode_pal.create(group, "PAL"));
|
||||
menu_settings_videomode.attach(menu_settings_videomode_ntsc.create(group, translate["NTSC"]));
|
||||
menu_settings_videomode.attach(menu_settings_videomode_pal.create(group, translate["PAL"]));
|
||||
group.reset();
|
||||
|
||||
menu_settings.attach(menu_settings_videofilter.create("Video Filter"));
|
||||
menu_settings.attach(menu_settings_videofilter.create(translate["Video Filter"]));
|
||||
group.add(&menu_settings_videofilter_hwpoint);
|
||||
group.add(&menu_settings_videofilter_hwlinear);
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_hwpoint.create(group, "Point"));
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_hwlinear.create(group, "Linear"));
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_hwpoint.create(group, translate["Point"]));
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_hwlinear.create(group, translate["Linear"]));
|
||||
group.reset();
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_sep1.create());
|
||||
group.add(&menu_settings_videofilter_swnone);
|
||||
@@ -184,14 +174,14 @@ MenuRadioItemGroup group;
|
||||
group.add(&menu_settings_videofilter_swscale2x);
|
||||
group.add(&menu_settings_videofilter_swhq2x);
|
||||
group.add(&menu_settings_videofilter_swntsc);
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_swnone.create(group, "None"));
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_swscanline.create(group, "Scanline"));
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_swscale2x.create(group, "Scale2x"));
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_swhq2x.create(group, "HQ2x"));
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_swntsc.create(group, "NTSC"));
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_swnone.create(group, translate["None"]));
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_swscanline.create(group, translate["Scanline"]));
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_swscale2x.create(group, translate["Scale2x"]));
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_swhq2x.create(group, translate["HQ2x"]));
|
||||
menu_settings_videofilter.attach(menu_settings_videofilter_swntsc.create(group, translate["NTSC"]));
|
||||
group.reset();
|
||||
|
||||
menu_settings.attach(menu_settings_videoframeskip.create("Video Frameskip"));
|
||||
menu_settings.attach(menu_settings_videoframeskip.create(translate["Video Frameskip"]));
|
||||
group.add(&menu_settings_videoframeskip_0);
|
||||
group.add(&menu_settings_videoframeskip_1);
|
||||
group.add(&menu_settings_videoframeskip_2);
|
||||
@@ -202,47 +192,49 @@ MenuRadioItemGroup group;
|
||||
group.add(&menu_settings_videoframeskip_7);
|
||||
group.add(&menu_settings_videoframeskip_8);
|
||||
group.add(&menu_settings_videoframeskip_9);
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_0.create(group, "0"));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_sep1.create());
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_1.create(group, "1"));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_2.create(group, "2"));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_3.create(group, "3"));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_4.create(group, "4"));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_5.create(group, "5"));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_6.create(group, "6"));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_7.create(group, "7"));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_8.create(group, "8"));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_9.create(group, "9"));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_0.create(group, translate["0"]));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_1.create(group, translate["1"]));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_2.create(group, translate["2"]));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_3.create(group, translate["3"]));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_4.create(group, translate["4"]));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_5.create(group, translate["5"]));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_6.create(group, translate["6"]));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_7.create(group, translate["7"]));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_8.create(group, translate["8"]));
|
||||
menu_settings_videoframeskip.attach(menu_settings_videoframeskip_9.create(group, translate["9"]));
|
||||
group.reset();
|
||||
|
||||
menu_settings.attach(menu_settings_sep1.create());
|
||||
menu_settings.attach(menu_settings_mute.create("Mute Sound Output"));
|
||||
menu_settings.attach(menu_settings_mute.create(translate["Mute Audio Output"]));
|
||||
menu_settings.attach(menu_settings_sep2.create());
|
||||
|
||||
menu_settings.attach(menu_settings_speedreg.create("Speed Regulation"));
|
||||
group.add(&menu_settings_speedreg_disabled);
|
||||
group.add(&menu_settings_speedreg_slowest);
|
||||
group.add(&menu_settings_speedreg_slow);
|
||||
group.add(&menu_settings_speedreg_normal);
|
||||
group.add(&menu_settings_speedreg_fast);
|
||||
group.add(&menu_settings_speedreg_fastest);
|
||||
menu_settings_speedreg.attach(menu_settings_speedreg_disabled.create(group, "Disabled"));
|
||||
menu_settings_speedreg.attach(menu_settings_speedreg_sep1.create());
|
||||
menu_settings_speedreg.attach(menu_settings_speedreg_slowest.create(group, "Slowest"));
|
||||
menu_settings_speedreg.attach(menu_settings_speedreg_slow.create(group, "Slow"));
|
||||
menu_settings_speedreg.attach(menu_settings_speedreg_normal.create(group, "Normal"));
|
||||
menu_settings_speedreg.attach(menu_settings_speedreg_fast.create(group, "Fast"));
|
||||
menu_settings_speedreg.attach(menu_settings_speedreg_fastest.create(group, "Fastest"));
|
||||
menu_settings.attach(menu_settings_emuspeed.create(translate["Emulation Speed"]));
|
||||
group.add(&menu_settings_emuspeed_slowest);
|
||||
group.add(&menu_settings_emuspeed_slow);
|
||||
group.add(&menu_settings_emuspeed_normal);
|
||||
group.add(&menu_settings_emuspeed_fast);
|
||||
group.add(&menu_settings_emuspeed_fastest);
|
||||
group.add(&menu_settings_emuspeed_disabled);
|
||||
menu_settings_emuspeed.attach(menu_settings_emuspeed_slowest.create(group, translate["50%"]));
|
||||
menu_settings_emuspeed.attach(menu_settings_emuspeed_slow.create(group, translate["75%"]));
|
||||
menu_settings_emuspeed.attach(menu_settings_emuspeed_normal.create(group, translate["100%"]));
|
||||
menu_settings_emuspeed.attach(menu_settings_emuspeed_fast.create(group, translate["150%"]));
|
||||
menu_settings_emuspeed.attach(menu_settings_emuspeed_fastest.create(group, translate["200%"]));
|
||||
menu_settings_emuspeed.attach(menu_settings_emuspeed_disabled.create(group, translate["Uncapped"]));
|
||||
group.reset();
|
||||
|
||||
menu_settings.attach(menu_settings_sep3.create());
|
||||
menu_settings.attach(menu_settings_config.create("Configuration ..."));
|
||||
menu_settings.attach(menu_settings_config.create(string() << translate["Configuration"] << " ..."));
|
||||
|
||||
attach(menu_misc.create("Misc"));
|
||||
menu_misc.attach(menu_misc_logaudio.create("Log Audio Data"));
|
||||
menu_misc.attach(menu_misc_showstatus.create("Show Statusbar"));
|
||||
attach(menu_misc.create(translate["Misc"]));
|
||||
menu_misc.attach(menu_misc_logaudio.create(translate["Log Audio Data"]));
|
||||
menu_misc.attach(menu_misc_showstatus.create(translate["Show Statusbar"]));
|
||||
menu_misc.attach(menu_misc_sep1.create());
|
||||
menu_misc.attach(menu_misc_about.create("About ..."));
|
||||
menu_misc.attach(menu_misc_about.create(string() << translate["About"] << " ..."));
|
||||
|
||||
menu_file_unload.disable();
|
||||
menu_file_reset.disable();
|
||||
menu_file_power.disable();
|
||||
|
||||
view.create(0, 256, 224);
|
||||
attach(view, 0, 0);
|
||||
@@ -289,12 +281,12 @@ MenuRadioItemGroup group;
|
||||
menu_settings_videoframeskip_9.on_tick =
|
||||
|
||||
menu_settings_mute.on_tick =
|
||||
menu_settings_speedreg_disabled.on_tick =
|
||||
menu_settings_speedreg_slowest.on_tick =
|
||||
menu_settings_speedreg_slow.on_tick =
|
||||
menu_settings_speedreg_normal.on_tick =
|
||||
menu_settings_speedreg_fast.on_tick =
|
||||
menu_settings_speedreg_fastest.on_tick =
|
||||
menu_settings_emuspeed_slowest.on_tick =
|
||||
menu_settings_emuspeed_slow.on_tick =
|
||||
menu_settings_emuspeed_normal.on_tick =
|
||||
menu_settings_emuspeed_fast.on_tick =
|
||||
menu_settings_emuspeed_fastest.on_tick =
|
||||
menu_settings_emuspeed_disabled.on_tick =
|
||||
menu_settings_config.on_tick =
|
||||
|
||||
menu_misc_logaudio.on_tick =
|
||||
@@ -302,10 +294,11 @@ MenuRadioItemGroup group;
|
||||
menu_misc_about.on_tick =
|
||||
|
||||
bind(&MainWindow::event, this);
|
||||
|
||||
if(config::misc.status_enable) status.show();
|
||||
}
|
||||
|
||||
void MainWindow::update_menu_settings() {
|
||||
locked = true;
|
||||
void MainWindow::sync() {
|
||||
event::load_video_settings();
|
||||
|
||||
switch(event::video_settings.multiplier) { default:
|
||||
@@ -338,16 +331,27 @@ void MainWindow::update_menu_settings() {
|
||||
|
||||
menu_settings_mute.check(config::audio.mute);
|
||||
|
||||
switch(config::system.speed_regulation) {
|
||||
case 0: menu_settings_speedreg_disabled.check(); break;
|
||||
case 1: menu_settings_speedreg_slowest.check(); break;
|
||||
case 2: menu_settings_speedreg_slow.check(); break;
|
||||
case 3: menu_settings_speedreg_normal.check(); break;
|
||||
case 4: menu_settings_speedreg_fast.check(); break;
|
||||
case 5: menu_settings_speedreg_fastest.check(); break;
|
||||
switch(config::video.frameskip) {
|
||||
case 0: menu_settings_videoframeskip_0.check(); break;
|
||||
case 1: menu_settings_videoframeskip_1.check(); break;
|
||||
case 2: menu_settings_videoframeskip_2.check(); break;
|
||||
case 3: menu_settings_videoframeskip_3.check(); break;
|
||||
case 4: menu_settings_videoframeskip_4.check(); break;
|
||||
case 5: menu_settings_videoframeskip_5.check(); break;
|
||||
case 6: menu_settings_videoframeskip_6.check(); break;
|
||||
case 7: menu_settings_videoframeskip_7.check(); break;
|
||||
case 8: menu_settings_videoframeskip_8.check(); break;
|
||||
case 9: menu_settings_videoframeskip_9.check(); break;
|
||||
}
|
||||
|
||||
switch(config::system.emulation_speed) {
|
||||
case 0: menu_settings_emuspeed_slowest.check(); break;
|
||||
case 1: menu_settings_emuspeed_slow.check(); break;
|
||||
case 2: menu_settings_emuspeed_normal.check(); break;
|
||||
case 3: menu_settings_emuspeed_fast.check(); break;
|
||||
case 4: menu_settings_emuspeed_fastest.check(); break;
|
||||
case 5: menu_settings_emuspeed_disabled.check(); break;
|
||||
}
|
||||
|
||||
menu_misc_showstatus.check(config::misc.status_enable);
|
||||
|
||||
locked = false;
|
||||
}
|
||||
|
@@ -36,7 +36,6 @@ public:
|
||||
MenuRadioItem menu_settings_videofilter_swntsc;
|
||||
MenuGroup menu_settings_videoframeskip;
|
||||
MenuRadioItem menu_settings_videoframeskip_0;
|
||||
MenuSeparator menu_settings_videoframeskip_sep1;
|
||||
MenuRadioItem menu_settings_videoframeskip_1;
|
||||
MenuRadioItem menu_settings_videoframeskip_2;
|
||||
MenuRadioItem menu_settings_videoframeskip_3;
|
||||
@@ -49,14 +48,13 @@ public:
|
||||
MenuSeparator menu_settings_sep1;
|
||||
MenuCheckItem menu_settings_mute;
|
||||
MenuSeparator menu_settings_sep2;
|
||||
MenuGroup menu_settings_speedreg;
|
||||
MenuRadioItem menu_settings_speedreg_disabled;
|
||||
MenuSeparator menu_settings_speedreg_sep1;
|
||||
MenuRadioItem menu_settings_speedreg_slowest;
|
||||
MenuRadioItem menu_settings_speedreg_slow;
|
||||
MenuRadioItem menu_settings_speedreg_normal;
|
||||
MenuRadioItem menu_settings_speedreg_fast;
|
||||
MenuRadioItem menu_settings_speedreg_fastest;
|
||||
MenuGroup menu_settings_emuspeed;
|
||||
MenuRadioItem menu_settings_emuspeed_slowest;
|
||||
MenuRadioItem menu_settings_emuspeed_slow;
|
||||
MenuRadioItem menu_settings_emuspeed_normal;
|
||||
MenuRadioItem menu_settings_emuspeed_fast;
|
||||
MenuRadioItem menu_settings_emuspeed_fastest;
|
||||
MenuRadioItem menu_settings_emuspeed_disabled;
|
||||
MenuSeparator menu_settings_sep3;
|
||||
MenuItem menu_settings_config;
|
||||
|
||||
@@ -68,11 +66,10 @@ public:
|
||||
|
||||
Canvas view;
|
||||
|
||||
bool locked;
|
||||
|
||||
bool input_ready();
|
||||
void setup();
|
||||
void update_menu_settings();
|
||||
void sync();
|
||||
|
||||
uintptr_t close(Event);
|
||||
uintptr_t event(Event);
|
||||
uintptr_t block(Event);
|
||||
|
@@ -5,16 +5,16 @@ uintptr_t MessageWindow::close(Event) {
|
||||
|
||||
void MessageWindow::setup() {
|
||||
create(Window::AutoCenter, 400, 100, "");
|
||||
message.create(0, 390, 60, "Test\nMessage");
|
||||
ok.create(0, 100, 30, "Ok");
|
||||
message.create(0, 390, 60, "");
|
||||
ok.create(0, 100, 25, translate["Ok"]);
|
||||
attach(message, 5, 5);
|
||||
attach(ok, 295, 65);
|
||||
attach(ok, 295, 70);
|
||||
|
||||
on_close = ok.on_tick = bind(&MessageWindow::close, this);
|
||||
}
|
||||
|
||||
void MessageWindow::show(const char *message_, const char *title_) {
|
||||
message.set_text(message_);
|
||||
set_text(title_);
|
||||
set_text(translate[title_]);
|
||||
focus();
|
||||
}
|
||||
|
@@ -1,10 +1,11 @@
|
||||
namespace config {
|
||||
|
||||
char filename[PATH_MAX + 16] = "bsnes.cfg";
|
||||
char bsnes_cfg[PATH_MAX] = "";
|
||||
char locale_cfg[PATH_MAX] = "";
|
||||
|
||||
struct System {
|
||||
static string_setting video, audio, input;
|
||||
static integral_setting speed_regulation;
|
||||
static integral_setting emulation_speed;
|
||||
static integral_setting gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma;
|
||||
} system;
|
||||
|
||||
@@ -12,15 +13,15 @@ string_setting System::video(config(), "system.video", "Video hardware interface
|
||||
string_setting System::audio(config(), "system.audio", "Audio hardware interface", "");
|
||||
string_setting System::input(config(), "system.input", "Input hardware interface", "");
|
||||
|
||||
integral_setting System::speed_regulation(config(), "system.speed_regulation",
|
||||
"Speed regulation setting\n"
|
||||
"0 = Disabled\n"
|
||||
"1 = Slowest\n"
|
||||
"2 = Slow\n"
|
||||
"3 = Normal\n"
|
||||
"4 = Fast\n"
|
||||
"5 = Fastest",
|
||||
integral_setting::decimal, 3);
|
||||
integral_setting System::emulation_speed(config(), "system.emulation_speed",
|
||||
"Relative speed of emulator compared to SNES hardware\n"
|
||||
"0 = 50%\n"
|
||||
"1 = 75%\n"
|
||||
"2 = 100%\n"
|
||||
"3 = 150%\n"
|
||||
"4 = 200%\n"
|
||||
"5 = Uncapped",
|
||||
integral_setting::decimal, 2);
|
||||
|
||||
integral_setting System::gamma_ramp(config(), "system.colorfilter.gamma_ramp",
|
||||
"Use precalculated TV-style gamma ramp", integral_setting::boolean, true);
|
||||
@@ -118,6 +119,11 @@ struct Input {
|
||||
static string_setting pause;
|
||||
static string_setting reset;
|
||||
static string_setting power;
|
||||
static string_setting quit;
|
||||
static string_setting speed_decrease;
|
||||
static string_setting speed_increase;
|
||||
static string_setting frameskip_decrease;
|
||||
static string_setting frameskip_increase;
|
||||
static string_setting toggle_fullscreen;
|
||||
static string_setting toggle_menubar;
|
||||
static string_setting toggle_statusbar;
|
||||
@@ -168,7 +174,12 @@ string_setting Input::GUI::load (config(), "input.gui.load",
|
||||
string_setting Input::GUI::pause (config(), "input.gui.pause", "", "f12");
|
||||
string_setting Input::GUI::reset (config(), "input.gui.reset", "", "none");
|
||||
string_setting Input::GUI::power (config(), "input.gui.power", "", "none");
|
||||
string_setting Input::GUI::toggle_fullscreen(config(), "input.gui.toggle_fullscreen", "", "f11");
|
||||
string_setting Input::GUI::quit (config(), "input.gui.quit", "", "none");
|
||||
string_setting Input::GUI::speed_decrease (config(), "input.gui.speed_decrease", "", "divide");
|
||||
string_setting Input::GUI::speed_increase (config(), "input.gui.speed_increase", "", "multiply");
|
||||
string_setting Input::GUI::frameskip_decrease(config(), "input.gui.frameskip_decrease", "", "subtract");
|
||||
string_setting Input::GUI::frameskip_increase(config(), "input.gui.frameskip_increase", "", "add");
|
||||
string_setting Input::GUI::toggle_fullscreen (config(), "input.gui.toggle_fullscreen", "", "f11");
|
||||
string_setting Input::GUI::toggle_menubar (config(), "input.gui.toggle_menubar", "", "escape");
|
||||
string_setting Input::GUI::toggle_statusbar (config(), "input.gui.toggle_statusbar", "", "escape");
|
||||
|
||||
@@ -187,4 +198,11 @@ string_setting Misc::status_text(config(), "misc.status_text",
|
||||
"%f = executed frames per second\n"
|
||||
"%m = maximum frames per second"
|
||||
"", "%n : %f / %m");
|
||||
};
|
||||
|
||||
struct Advanced {
|
||||
static integral_setting enable;
|
||||
} advanced;
|
||||
|
||||
integral_setting Advanced::enable(config(), "advanced.enable", "Enable advanced, developer-oriented UI options", integral_setting::boolean, false);
|
||||
|
||||
} //namespace config
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user