diff --git a/bsnes.exe b/bsnes.exe deleted file mode 100644 index 848cfe09..00000000 Binary files a/bsnes.exe and /dev/null differ diff --git a/demo_irqtest.smc b/demo_irqtest.smc deleted file mode 100644 index 384ae3c3..00000000 Binary files a/demo_irqtest.smc and /dev/null differ diff --git a/demo_nmitest.smc b/demo_nmitest.smc deleted file mode 100644 index b91d4ec9..00000000 Binary files a/demo_nmitest.smc and /dev/null differ diff --git a/irq.smc b/irq.smc deleted file mode 100644 index 1559b6d9..00000000 Binary files a/irq.smc and /dev/null differ diff --git a/nmi.smc b/nmi.smc deleted file mode 100644 index 876df233..00000000 Binary files a/nmi.smc and /dev/null differ diff --git a/src/Makefile b/src/Makefile index 0e964a61..15079f6c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -6,7 +6,7 @@ prefix = /usr/local ################ ifneq ($(findstring gcc,$(compiler)),) # GCC family - flags = -O3 -fomit-frame-pointer $(if $(call streq,$(platform),x),-mtune=native,) -Ilib + flags = -O3 -fomit-frame-pointer -Ilib c = $(compiler) $(flags) cpp = $(subst cc,++,$(compiler)) $(flags) obj = o @@ -16,7 +16,7 @@ ifneq ($(findstring gcc,$(compiler)),) # GCC family mkdef = -D$1 mklib = -l$1 else ifeq ($(compiler),cl) # Visual C++ - flags = /nologo /wd4355 /wd4996 /O2 /EHsc /Ilib + flags = /nologo /wd4355 /wd4805 /wd4996 /Ox /GL /EHsc /Ilib c = cl $(flags) cpp = cl $(flags) obj = obj @@ -79,7 +79,7 @@ link += $(if $(findstring input.sdl,$(ruby)),`sdl-config --libs`) #################################### objects = main libco hiro ruby libfilter string \ - config reader cart cheat \ + reader cart cheat \ memory smemory cpu scpu smp ssmp sdsp ppu bppu snes \ bsx srtc sdd1 spc7110 cx4 dsp1 dsp2 dsp3 dsp4 obc1 st010 @@ -98,11 +98,7 @@ rubydef := $(foreach c,$(subst .,_,$(call strupper,$(ruby))),$(call mkdef,$c)) # Windows resource file ifeq ($(platform),win) - ifeq ($(compiler),cl) - objects += obj/bsnes.res - else ifneq ($(findstring gcc,$(compiler)),) - objects += obj/bsnesrc.$(obj) - endif + objects += obj/resource.$(obj) endif ################ @@ -127,9 +123,8 @@ all: build; ### main ### ############ -obj/main.$(obj): ui/main.cpp ui/* ui/base/* ui/event/* ui/loader/* ui/settings/* -obj/bsnes.res: ui/bsnes.rc; rc /r /foobj/bsnes.res ui/bsnes.rc -obj/bsnesrc.$(obj): ui/bsnes.rc; windres ui/bsnes.rc obj/bsnesrc.$(obj) +obj/main.$(obj) : ui/main.cpp ui/* ui/base/* ui/event/* ui/loader/* ui/settings/* +obj/resource.$(obj): ui/bsnes.rc; windres ui/bsnes.rc obj/resource.$(obj) ################# ### libraries ### @@ -139,16 +134,15 @@ obj/ruby.$(obj): lib/ruby/ruby.cpp lib/ruby/* lib/ruby/video/* lib/ruby/audio/* $(call compile,$(rubydef) $(rubyflags)) obj/hiro.$(obj): lib/hiro/hiro.cpp lib/hiro/* lib/hiro/gtk/* lib/hiro/win/* $(call compile,$(if $(call streq,$(platform),x),`pkg-config --cflags gtk+-2.0`)) -obj/libco.$(obj): lib/libco/libco.c lib/libco/* - $(call compile,-static) +obj/libco.$(obj): lib/libco/libco.c lib/libco/* + $(call compile,$(if $(call strne,$(compiler),cl),-static)) obj/libfilter.$(obj): lib/libfilter/libfilter.cpp lib/libfilter/* -obj/string.$(obj): lib/nall/string.cpp lib/nall/* +obj/string.$(obj): lib/nall/string.cpp lib/nall/* ################# ### utilities ### ################# -obj/config.$(obj): config/config.cpp config/* obj/reader.$(obj): reader/reader.cpp reader/* obj/cart.$(obj) : cart/cart.cpp cart/* obj/cheat.$(obj) : cheat/cheat.cpp cheat/* diff --git a/src/base.hpp b/src/base.hpp index e27c13b6..dfe6b493 100644 --- a/src/base.hpp +++ b/src/base.hpp @@ -1,4 +1,4 @@ -#define BSNES_VERSION "0.038.05" +#define BSNES_VERSION "0.039" #define BSNES_TITLE "bsnes v" BSNES_VERSION #define BUSCORE sBus @@ -24,15 +24,13 @@ #include #include #include -#include #include #include #include #include -#include +#include #include #include -#include #include #include #include @@ -47,6 +45,5 @@ typedef uint8_t uint8; typedef uint16_t uint16; typedef uint32_t uint32; typedef uint64_t uint64; -typedef unsigned uint; #include "interface.hpp" diff --git a/src/cart/cart.cpp b/src/cart/cart.cpp index e152baf2..6c69d59f 100644 --- a/src/cart/cart.cpp +++ b/src/cart/cart.cpp @@ -1,9 +1,12 @@ -#include <../base.hpp> -#define CART_CPP - -#include +#include <../base.hpp> +#include <../chip/chip.hpp> +#include <../reader/reader.hpp> +#define CART_CPP + +#include #include +#include "cart.hpp" #include "cart_load.cpp" #include "cart_normal.cpp" #include "cart_bsx.cpp" @@ -22,11 +25,11 @@ namespace memory { Cartridge cartridge; -const char* Cartridge::name() { return info.filename; } -Cartridge::CartridgeMode Cartridge::mode() { return info.mode; } -Cartridge::MemoryMapper Cartridge::mapper() { return info.mapper; } -Cartridge::Region Cartridge::region() { return info.region; } -bool Cartridge::loaded() { return cart.loaded; } +const char* Cartridge::name() const { return info.filename; } +Cartridge::CartridgeMode Cartridge::mode() const { return info.mode; } +Cartridge::MemoryMapper Cartridge::mapper() const { return info.mapper; } +Cartridge::Region Cartridge::region() const { return info.region; } +bool Cartridge::loaded() const { return cart.loaded; } void Cartridge::load_begin(CartridgeMode mode) { cart.rom = cart.ram = cart.rtc = 0; @@ -111,7 +114,9 @@ Cartridge::~Cartridge() { if(cart.loaded == true) unload(); } -// +//========== +//cartinfo_t +//========== void Cartridge::cartinfo_t::reset() { type = TypeUnknown; @@ -165,3 +170,30 @@ Cartridge::info_t& Cartridge::info_t::operator=(const Cartridge::cartinfo_t &sou return *this; } + +//======= +//utility +//======= + +string Cartridge::filepath(const char *filename, const char *pathname) { + //if no pathname, return filename as-is + string file(filename); + replace(file, "\\", "/"); + if(!pathname || !*pathname) return file; + + //ensure path ends with trailing '/' + string path(pathname); + replace(path, "\\", "/"); + if(!strend(path, "/")) strcat(path, "/"); + + //replace relative path with absolute path + if(strbegin(path, "./")) { + ltrim(path, "./"); + path = string() << snes.config.path.base << path; + } + + //remove folder part of filename + lstring part; + split(part, "/", file); + return path << part[count(part) - 1]; +} diff --git a/src/cart/cart.hpp b/src/cart/cart.hpp index 83e35ccb..5b6b91d1 100644 --- a/src/cart/cart.hpp +++ b/src/cart/cart.hpp @@ -29,11 +29,11 @@ public: Complement = 0x1c, //inverse checksum Checksum = 0x1e, ResetVector = 0x3c, - }; - - enum Region { - NTSC, - PAL, + }; + + enum Region { + NTSC, + PAL, }; enum MemoryMapper { @@ -55,28 +55,28 @@ public: DSP1HiROM, }; - const char* name(); - CartridgeMode mode(); - MemoryMapper mapper(); - Region region(); + const char* name() const; + CartridgeMode mode() const; + MemoryMapper mapper() const; + Region region() const; struct { bool loaded; char fn[PATH_MAX]; uint8 *rom, *ram, *rtc; - uint rom_size, ram_size, rtc_size; + unsigned rom_size, ram_size, rtc_size; } cart; struct { char fn[PATH_MAX]; uint8 *ram; - uint ram_size; + unsigned ram_size; } bs; struct { char fn[PATH_MAX]; uint8 *rom, *ram; - uint rom_size, ram_size; + unsigned rom_size, ram_size; } stA, stB; struct cartinfo_t { @@ -159,7 +159,7 @@ public: void unload_cart_bsc(); void unload_cart_st(); - bool loaded(); + bool loaded() const; void load_begin(CartridgeMode); void load_end(); bool unload(); @@ -167,29 +167,31 @@ public: void read_header(cartinfo_t &info, const uint8_t *data, unsigned size); unsigned find_header(const uint8_t *data, unsigned size); unsigned score_header(const uint8_t *data, unsigned size, unsigned addr); - - enum CompressionMode { - CompressionNone, //always load without compression - CompressionInspect, //use file header inspection - CompressionAuto, //use file extension or file header inspection (configured by user) + + enum CompressionMode { + CompressionNone, //always load without compression + CompressionInspect, //use file header inspection + CompressionAuto, //use file extension or file header inspection (configured by user) }; - bool load_file(const char *fn, uint8 *&data, uint &size, CompressionMode compression = CompressionNone); - bool save_file(const char *fn, uint8 *data, uint size); + bool load_file(const char *fn, uint8 *&data, unsigned &size, CompressionMode compression = CompressionNone); + bool save_file(const char *fn, uint8 *data, unsigned size); bool apply_patch(const uint8_t *pdata, unsigned psize, uint8_t *&data, unsigned &size); - char* modify_extension(char *filename, const char *extension); - char* get_base_filename(char *filename); - char* get_path_filename(char *filename, const char *path, const char *source, const char *extension); + char* modify_extension(char *filename, const char *extension); + char* get_base_filename(char *filename); + char* get_path_filename(char *filename, const char *path, const char *source, const char *extension); char* get_patch_filename(const char *source, const char *extension); - char* get_save_filename(const char *source, const char *extension); - char* get_cheat_filename(const char *source, const char *extension); + char* get_save_filename(const char *source, const char *extension); + char* get_cheat_filename(const char *source, const char *extension); + + static string filepath(const char *filename, const char *pathname); Cartridge(); ~Cartridge(); -private: +private: char patchfn[PATH_MAX]; char savefn[PATH_MAX]; - char rtcfn[PATH_MAX]; + char rtcfn[PATH_MAX]; char cheatfn[PATH_MAX]; }; diff --git a/src/cart/cart_bsc.cpp b/src/cart/cart_bsc.cpp index e1cb44c8..218be630 100644 --- a/src/cart/cart_bsc.cpp +++ b/src/cart/cart_bsc.cpp @@ -41,4 +41,4 @@ void Cartridge::unload_cart_bsc() { if(cart.ram) save_file(get_save_filename(cart.fn, "srm"), cart.ram, cart.ram_size); } -#endif //ifdef CART_CPP +#endif diff --git a/src/cart/cart_bsx.cpp b/src/cart/cart_bsx.cpp index 7836907f..91774236 100644 --- a/src/cart/cart_bsx.cpp +++ b/src/cart/cart_bsx.cpp @@ -46,4 +46,4 @@ void Cartridge::unload_cart_bsx() { save_file(get_save_filename(cart.fn, "psr"), bsxcart.psram.handle(), bsxcart.psram.size()); } -#endif //ifdef CART_CPP +#endif diff --git a/src/cart/cart_file.cpp b/src/cart/cart_file.cpp index 9ea88ffa..f55eaf69 100644 --- a/src/cart/cart_file.cpp +++ b/src/cart/cart_file.cpp @@ -54,28 +54,28 @@ char* Cartridge::get_base_filename(char *filename) { char* Cartridge::get_path_filename(char *filename, const char *path, const char *source, const char *extension) { strcpy(filename, source); modify_extension(filename, extension); - strcpy(filename, config::filepath(filename, path)); + strcpy(filename, filepath(filename, path)); return filename; } char* Cartridge::get_patch_filename(const char *source, const char *extension) { - return get_path_filename(patchfn, config::path.patch, source, extension); + return get_path_filename(patchfn, snes.config.path.patch, source, extension); } char* Cartridge::get_save_filename(const char *source, const char *extension) { - return get_path_filename(savefn, config::path.save, source, extension); + return get_path_filename(savefn, snes.config.path.save, source, extension); } char* Cartridge::get_cheat_filename(const char *source, const char *extension) { - return get_path_filename(cheatfn, config::path.cheat, source, extension); + return get_path_filename(cheatfn, snes.config.path.cheat, source, extension); } -bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size, CompressionMode compression) { +bool Cartridge::load_file(const char *fn, uint8 *&data, unsigned &size, CompressionMode compression) { if(file::exists(fn) == false) return false; Reader::Type filetype = Reader::Normal; if(compression == CompressionInspect) filetype = Reader::detect(fn, true); - if(compression == CompressionAuto) filetype = Reader::detect(fn, config::file.autodetect_type); + if(compression == CompressionAuto) filetype = Reader::detect(fn, snes.config.file.autodetect_type); switch(filetype) { default: case Reader::Normal: { @@ -125,7 +125,7 @@ bool Cartridge::apply_patch(const uint8_t *pdata, const unsigned psize, uint8_t bool apply = false; if(result == ups::ok) apply = true; - if(config::file.bypass_patch_crc32 == true) { + if(snes.config.file.bypass_patch_crc32 == true) { if(result == ups::input_crc32_invalid) apply = true; if(result == ups::output_crc32_invalid) apply = true; } @@ -141,7 +141,7 @@ bool Cartridge::apply_patch(const uint8_t *pdata, const unsigned psize, uint8_t return apply; } -bool Cartridge::save_file(const char *fn, uint8 *data, uint size) { +bool Cartridge::save_file(const char *fn, uint8 *data, unsigned size) { file fp; if(!fp.open(fn, file::mode_write)) return false; fp.write(data, size); @@ -149,4 +149,4 @@ bool Cartridge::save_file(const char *fn, uint8 *data, uint size) { return true; } -#endif //ifdef CART_CPP +#endif diff --git a/src/cart/cart_header.cpp b/src/cart/cart_header.cpp index b628e3d7..05e201dc 100644 --- a/src/cart/cart_header.cpp +++ b/src/cart/cart_header.cpp @@ -4,7 +4,10 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size info.reset(); unsigned index = find_header(data, size); + //======================= //detect BS-X flash carts + //======================= + if(data[index + 0x13] == 0x00 || data[index + 0x13] == 0xff) { if(data[index + 0x14] == 0x00) { const uint8_t n15 = data[index + 0x15]; @@ -19,7 +22,10 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size } } + //========================= //detect Sufami Turbo carts + //========================= + if(!memcmp(data, "BANDAI SFC-ADX", 14)) { if(!memcmp(data + 16, "SFC-ADX BACKUP", 14)) { info.type = TypeSufamiTurboBIOS; @@ -28,15 +34,18 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size } info.mapper = STROM; info.region = NTSC; //Sufami Turbo only released in Japan - return; + return; //RAM size handled internally by load_cart_st(); } - //standard cart - uint8 mapper = data[index + Mapper]; - uint8 rom_type = data[index + RomType]; - uint8 rom_size = data[index + RomSize]; - uint8 company = data[index + Company]; - uint8 region = data[index + CartRegion] & 0x7f; + //===================== + //detect standard carts + //===================== + + const uint8 mapper = data[index + Mapper]; + const uint8 rom_type = data[index + RomType]; + const uint8 rom_size = data[index + RomSize]; + const uint8 company = data[index + Company]; + const uint8 region = data[index + CartRegion] & 0x7f; //detect presence of BS-X flash cartridge connector (reads extended header information) if(data[index - 14] == 'Z') { @@ -55,25 +64,28 @@ void Cartridge::read_header(cartinfo_t &info, const uint8_t *data, unsigned size //BS-X base cart info.type = TypeBSXBIOS; info.mapper = BSXROM; + info.region = NTSC; //BS-X only released in Japan + return; //RAM size handled internally by load_cart_bsx() -> BSXCart class } else { + //BS-X slotted cart info.type = TypeBSC; info.mapper = (index == 0x7fc0 ? BSCLoROM : BSCHiROM); } - return; - } + } else { + //standard cart + info.type = TypeNormal; - info.type = TypeNormal; - - if(index == 0x7fc0 && size >= 0x401000) { - info.mapper = ExLoROM; - } else if(index == 0x7fc0 && mapper == 0x32) { - info.mapper = ExLoROM; - } else if(index == 0x7fc0) { - info.mapper = LoROM; - } else if(index == 0xffc0) { - info.mapper = HiROM; - } else { //index == 0x40ffc0 - info.mapper = ExHiROM; + if(index == 0x7fc0 && size >= 0x401000) { + info.mapper = ExLoROM; + } else if(index == 0x7fc0 && mapper == 0x32) { + info.mapper = ExLoROM; + } else if(index == 0x7fc0) { + info.mapper = LoROM; + } else if(index == 0xffc0) { + info.mapper = HiROM; + } else { //index == 0x40ffc0 + info.mapper = ExHiROM; + } } if(mapper == 0x20 && (rom_type == 0x13 || rom_type == 0x14 || rom_type == 0x15 || rom_type == 0x1a)) { @@ -186,7 +198,7 @@ unsigned Cartridge::score_header(const uint8_t *data, unsigned size, unsigned ad uint16 complement = data[addr + Complement ] | (data[addr + Complement + 1] << 8); uint8 resetop = data[(addr & ~0x7fff) | (resetvector & 0x7fff)]; //first opcode executed upon reset - uint8 mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit + uint8 mapper = data[addr + Mapper] & ~0x10; //mask off irrelevent FastROM-capable bit //$00:[000-7fff] contains uninitialized RAM and MMIO. //reset vector must point to ROM at $00:[8000-ffff] to be considered valid. @@ -248,7 +260,7 @@ unsigned Cartridge::score_header(const uint8_t *data, unsigned size, unsigned ad if(addr == 0x007fc0 && mapper == 0x22) score += 2; //0x22 is usually ExLoROM if(addr == 0x40ffc0 && mapper == 0x25) score += 2; //0x25 is usually ExHiROM - if(data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header + if(data[addr + Company] == 0x33) score += 2; //0x33 indicates extended header if(data[addr + RomType] < 0x08) score++; if(data[addr + RomSize] < 0x10) score++; if(data[addr + RamSize] < 0x08) score++; @@ -258,4 +270,4 @@ unsigned Cartridge::score_header(const uint8_t *data, unsigned size, unsigned ad return score; } -#endif //ifdef CART_CPP +#endif diff --git a/src/cart/cart_load.cpp b/src/cart/cart_load.cpp index 75e4275b..4a4037ec 100644 --- a/src/cart/cart_load.cpp +++ b/src/cart/cart_load.cpp @@ -47,4 +47,4 @@ bool Cartridge::load_ram(const char *filename, uint8_t *&data, unsigned size, ui return true; } -#endif //ifdef CART_CPP +#endif diff --git a/src/cart/cart_normal.cpp b/src/cart/cart_normal.cpp index 11073842..79861f3f 100644 --- a/src/cart/cart_normal.cpp +++ b/src/cart/cart_normal.cpp @@ -32,4 +32,4 @@ void Cartridge::unload_cart_normal() { if(cart.rtc) save_file(get_save_filename(cart.fn, "rtc"), cart.rtc, cart.rtc_size); } -#endif //ifdef CART_CPP +#endif diff --git a/src/cart/cart_st.cpp b/src/cart/cart_st.cpp index b32b5035..0c5fc7af 100644 --- a/src/cart/cart_st.cpp +++ b/src/cart/cart_st.cpp @@ -59,4 +59,4 @@ void Cartridge::unload_cart_st() { if(stB.ram) save_file(get_save_filename(stB.fn, "srm"), stB.ram, stB.ram_size); } -#endif //ifdef CART_CPP +#endif diff --git a/src/cc.bat b/src/cc.bat index 2efde1c3..9e270d97 100644 --- a/src/cc.bat +++ b/src/cc.bat @@ -1,3 +1,3 @@ -@make platform=win compiler=mingw32-gcc -::@make platform=win compiler=mingw32-gcc enable_gzip=true enable_jma=true +@mingw32-make platform=win compiler=mingw32-gcc +::@mingw32-make platform=win compiler=mingw32-gcc enable_gzip=true enable_jma=true @pause diff --git a/src/cheat/cheat.cpp b/src/cheat/cheat.cpp index 2dc25281..30da603b 100644 --- a/src/cheat/cheat.cpp +++ b/src/cheat/cheat.cpp @@ -1,13 +1,21 @@ #include <../base.hpp> +#include Cheat cheat; Cheat::cheat_t& Cheat::cheat_t::operator=(const Cheat::cheat_t& source) { enabled = source.enabled; - addr = source.addr; - data = source.data; - code = source.code; - desc = source.desc; + code = source.code; + desc = source.desc; + count = source.count; + + addr.reset(); + data.reset(); + for(unsigned n = 0; n < count; n++) { + addr[n] = source.addr[n]; + data[n] = source.data[n]; + } + return *this; } @@ -16,14 +24,200 @@ bool Cheat::cheat_t::operator<(const Cheat::cheat_t& source) { return strcmp(desc, source.desc) < 0; } -/***** - * string <> binary code translation routines - * decode() "7e1234:56" -> 0x7e123456 - * encode() 0x7e123456 -> "7e1234:56" - *****/ +//parse item ("0123-4567+89AB-CDEF"), return cheat_t item +//return true if code is valid, false otherwise +bool Cheat::decode(const char *s, Cheat::cheat_t &item) const { + item.enabled = false; + item.count = 0; -bool Cheat::decode(const char *str, unsigned &addr, uint8 &data, type_t &type) { - string t = str; + lstring list; + split(list, "+", s); + + for(unsigned n = 0; n < list.size(); n++) { + unsigned addr; + uint8_t data; + type_t type; + if(decode(list[n], addr, data, type) == false) return false; + + item.addr[item.count] = addr; + item.data[item.count] = data; + item.count++; + } + + return true; +} + +//read() is used by MemBus::read() if Cheat::enabled(addr) returns true to look up cheat code. +//returns true if cheat code was found, false if it was not. +//when true, cheat code substitution value is stored in data. +bool Cheat::read(unsigned addr, uint8_t &data) const { + addr = mirror_address(addr); + for(unsigned i = 0; i < code.size(); i++) { + if(enabled(i) == false) continue; + + for(unsigned n = 0; n < code[i].count; n++) { + if(addr == mirror_address(code[i].addr[n])) { + data = code[i].data[n]; + return true; + } + } + } + + //code not found, or code is disabled + return false; +} + +//================================ +//cheat list manipulation routines +//================================ + +bool Cheat::add(bool enable, const char *code_, const char *desc_) { + cheat_t item; + if(decode(code_, item) == false) return false; + + unsigned i = code.size(); + code[i] = item; + code[i].enabled = enable; + code[i].desc = desc_; + code[i].code = code_; + encode_description(code[i].desc); + update(code[i]); + + update_cheat_status(); + return true; +} + +bool Cheat::edit(unsigned i, bool enable, const char *code_, const char *desc_) { + cheat_t item; + if(decode(code_, item) == false) return false; + + //disable current code and clear from code lookup table + code[i].enabled = false; + update(code[i]); + + code[i] = item; + code[i].enabled = enable; + code[i].desc = desc_; + code[i].code = code_; + encode_description(code[i].desc); + update(code[i]); + + update_cheat_status(); + return true; +} + +bool Cheat::remove(unsigned i) { + unsigned size = code.size(); + if(i >= size) return false; //also verifies size cannot be < 1 + + for(unsigned n = i; n < size - 1; n++) code[n] = code[n + 1]; + code.resize(size - 1); + + update_cheat_status(); + return true; +} + +bool Cheat::get(unsigned i, cheat_t &item) const { + if(i >= code.size()) return false; + + item = code[i]; + decode_description(item.desc); + return true; +} + +//============================== +//cheat status modifier routines +//============================== + +bool Cheat::enabled(unsigned i) const { + return (i < code.size() ? code[i].enabled : false); +} + +void Cheat::enable(unsigned i) { + if(i >= code.size()) return; + + code[i].enabled = true; + update(code[i]); + update_cheat_status(); +} + +void Cheat::disable(unsigned i) { + if(i >= code.size()) return; + + code[i].enabled = false; + update(code[i]); + update_cheat_status(); +} + +//=============================== +//cheat file load / save routines +// +//file format: +//"description", status, nnnn-nnnn[+nnnn-nnnn...]\r\n +//... +//=============================== + +bool Cheat::load(const char *fn) { + string data; + if(!fread(data, fn)) return false; + replace(data, "\r\n", "\n"); + qreplace(data, " ", ""); + + lstring line; + split(line, "\n", data); + for(unsigned i = 0; i < line.size(); i++) { + lstring part; + qsplit(part, ",", line[i]); + if(part.size() != 3) continue; + trim(part[0], "\""); + add(part[1] == "enabled", /* code = */ part[2], /* desc = */ part[0]); + } + + return true; +} + +bool Cheat::save(const char *fn) const { + file fp; + if(!fp.open(fn, file::mode_write)) return false; + for(unsigned i = 0; i < code.size(); i++) { + fp.print(string() + << "\"" << code[i].desc << "\", " + << (code[i].enabled ? "enabled, " : "disabled, ") + << code[i].code << "\r\n"); + } + fp.close(); + return true; +} + +void Cheat::sort() { + if(code.size() <= 1) return; //nothing to sort? + cheat_t *buffer = new cheat_t[code.size()]; + for(unsigned i = 0; i < code.size(); i++) buffer[i] = code[i]; + nall::sort(buffer, code.size()); + for(unsigned i = 0; i < code.size(); i++) code[i] = buffer[i]; + delete[] buffer; +} + +void Cheat::clear() { + cheat_system_enabled = false; + memset(mask, 0, 0x200000); + code.reset(); +} + +Cheat::Cheat() { + clear(); +} + +//================== +//internal functions +//================== + +//string <> binary code translation routines +//decode() "7e123456" -> 0x7e123456 +//encode() 0x7e123456 -> "7e123456" + +bool Cheat::decode(const char *s, unsigned &addr, uint8_t &data, type_t &type) const { + string t = s; strlower(t); #define ischr(n) ((n >= '0' && n <= '9') || (n >= 'a' && n <= 'f')) @@ -51,18 +245,18 @@ bool Cheat::decode(const char *str, unsigned &addr, uint8 &data, type_t &type) { //8421 8421 8421 8421 8421 8421 //abcd efgh ijkl mnop qrst uvwx //ijkl qrst opab cduv wxef ghmn - addr = (!!(r & 0x002000) << 23) | (!!(r & 0x001000) << 22) | - (!!(r & 0x000800) << 21) | (!!(r & 0x000400) << 20) | - (!!(r & 0x000020) << 19) | (!!(r & 0x000010) << 18) | - (!!(r & 0x000008) << 17) | (!!(r & 0x000004) << 16) | - (!!(r & 0x800000) << 15) | (!!(r & 0x400000) << 14) | - (!!(r & 0x200000) << 13) | (!!(r & 0x100000) << 12) | - (!!(r & 0x000002) << 11) | (!!(r & 0x000001) << 10) | - (!!(r & 0x008000) << 9) | (!!(r & 0x004000) << 8) | - (!!(r & 0x080000) << 7) | (!!(r & 0x040000) << 6) | - (!!(r & 0x020000) << 5) | (!!(r & 0x010000) << 4) | - (!!(r & 0x000200) << 3) | (!!(r & 0x000100) << 2) | - (!!(r & 0x000080) << 1) | (!!(r & 0x000040) << 0); + addr = (!!(r & 0x002000) << 23) | (!!(r & 0x001000) << 22) + | (!!(r & 0x000800) << 21) | (!!(r & 0x000400) << 20) + | (!!(r & 0x000020) << 19) | (!!(r & 0x000010) << 18) + | (!!(r & 0x000008) << 17) | (!!(r & 0x000004) << 16) + | (!!(r & 0x800000) << 15) | (!!(r & 0x400000) << 14) + | (!!(r & 0x200000) << 13) | (!!(r & 0x100000) << 12) + | (!!(r & 0x000002) << 11) | (!!(r & 0x000001) << 10) + | (!!(r & 0x008000) << 9) | (!!(r & 0x004000) << 8) + | (!!(r & 0x080000) << 7) | (!!(r & 0x040000) << 6) + | (!!(r & 0x020000) << 5) | (!!(r & 0x010000) << 4) + | (!!(r & 0x000200) << 3) | (!!(r & 0x000100) << 2) + | (!!(r & 0x000080) << 1) | (!!(r & 0x000040) << 0); data = r >> 24; return true; } else { @@ -70,43 +264,53 @@ bool Cheat::decode(const char *str, unsigned &addr, uint8 &data, type_t &type) { } } -bool Cheat::encode(string &str, unsigned addr, uint8 data, type_t type) { +bool Cheat::encode(string &s, unsigned addr, uint8_t data, type_t type) const { char t[16]; if(type == ProActionReplay) { - sprintf(t, "%.6x:%.2x", addr, data); - str = t; + sprintf(t, "%.6x%.2x", addr, data); + s = t; return true; } else if(type == GameGenie) { unsigned r = addr; - addr = (!!(r & 0x008000) << 23) | (!!(r & 0x004000) << 22) | - (!!(r & 0x002000) << 21) | (!!(r & 0x001000) << 20) | - (!!(r & 0x000080) << 19) | (!!(r & 0x000040) << 18) | - (!!(r & 0x000020) << 17) | (!!(r & 0x000010) << 16) | - (!!(r & 0x000200) << 15) | (!!(r & 0x000100) << 14) | - (!!(r & 0x800000) << 13) | (!!(r & 0x400000) << 12) | - (!!(r & 0x200000) << 11) | (!!(r & 0x100000) << 10) | - (!!(r & 0x000008) << 9) | (!!(r & 0x000004) << 8) | - (!!(r & 0x000002) << 7) | (!!(r & 0x000001) << 6) | - (!!(r & 0x080000) << 5) | (!!(r & 0x040000) << 4) | - (!!(r & 0x020000) << 3) | (!!(r & 0x010000) << 2) | - (!!(r & 0x000800) << 1) | (!!(r & 0x000400) << 0); + addr = (!!(r & 0x008000) << 23) | (!!(r & 0x004000) << 22) + | (!!(r & 0x002000) << 21) | (!!(r & 0x001000) << 20) + | (!!(r & 0x000080) << 19) | (!!(r & 0x000040) << 18) + | (!!(r & 0x000020) << 17) | (!!(r & 0x000010) << 16) + | (!!(r & 0x000200) << 15) | (!!(r & 0x000100) << 14) + | (!!(r & 0x800000) << 13) | (!!(r & 0x400000) << 12) + | (!!(r & 0x200000) << 11) | (!!(r & 0x100000) << 10) + | (!!(r & 0x000008) << 9) | (!!(r & 0x000004) << 8) + | (!!(r & 0x000002) << 7) | (!!(r & 0x000001) << 6) + | (!!(r & 0x080000) << 5) | (!!(r & 0x040000) << 4) + | (!!(r & 0x020000) << 3) | (!!(r & 0x010000) << 2) + | (!!(r & 0x000800) << 1) | (!!(r & 0x000400) << 0); sprintf(t, "%.2x%.2x-%.4x", data, addr >> 16, addr & 0xffff); strtr(t, "0123456789abcdef", "df4709156bc8a23e"); - str = t; + s = t; return true; } else { return false; } } -/***** - * address lookup table manipulation and mirroring - * mirror_address() 0x000000 -> 0x7e0000 - * set() enable specified address, mirror accordingly - * clear() disable specified address, mirror accordingly - *****/ +//update_cheat_status() will scan to see if any codes are +//enabled. if any are, make sure the cheat system is on. +//otherwise, turn cheat system off to speed up emulation. +void Cheat::update_cheat_status() { + for(unsigned i = 0; i < code.size(); i++) { + if(code[i].enabled) { + cheat_system_enabled = true; + return; + } + } + cheat_system_enabled = false; +} +//address lookup table manipulation and mirroring +//mirror_address() 0x000000 -> 0x7e0000 +//set() enable specified address, mirror accordingly +//clear() disable specified address, mirror accordingly unsigned Cheat::mirror_address(unsigned addr) const { if((addr & 0x40e000) != 0x0000) return addr; //8k WRAM mirror @@ -114,6 +318,14 @@ unsigned Cheat::mirror_address(unsigned addr) const { return (0x7e0000 + (addr & 0x1fff)); } +//updates mask[] table enabled bits; +//must be called after modifying item.enabled state. +void Cheat::update(const cheat_t &item) { + for(unsigned n = 0; n < item.count; n++) { + (item.enabled) ? set(item.addr[n]) : clear(item.addr[n]); + } +} + void Cheat::set(unsigned addr) { addr = mirror_address(addr); @@ -136,7 +348,7 @@ void Cheat::clear(unsigned addr) { //if there is more than one cheat code using the same address, //(eg with a different override value) then do not clear code //lookup table entry. - uint8 r; + uint8_t r; if(read(addr, r) == true) return; mask[addr >> 3] &= ~(1 << (addr & 7)); @@ -152,185 +364,16 @@ void Cheat::clear(unsigned addr) { } } -/***** - * read() is used by MemBus::read() if Cheat::enabled(addr) - * returns true to look up cheat code. - * returns true if cheat code was found, false if it was not. - * when true, cheat code substitution value is stored in data. - *****/ +//these two functions are used to safely store description text inside .cfg file format. -bool Cheat::read(unsigned addr, uint8 &data) const { - addr = mirror_address(addr); - for(unsigned i = 0; i < code.size(); i++) { - if(enabled(i) == false) continue; - if(addr == mirror_address(code[i].addr)) { - data = code[i].data; - return true; - } - } - //code not found, or code is disabled - return false; +string& Cheat::encode_description(string &desc) const { + replace(desc, "\"", "\\q"); + replace(desc, "\n", "\\n"); + return desc; } -/***** - * update_cheat_status() will scan to see if any codes are - * enabled. if any are, make sure the cheat system is on. - * otherwise, turn cheat system off to speed up emulation. - *****/ - -void Cheat::update_cheat_status() { - for(unsigned i = 0; i < code.size(); i++) { - if(code[i].enabled) { - cheat_system_enabled = true; - return; - } - } - cheat_system_enabled = false; -} - -/***** - * cheat list manipulation routines - *****/ - -bool Cheat::add(bool enable, const char *code_, const char *desc_) { - unsigned addr; - uint8 data; - type_t type; - if(decode(code_, addr, data, type) == false) return false; - - unsigned n = code.size(); - code[n].enabled = enable; - code[n].addr = addr; - code[n].data = data; - code[n].code = code_; - code[n].desc = desc_; - (enable) ? set(addr) : clear(addr); - - update_cheat_status(); - return true; -} - -bool Cheat::edit(unsigned n, bool enable, const char *code_, const char *desc_) { - unsigned addr; - uint8 data; - type_t type; - if(decode(code_, addr, data, type) == false) return false; - - //disable current code and clear from code lookup table - code[n].enabled = false; - clear(code[n].addr); - - //update code and enable in code lookup table - code[n].enabled = enable; - code[n].addr = addr; - code[n].data = data; - code[n].code = code_; - code[n].desc = desc_; - set(addr); - - update_cheat_status(); - return true; -} - -bool Cheat::remove(unsigned n) { - unsigned size = code.size(); - if(n >= size) return false; //also verifies size cannot be < 1 - - for(unsigned i = n; i < size - 1; i++) code[i] = code[i + 1]; - code.resize(size - 1); - - update_cheat_status(); - return true; -} - -bool Cheat::get(unsigned n, cheat_t &cheat) const { - if(n >= code.size()) return false; - - cheat = code[n]; - return true; -} - -/***** - * code status modifier routines - *****/ - -bool Cheat::enabled(unsigned n) const { - return (n < code.size()) ? code[n].enabled : false; -} - -void Cheat::enable(unsigned n) { - if(n >= code.size()) return; - - code[n].enabled = true; - set(code[n].addr); - update_cheat_status(); -} - -void Cheat::disable(unsigned n) { - if(n >= code.size()) return; - - code[n].enabled = false; - clear(code[n].addr); - update_cheat_status(); -} - -/***** - * cheat file manipulation routines - *****/ - -/* file format: */ -/* nnnn-nnnn = status, "description" \r\n */ -/* ... */ - -bool Cheat::load(const char *fn) { - string data; - if(!fread(data, fn)) return false; - replace(data, "\r\n", "\n"); - qreplace(data, "=", ","); - qreplace(data, " ", ""); - - lstring line; - split(line, "\n", data); - for(unsigned i = 0; i < ::count(line); i++) { - lstring part; - split(part, ",", line[i]); - if(::count(part) != 3) continue; - trim(part[2], "\""); - add(part[1] == "enabled", part[0], part[2]); - } - - return true; -} - -bool Cheat::save(const char *fn) const { - file fp; - if(!fp.open(fn, file::mode_write)) return false; - for(unsigned i = 0; i < code.size(); i++) { - fp.print(string() - << code[i].code << " = " - << (code[i].enabled ? "enabled" : "disabled") << ", " - << "\"" << code[i].desc << "\"" - << "\r\n"); - } - fp.close(); - return true; -} - -void Cheat::sort() { - if(code.size() <= 1) return; //nothing to sort? - cheat_t *buffer = new cheat_t[code.size()]; - for(unsigned i = 0; i < code.size(); i++) buffer[i] = code[i]; - nall::sort(buffer, code.size()); - for(unsigned i = 0; i < code.size(); i++) code[i] = buffer[i]; - delete[] buffer; -} - -void Cheat::clear() { - cheat_system_enabled = false; - memset(mask, 0, 0x200000); - code.reset(); -} - -Cheat::Cheat() { - clear(); +string& Cheat::decode_description(string &desc) const { + replace(desc, "\\q", "\""); + replace(desc, "\\n", "\n"); + return desc; } diff --git a/src/cheat/cheat.hpp b/src/cheat/cheat.hpp index ac8a543d..9cc92a40 100644 --- a/src/cheat/cheat.hpp +++ b/src/cheat/cheat.hpp @@ -6,32 +6,33 @@ public: }; struct cheat_t { - bool enabled; - unsigned addr; - uint8 data; - string code; - string desc; + bool enabled; + string code; + string desc; + + unsigned count; + array addr; + array data; cheat_t& operator=(const cheat_t&); bool operator<(const cheat_t&); }; - static bool decode(const char *str, unsigned &addr, uint8 &data, type_t &type); - static bool encode(string &str, unsigned addr, uint8 data, type_t type); + bool decode(const char *s, cheat_t &item) const; + bool read(unsigned addr, uint8_t &data) const; inline bool enabled() const { return cheat_system_enabled; } inline unsigned count() const { return code.size(); } - inline bool exists(unsigned addr) const { return bool(mask[addr >> 3] & 1 << (addr & 7)); } - - bool read(unsigned addr, uint8 &data) const; + inline bool exists(unsigned addr) const { return mask[addr >> 3] & 1 << (addr & 7); } bool add(bool enable, const char *code, const char *desc); - bool edit(unsigned n, bool enable, const char *code, const char *desc); - bool get(unsigned n, cheat_t &cheat) const; - bool remove(unsigned n); - bool enabled(unsigned n) const; - void enable(unsigned n); - void disable(unsigned n); + bool edit(unsigned i, bool enable, const char *code, const char *desc); + bool remove(unsigned i); + bool get(unsigned i, cheat_t &item) const; + + bool enabled(unsigned i) const; + void enable(unsigned i); + void disable(unsigned i); bool load(const char *fn); bool save(const char *fn) const; @@ -43,13 +44,21 @@ public: private: bool cheat_system_enabled; - uint8 mask[0x200000]; + uint8_t mask[0x200000]; vector code; + bool decode(const char *str, unsigned &addr, uint8_t &data, type_t &type) const; + bool encode(string &str, unsigned addr, uint8_t data, type_t type) const; + void update_cheat_status(); unsigned mirror_address(unsigned addr) const; + + void update(const cheat_t& item); void set(unsigned addr); void clear(unsigned addr); + + string& encode_description(string &desc) const; + string& decode_description(string &desc) const; }; extern Cheat cheat; diff --git a/src/chip/bsx/bsx.cpp b/src/chip/bsx/bsx.cpp index c4e16325..9d4de100 100644 --- a/src/chip/bsx/bsx.cpp +++ b/src/chip/bsx/bsx.cpp @@ -1,6 +1,8 @@ -#include <../base.hpp> +#include <../base.hpp> +#include <../cart/cart.hpp> #define BSX_CPP +#include "bsx.hpp" #include "bsx_base.cpp" #include "bsx_cart.cpp" #include "bsx_flash.cpp" diff --git a/src/chip/bsx/bsx.hpp b/src/chip/bsx/bsx.hpp index d1ae221a..ebab28a9 100644 --- a/src/chip/bsx/bsx.hpp +++ b/src/chip/bsx/bsx.hpp @@ -5,8 +5,8 @@ public: void power(); void reset(); - uint8 mmio_read(uint addr); - void mmio_write(uint addr, uint8 data); + uint8 mmio_read(unsigned addr); + void mmio_write(unsigned addr, uint8 data); private: struct { @@ -29,8 +29,8 @@ public: void power(); void reset(); - uint8 mmio_read(uint addr); - void mmio_write(uint addr, uint8 data); + uint8 mmio_read(unsigned addr); + void mmio_write(unsigned addr, uint8 data); MappedRAM sram; MappedRAM psram; @@ -56,13 +56,13 @@ public: void power(); void reset(); - uint size(); - uint8 read(uint addr); - void write(uint addr, uint8 data); + unsigned size(); + uint8 read(unsigned addr); + void write(unsigned addr, uint8 data); private: struct { - uint command; + unsigned command; uint8 write_old; uint8 write_new; diff --git a/src/chip/bsx/bsx_base.cpp b/src/chip/bsx/bsx_base.cpp index 090226b6..3e81ece7 100644 --- a/src/chip/bsx/bsx_base.cpp +++ b/src/chip/bsx/bsx_base.cpp @@ -15,7 +15,7 @@ void BSXBase::reset() { memset(®s, 0x00, sizeof regs); } -uint8 BSXBase::mmio_read(uint addr) { +uint8 BSXBase::mmio_read(unsigned addr) { addr &= 0xffff; switch(addr) { @@ -28,7 +28,7 @@ uint8 BSXBase::mmio_read(uint addr) { case 0x2190: return regs.r2190; case 0x2192: { - uint counter = regs.r2192_counter++; + unsigned counter = regs.r2192_counter++; if(regs.r2192_counter >= 18) regs.r2192_counter = 0; if(counter == 0) { @@ -73,7 +73,7 @@ uint8 BSXBase::mmio_read(uint addr) { return cpu.regs.mdr; } -void BSXBase::mmio_write(uint addr, uint8 data) { +void BSXBase::mmio_write(unsigned addr, uint8 data) { addr &= 0xffff; switch(addr) { @@ -134,4 +134,4 @@ void BSXBase::mmio_write(uint addr, uint8 data) { } } -#endif //ifdef BSX_CPP +#endif diff --git a/src/chip/bsx/bsx_cart.cpp b/src/chip/bsx/bsx_cart.cpp index 49585061..ed875cf8 100644 --- a/src/chip/bsx/bsx_cart.cpp +++ b/src/chip/bsx/bsx_cart.cpp @@ -12,7 +12,7 @@ void BSXCart::power() { } void BSXCart::reset() { - for(uint i = 0; i < 16; i++) regs.r[i] = 0x00; + for(unsigned i = 0; i < 16; i++) regs.r[i] = 0x00; regs.r[0x07] = 0x80; regs.r[0x08] = 0x80; @@ -57,7 +57,7 @@ void BSXCart::update_memory_map() { bus.map(Bus::MapLinear, 0x70, 0x77, 0x0000, 0xffff, psram); } -uint8 BSXCart::mmio_read(uint addr) { +uint8 BSXCart::mmio_read(unsigned addr) { if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO uint8 n = (addr >> 16) & 15; return regs.r[n]; @@ -70,7 +70,7 @@ uint8 BSXCart::mmio_read(uint addr) { return 0x00; } -void BSXCart::mmio_write(uint addr, uint8 data) { +void BSXCart::mmio_write(unsigned addr, uint8 data) { if((addr & 0xf0ffff) == 0x005000) { //$[00-0f]:5000 MMIO uint8 n = (addr >> 16) & 15; regs.r[n] = data; @@ -96,4 +96,4 @@ BSXCart::~BSXCart() { delete[] psram_data; } -#endif //ifdef BSX_CPP +#endif diff --git a/src/chip/bsx/bsx_flash.cpp b/src/chip/bsx/bsx_flash.cpp index 43f925fd..781d2ea6 100644 --- a/src/chip/bsx/bsx_flash.cpp +++ b/src/chip/bsx/bsx_flash.cpp @@ -17,11 +17,11 @@ void BSXFlash::reset() { regs.write_enable = false; } -uint BSXFlash::size() { +unsigned BSXFlash::size() { return memory::bscram.size(); } -uint8 BSXFlash::read(uint addr) { +uint8 BSXFlash::read(unsigned addr) { if(addr == 0x0002) { if(regs.flash_enable) return 0x80; } @@ -48,7 +48,7 @@ uint8 BSXFlash::read(uint addr) { return memory::bscram.read(addr); } -void BSXFlash::write(uint addr, uint8 data) { +void BSXFlash::write(unsigned addr, uint8 data) { //there exist both read-only and read-write BS-X flash cartridges ... //unfortunately, the vendor info is not stored inside memory dumps //of BS-X flashcarts, so it is impossible to determine whether a @@ -110,4 +110,4 @@ void BSXFlash::write(uint addr, uint8 data) { } } -#endif //ifdef BSX_CPP +#endif diff --git a/src/chip/cx4/cx4.cpp b/src/chip/cx4/cx4.cpp index 5335e217..963d42cc 100644 --- a/src/chip/cx4/cx4.cpp +++ b/src/chip/cx4/cx4.cpp @@ -8,6 +8,7 @@ #include <../base.hpp> #define CX4_CPP +#include "cx4.hpp" #include "cx4data.cpp" #include "cx4fn.cpp" #include "cx4oam.cpp" @@ -78,7 +79,7 @@ uint16 dest, count; } } -void Cx4::write(uint addr, uint8 data) { +void Cx4::write(unsigned addr, uint8 data) { addr &= 0x1fff; if(addr < 0x0c00) { @@ -160,7 +161,7 @@ void Cx4::writel(uint16 addr, uint32 data) { write(addr + 2, data >> 16); } -uint8 Cx4::read(uint addr) { +uint8 Cx4::read(unsigned addr) { addr &= 0x1fff; if(addr < 0x0c00) { diff --git a/src/chip/cx4/cx4.hpp b/src/chip/cx4/cx4.hpp index d1133d43..c4cf9505 100644 --- a/src/chip/cx4/cx4.hpp +++ b/src/chip/cx4/cx4.hpp @@ -90,8 +90,8 @@ public: void power(); void reset(); - uint8 read (uint addr); - void write(uint addr, uint8 data); + uint8 read (unsigned addr); + void write(unsigned addr, uint8 data); }; extern Cx4 cx4; diff --git a/src/chip/cx4/cx4data.cpp b/src/chip/cx4/cx4data.cpp index 0308c833..426dfeeb 100644 --- a/src/chip/cx4/cx4data.cpp +++ b/src/chip/cx4/cx4data.cpp @@ -184,4 +184,4 @@ const int16 Cx4::CosTable[512] = { 32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765 }; -#endif //ifdef CX4_CPP +#endif diff --git a/src/chip/cx4/cx4fn.cpp b/src/chip/cx4/cx4fn.cpp index ca0f8dd7..ed60bc8c 100644 --- a/src/chip/cx4/cx4fn.cpp +++ b/src/chip/cx4/cx4fn.cpp @@ -243,4 +243,4 @@ uint8 bit = 0x80; } } -#endif //ifdef CX4_CPP +#endif diff --git a/src/chip/cx4/cx4oam.cpp b/src/chip/cx4/cx4oam.cpp index 6173cb05..8214fbb1 100644 --- a/src/chip/cx4/cx4oam.cpp +++ b/src/chip/cx4/cx4oam.cpp @@ -220,4 +220,4 @@ uint16 mask2 = 0x3f3f; } } -#endif //ifdef CX4_CPP +#endif diff --git a/src/chip/cx4/cx4ops.cpp b/src/chip/cx4/cx4ops.cpp index 8cc509ee..f5373cc5 100644 --- a/src/chip/cx4/cx4ops.cpp +++ b/src/chip/cx4/cx4ops.cpp @@ -223,4 +223,4 @@ void Cx4::op89() { str(1, 0xffffff); } -#endif //ifdef CX4_CPP +#endif diff --git a/src/chip/dsp1/dsp1.cpp b/src/chip/dsp1/dsp1.cpp index de403abf..1e67af74 100644 --- a/src/chip/dsp1/dsp1.cpp +++ b/src/chip/dsp1/dsp1.cpp @@ -1,6 +1,8 @@ -#include <../base.hpp> +#include <../base.hpp> +#include <../cart/cart.hpp> #define DSP1_CPP +#include "dsp1.hpp" #include "dsp1emu.cpp" void DSP1::init() {} @@ -46,11 +48,11 @@ bool DSP1::addr_decode(uint16 addr) { return 0; } -uint8 DSP1::read(uint addr) { +uint8 DSP1::read(unsigned addr) { return (addr_decode(addr) == 0) ? dsp1.getDr() : dsp1.getSr(); } -void DSP1::write(uint addr, uint8 data) { +void DSP1::write(unsigned addr, uint8 data) { if(addr_decode(addr) == 0) { dsp1.setDr(data); } diff --git a/src/chip/dsp1/dsp1.hpp b/src/chip/dsp1/dsp1.hpp index 95c72a4b..5bbdc74d 100644 --- a/src/chip/dsp1/dsp1.hpp +++ b/src/chip/dsp1/dsp1.hpp @@ -11,8 +11,8 @@ public: void power(); void reset(); - uint8 read(uint addr); - void write(uint addr, uint8 data); + uint8 read(unsigned addr); + void write(unsigned addr, uint8 data); }; extern DSP1 dsp1; diff --git a/src/chip/dsp1/dsp1emu.cpp b/src/chip/dsp1/dsp1emu.cpp index 58dd2dea..0e6a29c9 100644 --- a/src/chip/dsp1/dsp1emu.cpp +++ b/src/chip/dsp1/dsp1emu.cpp @@ -1622,4 +1622,4 @@ const int16 Dsp1::SinTable[256] = { ////////////////////////////////////////////////////////////////// -#endif //ifdef DSP1_CPP +#endif diff --git a/src/chip/dsp2/dsp2.cpp b/src/chip/dsp2/dsp2.cpp index 2d36d657..de40c0e3 100644 --- a/src/chip/dsp2/dsp2.cpp +++ b/src/chip/dsp2/dsp2.cpp @@ -1,6 +1,7 @@ #include <../base.hpp> #define DSP2_CPP +#include "dsp2.hpp" #include "dsp2_op.cpp" void DSP2::init() {} @@ -29,8 +30,8 @@ void DSP2::reset() { status.op0dinlen = 0; } -uint8 DSP2::read(uint addr) { -uint8 r = 0xff; +uint8 DSP2::read(unsigned addr) { + uint8 r = 0xff; if(status.out_count) { r = status.output[status.out_index++]; status.out_index &= 511; @@ -41,7 +42,7 @@ uint8 r = 0xff; return r; } -void DSP2::write(uint addr, uint8 data) { +void DSP2::write(unsigned addr, uint8 data) { if(status.waiting_for_command) { status.command = data; status.in_index = 0; diff --git a/src/chip/dsp2/dsp2.hpp b/src/chip/dsp2/dsp2.hpp index cf125b23..e84c9391 100644 --- a/src/chip/dsp2/dsp2.hpp +++ b/src/chip/dsp2/dsp2.hpp @@ -1,10 +1,10 @@ class DSP2 : public Memory { public: struct { - bool waiting_for_command; - uint command; - uint in_count, in_index; - uint out_count, out_index; + bool waiting_for_command; + unsigned command; + unsigned in_count, in_index; + unsigned out_count, out_index; uint8 parameters[512]; uint8 output[512]; @@ -26,8 +26,8 @@ public: void power(); void reset(); - uint8 read(uint addr); - void write(uint addr, uint8 data); + uint8 read(unsigned addr); + void write(unsigned addr, uint8 data); DSP2(); ~DSP2(); diff --git a/src/chip/dsp2/dsp2_op.cpp b/src/chip/dsp2/dsp2_op.cpp index fec67bd6..dc6c7cc7 100644 --- a/src/chip/dsp2/dsp2_op.cpp +++ b/src/chip/dsp2/dsp2_op.cpp @@ -174,4 +174,4 @@ uint8 pixelarray[512]; } } -#endif //ifdef DSP2_CPP +#endif diff --git a/src/chip/dsp3/dsp3.cpp b/src/chip/dsp3/dsp3.cpp index ad88fe23..e6c7c7c1 100644 --- a/src/chip/dsp3/dsp3.cpp +++ b/src/chip/dsp3/dsp3.cpp @@ -1,6 +1,7 @@ #include <../base.hpp> #define DSP3_CPP +#include "dsp3.hpp" namespace DSP3i { #define bool8 uint8 #include "dsp3emu.c" @@ -21,13 +22,13 @@ void DSP3::reset() { DSP3i::DSP3_Reset(); } -uint8 DSP3::read(uint addr) { +uint8 DSP3::read(unsigned addr) { DSP3i::dsp3_address = addr & 0xffff; DSP3i::DSP3GetByte(); return DSP3i::dsp3_byte; } -void DSP3::write(uint addr, uint8 data) { +void DSP3::write(unsigned addr, uint8 data) { DSP3i::dsp3_address = addr & 0xffff; DSP3i::dsp3_byte = data; DSP3i::DSP3SetByte(); diff --git a/src/chip/dsp3/dsp3.hpp b/src/chip/dsp3/dsp3.hpp index b596963a..38696334 100644 --- a/src/chip/dsp3/dsp3.hpp +++ b/src/chip/dsp3/dsp3.hpp @@ -5,8 +5,8 @@ public: void power(); void reset(); - uint8 read (uint addr); - void write(uint addr, uint8 data); + uint8 read (unsigned addr); + void write(unsigned addr, uint8 data); }; extern DSP3 dsp3; diff --git a/src/chip/dsp3/dsp3emu.c b/src/chip/dsp3/dsp3emu.c index 7ce0d81e..21f82a6c 100644 --- a/src/chip/dsp3/dsp3emu.c +++ b/src/chip/dsp3/dsp3emu.c @@ -1143,4 +1143,4 @@ void InitDSP3() DSP3_Reset(); } -#endif //ifdef DSP3_CPP +#endif diff --git a/src/chip/dsp4/dsp4.cpp b/src/chip/dsp4/dsp4.cpp index 9e43f431..aed7caf5 100644 --- a/src/chip/dsp4/dsp4.cpp +++ b/src/chip/dsp4/dsp4.cpp @@ -1,6 +1,7 @@ #include <../base.hpp> #define DSP4_CPP +#include "dsp4.hpp" namespace DSP4i { inline uint16 READ_WORD(uint8 *addr) { return (addr[0]) + (addr[1] << 8); @@ -34,7 +35,7 @@ void DSP4::reset() { DSP4i::InitDSP4(); } -uint8 DSP4::read(uint addr) { +uint8 DSP4::read(unsigned addr) { addr &= 0xffff; if(addr < 0xc000) { DSP4i::dsp4_address = addr; @@ -44,7 +45,7 @@ uint8 DSP4::read(uint addr) { return 0x80; } -void DSP4::write(uint addr, uint8 data) { +void DSP4::write(unsigned addr, uint8 data) { addr &= 0xffff; if(addr < 0xc000) { DSP4i::dsp4_address = addr; diff --git a/src/chip/dsp4/dsp4.hpp b/src/chip/dsp4/dsp4.hpp index 75c19eca..17d6533a 100644 --- a/src/chip/dsp4/dsp4.hpp +++ b/src/chip/dsp4/dsp4.hpp @@ -5,8 +5,8 @@ public: void power(); void reset(); - uint8 read (uint addr); - void write(uint addr, uint8 data); + uint8 read (unsigned addr); + void write(unsigned addr, uint8 data); }; extern DSP4 dsp4; diff --git a/src/chip/dsp4/dsp4emu.c b/src/chip/dsp4/dsp4emu.c index 50785775..1b6ea272 100644 --- a/src/chip/dsp4/dsp4emu.c +++ b/src/chip/dsp4/dsp4emu.c @@ -2147,4 +2147,4 @@ void DSP4GetByte() } } -#endif //ifdef DSP4_CPP +#endif diff --git a/src/chip/obc1/obc1.cpp b/src/chip/obc1/obc1.cpp index eeb5a2ce..96069953 100644 --- a/src/chip/obc1/obc1.cpp +++ b/src/chip/obc1/obc1.cpp @@ -1,4 +1,6 @@ #include <../base.hpp> +#include <../cart/cart.hpp> +#include "obc1.hpp" void OBC1::init() {} void OBC1::enable() {} diff --git a/src/chip/sdd1/sdd1.cpp b/src/chip/sdd1/sdd1.cpp index e845f13b..8530b4bd 100644 --- a/src/chip/sdd1/sdd1.cpp +++ b/src/chip/sdd1/sdd1.cpp @@ -1,6 +1,8 @@ -#include <../base.hpp> +#include <../base.hpp> +#include <../cart/cart.hpp> #define SDD1_CPP +#include "sdd1.hpp" #include "sdd1emu.cpp" void SDD1::init() {} @@ -42,7 +44,7 @@ void SDD1::reset() { bus.map(Bus::MapDirect, 0xc0, 0xff, 0x0000, 0xffff, *this); } -uint8 SDD1::mmio_read(uint addr) { +uint8 SDD1::mmio_read(unsigned addr) { addr &= 0xffff; if((addr & 0x4380) == 0x4300) { @@ -59,7 +61,7 @@ uint8 SDD1::mmio_read(uint addr) { return cpu.regs.mdr; } -void SDD1::mmio_write(uint addr, uint8 data) { +void SDD1::mmio_write(unsigned addr, uint8 data) { addr &= 0xffff; if((addr & 0x4380) == 0x4300) { diff --git a/src/chip/sdd1/sdd1emu.cpp b/src/chip/sdd1/sdd1emu.cpp index 449082ab..2581ff98 100644 --- a/src/chip/sdd1/sdd1emu.cpp +++ b/src/chip/sdd1/sdd1emu.cpp @@ -448,4 +448,4 @@ SDD1emu::SDD1emu() : /////////////////////////////////////////////////////////// -#endif //ifdef SDD1_CPP +#endif diff --git a/src/chip/spc7110/spc7110.cpp b/src/chip/spc7110/spc7110.cpp index d6a84660..c33dda1b 100644 --- a/src/chip/spc7110/spc7110.cpp +++ b/src/chip/spc7110/spc7110.cpp @@ -1,6 +1,8 @@ #include <../base.hpp> +#include <../cart/cart.hpp> #define SPC7110_CPP +#include "spc7110.hpp" #include "decomp.cpp" const unsigned SPC7110::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; @@ -92,18 +94,30 @@ void SPC7110::set_data_pointer(unsigned addr) { r4811 = addr; r4812 = addr >> 8; 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; + time_t rtc_time + = (memory::cartrtc.read(16) << 0) + | (memory::cartrtc.read(17) << 8) + | (memory::cartrtc.read(18) << 16) + | (memory::cartrtc.read(19) << 24); + time_t current_time = time(0); + + //sizeof(time_t) is platform-dependent; though memory::cartrtc needs to be platform-agnostic. + //yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by + //accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow + //memory::cartrtc timestamp to remain valid for up to ~34 years from the last update, even if + //time_t overflows. calculation should be valid regardless of number representation, time_t size, + //or whether time_t is signed or unsigned. + time_t diff + = (current_time >= rtc_time) + ? (current_time - rtc_time) + : (std::numeric_limits::max() - rtc_time + current_time + 1); //compensate for overflow + if(diff > std::numeric_limits::max() / 2) diff = 0; //compensate for underflow 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 + 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) { + if(diff > 0 && update == true) { 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; @@ -114,9 +128,9 @@ void SPC7110::update_time(int offset) { day--; month--; - year += (year >= 90) ? 1900 : 2000; //range = 1990-2089 + year += (year >= 90) ? 1900 : 2000; //range = 1990-2089 - second += (unsigned)(current_time - rtc_time); + second += diff; while(second >= 60) { second -= 60; @@ -168,13 +182,13 @@ void SPC7110::update_time(int offset) { memory::cartrtc.write(12, weekday % 7); } - memory::cartrtc.write(16, current_time); - memory::cartrtc.write(17, current_time >> 8); + memory::cartrtc.write(16, current_time >> 0); + 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) { +uint8 SPC7110::mmio_read(unsigned addr) { addr &= 0xffff; switch(addr) { @@ -215,7 +229,7 @@ uint8 SPC7110::mmio_read(uint addr) { unsigned addr = data_pointer(); unsigned adjust = data_adjust(); - if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend + if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend unsigned adjustaddr = addr; if(r4818 & 2) { @@ -226,7 +240,7 @@ uint8 SPC7110::mmio_read(uint addr) { 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 & 4) increment = (int16)increment; //16-bit sign extend if((r4818 & 16) == 0) { set_data_pointer(addr + increment); @@ -250,7 +264,7 @@ uint8 SPC7110::mmio_read(uint addr) { unsigned addr = data_pointer(); unsigned adjust = data_adjust(); - if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend + if(r4818 & 8) adjust = (int16)adjust; //16-bit sign extend uint8 data = memory::cartrom.read(datarom_addr(addr + adjust)); if((r4818 & 0x60) == 0x60) { @@ -322,7 +336,7 @@ uint8 SPC7110::mmio_read(uint addr) { return cpu.regs.mdr; } -void SPC7110::mmio_write(uint addr, uint8 data) { +void SPC7110::mmio_write(unsigned addr, uint8 data) { addr &= 0xffff; switch(addr) { @@ -373,11 +387,11 @@ void SPC7110::mmio_write(uint addr, uint8 data) { if((r4818 & 0x60) == 0x20) { unsigned increment = data_adjust() & 0xff; - if(r4818 & 8) increment = (int8)increment; //8-bit sign extend + 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 + if(r4818 & 8) increment = (int16)increment; //16-bit sign extend set_data_pointer(data_pointer() + increment); } } break; @@ -390,11 +404,11 @@ void SPC7110::mmio_write(uint addr, uint8 data) { if((r4818 & 0x60) == 0x20) { unsigned increment = data_adjust() & 0xff; - if(r4818 & 8) increment = (int8)increment; //8-bit sign extend + 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 + if(r4818 & 8) increment = (int16)increment; //16-bit sign extend set_data_pointer(data_pointer() + increment); } } break; @@ -615,7 +629,7 @@ void SPC7110::mmio_write(uint addr, uint8 data) { } } -uint8 SPC7110::read(uint addr) { +uint8 SPC7110::read(unsigned addr) { //$[00-0f|80-8f]:[8000-ffff], $[c0-cf]:[0000-ffff] mapped directly to memory::cartrom if((addr & 0xffe000) == 0x006000 || (addr & 0xffe000) == 0x306000) { @@ -646,7 +660,7 @@ uint8 SPC7110::read(uint addr) { return cpu.regs.mdr; } -void SPC7110::write(uint addr, uint8 data) { +void SPC7110::write(unsigned addr, uint8 data) { if((addr & 0xffe000) == 0x006000 || (addr & 0xffe000) == 0x306000) { //$[00|30]:[6000-7fff] if(r4830 & 0x80) memory::cartram.write(addr & 0x1fff, data); diff --git a/src/chip/spc7110/spc7110.hpp b/src/chip/spc7110/spc7110.hpp index 2c9b6bf1..45baefca 100644 --- a/src/chip/spc7110/spc7110.hpp +++ b/src/chip/spc7110/spc7110.hpp @@ -35,11 +35,11 @@ public: void update_time(int offset = 0); time_t create_time(); - uint8 mmio_read (uint addr); - void mmio_write(uint addr, uint8 data); + uint8 mmio_read (unsigned addr); + void mmio_write(unsigned addr, uint8 data); - uint8 read (uint addr); - void write(uint addr, uint8 data); + uint8 read (unsigned addr); + void write(unsigned addr, uint8 data); //spc7110decomp void decomp_init(); diff --git a/src/chip/srtc/srtc.cpp b/src/chip/srtc/srtc.cpp index 335cb965..f76ecf4a 100644 --- a/src/chip/srtc/srtc.cpp +++ b/src/chip/srtc/srtc.cpp @@ -1,4 +1,6 @@ #include <../base.hpp> +#include <../cart/cart.hpp> +#include "srtc.hpp" const unsigned SRTC::months[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; @@ -21,14 +23,26 @@ void SRTC::reset() { } 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 rtc_time + = (memory::cartrtc.read(16) << 0) + | (memory::cartrtc.read(17) << 8) + | (memory::cartrtc.read(18) << 16) + | (memory::cartrtc.read(19) << 24); time_t current_time = time(0); - if(current_time > rtc_time) { + + //sizeof(time_t) is platform-dependent; though memory::cartrtc needs to be platform-agnostic. + //yet platforms with 32-bit signed time_t will overflow every ~68 years. handle this by + //accounting for overflow at the cost of 1-bit precision (to catch underflow). this will allow + //memory::cartrtc timestamp to remain valid for up to ~34 years from the last update, even if + //time_t overflows. calculation should be valid regardless of number representation, time_t size, + //or whether time_t is signed or unsigned. + time_t diff + = (current_time >= rtc_time) + ? (current_time - rtc_time) + : (std::numeric_limits::max() - rtc_time + current_time + 1); //compensate for overflow + if(diff > std::numeric_limits::max() / 2) diff = 0; //compensate for underflow + + if(diff > 0) { 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; @@ -41,8 +55,7 @@ void SRTC::update_time() { month--; year += 1000; - second += (unsigned)(current_time - rtc_time); - + second += diff; while(second >= 60) { second -= 60; @@ -94,8 +107,8 @@ void SRTC::update_time() { memory::cartrtc.write(12, weekday % 7); } - memory::cartrtc.write(16, current_time); - memory::cartrtc.write(17, current_time >> 8); + memory::cartrtc.write(16, current_time >> 0); + memory::cartrtc.write(17, current_time >> 8); memory::cartrtc.write(18, current_time >> 16); memory::cartrtc.write(19, current_time >> 24); } @@ -104,8 +117,8 @@ void SRTC::update_time() { //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 + 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)); @@ -136,7 +149,7 @@ unsigned SRTC::weekday(unsigned year, unsigned month, unsigned day) { } sum += day - 1; - return (sum + 1) % 7; //1900-01-01 was a Monday + return (sum + 1) % 7; //1900-01-01 was a Monday } uint8 SRTC::mmio_read(unsigned addr) { @@ -164,7 +177,7 @@ void SRTC::mmio_write(unsigned addr, uint8 data) { addr &= 0xffff; if(addr == 0x2801) { - data &= 0x0f; //only the low four bits are used + data &= 0x0f; //only the low four bits are used if(data == 0x0d) { rtc_mode = RTCM_Read; @@ -177,7 +190,7 @@ void SRTC::mmio_write(unsigned addr, uint8 data) { return; } - if(data == 0x0f) return; //unknown behavior + if(data == 0x0f) return; //unknown behavior if(rtc_mode == RTCM_Write) { if(rtc_index >= 0 && rtc_index < 12) { diff --git a/src/chip/st010/st010.cpp b/src/chip/st010/st010.cpp index 1fa4a724..c0c8f906 100644 --- a/src/chip/st010/st010.cpp +++ b/src/chip/st010/st010.cpp @@ -1,6 +1,7 @@ #include <../base.hpp> #define ST010_CPP +#include "st010.hpp" #include "st010_data.hpp" #include "st010_op.cpp" @@ -62,11 +63,11 @@ void ST010::reset() { // -uint8 ST010::read(uint addr) { +uint8 ST010::read(unsigned addr) { return readb(addr); } -void ST010::write(uint addr, uint8 data) { +void ST010::write(unsigned addr, uint8 data) { writeb(addr, data); if((addr & 0xfff) == 0x0021 && (data & 0x80)) { diff --git a/src/chip/st010/st010.hpp b/src/chip/st010/st010.hpp index dbabdee5..d4445cea 100644 --- a/src/chip/st010/st010.hpp +++ b/src/chip/st010/st010.hpp @@ -5,8 +5,8 @@ public: void power(); void reset(); - uint8 read (uint addr); - void write(uint addr, uint8 data); + uint8 read (unsigned addr); + void write(unsigned addr, uint8 data); private: uint8 ram[0x1000]; diff --git a/src/chip/st010/st010_op.cpp b/src/chip/st010/st010_op.cpp index 1eb9c55c..77b4a9c1 100644 --- a/src/chip/st010/st010_op.cpp +++ b/src/chip/st010/st010_op.cpp @@ -258,4 +258,4 @@ int16 x1, y1; writew(0x0012, y1); } -#endif //ifdef ST010_CPP +#endif diff --git a/src/clean.bat b/src/clean.bat index 3a500869..1d563cce 100644 --- a/src/clean.bat +++ b/src/clean.bat @@ -1 +1 @@ -@make platform=win compiler=mingw32-gcc clean +@mingw32-make platform=win compiler=mingw32-gcc clean diff --git a/src/config/config.cpp b/src/config/config.cpp deleted file mode 100644 index dab0868b..00000000 --- a/src/config/config.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include <../base.hpp> - -namespace config { - -configuration& config() { - static configuration config; - return config; -} - -string filepath(const char *filename, const char *pathname) { - //if no pathname, return filename as-is - string file(filename); - replace(file, "\\", "/"); - if(!pathname || !*pathname) return file; - - //ensure path ends with trailing '/' - string path(pathname); - replace(path, "\\", "/"); - if(!strend(path, "/")) strcat(path, "/"); - - //replace relative path with absolute path - if(strbegin(path, "./")) { - ltrim(path, "./"); - path = string() << config::path.base << path; - } - - //remove folder part of filename - lstring part; - split(part, "/", file); - return path << part[count(part) - 1]; -} - -integral_setting File::autodetect_type(config(), "file.autodetect_type", - "Auto-detect file type by inspecting file header, rather than by file extension.\n" - "In other words, if a .zip file is renamed to .smc, it will still be correctly " - "identified as a .zip file. However, there is an infinitesimal (1:~500,000,000) " - "chance of a false detection when loading an uncompressed image file, if this " - "option is enabled.", - integral_setting::boolean, false); - -integral_setting File::bypass_patch_crc32(config(), "file.bypass_patch_crc32", - "UPS patches contain CRC32s to validate that a patch was applied successfully.\n" - "By default, if this validation fails, said patch will not be applied. " - "Setting this option to true will bypass the validation, " - "which may or may not result in a working image. " - "Thus, enabling this option is strongly discouraged.", - integral_setting::boolean, false); - -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::save(config(), "path.save", - "Default path for all save RAM files (\"\" = use current directory)", ""); -string_setting Path::patch(config(), "path.patch", - "Default path for all UPS patch files (\"\" = use current directory)", ""); -string_setting Path::cheat(config(), "path.cheat", - "Default path for all cheat files (\"\" = use current directory)", ""); -string_setting Path::exportdata(config(), "path.export", - "Default path for all exported data files\n", ""); - -string_setting Path::bsx(config(), "path.bsx", "", ""); -string_setting Path::st(config(), "path.st", "", ""); - -integral_setting SNES::controller_port1(config(), "snes.controller_port1", - "Controller attached to SNES port 1", integral_setting::decimal, ::SNES::Input::DeviceJoypad); -integral_setting SNES::controller_port2(config(), "snes.controller_port2", - "Controller attached to SNES port 2", integral_setting::decimal, ::SNES::Input::DeviceJoypad); -integral_setting SNES::expansion_port(config(), "snes.expansion_port", - "Device attached to SNES expansion port\n" - "0 = None\n" - "1 = Satellaview BS-X", - integral_setting::decimal, ::SNES::ExpansionBSX); -integral_setting SNES::region(config(), "snes.region", - "SNES regional model\n" - "0 = Auto-detect based on cartridge\n" - "1 = NTSC\n" - "2 = PAL", - integral_setting::decimal, ::SNES::Autodetect); - -integral_setting CPU::ntsc_clock_rate(config(), "cpu.ntsc_clock_rate", - "NTSC S-CPU clock rate (in hz)", integral_setting::decimal, 21477272); -integral_setting CPU::pal_clock_rate(config(), "cpu.pal_clock_rate", - "PAL S-CPU clock rate (in hz)", integral_setting::decimal, 21281370); -integral_setting CPU::wram_init_value(config(), "cpu.wram_init_value", - "Value to initialize 128k WRAM to upon power cycle.\n" - "Note that on real hardware, this value is undefined; meaning it can vary " - "per power-on, and per SNES unit. Such randomness is undesirable for an " - "emulator, so a static value is needed. There is also some form of pattern " - "to the randomness that has yet to be determined, which some games rely upon.\n" - "A value of 0x55 is safe for all known commercial software, and should be used. " - "However, some software written for SNES copiers, or backup units, relies on " - "WRAM being initialized to 0x00; which was a side-effect of the BIOS program " - "which executed on these copiers. Using 0x00 will therefore fix many homebrew " - "programs, but *will* break some poorly programmed commercial software titles, " - "which do not properly initialize WRAM upon power cycle.", - integral_setting::hex, 0x55); - -integral_setting SMP::ntsc_clock_rate(config(), "smp.ntsc_clock_rate", - "NTSC S-SMP clock rate (in hz)", integral_setting::decimal, 32041 * 768); -integral_setting SMP::pal_clock_rate(config(), "smp.pal_clock_rate", - "PAL S-SMP clock rate (in hz)", integral_setting::decimal, 32041 * 768); - -integral_setting Temp::alu_mul_delay(config(), "temp.alu_mul_delay", - "", integral_setting::decimal, 32); -integral_setting Temp::alu_div_delay(config(), "temp.alu_div_delay", - "", integral_setting::decimal, 64); - -} //namespace config diff --git a/src/config/config.hpp b/src/config/config.hpp deleted file mode 100644 index 1ff13109..00000000 --- a/src/config/config.hpp +++ /dev/null @@ -1,38 +0,0 @@ -namespace config { - -extern configuration& config(); - -string filepath(const char *filename, const char *pathname); - -extern struct File { - static integral_setting autodetect_type; - static integral_setting bypass_patch_crc32; -} file; - -extern struct Path { - static string_setting base, user; - static string_setting rom, save, patch, cheat, exportdata; - static string_setting bsx, st; -} path; - -extern struct SNES { - static integral_setting controller_port1; - static integral_setting controller_port2; - static integral_setting expansion_port; - static integral_setting region; -} snes; - -extern struct CPU { - static integral_setting ntsc_clock_rate, pal_clock_rate; - static integral_setting wram_init_value; -} cpu; - -extern struct SMP { - static integral_setting ntsc_clock_rate, pal_clock_rate; -} smp; - -extern struct Temp { - static integral_setting alu_mul_delay, alu_div_delay; -} temp; - -}; diff --git a/src/cpu/scpu/core/core.cpp b/src/cpu/scpu/core/core.cpp index 4ec0d0c4..b746d6bc 100644 --- a/src/cpu/scpu/core/core.cpp +++ b/src/cpu/scpu/core/core.cpp @@ -10,14 +10,14 @@ void sCPU::enter() { add_clocks(186); loop: - if(event.irq) { - event.irq = false; - if(status.nmi_pending == true) { + if(status.interrupt_pending) { + status.interrupt_pending = false; + if(status.nmi_pending) { status.nmi_pending = false; - event.irq_vector = (regs.e == false) ? 0xffea : 0xfffa; - } else if(status.irq_pending == true) { + status.interrupt_vector = (regs.e == false ? 0xffea : 0xfffa); + } else if(status.irq_pending) { status.irq_pending = false; - event.irq_vector = (regs.e == false) ? 0xffee : 0xfffe; + status.interrupt_vector = (regs.e == false ? 0xffee : 0xfffe); } op_irq(); } @@ -40,15 +40,15 @@ void sCPU::enter() { void sCPU::op_irq() { op_read(regs.pc.d); op_io(); - if(!regs.e)op_writestack(regs.pc.b); + if(!regs.e) op_writestack(regs.pc.b); op_writestack(regs.pc.h); op_writestack(regs.pc.l); op_writestack(regs.e ? (regs.p & ~0x10) : regs.p); - rd.l = op_read(event.irq_vector + 0); + rd.l = op_read(status.interrupt_vector + 0); regs.pc.b = 0x00; regs.p.i = 1; regs.p.d = 0; - rd.h = op_read(event.irq_vector + 1); + rd.h = op_read(status.interrupt_vector + 1); regs.pc.w = rd.w; } @@ -57,11 +57,11 @@ void sCPU::op_irq() { //this affects the following opcodes: // clc, cld, cli, clv, sec, sed, sei, // tax, tay, txa, txy, tya, tyx, -// tcd, tcs, tdc, tsc, tsx, tcs, +// tcd, tcs, tdc, tsc, tsx, txs, // inc, inx, iny, dec, dex, dey, // asl, lsr, rol, ror, nop, xce. alwaysinline void sCPU::op_io_irq() { - if(event.irq) { + if(status.interrupt_pending) { //IRQ pending, modify I/O cycle to bus read cycle, do not increment PC op_read(regs.pc.d); } else { @@ -87,4 +87,4 @@ alwaysinline void sCPU::op_io_cond6(uint16 addr) { } } -#endif //ifdef SCPU_CPP +#endif diff --git a/src/cpu/scpu/core/op_misc.b b/src/cpu/scpu/core/op_misc.b index 0e53d147..491b14af 100644 --- a/src/cpu/scpu/core/op_misc.b +++ b/src/cpu/scpu/core/op_misc.b @@ -62,9 +62,9 @@ stp(0xdb) { } wai(0xcb) { -//last_cycle() will clear event.wai once an NMI / IRQ edge is reached -1:event.wai = true; - while(event.wai) { +//last_cycle() will clear status.wai_lock once an NMI / IRQ edge is reached +1:status.wai_lock = true; + while(status.wai_lock) { last_cycle(); op_io(); } diff --git a/src/cpu/scpu/core/op_misc.cpp b/src/cpu/scpu/core/op_misc.cpp index 98bc7567..ef1fc98c 100644 --- a/src/cpu/scpu/core/op_misc.cpp +++ b/src/cpu/scpu/core/op_misc.cpp @@ -1,3 +1,5 @@ +#ifdef SCPU_CPP + //nop case 0xea: { last_cycle(); @@ -103,9 +105,9 @@ case 0xdb: { //wai case 0xcb: { - //last_cycle() will clear event.wai once an NMI / IRQ edge is reached - event.wai = true; - while(event.wai) { + //last_cycle() will clear status.wai_lock once an NMI / IRQ edge is reached + status.wai_lock = true; + while(status.wai_lock) { last_cycle(); op_io(); } @@ -534,3 +536,4 @@ case 0x62: { if(regs.e) regs.s.h = 0x01; } break; +#endif diff --git a/src/cpu/scpu/core/op_pc.cpp b/src/cpu/scpu/core/op_pc.cpp index 761bb228..9588206a 100644 --- a/src/cpu/scpu/core/op_pc.cpp +++ b/src/cpu/scpu/core/op_pc.cpp @@ -1,3 +1,5 @@ +#ifdef SCPU_CPP + //bcc case 0x90: { if(!!regs.p.c) last_cycle(); @@ -274,3 +276,4 @@ case 0x6b: { if(regs.e) regs.s.h = 0x01; } break; +#endif diff --git a/src/cpu/scpu/core/op_read.cpp b/src/cpu/scpu/core/op_read.cpp index 76f8ce72..a486b5f5 100644 --- a/src/cpu/scpu/core/op_read.cpp +++ b/src/cpu/scpu/core/op_read.cpp @@ -1,3 +1,5 @@ +#ifdef SCPU_CPP + //adc_const case 0x69: { if(regs.p.m) last_cycle(); @@ -1649,3 +1651,4 @@ case 0x89: { regs.p.z = ((rd.w & regs.a.w) == 0); } break; +#endif diff --git a/src/cpu/scpu/core/op_rmw.cpp b/src/cpu/scpu/core/op_rmw.cpp index f04702a4..6d37dd0b 100644 --- a/src/cpu/scpu/core/op_rmw.cpp +++ b/src/cpu/scpu/core/op_rmw.cpp @@ -1,3 +1,5 @@ +#ifdef SCPU_CPP + //inc case 0x1a: { last_cycle(); @@ -568,3 +570,4 @@ case 0x76: { op_writedp(dp + regs.x.w, rd.l); } break; +#endif diff --git a/src/cpu/scpu/core/op_write.cpp b/src/cpu/scpu/core/op_write.cpp index 438e6767..d2362e62 100644 --- a/src/cpu/scpu/core/op_write.cpp +++ b/src/cpu/scpu/core/op_write.cpp @@ -1,3 +1,5 @@ +#ifdef SCPU_CPP + //sta_addr case 0x8d: { aa.l = op_readpc(); @@ -288,3 +290,4 @@ case 0x93: { op_writedbr(aa.w + regs.y.w + 1, regs.a.h); } break; +#endif diff --git a/src/cpu/scpu/deltaqueue.cpp b/src/cpu/scpu/deltaqueue.cpp deleted file mode 100644 index 6fd321e1..00000000 --- a/src/cpu/scpu/deltaqueue.cpp +++ /dev/null @@ -1,88 +0,0 @@ -#ifdef SCPU_CPP - -//delta queue scheduler is used to time multiple events with the following properties: -//O(1) test (tick) -//O(log n) insert (enqueue) -//O(log n) remove (dequeue) -// -//notes: -//implementation uses binary min-heap array; -//tick() uses 2's-complement signed math to avoid overflow errors; -//enqueue() takes relative timestamps, which are converted to absolute times internally. - -class deltaqueue { - enum { queuesize = 64 }; //maximum number of events that can be queued at the same time. - -public: - alwaysinline void tick(unsigned ticks) { - counter += ticks; - - while(heapsize) { - if((signed)(counter - heap[0].counter) < 0) break; //if(counter < heap[0].counter) break; - unsigned event = heap[0].event; - dequeue(); - cpu.queue_event(event); - } - } - - void enqueue(unsigned event, unsigned ticks) { - unsigned child = heapsize++; - - heap[child].event = event; - heap[child].counter = counter + ticks; - - while(child) { - unsigned parent = (child - 1) >> 1; - if(heap[child].counter >= heap[parent].counter) break; - swap(parent, child); - child = parent; - } - } - - void dequeue() { - heap[0].counter = heap[--heapsize].counter; - heap[0].event = heap[heapsize].event; - heap[heapsize].counter = ~0; - - unsigned parent = 0; - while(true) { - unsigned child = (parent << 1) + 1; - if(heap[child + 1].counter < heap[child].counter) child++; - if(heap[parent].counter <= heap[child].counter) break; - swap(parent, child); - parent = child; - } - } - - void reset() { - counter = 0; - heapsize = 0; - for(unsigned i = 0; i < queuesize << 1; i++) heap[i].counter = ~0; - } - - deltaqueue() { - reset(); - } - -public: - unsigned counter; - unsigned heapsize; - - struct { - unsigned counter; - unsigned event; - } heap[queuesize << 1]; - - void swap(unsigned x, unsigned y) { - unsigned counter = heap[x].counter; - unsigned event = heap[x].event; - - heap[x].counter = heap[y].counter; - heap[x].event = heap[y].event; - - heap[y].counter = counter; - heap[y].event = event; - } -}; - -#endif //ifdef SCPU_CPP diff --git a/src/cpu/scpu/dma/dma.cpp b/src/cpu/scpu/dma/dma.cpp index a5888bee..de73d563 100644 --- a/src/cpu/scpu/dma/dma.cpp +++ b/src/cpu/scpu/dma/dma.cpp @@ -1,6 +1,6 @@ #ifdef SCPU_CPP -void sCPU::dma_add_clocks(uint clocks) { +void sCPU::dma_add_clocks(unsigned clocks) { status.dma_clocks += clocks; add_clocks(clocks); } @@ -122,7 +122,7 @@ void sCPU::dma_run() { } status.irq_lock = true; - delta.enqueue(EventIrqLockRelease, 2); + event.enqueue(2, EventIrqLockRelease); } /***** @@ -205,7 +205,7 @@ void sCPU::hdma_run() { } status.irq_lock = true; - delta.enqueue(EventIrqLockRelease, 2); + event.enqueue(2, EventIrqLockRelease); } void sCPU::hdma_init_reset() { @@ -227,7 +227,7 @@ void sCPU::hdma_init() { } status.irq_lock = true; - delta.enqueue(EventIrqLockRelease, 2); + event.enqueue(2, EventIrqLockRelease); } /***** diff --git a/src/cpu/scpu/dma/dma.hpp b/src/cpu/scpu/dma/dma.hpp index 3a7af05e..79102f05 100644 --- a/src/cpu/scpu/dma/dma.hpp +++ b/src/cpu/scpu/dma/dma.hpp @@ -45,7 +45,7 @@ bool hdma_do_transfer; } channel[8]; - void dma_add_clocks(uint clocks); + void dma_add_clocks(unsigned clocks); bool dma_addr_valid(uint32 abus); uint8 dma_read(uint32 abus); void dma_transfer(bool direction, uint8 bbus, uint32 abus); diff --git a/src/cpu/scpu/mmio/mmio.cpp b/src/cpu/scpu/mmio/mmio.cpp index 5fc033ad..7441cb26 100644 --- a/src/cpu/scpu/mmio/mmio.cpp +++ b/src/cpu/scpu/mmio/mmio.cpp @@ -1,538 +1,534 @@ #ifdef SCPU_CPP -uint8 sCPU::pio() { return status.pio; } -bool sCPU::joylatch() { return status.joypad_strobe_latch; } - -//WMDATA -uint8 sCPU::mmio_r2180() { - uint8 r = bus.read(0x7e0000 | status.wram_addr); - status.wram_addr = (status.wram_addr + 1) & 0x01ffff; - return r; -} - -//WMDATA -void sCPU::mmio_w2180(uint8 data) { - bus.write(0x7e0000 | status.wram_addr, data); - status.wram_addr = (status.wram_addr + 1) & 0x01ffff; -} - -//WMADDL -void sCPU::mmio_w2181(uint8 data) { - status.wram_addr = (status.wram_addr & 0xffff00) | (data); - status.wram_addr &= 0x01ffff; -} - -//WMADDM -void sCPU::mmio_w2182(uint8 data) { - status.wram_addr = (status.wram_addr & 0xff00ff) | (data << 8); - status.wram_addr &= 0x01ffff; -} - -//WMADDH -void sCPU::mmio_w2183(uint8 data) { - status.wram_addr = (status.wram_addr & 0x00ffff) | (data << 16); - status.wram_addr &= 0x01ffff; -} - -//JOYSER0 -//bit 0 is shared between JOYSER0 and JOYSER1, therefore -//strobing $4016.d0 affects both controller port latches. -//$4017 bit 0 writes are ignored. -void sCPU::mmio_w4016(uint8 data) { - status.joypad_strobe_latch = !!(data & 1); - - if(status.joypad_strobe_latch == 1) { - snes.input.poll(); - } -} - -//JOYSER0 -//7-2 = MDR -//1-0 = Joypad serial data -// -//TODO: test whether strobe latch of zero returns -//realtime or buffered status of joypadN.b -uint8 sCPU::mmio_r4016() { - uint8 r = regs.mdr & 0xfc; - r |= snes.input.port_read(0) & 3; - return r; -} - -//JOYSER1 -//7-5 = MDR -//4-2 = Always 1 (pins are connected to GND) -//1-0 = Joypad serial data -uint8 sCPU::mmio_r4017() { - uint8 r = (regs.mdr & 0xe0) | 0x1c; - r |= snes.input.port_read(1) & 3; - return r; -} - -//NMITIMEN -void sCPU::mmio_w4200(uint8 data) { - status.auto_joypad_poll = !!(data & 0x01); - nmitimen_update(data); -} - -//WRIO -void sCPU::mmio_w4201(uint8 data) { - if((status.pio & 0x80) && !(data & 0x80)) { - ppu.latch_counters(); - } - status.pio = data; -} - -//WRMPYA -void sCPU::mmio_w4202(uint8 data) { - status.mul_a = data; -} - -//WRMPYB -void sCPU::mmio_w4203(uint8 data) { - status.mul_b = data; - status.r4216 = status.mul_a * status.mul_b; - - status.alu_lock = true; - delta.enqueue(EventAluLockRelease, temp_.alu_mul_delay); -} - -//WRDIVL -void sCPU::mmio_w4204(uint8 data) { - status.div_a = (status.div_a & 0xff00) | (data); -} - -//WRDIVH -void sCPU::mmio_w4205(uint8 data) { - status.div_a = (status.div_a & 0x00ff) | (data << 8); -} - -//WRDIVB -void sCPU::mmio_w4206(uint8 data) { - status.div_b = data; - status.r4214 = (status.div_b) ? status.div_a / status.div_b : 0xffff; - status.r4216 = (status.div_b) ? status.div_a % status.div_b : status.div_a; - - status.alu_lock = true; - delta.enqueue(EventAluLockRelease, temp_.alu_div_delay); -} - -//HTIMEL -void sCPU::mmio_w4207(uint8 data) { - status.hirq_pos = (status.hirq_pos & ~0xff) | (data); - status.hirq_pos &= 0x01ff; - hvtime_update(0x4207); -} - -//HTIMEH -void sCPU::mmio_w4208(uint8 data) { - status.hirq_pos = (status.hirq_pos & 0xff) | (data << 8); - status.hirq_pos &= 0x01ff; - hvtime_update(0x4208); -} - -//VTIMEL -void sCPU::mmio_w4209(uint8 data) { - status.virq_pos = (status.virq_pos & ~0xff) | (data); - status.virq_pos &= 0x01ff; - hvtime_update(0x4209); -} - -//VTIMEH -void sCPU::mmio_w420a(uint8 data) { - status.virq_pos = (status.virq_pos & 0xff) | (data << 8); - status.virq_pos &= 0x01ff; - hvtime_update(0x420a); -} - -//DMAEN -void sCPU::mmio_w420b(uint8 data) { - for(unsigned i = 0; i < 8; i++) { - channel[i].dma_enabled = data & (1 << i); - } - if(data) status.dma_pending = true; -} - -//HDMAEN -void sCPU::mmio_w420c(uint8 data) { - for(unsigned i = 0; i < 8; i++) { - channel[i].hdma_enabled = data & (1 << i); - } -} - -//MEMSEL -void sCPU::mmio_w420d(uint8 data) { - bus.set_speed(data & 1); -} - -//RDNMI -//7 = NMI acknowledge -//6-4 = MDR -//3-0 = CPU (5a22) version -uint8 sCPU::mmio_r4210() { - uint8 r = (regs.mdr & 0x70); - r |= (uint8)(rdnmi()) << 7; - r |= (cpu_version & 0x0f); - return r; -} - -//TIMEUP -//7 = IRQ acknowledge -//6-0 = MDR -uint8 sCPU::mmio_r4211() { - uint8 r = (regs.mdr & 0x7f); - r |= (uint8)(timeup()) << 7; - return r; -} - -//HVBJOY -//7 = VBLANK acknowledge -//6 = HBLANK acknowledge -//5-1 = MDR -//0 = JOYPAD acknowledge -uint8 sCPU::mmio_r4212() { - uint8 r = (regs.mdr & 0x3e); - uint16 vs = ppu.overscan() == false ? 225 : 240; - - //auto joypad polling - if(ppu.vcounter() >= vs && ppu.vcounter() <= (vs + 2))r |= 0x01; - - //hblank - if(ppu.hcounter() <= 2 || ppu.hcounter() >= 1096)r |= 0x40; - - //vblank - if(ppu.vcounter() >= vs)r |= 0x80; - - return r; -} - -//RDIO -uint8 sCPU::mmio_r4213() { - return status.pio; -} - -//RDDIVL -uint8 sCPU::mmio_r4214() { - if(status.alu_lock) return 0; - return status.r4214; -} - -//RDDIVH -uint8 sCPU::mmio_r4215() { - if(status.alu_lock) return 0; - return status.r4214 >> 8; -} - -//RDMPYL -uint8 sCPU::mmio_r4216() { - if(status.alu_lock) return 0; - return status.r4216; -} - -//RDMPYH -uint8 sCPU::mmio_r4217() { - if(status.alu_lock) return 0; - return status.r4216 >> 8; -} - -//TODO: handle reads during joypad polling (v=225-227) -uint8 sCPU::mmio_r4218() { return status.joy1l; } //JOY1L -uint8 sCPU::mmio_r4219() { return status.joy1h; } //JOY1H -uint8 sCPU::mmio_r421a() { return status.joy2l; } //JOY2L -uint8 sCPU::mmio_r421b() { return status.joy2h; } //JOY2H -uint8 sCPU::mmio_r421c() { return status.joy3l; } //JOY3L -uint8 sCPU::mmio_r421d() { return status.joy3h; } //JOY3H -uint8 sCPU::mmio_r421e() { return status.joy4l; } //JOY4L -uint8 sCPU::mmio_r421f() { return status.joy4h; } //JOY4H - -//DMAPx -uint8 sCPU::mmio_r43x0(uint8 i) { - return channel[i].dmap; -} - -//BBADx -uint8 sCPU::mmio_r43x1(uint8 i) { - return channel[i].destaddr; -} - -//A1TxL -uint8 sCPU::mmio_r43x2(uint8 i) { - return channel[i].srcaddr; -} - -//A1TxH -uint8 sCPU::mmio_r43x3(uint8 i) { - return channel[i].srcaddr >> 8; -} - -//A1Bx -uint8 sCPU::mmio_r43x4(uint8 i) { - return channel[i].srcbank; -} - -//DASxL -//union { uint16 xfersize; uint16 hdma_iaddr; }; -uint8 sCPU::mmio_r43x5(uint8 i) { - return channel[i].xfersize; -} - -//DASxH -//union { uint16 xfersize; uint16 hdma_iaddr; }; -uint8 sCPU::mmio_r43x6(uint8 i) { - return channel[i].xfersize >> 8; -} - -//DASBx -uint8 sCPU::mmio_r43x7(uint8 i) { - return channel[i].hdma_ibank; -} - -//A2AxL -uint8 sCPU::mmio_r43x8(uint8 i) { - return channel[i].hdma_addr; -} - -//A2AxH -uint8 sCPU::mmio_r43x9(uint8 i) { - return channel[i].hdma_addr >> 8; -} - -//NTRLx -uint8 sCPU::mmio_r43xa(uint8 i) { - return channel[i].hdma_line_counter; -} - -//??? -uint8 sCPU::mmio_r43xb(uint8 i) { - return channel[i].unknown; -} - -//DMAPx -void sCPU::mmio_w43x0(uint8 i, uint8 data) { - channel[i].dmap = data; - channel[i].direction = !!(data & 0x80); - channel[i].hdma_indirect = !!(data & 0x40); - channel[i].reversexfer = !!(data & 0x10); - channel[i].fixedxfer = !!(data & 0x08); - channel[i].xfermode = data & 7; -} - -//DDBADx -void sCPU::mmio_w43x1(uint8 i, uint8 data) { - channel[i].destaddr = data; -} - -//A1TxL -void sCPU::mmio_w43x2(uint8 i, uint8 data) { - channel[i].srcaddr = (channel[i].srcaddr & 0xff00) | (data); -} - -//A1TxH -void sCPU::mmio_w43x3(uint8 i, uint8 data) { - channel[i].srcaddr = (channel[i].srcaddr & 0x00ff) | (data << 8); -} - -//A1Bx -void sCPU::mmio_w43x4(uint8 i, uint8 data) { - channel[i].srcbank = data; -} - -//DASxL -//union { uint16 xfersize; uint16 hdma_iaddr; }; -void sCPU::mmio_w43x5(uint8 i, uint8 data) { - channel[i].xfersize = (channel[i].xfersize & 0xff00) | (data); -} - -//DASxH -//union { uint16 xfersize; uint16 hdma_iaddr; }; -void sCPU::mmio_w43x6(uint8 i, uint8 data) { - channel[i].xfersize = (channel[i].xfersize & 0x00ff) | (data << 8); -} - -//DASBx -void sCPU::mmio_w43x7(uint8 i, uint8 data) { - channel[i].hdma_ibank = data; -} - -//A2AxL -void sCPU::mmio_w43x8(uint8 i, uint8 data) { - channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | (data); -} - -//A2AxH -void sCPU::mmio_w43x9(uint8 i, uint8 data) { - channel[i].hdma_addr = (channel[i].hdma_addr & 0x00ff) | (data << 8); -} - -//NTRLx -void sCPU::mmio_w43xa(uint8 i, uint8 data) { - channel[i].hdma_line_counter = data; -} - -//??? -void sCPU::mmio_w43xb(uint8 i, uint8 data) { - channel[i].unknown = data; -} - -void sCPU::mmio_power() { -} - -void sCPU::mmio_reset() { - //$2181-$2183 - status.wram_addr = 0x000000; - - //$4016-$4017 - status.joypad_strobe_latch = 0; - status.joypad1_bits = ~0; - status.joypad2_bits = ~0; - - //$4200 - status.nmi_enabled = false; - status.hirq_enabled = false; - status.virq_enabled = false; - status.auto_joypad_poll = false; - - //$4201 - status.pio = 0xff; - - //$4202-$4203 - status.mul_a = 0xff; - status.mul_b = 0xff; - - //$4204-$4206 - status.div_a = 0xffff; - status.div_b = 0xff; - - //$4207-$420a - status.hirq_pos = 0x01ff; - status.virq_pos = 0x01ff; - - //$4214-$4217 - status.r4214 = 0x0000; - status.r4216 = 0x0000; - - //$4218-$421f - status.joy1l = 0x00; - status.joy1h = 0x00; - status.joy2l = 0x00; - status.joy2h = 0x00; - status.joy3l = 0x00; - status.joy3h = 0x00; - status.joy4l = 0x00; - status.joy4h = 0x00; -} - -uint8 sCPU::mmio_read(uint addr) { - addr &= 0xffff; - - //APU - if((addr & 0xffc0) == 0x2140) { //$2140-$217f - scheduler.sync_cpusmp(); - return smp.port_read(addr & 3); - } - - //DMA - if((addr & 0xff80) == 0x4300) { //$4300-$437f - uint i = (addr >> 4) & 7; - switch(addr & 0xf) { - case 0x0: return mmio_r43x0(i); - case 0x1: return mmio_r43x1(i); - case 0x2: return mmio_r43x2(i); - case 0x3: return mmio_r43x3(i); - case 0x4: return mmio_r43x4(i); - case 0x5: return mmio_r43x5(i); - case 0x6: return mmio_r43x6(i); - case 0x7: return mmio_r43x7(i); - case 0x8: return mmio_r43x8(i); - case 0x9: return mmio_r43x9(i); - case 0xa: return mmio_r43xa(i); - case 0xb: return mmio_r43xb(i); - case 0xc: return regs.mdr; //unmapped - case 0xd: return regs.mdr; //unmapped - case 0xe: return regs.mdr; //unmapped - case 0xf: return mmio_r43xb(i); //mirror of $43xb - } - } - - switch(addr) { - case 0x2180: return mmio_r2180(); - case 0x4016: return mmio_r4016(); - case 0x4017: return mmio_r4017(); - case 0x4210: return mmio_r4210(); - case 0x4211: return mmio_r4211(); - case 0x4212: return mmio_r4212(); - case 0x4213: return mmio_r4213(); - case 0x4214: return mmio_r4214(); - case 0x4215: return mmio_r4215(); - case 0x4216: return mmio_r4216(); - case 0x4217: return mmio_r4217(); - case 0x4218: return mmio_r4218(); - case 0x4219: return mmio_r4219(); - case 0x421a: return mmio_r421a(); - case 0x421b: return mmio_r421b(); - case 0x421c: return mmio_r421c(); - case 0x421d: return mmio_r421d(); - case 0x421e: return mmio_r421e(); - case 0x421f: return mmio_r421f(); - } - - return regs.mdr; -} - -void sCPU::mmio_write(uint addr, uint8 data) { - addr &= 0xffff; - - //APU - if((addr & 0xffc0) == 0x2140) { //$2140-$217f - scheduler.sync_cpusmp(); - port_write(addr & 3, data); - return; - } - - //DMA - if((addr & 0xff80) == 0x4300) { //$4300-$437f - uint i = (addr >> 4) & 7; - switch(addr & 0xf) { - case 0x0: mmio_w43x0(i, data); return; - case 0x1: mmio_w43x1(i, data); return; - case 0x2: mmio_w43x2(i, data); return; - case 0x3: mmio_w43x3(i, data); return; - case 0x4: mmio_w43x4(i, data); return; - case 0x5: mmio_w43x5(i, data); return; - case 0x6: mmio_w43x6(i, data); return; - case 0x7: mmio_w43x7(i, data); return; - case 0x8: mmio_w43x8(i, data); return; - case 0x9: mmio_w43x9(i, data); return; - case 0xa: mmio_w43xa(i, data); return; - case 0xb: mmio_w43xb(i, data); return; - case 0xc: return; //unmapped - case 0xd: return; //unmapped - case 0xe: return; //unmapped - case 0xf: mmio_w43xb(i, data); return; //mirror of $43xb - } - } - - switch(addr) { - case 0x2180: mmio_w2180(data); return; - case 0x2181: mmio_w2181(data); return; - case 0x2182: mmio_w2182(data); return; - case 0x2183: mmio_w2183(data); return; - case 0x4016: mmio_w4016(data); return; - case 0x4017: return; //unmapped - case 0x4200: mmio_w4200(data); return; - case 0x4201: mmio_w4201(data); return; - case 0x4202: mmio_w4202(data); return; - case 0x4203: mmio_w4203(data); return; - case 0x4204: mmio_w4204(data); return; - case 0x4205: mmio_w4205(data); return; - case 0x4206: mmio_w4206(data); return; - case 0x4207: mmio_w4207(data); return; - case 0x4208: mmio_w4208(data); return; - case 0x4209: mmio_w4209(data); return; - case 0x420a: mmio_w420a(data); return; - case 0x420b: mmio_w420b(data); return; - case 0x420c: mmio_w420c(data); return; - case 0x420d: mmio_w420d(data); return; - } -} +uint8 sCPU::pio() { return status.pio; } +bool sCPU::joylatch() { return status.joypad_strobe_latch; } + +//WMDATA +uint8 sCPU::mmio_r2180() { + uint8 r = bus.read(0x7e0000 | status.wram_addr); + status.wram_addr = (status.wram_addr + 1) & 0x01ffff; + return r; +} + +//WMDATA +void sCPU::mmio_w2180(uint8 data) { + bus.write(0x7e0000 | status.wram_addr, data); + status.wram_addr = (status.wram_addr + 1) & 0x01ffff; +} + +//WMADDL +void sCPU::mmio_w2181(uint8 data) { + status.wram_addr = (status.wram_addr & 0xffff00) | (data); + status.wram_addr &= 0x01ffff; +} + +//WMADDM +void sCPU::mmio_w2182(uint8 data) { + status.wram_addr = (status.wram_addr & 0xff00ff) | (data << 8); + status.wram_addr &= 0x01ffff; +} + +//WMADDH +void sCPU::mmio_w2183(uint8 data) { + status.wram_addr = (status.wram_addr & 0x00ffff) | (data << 16); + status.wram_addr &= 0x01ffff; +} + +//JOYSER0 +//bit 0 is shared between JOYSER0 and JOYSER1, therefore +//strobing $4016.d0 affects both controller port latches. +//$4017 bit 0 writes are ignored. +void sCPU::mmio_w4016(uint8 data) { + status.joypad_strobe_latch = !!(data & 1); + + if(status.joypad_strobe_latch == 1) { + snes.input.poll(); + } +} + +//JOYSER0 +//7-2 = MDR +//1-0 = Joypad serial data +// +//TODO: test whether strobe latch of zero returns +//realtime or buffered status of joypadN.b +uint8 sCPU::mmio_r4016() { + uint8 r = regs.mdr & 0xfc; + r |= snes.input.port_read(0) & 3; + return r; +} + +//JOYSER1 +//7-5 = MDR +//4-2 = Always 1 (pins are connected to GND) +//1-0 = Joypad serial data +uint8 sCPU::mmio_r4017() { + uint8 r = (regs.mdr & 0xe0) | 0x1c; + r |= snes.input.port_read(1) & 3; + return r; +} + +//NMITIMEN +void sCPU::mmio_w4200(uint8 data) { + status.auto_joypad_poll = !!(data & 0x01); + nmitimen_update(data); +} + +//WRIO +void sCPU::mmio_w4201(uint8 data) { + if((status.pio & 0x80) && !(data & 0x80)) { + ppu.latch_counters(); + } + status.pio = data; +} + +//WRMPYA +void sCPU::mmio_w4202(uint8 data) { + status.mul_a = data; +} + +//WRMPYB +void sCPU::mmio_w4203(uint8 data) { + status.mul_b = data; + status.r4216 = status.mul_a * status.mul_b; + + status.alu_lock = true; + event.enqueue(snes.config.cpu.alu_mul_delay, EventAluLockRelease); +} + +//WRDIVL +void sCPU::mmio_w4204(uint8 data) { + status.div_a = (status.div_a & 0xff00) | (data); +} + +//WRDIVH +void sCPU::mmio_w4205(uint8 data) { + status.div_a = (status.div_a & 0x00ff) | (data << 8); +} + +//WRDIVB +void sCPU::mmio_w4206(uint8 data) { + status.div_b = data; + status.r4214 = (status.div_b) ? status.div_a / status.div_b : 0xffff; + status.r4216 = (status.div_b) ? status.div_a % status.div_b : status.div_a; + + status.alu_lock = true; + event.enqueue(snes.config.cpu.alu_div_delay, EventAluLockRelease); +} + +//HTIMEL +void sCPU::mmio_w4207(uint8 data) { + status.hirq_pos = (status.hirq_pos & ~0xff) | (data); + status.hirq_pos &= 0x01ff; +} + +//HTIMEH +void sCPU::mmio_w4208(uint8 data) { + status.hirq_pos = (status.hirq_pos & 0xff) | (data << 8); + status.hirq_pos &= 0x01ff; +} + +//VTIMEL +void sCPU::mmio_w4209(uint8 data) { + status.virq_pos = (status.virq_pos & ~0xff) | (data); + status.virq_pos &= 0x01ff; +} + +//VTIMEH +void sCPU::mmio_w420a(uint8 data) { + status.virq_pos = (status.virq_pos & 0xff) | (data << 8); + status.virq_pos &= 0x01ff; +} + +//DMAEN +void sCPU::mmio_w420b(uint8 data) { + for(unsigned i = 0; i < 8; i++) { + channel[i].dma_enabled = data & (1 << i); + } + if(data) status.dma_pending = true; +} + +//HDMAEN +void sCPU::mmio_w420c(uint8 data) { + for(unsigned i = 0; i < 8; i++) { + channel[i].hdma_enabled = data & (1 << i); + } +} + +//MEMSEL +void sCPU::mmio_w420d(uint8 data) { + bus.set_speed(data & 1); +} + +//RDNMI +//7 = NMI acknowledge +//6-4 = MDR +//3-0 = CPU (5a22) version +uint8 sCPU::mmio_r4210() { + uint8 r = (regs.mdr & 0x70); + r |= (uint8)(rdnmi()) << 7; + r |= (cpu_version & 0x0f); + return r; +} + +//TIMEUP +//7 = IRQ acknowledge +//6-0 = MDR +uint8 sCPU::mmio_r4211() { + uint8 r = (regs.mdr & 0x7f); + r |= (uint8)(timeup()) << 7; + return r; +} + +//HVBJOY +//7 = VBLANK acknowledge +//6 = HBLANK acknowledge +//5-1 = MDR +//0 = JOYPAD acknowledge +uint8 sCPU::mmio_r4212() { + uint8 r = (regs.mdr & 0x3e); + uint16 vs = ppu.overscan() == false ? 225 : 240; + + //auto joypad polling + if(ppu.vcounter() >= vs && ppu.vcounter() <= (vs + 2))r |= 0x01; + + //hblank + if(ppu.hcounter() <= 2 || ppu.hcounter() >= 1096)r |= 0x40; + + //vblank + if(ppu.vcounter() >= vs)r |= 0x80; + + return r; +} + +//RDIO +uint8 sCPU::mmio_r4213() { + return status.pio; +} + +//RDDIVL +uint8 sCPU::mmio_r4214() { + if(status.alu_lock) return 0; + return status.r4214; +} + +//RDDIVH +uint8 sCPU::mmio_r4215() { + if(status.alu_lock) return 0; + return status.r4214 >> 8; +} + +//RDMPYL +uint8 sCPU::mmio_r4216() { + if(status.alu_lock) return 0; + return status.r4216; +} + +//RDMPYH +uint8 sCPU::mmio_r4217() { + if(status.alu_lock) return 0; + return status.r4216 >> 8; +} + +//TODO: handle reads during joypad polling (v=225-227) +uint8 sCPU::mmio_r4218() { return status.joy1l; } //JOY1L +uint8 sCPU::mmio_r4219() { return status.joy1h; } //JOY1H +uint8 sCPU::mmio_r421a() { return status.joy2l; } //JOY2L +uint8 sCPU::mmio_r421b() { return status.joy2h; } //JOY2H +uint8 sCPU::mmio_r421c() { return status.joy3l; } //JOY3L +uint8 sCPU::mmio_r421d() { return status.joy3h; } //JOY3H +uint8 sCPU::mmio_r421e() { return status.joy4l; } //JOY4L +uint8 sCPU::mmio_r421f() { return status.joy4h; } //JOY4H + +//DMAPx +uint8 sCPU::mmio_r43x0(uint8 i) { + return channel[i].dmap; +} + +//BBADx +uint8 sCPU::mmio_r43x1(uint8 i) { + return channel[i].destaddr; +} + +//A1TxL +uint8 sCPU::mmio_r43x2(uint8 i) { + return channel[i].srcaddr; +} + +//A1TxH +uint8 sCPU::mmio_r43x3(uint8 i) { + return channel[i].srcaddr >> 8; +} + +//A1Bx +uint8 sCPU::mmio_r43x4(uint8 i) { + return channel[i].srcbank; +} + +//DASxL +//union { uint16 xfersize; uint16 hdma_iaddr; }; +uint8 sCPU::mmio_r43x5(uint8 i) { + return channel[i].xfersize; +} + +//DASxH +//union { uint16 xfersize; uint16 hdma_iaddr; }; +uint8 sCPU::mmio_r43x6(uint8 i) { + return channel[i].xfersize >> 8; +} + +//DASBx +uint8 sCPU::mmio_r43x7(uint8 i) { + return channel[i].hdma_ibank; +} + +//A2AxL +uint8 sCPU::mmio_r43x8(uint8 i) { + return channel[i].hdma_addr; +} + +//A2AxH +uint8 sCPU::mmio_r43x9(uint8 i) { + return channel[i].hdma_addr >> 8; +} + +//NTRLx +uint8 sCPU::mmio_r43xa(uint8 i) { + return channel[i].hdma_line_counter; +} + +//??? +uint8 sCPU::mmio_r43xb(uint8 i) { + return channel[i].unknown; +} + +//DMAPx +void sCPU::mmio_w43x0(uint8 i, uint8 data) { + channel[i].dmap = data; + channel[i].direction = !!(data & 0x80); + channel[i].hdma_indirect = !!(data & 0x40); + channel[i].reversexfer = !!(data & 0x10); + channel[i].fixedxfer = !!(data & 0x08); + channel[i].xfermode = data & 7; +} + +//DDBADx +void sCPU::mmio_w43x1(uint8 i, uint8 data) { + channel[i].destaddr = data; +} + +//A1TxL +void sCPU::mmio_w43x2(uint8 i, uint8 data) { + channel[i].srcaddr = (channel[i].srcaddr & 0xff00) | (data); +} + +//A1TxH +void sCPU::mmio_w43x3(uint8 i, uint8 data) { + channel[i].srcaddr = (channel[i].srcaddr & 0x00ff) | (data << 8); +} + +//A1Bx +void sCPU::mmio_w43x4(uint8 i, uint8 data) { + channel[i].srcbank = data; +} + +//DASxL +//union { uint16 xfersize; uint16 hdma_iaddr; }; +void sCPU::mmio_w43x5(uint8 i, uint8 data) { + channel[i].xfersize = (channel[i].xfersize & 0xff00) | (data); +} + +//DASxH +//union { uint16 xfersize; uint16 hdma_iaddr; }; +void sCPU::mmio_w43x6(uint8 i, uint8 data) { + channel[i].xfersize = (channel[i].xfersize & 0x00ff) | (data << 8); +} + +//DASBx +void sCPU::mmio_w43x7(uint8 i, uint8 data) { + channel[i].hdma_ibank = data; +} + +//A2AxL +void sCPU::mmio_w43x8(uint8 i, uint8 data) { + channel[i].hdma_addr = (channel[i].hdma_addr & 0xff00) | (data); +} + +//A2AxH +void sCPU::mmio_w43x9(uint8 i, uint8 data) { + channel[i].hdma_addr = (channel[i].hdma_addr & 0x00ff) | (data << 8); +} + +//NTRLx +void sCPU::mmio_w43xa(uint8 i, uint8 data) { + channel[i].hdma_line_counter = data; +} + +//??? +void sCPU::mmio_w43xb(uint8 i, uint8 data) { + channel[i].unknown = data; +} + +void sCPU::mmio_power() { +} + +void sCPU::mmio_reset() { + //$2181-$2183 + status.wram_addr = 0x000000; + + //$4016-$4017 + status.joypad_strobe_latch = 0; + status.joypad1_bits = ~0; + status.joypad2_bits = ~0; + + //$4200 + status.nmi_enabled = false; + status.hirq_enabled = false; + status.virq_enabled = false; + status.auto_joypad_poll = false; + + //$4201 + status.pio = 0xff; + + //$4202-$4203 + status.mul_a = 0xff; + status.mul_b = 0xff; + + //$4204-$4206 + status.div_a = 0xffff; + status.div_b = 0xff; + + //$4207-$420a + status.hirq_pos = 0x01ff; + status.virq_pos = 0x01ff; + + //$4214-$4217 + status.r4214 = 0x0000; + status.r4216 = 0x0000; + + //$4218-$421f + status.joy1l = 0x00; + status.joy1h = 0x00; + status.joy2l = 0x00; + status.joy2h = 0x00; + status.joy3l = 0x00; + status.joy3h = 0x00; + status.joy4l = 0x00; + status.joy4h = 0x00; +} + +uint8 sCPU::mmio_read(unsigned addr) { + addr &= 0xffff; + + //APU + if((addr & 0xffc0) == 0x2140) { //$2140-$217f + scheduler.sync_cpusmp(); + return smp.port_read(addr & 3); + } + + //DMA + if((addr & 0xff80) == 0x4300) { //$4300-$437f + unsigned i = (addr >> 4) & 7; + switch(addr & 0xf) { + case 0x0: return mmio_r43x0(i); + case 0x1: return mmio_r43x1(i); + case 0x2: return mmio_r43x2(i); + case 0x3: return mmio_r43x3(i); + case 0x4: return mmio_r43x4(i); + case 0x5: return mmio_r43x5(i); + case 0x6: return mmio_r43x6(i); + case 0x7: return mmio_r43x7(i); + case 0x8: return mmio_r43x8(i); + case 0x9: return mmio_r43x9(i); + case 0xa: return mmio_r43xa(i); + case 0xb: return mmio_r43xb(i); + case 0xc: return regs.mdr; //unmapped + case 0xd: return regs.mdr; //unmapped + case 0xe: return regs.mdr; //unmapped + case 0xf: return mmio_r43xb(i); //mirror of $43xb + } + } + + switch(addr) { + case 0x2180: return mmio_r2180(); + case 0x4016: return mmio_r4016(); + case 0x4017: return mmio_r4017(); + case 0x4210: return mmio_r4210(); + case 0x4211: return mmio_r4211(); + case 0x4212: return mmio_r4212(); + case 0x4213: return mmio_r4213(); + case 0x4214: return mmio_r4214(); + case 0x4215: return mmio_r4215(); + case 0x4216: return mmio_r4216(); + case 0x4217: return mmio_r4217(); + case 0x4218: return mmio_r4218(); + case 0x4219: return mmio_r4219(); + case 0x421a: return mmio_r421a(); + case 0x421b: return mmio_r421b(); + case 0x421c: return mmio_r421c(); + case 0x421d: return mmio_r421d(); + case 0x421e: return mmio_r421e(); + case 0x421f: return mmio_r421f(); + } + + return regs.mdr; +} + +void sCPU::mmio_write(unsigned addr, uint8 data) { + addr &= 0xffff; + + //APU + if((addr & 0xffc0) == 0x2140) { //$2140-$217f + scheduler.sync_cpusmp(); + port_write(addr & 3, data); + return; + } + + //DMA + if((addr & 0xff80) == 0x4300) { //$4300-$437f + unsigned i = (addr >> 4) & 7; + switch(addr & 0xf) { + case 0x0: mmio_w43x0(i, data); return; + case 0x1: mmio_w43x1(i, data); return; + case 0x2: mmio_w43x2(i, data); return; + case 0x3: mmio_w43x3(i, data); return; + case 0x4: mmio_w43x4(i, data); return; + case 0x5: mmio_w43x5(i, data); return; + case 0x6: mmio_w43x6(i, data); return; + case 0x7: mmio_w43x7(i, data); return; + case 0x8: mmio_w43x8(i, data); return; + case 0x9: mmio_w43x9(i, data); return; + case 0xa: mmio_w43xa(i, data); return; + case 0xb: mmio_w43xb(i, data); return; + case 0xc: return; //unmapped + case 0xd: return; //unmapped + case 0xe: return; //unmapped + case 0xf: mmio_w43xb(i, data); return; //mirror of $43xb + } + } + + switch(addr) { + case 0x2180: mmio_w2180(data); return; + case 0x2181: mmio_w2181(data); return; + case 0x2182: mmio_w2182(data); return; + case 0x2183: mmio_w2183(data); return; + case 0x4016: mmio_w4016(data); return; + case 0x4017: return; //unmapped + case 0x4200: mmio_w4200(data); return; + case 0x4201: mmio_w4201(data); return; + case 0x4202: mmio_w4202(data); return; + case 0x4203: mmio_w4203(data); return; + case 0x4204: mmio_w4204(data); return; + case 0x4205: mmio_w4205(data); return; + case 0x4206: mmio_w4206(data); return; + case 0x4207: mmio_w4207(data); return; + case 0x4208: mmio_w4208(data); return; + case 0x4209: mmio_w4209(data); return; + case 0x420a: mmio_w420a(data); return; + case 0x420b: mmio_w420b(data); return; + case 0x420c: mmio_w420c(data); return; + case 0x420d: mmio_w420d(data); return; + } +} #endif //ifdef SCPU_CPP diff --git a/src/cpu/scpu/mmio/mmio.hpp b/src/cpu/scpu/mmio/mmio.hpp index 242bba11..839d0a52 100644 --- a/src/cpu/scpu/mmio/mmio.hpp +++ b/src/cpu/scpu/mmio/mmio.hpp @@ -1,7 +1,7 @@ void mmio_power(); void mmio_reset(); - uint8 mmio_read(uint addr); - void mmio_write(uint addr, uint8 data); + uint8 mmio_read(unsigned addr); + void mmio_write(unsigned addr, uint8 data); uint8 pio(); bool joylatch(); diff --git a/src/cpu/scpu/scpu.cpp b/src/cpu/scpu/scpu.cpp index 62118eea..870171c6 100644 --- a/src/cpu/scpu/scpu.cpp +++ b/src/cpu/scpu/scpu.cpp @@ -1,8 +1,8 @@ -#include <../base.hpp> +#include <../base.hpp> #define SCPU_CPP -#include "deltaqueue.cpp" -deltaqueue delta; +#include +priority_queue event(512, bind(&sCPU::queue_event, &cpu)); #include "core/core.cpp" #include "dma/dma.cpp" @@ -36,9 +36,9 @@ void sCPU::reset() { regs.e = 1; regs.mdr = 0x00; - event.wai = false; - event.irq = false; - event.irq_vector = 0xfffc; //reset vector address + status.wai_lock = false; + status.interrupt_pending = false; + status.interrupt_vector = 0xfffc; //reset vector address mmio_reset(); dma_reset(); diff --git a/src/cpu/scpu/scpu.hpp b/src/cpu/scpu/scpu.hpp index 9ed4d6dd..3be415fd 100644 --- a/src/cpu/scpu/scpu.hpp +++ b/src/cpu/scpu/scpu.hpp @@ -8,25 +8,17 @@ public: #include "mmio/mmio.hpp" #include "timing/timing.hpp" - struct { - bool wai; - bool irq; - uint16 irq_vector; - unsigned cycle_edge; - } event; - enum DmaState { DmaInactive, DmaRun, DmaCpuSync }; - struct { - unsigned alu_mul_delay; - unsigned alu_div_delay; - } temp_; - struct { //core uint8 opcode; bool in_opcode; + bool wai_lock; + bool interrupt_pending; + uint16 interrupt_vector; + unsigned clock_count; unsigned line_clocks; @@ -39,16 +31,15 @@ public: bool nmi_line; bool nmi_transition; bool nmi_pending; - unsigned nmi_hold; + bool nmi_hold; - uint16 virq_trigger_pos, hirq_trigger_pos; bool irq_valid; bool irq_line; bool irq_transition; bool irq_pending; - unsigned irq_hold; + bool irq_hold; - //dma + //DMA unsigned dma_counter; unsigned dma_clocks; bool dma_pending; @@ -56,7 +47,7 @@ public: bool hdma_mode; //0 = init, 1 = run DmaState dma_state; - //mmio + //MMIO //$2181-$2183 uint32 wram_addr; diff --git a/src/cpu/scpu/timing/event.cpp b/src/cpu/scpu/timing/event.cpp index 437cbfd0..82de9247 100644 --- a/src/cpu/scpu/timing/event.cpp +++ b/src/cpu/scpu/timing/event.cpp @@ -2,26 +2,34 @@ void sCPU::queue_event(unsigned id) { switch(id) { + //interrupts triggered during (H)DMA do not trigger immediately after case EventIrqLockRelease: { status.irq_lock = false; } break; + //ALU multiplication / division results are not immediately calculated; + //the exact formula for the calculations are unknown, but this lock at least + //allows emulation to avoid returning to fully computed results too soon. case EventAluLockRelease: { status.alu_lock = false; } break; + //S-CPU WRAM consists of two 64kbyte DRAM chips, which must be refreshed + //once per scanline to avoid memory decay. case EventDramRefresh: { add_clocks(40); } break; + //HDMA init routine; occurs once per frame case EventHdmaInit: { - event.cycle_edge |= EventFlagHdmaInit; + cycle_edge_state |= EventFlagHdmaInit; } break; + //HDMA run routine; occurs once per scanline case EventHdmaRun: { - event.cycle_edge |= EventFlagHdmaRun; + cycle_edge_state |= EventFlagHdmaRun; } break; } } -#endif //ifdef SCPU_CPP +#endif diff --git a/src/cpu/scpu/timing/irq.cpp b/src/cpu/scpu/timing/irq.cpp index 7830e78b..5b4a5598 100644 --- a/src/cpu/scpu/timing/irq.cpp +++ b/src/cpu/scpu/timing/irq.cpp @@ -1,65 +1,47 @@ #ifdef SCPU_CPP -void sCPU::update_interrupts() { - unsigned vtime = status.virq_pos; - unsigned htime = status.hirq_enabled ? status.hirq_pos : 0; - unsigned vlimit = (snes.region() == SNES::NTSC ? 525 : 625) >> 1; - - //an IRQ for the very last dot of a field cannot trigger an IRQ - if((vtime == (vlimit - 1) && htime == 339 && ppu.interlace() == false) - || (vtime == vlimit && htime == 339) - ) { - vtime = 0x03ff; - htime = 0x03ff; - } - - status.virq_trigger_pos = vtime; - status.hirq_trigger_pos = 4 * (status.hirq_enabled ? htime + 1 : 0); -} - -alwaysinline void sCPU::poll_interrupts() { - uint16_t vpos, hpos; - +//called once every four clock cycles; +//as NMI steps by scanlines (divisible by 4) and IRQ by PPU 4-cycle dots. +// +//ppu.(vh)counter(n) returns the value of said counters n-clocks before current time; +//it is used to emulate hardware communication delay between opcode and interrupt units. +void sCPU::poll_interrupts() { //NMI hold if(status.nmi_hold) { - status.nmi_hold -= 2; - if(status.nmi_hold == 0) { - if(status.nmi_enabled == true) status.nmi_transition = true; - } + status.nmi_hold = false; + if(status.nmi_enabled) status.nmi_transition = true; } //NMI test - vpos = ppu.vcounter(2); - hpos = ppu.hcounter(2); - bool nmi_valid = (vpos >= (!ppu.overscan() ? 225 : 240)); - if(status.nmi_valid == false && nmi_valid == true) { + bool nmi_valid = (ppu.vcounter(2) >= (!ppu.overscan() ? 225 : 240)); + if(!status.nmi_valid && nmi_valid) { //0->1 edge sensitive transition status.nmi_line = true; - status.nmi_hold = 4; - } else if(status.nmi_valid == true && nmi_valid == false) { + status.nmi_hold = true; //hold /NMI for four cycles + } else if(status.nmi_valid && !nmi_valid) { //1->0 edge sensitive transition status.nmi_line = false; } status.nmi_valid = nmi_valid; //IRQ hold - if(status.irq_hold) status.irq_hold -= 2; - if(status.irq_line == true && status.irq_hold == 0) { - if(status.virq_enabled == true || status.hirq_enabled == true) status.irq_transition = true; + status.irq_hold = false; + if(status.irq_line) { + if(status.virq_enabled || status.hirq_enabled) status.irq_transition = true; } //IRQ test - vpos = ppu.vcounter(10); - hpos = ppu.hcounter(10); - bool irq_valid = (status.virq_enabled == true || status.hirq_enabled == true); - if(irq_valid == true) { - if(status.virq_enabled == true && vpos != status.virq_trigger_pos) irq_valid = false; - if(status.hirq_enabled == true && hpos != status.hirq_trigger_pos) irq_valid = false; + bool irq_valid = (status.virq_enabled || status.hirq_enabled); + if(irq_valid) { + if((status.virq_enabled && ppu.vcounter(10) != (status.virq_pos)) + || (status.hirq_enabled && ppu.hcounter(10) != (status.hirq_pos + 1) * 4) + || (status.virq_pos && ppu.vcounter(6) == 0) //IRQs cannot trigger on last dot of field + ) irq_valid = false; } - if(status.irq_valid == false && irq_valid == true) { + if(!status.irq_valid && irq_valid) { //0->1 edge sensitive transition status.irq_line = true; - status.irq_hold = 4; + status.irq_hold = true; //hold /IRQ for four cycles } status.irq_valid = irq_valid; } @@ -68,37 +50,32 @@ void sCPU::nmitimen_update(uint8 data) { bool nmi_enabled = status.nmi_enabled; bool virq_enabled = status.virq_enabled; bool hirq_enabled = status.hirq_enabled; - status.nmi_enabled = !!(data & 0x80); - status.virq_enabled = !!(data & 0x20); - status.hirq_enabled = !!(data & 0x10); + status.nmi_enabled = data & 0x80; + status.virq_enabled = data & 0x20; + status.hirq_enabled = data & 0x10; //0->1 edge sensitive transition - if(nmi_enabled == false && status.nmi_enabled == true && status.nmi_line == true) { + if(!nmi_enabled && status.nmi_enabled && status.nmi_line) { status.nmi_transition = true; } //?->1 level sensitive transition - if(status.virq_enabled == true && status.hirq_enabled == false && status.irq_line == true) { + if(status.virq_enabled && !status.hirq_enabled && status.irq_line) { status.irq_transition = true; } - if(status.virq_enabled == false && status.hirq_enabled == false) { + if(!status.virq_enabled && !status.hirq_enabled) { status.irq_line = false; status.irq_transition = false; } - update_interrupts(); status.irq_lock = true; - delta.enqueue(EventIrqLockRelease, 2); -} - -void sCPU::hvtime_update(uint16 addr) { - update_interrupts(); + event.enqueue(2, EventIrqLockRelease); } bool sCPU::rdnmi() { bool result = status.nmi_line; - if(status.nmi_hold == 0) { + if(!status.nmi_hold) { status.nmi_line = false; } return result; @@ -106,25 +83,25 @@ bool sCPU::rdnmi() { bool sCPU::timeup() { bool result = status.irq_line; - if(status.irq_hold == 0) { + if(!status.irq_hold) { status.irq_line = false; status.irq_transition = false; } return result; } -alwaysinline bool sCPU::nmi_test() { - if(status.nmi_transition == false) return false; +bool sCPU::nmi_test() { + if(!status.nmi_transition) return false; status.nmi_transition = false; - event.wai = false; + status.wai_lock = false; return true; } -alwaysinline bool sCPU::irq_test() { - if(status.irq_transition == false) return false; +bool sCPU::irq_test() { + if(!status.irq_transition) return false; status.irq_transition = false; - event.wai = false; + status.wai_lock = false; return !regs.p.i; } -#endif //ifdef SCPU_CPP +#endif diff --git a/src/cpu/scpu/timing/joypad.cpp b/src/cpu/scpu/timing/joypad.cpp index 34b9e772..c754c4dc 100644 --- a/src/cpu/scpu/timing/joypad.cpp +++ b/src/cpu/scpu/timing/joypad.cpp @@ -25,4 +25,4 @@ void sCPU::run_auto_joypad_poll() { status.joy4h = joy4 >> 8; } -#endif //ifdef SCPU_CPP +#endif diff --git a/src/cpu/scpu/timing/timing.cpp b/src/cpu/scpu/timing/timing.cpp index c47db9a9..c43ed5fd 100644 --- a/src/cpu/scpu/timing/timing.cpp +++ b/src/cpu/scpu/timing/timing.cpp @@ -9,14 +9,16 @@ unsigned sCPU::dma_counter() { } void sCPU::add_clocks(unsigned clocks) { - delta.tick(clocks); + event.tick(clocks); unsigned ticks = clocks >> 1; while(ticks--) { ppu.tick(); - snes.input.tick(); - poll_interrupts(); + if((ppu.hcounter() & 2) == 0) { + snes.input.tick(); + } else { + poll_interrupts(); + } } - scheduler.addclocks_cpu(clocks); } @@ -26,20 +28,18 @@ void sCPU::scanline() { if(ppu.vcounter() == 0) { //hdma init triggers once every frame - delta.enqueue(EventHdmaInit, cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter()); + event.enqueue(cpu_version == 1 ? 12 + 8 - dma_counter() : 12 + dma_counter(), EventHdmaInit); } //dram refresh occurs once every scanline if(cpu_version == 2) status.dram_refresh_position = 530 + 8 - dma_counter(); - delta.enqueue(EventDramRefresh, status.dram_refresh_position); + event.enqueue(status.dram_refresh_position, EventDramRefresh); //hdma triggers once every visible scanline if(ppu.vcounter() <= (ppu.overscan() == false ? 224 : 239)) { - delta.enqueue(EventHdmaRun, 1104); + event.enqueue(1104, EventHdmaRun); } - update_interrupts(); - if(status.auto_joypad_poll == true && ppu.vcounter() == (ppu.overscan() == false ? 227 : 242)) { snes.input.poll(); run_auto_joypad_poll(); @@ -56,8 +56,8 @@ void sCPU::precycle_edge() { //used to test for H/DMA, which can trigger on the edge of every opcode cycle. void sCPU::cycle_edge() { - while(event.cycle_edge) { - switch(event.cycle_edge & -event.cycle_edge) { //switch on lowest bit (flag) set + while(cycle_edge_state) { + switch(bit::lowest(cycle_edge_state)) { case EventFlagHdmaInit: { hdma_init_reset(); if(hdma_enabled_channels()) { @@ -74,7 +74,7 @@ void sCPU::cycle_edge() { } break; } - event.cycle_edge &= event.cycle_edge - 1; //clear lowest bit set + cycle_edge_state = bit::clear_lowest(cycle_edge_state); } //H/DMA pending && DMA inactive? @@ -119,43 +119,39 @@ void sCPU::cycle_edge() { //status.irq_lock is used to simulate hardware delay before interrupts can //trigger during certain events (immediately after DMA, writes to $4200, etc) void sCPU::last_cycle() { - if(status.irq_lock) return; + if(!status.irq_lock) { + status.nmi_pending |= nmi_test(); + status.irq_pending |= irq_test(); - status.nmi_pending |= nmi_test(); - status.irq_pending |= irq_test(); - - event.irq = (status.nmi_pending || status.irq_pending); + status.interrupt_pending = (status.nmi_pending || status.irq_pending); + } } void sCPU::timing_power() { } void sCPU::timing_reset() { - delta.reset(); - - temp_.alu_mul_delay = config::temp.alu_mul_delay; - temp_.alu_div_delay = config::temp.alu_div_delay; + event.reset(); status.clock_count = 0; status.line_clocks = ppu.lineclocks(); status.irq_lock = false; status.alu_lock = false; - status.dram_refresh_position = (cpu_version == 1) ? 530 : 538; + status.dram_refresh_position = (cpu_version == 1 ? 530 : 538); + event.enqueue(status.dram_refresh_position, EventDramRefresh); status.nmi_valid = false; status.nmi_line = false; status.nmi_transition = false; status.nmi_pending = false; - status.nmi_hold = 0; + status.nmi_hold = false; status.irq_valid = false; status.irq_line = false; status.irq_transition = false; status.irq_pending = false; - status.irq_hold = 0; - - update_interrupts(); + status.irq_hold = false; status.dma_counter = 0; status.dma_clocks = 0; @@ -164,9 +160,7 @@ void sCPU::timing_reset() { status.hdma_mode = 0; status.dma_state = DmaInactive; - event.cycle_edge = 0; + cycle_edge_state = 0; } -#undef ntsc_color_burst_phase_shift_scanline - -#endif //ifdef SCPU_CPP +#endif diff --git a/src/cpu/scpu/timing/timing.hpp b/src/cpu/scpu/timing/timing.hpp index b46d2ddb..092e7f07 100644 --- a/src/cpu/scpu/timing/timing.hpp +++ b/src/cpu/scpu/timing/timing.hpp @@ -10,6 +10,7 @@ EventFlagHdmaInit = 1 << 0, EventFlagHdmaRun = 1 << 1, }; + unsigned cycle_edge_state; //timing.cpp unsigned dma_counter(); @@ -25,18 +26,16 @@ void timing_reset(); //irq.cpp - void update_interrupts(); - void poll_interrupts(); + alwaysinline void poll_interrupts(); void nmitimen_update(uint8 data); - void hvtime_update(uint16 addr); bool rdnmi(); bool timeup(); - bool nmi_test(); - bool irq_test(); + alwaysinline bool nmi_test(); + alwaysinline bool irq_test(); //joypad.cpp void run_auto_joypad_poll(); //event.cpp - void queue_event(unsigned); //deltaqueue callback function + void queue_event(unsigned); //priorityqueue callback function diff --git a/src/data/bsnes.ico b/src/data/bsnes.ico index 646d8c5f..54acded4 100644 Binary files a/src/data/bsnes.ico and b/src/data/bsnes.ico differ diff --git a/src/data/controller.h b/src/data/controller.h index 1cbe2108..90b12068 100644 --- a/src/data/controller.h +++ b/src/data/controller.h @@ -1,3 +1,7 @@ +#if defined(_MSC_VER) +//TODO: Visual C++ cannot handle strings > 65536 bytes. Need to find workaround. +static char enc_controller[65536 * 2] = { 0 }; +#else static char enc_controller[] = { "_v8B8AHwAfAB8AHwAfAB8P8B8AHwAfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHw" "AfB_AfAB8AHwAfAB8AHwAeD9AP396OjomJiZAHBwcG5ubmpqAGpYWFhLS0tBAEFB" @@ -1032,3 +1036,4 @@ static char enc_controller[] = { "AfAB8AHwAfAB8AHw_wHwAfAB8AHwAfAB8AHwAfD_AfAB8AHwAfAB8AHwAfAB8P9G" "8kbyRvJG8kbyRvJG8kby_0byqPAB8AHwAfAB8AHwAfAPAfAB8AHwATA" }; +#endif diff --git a/src/interface.hpp b/src/interface.hpp index d6193203..09b75fff 100644 --- a/src/interface.hpp +++ b/src/interface.hpp @@ -1,24 +1,20 @@ -#include "reader/reader.hpp" #include "cheat/cheat.hpp" -#include "config/config.hpp" #include "memory/memory.hpp" #include "memory/smemory/smemory.hpp" -#include "cart/cart.hpp" - #include "cpu/cpu.hpp" #include "cpu/scpu/scpu.hpp" +#include "ppu/ppu.hpp" +#include "ppu/bppu/bppu.hpp" + #include "smp/smp.hpp" #include "smp/ssmp/ssmp.hpp" #include "dsp/dsp.hpp" #include "dsp/sdsp/sdsp.hpp" -#include "ppu/ppu.hpp" -#include "ppu/bppu/bppu.hpp" - extern BUSCORE bus; extern CPUCORE cpu; extern SMPCORE smp; @@ -26,4 +22,3 @@ extern DSPCORE dsp; extern PPUCORE ppu; #include "snes/snes.hpp" -#include "chip/chip.hpp" diff --git a/src/lib/hiro/win/editbox.cpp b/src/lib/hiro/win/editbox.cpp index da7373d3..6949e7bc 100644 --- a/src/lib/hiro/win/editbox.cpp +++ b/src/lib/hiro/win/editbox.cpp @@ -8,6 +8,8 @@ void pEditbox::create(unsigned style, unsigned width, unsigned height, const cha (style & Editbox::HorizontalScrollNever ) ? 0 : ES_AUTOHSCROLL; + autovscroll = (vscroll == ES_AUTOVSCROLL); + hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"", WS_CHILD | WS_VISIBLE | vscroll | hscroll | (multiline == true ? ES_MULTILINE | ES_WANTRETURN : WS_TABSTOP) | @@ -16,6 +18,12 @@ void pEditbox::create(unsigned style, unsigned width, unsigned height, const cha phiro().default_hwnd, (HMENU)instance, GetModuleHandle(0), 0); SendMessage(hwnd, WM_SETFONT, (WPARAM)phiro().default_font, 0); set_text(text); + update(); +} + +void pEditbox::resize(unsigned width, unsigned height) { + pFormControl::resize(width, height); + update(); } void pEditbox::set_text(const char *text) { @@ -23,6 +31,7 @@ void pEditbox::set_text(const char *text) { replace(temp, "\r", ""); replace(temp, "\n", "\r\n"); SetWindowText(hwnd, utf16(temp)); + update(); } unsigned pEditbox::get_text(char *text, unsigned length) { @@ -36,4 +45,40 @@ unsigned pEditbox::get_text(char *text, unsigned length) { } pEditbox::pEditbox(Editbox &self_) : pFormControl(self_), self(self_) { + autovscroll = false; +} + +//======== +//internal +//======== + +//WS_VSCROLL always shows the scrollbar; +//ES_AUTOVSCROLL never shows the scrollbar but allows unlimited text; +//no style disallows more text than what fits in the window. +// +//below routine simulates the effect of allowing unlimited text, but only +//showing the scrollbar when it is needed. not sure how to simulate this effect +//for horizontal scrolling at this time. +// +//below routine should be called whenever the font, text or window size is +//modified. +void pEditbox::update() { + if(autovscroll == true) { + //determine how many lines of text this control allows + RECT rect; + SendMessage(hwnd, EM_GETRECT, 0, (LPARAM)&rect); + unsigned height = rect.bottom - rect.top; + + //determine the height of a single line of text + HDC hdc = GetDC(hwnd); + SelectObject(hdc, phiro().default_font); + DrawText(hdc, L"byuu", -1, &rect, DT_CALCRECT); + ReleaseDC(hwnd, hdc); + unsigned lineheight = rect.bottom - rect.top; + + //only show the scrollbar when there are more lines of text + //than the control can show at once. + unsigned linecount = SendMessage(hwnd, EM_GETLINECOUNT, 0, 0); + ShowScrollBar(hwnd, SB_VERT, linecount > (height / lineheight)); + } } diff --git a/src/lib/hiro/win/editbox.hpp b/src/lib/hiro/win/editbox.hpp index 075d47f8..512091fb 100644 --- a/src/lib/hiro/win/editbox.hpp +++ b/src/lib/hiro/win/editbox.hpp @@ -2,8 +2,13 @@ class pEditbox : public pFormControl { public: Editbox &self; void create(unsigned style, unsigned width, unsigned height, const char *text = ""); + void resize(unsigned width, unsigned height); unsigned get_text(char *text, unsigned length = -1U); void set_text(const char *text = ""); pEditbox(Editbox&); + +//private: + bool autovscroll; + void update(); }; diff --git a/src/lib/hiro/win/hiro.cpp b/src/lib/hiro/win/hiro.cpp index 2a361409..6a28643e 100644 --- a/src/lib/hiro/win/hiro.cpp +++ b/src/lib/hiro/win/hiro.cpp @@ -232,7 +232,7 @@ pHiro& phiro() { HFONT pHiro::create_font(const char *name, unsigned size) { return CreateFont( - -(size * 96.0 / 72.0 + 0.5), //96 = DPI + -(size * 96.0 / 72.0 + 0.5), //96 = DPI 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, utf16(name) ); @@ -375,6 +375,7 @@ LRESULT pHiro::wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { case Widget::EditboxType: { Editbox &editbox = (Editbox&)*widget; if(HIWORD(wparam) == EN_CHANGE) { + editbox.p.update(); //called to dynamically display vertical scrollbar if needed if(editbox.on_change) editbox.on_change(event_t(event_t::Change, 0, &editbox)); } } break; diff --git a/src/lib/hiro/win/hiro.hpp b/src/lib/hiro/win/hiro.hpp index 16ab6d6c..7461d695 100644 --- a/src/lib/hiro/win/hiro.hpp +++ b/src/lib/hiro/win/hiro.hpp @@ -13,12 +13,14 @@ #define NOMINMAX #define _NO_OLDNAMES +#define mkdir _mkdir #define UNICODE #include #include #include #include #include +#undef mkdir #include using nall::min; diff --git a/src/lib/libfilter/ntsc.hpp b/src/lib/libfilter/ntsc.hpp index 953f4885..496e791e 100644 --- a/src/lib/libfilter/ntsc.hpp +++ b/src/lib/libfilter/ntsc.hpp @@ -3,6 +3,7 @@ class NTSCFilter : public Filter { public: void render(uint32_t*, unsigned, unsigned&, unsigned&, uint16_t*, unsigned, unsigned*, unsigned, unsigned); + void adjust(float hue, float saturation, float contrast, float brightness, float sharpness, bool merge_fields); NTSCFilter(); ~NTSCFilter(); @@ -10,8 +11,6 @@ public: private: struct snes_ntsc_t *ntsc; int burst, burst_toggle; - - void adjust(float hue, float saturation, float contrast, float brightness, float sharpness, bool merge_fields); }; extern NTSCFilter filter_ntsc; diff --git a/src/lib/nall/algorithm.hpp b/src/lib/nall/algorithm.hpp index bce2f70a..98b39528 100644 --- a/src/lib/nall/algorithm.hpp +++ b/src/lib/nall/algorithm.hpp @@ -1,27 +1,23 @@ #ifndef NALL_ALGORITHM_HPP #define NALL_ALGORITHM_HPP -namespace nall { - #undef min #undef max -template -T min(const T& t, const U& u) { - return t < u ? t : u; +namespace nall { + template T min(const T& t, const U& u) { + return t < u ? t : u; + } + + template T max(const T& t, const U& u) { + return t > u ? t : u; + } + + //pseudo-random number generator + inline unsigned prng() { + static unsigned n = 0; + return n = (n >> 1) ^ (((n & 1) - 1) & 0xedb88320); + } } -template -T max(const T& t, const U& u) { - return t > u ? t : u; -} - -//pseudo-random number generator -inline unsigned prng() { - static unsigned n = 0; - return n = (n >> 1) ^ (((n & 1) - 1) & 0xedb88320); -} - -} //namespace nall - -#endif //ifndef NALL_ALGORITHM_HPP +#endif diff --git a/src/lib/nall/any.hpp b/src/lib/nall/any.hpp index a4417e00..9689af13 100644 --- a/src/lib/nall/any.hpp +++ b/src/lib/nall/any.hpp @@ -6,71 +6,69 @@ #include namespace nall { + class any { + public: + bool empty() const { return container; } + const std::type_info& type() const { return container ? container->type() : typeid(void); } -class any { -public: - bool empty() const { return container; } - const std::type_info& type() const { return container ? container->type() : typeid(void); } + template any& operator=(const T& value_) { + typedef typename static_if< + is_array::value, + typename remove_extent::type>::type*, + T + >::type auto_t; - template any& operator=(const T& value_) { - typedef typename static_if< - is_array::value, - typename remove_extent::type>::type*, - T - >::type auto_t; + if(type() == typeid(auto_t)) { + static_cast*>(container)->value = (auto_t)value_; + } else { + if(container) delete container; + container = new holder((auto_t)value_); + } - if(type() == typeid(auto_t)) { - static_cast*>(container)->value = (auto_t)value_; - } else { - if(container) delete container; - container = new holder((auto_t)value_); + return *this; } - return *this; - } + any() : container(0) {} + template any(const T& value_) : container(0) { operator=(value_); } - any() : container(0) {} - template any(const T& value_) : container(0) { operator=(value_); } + private: + struct placeholder { + virtual const std::type_info& type() const = 0; + } *container; -private: - struct placeholder { - virtual const std::type_info& type() const = 0; - } *container; + template struct holder : placeholder { + T value; + const std::type_info& type() const { return typeid(T); } + holder(const T& value_) : value(value_) {} + }; - template struct holder : placeholder { - T value; - const std::type_info& type() const { return typeid(T); } - holder(const T& value_) : value(value_) {} + template friend T any_cast(any&); + template friend T any_cast(const any&); + template friend T* any_cast(any*); + template friend const T* any_cast(const any*); }; - template friend T any_cast(any&); - template friend T any_cast(const any&); - template friend T* any_cast(any*); - template friend const T* any_cast(const any*); -}; + template T any_cast(any &value) { + typedef typename remove_reference::type nonref; + if(value.type() != typeid(nonref)) throw; + return static_cast*>(value.container)->value; + } -template T any_cast(any &value) { - typedef typename remove_reference::type nonref; - if(value.type() != typeid(nonref)) throw; - return static_cast*>(value.container)->value; + template T any_cast(const any &value) { + typedef const typename remove_reference::type nonref; + if(value.type() != typeid(nonref)) throw; + return static_cast*>(value.container)->value; + } + + template T* any_cast(any *value) { + if(!value || value->type() != typeid(T)) return 0; + return &static_cast*>(value->container)->value; + } + + template const T* any_cast(const any *value) { + if(!value || value->type() != typeid(T)) return 0; + return &static_cast*>(value->container)->value; + } } -template T any_cast(const any &value) { - typedef const typename remove_reference::type nonref; - if(value.type() != typeid(nonref)) throw; - return static_cast*>(value.container)->value; -} - -template T* any_cast(any *value) { - if(!value || value->type() != typeid(T)) return 0; - return &static_cast*>(value->container)->value; -} - -template const T* any_cast(const any *value) { - if(!value || value->type() != typeid(T)) return 0; - return &static_cast*>(value->container)->value; -} - -} //namespace nall - -#endif //ifndef NALL_ANY_HPP +#endif diff --git a/src/lib/nall/array.hpp b/src/lib/nall/array.hpp index 0b733d2f..d2f1947d 100644 --- a/src/lib/nall/array.hpp +++ b/src/lib/nall/array.hpp @@ -3,92 +3,87 @@ #include #include +#include namespace nall { + //dynamic vector array + //neither constructor nor destructor is ever invoked; + //thus, this should only be used for POD objects. + template class array { + protected: + T *pool; + unsigned poolsize, buffersize; -//dynamic vector array -//neither constructor nor destructor is ever invoked; -//this this should only be used for POD objects. + public: + unsigned size() const { return buffersize; } + unsigned capacity() const { return poolsize; } -template class array { -protected: - T *pool; - unsigned poolsize, buffersize; + void reset() { + if(pool) free(pool); + pool = 0; + poolsize = 0; + buffersize = 0; + } - unsigned findsize(unsigned size) const { - if(size <= 0x100) return 0x100; - if(size <= 0x400) return 0x400; - if(size <= 0x1000) return 0x1000; - if(size <= 0x4000) return 0x4000; - if(size <= 0x10000) return 0x10000; - if(size <= 0x40000) return 0x40000; - if(size <= 0x100000) return 0x100000; + void reserve(unsigned newsize) { + if(newsize == poolsize) return; - return (size + 0x100000) & ~0xfffff; - } + pool = (T*)realloc(pool, newsize * sizeof(T)); + poolsize = newsize; + buffersize = min(buffersize, newsize); + } -public: - unsigned size() const { return buffersize; } - unsigned capacity() const { return poolsize; } + void resize(unsigned newsize) { + if(newsize > poolsize) reserve(bit::round(newsize)); //round reserve size up to power of 2 + buffersize = newsize; + } - void reset() { - if(pool) free(pool); - pool = 0; - poolsize = 0; - buffersize = 0; - } + T* get(unsigned minsize = 0) { + if(minsize > buffersize) resize(minsize); + if(minsize > buffersize) throw "array[] out of bounds"; + return pool; + } - void reserve(unsigned newsize) { - if(newsize == poolsize) return; + void add(const T data) { + operator[](buffersize) = data; + } - pool = (T*)realloc(pool, newsize * sizeof(T)); - poolsize = newsize; - buffersize = min(buffersize, newsize); - } + void clear() { + memset(pool, 0, buffersize * sizeof(T)); + } - void resize(unsigned newsize) { - if(newsize > poolsize) reserve(findsize(newsize)); - buffersize = newsize; - } + array() { + pool = 0; + poolsize = 0; + buffersize = 0; + } - T* get(unsigned minsize = 0) { - if(minsize > buffersize) resize(minsize); - if(minsize > buffersize) throw "array[] out of bounds"; - return pool; - } + ~array() { reset(); } - void add(const T data) { operator[](buffersize) = data; } - void clear() { memset(pool, 0, buffersize * sizeof(T)); } + array(const array &source) : pool(0) { + operator=(source); + } - array() { - pool = 0; - poolsize = 0; - buffersize = 0; - } + array& operator=(const array &source) { + if(pool) free(pool); + buffersize = source.buffersize; + poolsize = source.poolsize; + pool = (T*)malloc(sizeof(T) * poolsize); //allocate entire pool size, + memcpy(pool, source.pool, sizeof(T) * buffersize); //... but only copy used pool objects + return *this; + } - ~array() { reset(); } + inline T& operator[](unsigned index) { + if(index >= buffersize) resize(index + 1); + if(index >= buffersize) throw "array[] out of bounds"; + return pool[index]; + } - array& operator=(const array &source) { - if(pool) free(pool); - buffersize = source.buffersize; - poolsize = source.poolsize; - pool = (T*)realloc(pool, sizeof(T) * poolsize); //allocate entire pool size, - memcpy(pool, source.pool, sizeof(T) * buffersize); //... but only copy used pool objects - return *this; - } + inline const T& operator[](unsigned index) const { + if(index >= buffersize) throw "array[] out of bounds"; + return pool[index]; + } + }; +} - inline T& operator[](unsigned index) { - if(index >= buffersize) resize(index + 1); - if(index >= buffersize) throw "array[] out of bounds"; - return pool[index]; - } - - inline const T& operator[](unsigned index) const { - if(index >= buffersize) throw "array[] out of bounds"; - return pool[index]; - } -}; - -} //namespace nall - -#endif //ifndef NALL_ARRAY_HPP +#endif diff --git a/src/lib/nall/base64.hpp b/src/lib/nall/base64.hpp index a4f3d07e..8b107b20 100644 --- a/src/lib/nall/base64.hpp +++ b/src/lib/nall/base64.hpp @@ -1,94 +1,92 @@ #ifndef NALL_BASE64_HPP #define NALL_BASE64_HPP +#include + #include #include -#include - namespace nall { + class base64 { + public: + static bool encode(char *&output, const uint8_t* input, unsigned inlength) { + output = new(zeromemory) char[inlength * 8 / 6 + 6]; -class base64 { -public: - static bool encode(char *&output, const uint8_t* input, unsigned inlength) { - output = new(zeromemory) char[inlength * 8 / 6 + 6]; + unsigned i = 0, o = 0; + while(i < inlength) { + switch(i % 3) { + case 0: { + output[o++] = enc(input[i] >> 2); + output[o] = enc((input[i] & 3) << 4); + } break; - unsigned i = 0, o = 0; - while(i < inlength) { - switch(i % 3) { - case 0: { - output[o++] = enc(input[i] >> 2); - output[o] = enc((input[i] & 3) << 4); - } break; + case 1: { + uint8_t prev = dec(output[o]); + output[o++] = enc(prev + (input[i] >> 4)); + output[o] = enc((input[i] & 15) << 2); + } break; - case 1: { - uint8_t prev = dec(output[o]); - output[o++] = enc(prev + (input[i] >> 4)); - output[o] = enc((input[i] & 15) << 2); - } break; + case 2: { + uint8_t prev = dec(output[o]); + output[o++] = enc(prev + (input[i] >> 6)); + output[o++] = enc(input[i] & 63); + } break; + } - case 2: { - uint8_t prev = dec(output[o]); - output[o++] = enc(prev + (input[i] >> 6)); - output[o++] = enc(input[i] & 63); - } break; + i++; } - i++; + return true; } - return true; - } + static bool decode(uint8_t *&output, unsigned &outlength, const char *input) { + unsigned inlength = strlen(input), infix = 0; + output = new(zeromemory) uint8_t[inlength]; - static bool decode(uint8_t *&output, unsigned &outlength, const char *input) { - unsigned inlength = strlen(input), infix = 0; - output = new(zeromemory) uint8_t[inlength]; + unsigned i = 0, o = 0; + while(i < inlength) { + uint8_t x = dec(input[i]); - unsigned i = 0, o = 0; - while(i < inlength) { - uint8_t x = dec(input[i]); + switch(i++ & 3) { + case 0: { + output[o] = x << 2; + } break; - switch(i++ & 3) { - case 0: { - output[o] = x << 2; - } break; + case 1: { + output[o++] |= x >> 4; + output[o] = (x & 15) << 4; + } break; - case 1: { - output[o++] |= x >> 4; - output[o] = (x & 15) << 4; - } break; + case 2: { + output[o++] |= x >> 2; + output[o] = (x & 3) << 6; + } break; - case 2: { - output[o++] |= x >> 2; - output[o] = (x & 3) << 6; - } break; - - case 3: { - output[o++] |= x; - } break; + case 3: { + output[o++] |= x; + } break; + } } + + outlength = o; + return true; } - outlength = o; - return true; - } + private: + static char enc(uint8_t n) { + static char lookup_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + return lookup_table[n & 63]; + } -private: - static char enc(uint8_t n) { - static char lookup_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; - return lookup_table[n & 63]; - } + static uint8_t dec(char n) { + if(n >= 'A' && n <= 'Z') return n - 'A'; + if(n >= 'a' && n <= 'z') return n - 'a' + 26; + if(n >= '0' && n <= '9') return n - '0' + 52; + if(n == '-') return 62; + if(n == '_') return 63; + return 0; + } + }; +} - static uint8_t dec(char n) { - if(n >= 'A' && n <= 'Z') return n - 'A'; - if(n >= 'a' && n <= 'z') return n - 'a' + 26; - if(n >= '0' && n <= '9') return n - '0' + 52; - if(n == '-') return 62; - if(n == '_') return 63; - return 0; - } -}; - -} //namespace nall - -#endif //ifndef NALL_BASE64_HPP +#endif diff --git a/src/lib/nall/bit.hpp b/src/lib/nall/bit.hpp index d6c0cbbc..169fc144 100644 --- a/src/lib/nall/bit.hpp +++ b/src/lib/nall/bit.hpp @@ -2,27 +2,50 @@ #define NALL_BIT_HPP namespace nall { + template inline unsigned uclamp(const unsigned x) { + enum { y = (1U << bits) - 1 }; + return y + ((x - y) & -(x < y)); //min(x, y); + } -template inline unsigned uclamp(const unsigned x) { - enum { y = (1U << bits) - 1 }; - return y + ((x - y) & -(x < y)); //min(x, y); + template inline unsigned uclip(const unsigned x) { + enum { m = (1U << bits) - 1 }; + return (x & m); + } + + template inline signed sclamp(const signed x) { + enum { b = 1U << (bits - 1), m = (1U << (bits - 1)) - 1 }; + return (x > m) ? m : (x < -b) ? -b : x; + } + + template inline signed sclip(const signed x) { + enum { b = 1U << (bits - 1), m = (1U << bits) - 1 }; + return ((x & m) ^ b) - b; + } + + namespace bit { + //lowest(0b1110) == 0b0010 + template inline T lowest(const T x) { + return x & -x; + } + + //clear_lowest(0b1110) == 0b1100 + template inline T clear_lowest(const T x) { + return x & (x - 1); + } + + //set_lowest(0b0101) == 0b0111 + template inline T set_lowest(const T x) { + return x | (x + 1); + } + + //round up to next highest single bit: + //round(15) == 16, round(16) == 16, round(17) == 32 + inline unsigned round(unsigned x) { + if((x & (x - 1)) == 0) return x; + while(x & (x - 1)) x &= x - 1; + return x << 1; + } + } } -template inline unsigned uclip(const unsigned x) { - enum { m = (1U << bits) - 1 }; - return (x & m); -} - -template inline signed sclamp(const signed x) { - enum { b = 1U << (bits - 1), m = (1U << (bits - 1)) - 1 }; - return (x > m) ? m : (x < -b) ? -b : x; -} - -template inline signed sclip(const signed x) { - enum { b = 1U << (bits - 1), m = (1U << bits) - 1 }; - return ((x & m) ^ b) - b; -} - -} //namespace nall - -#endif //ifndef NALL_BIT_HPP +#endif diff --git a/src/lib/nall/config.hpp b/src/lib/nall/config.hpp index 686336e9..0dde4a15 100644 --- a/src/lib/nall/config.hpp +++ b/src/lib/nall/config.hpp @@ -1,178 +1,114 @@ -#ifndef NALL_CONFIG_HPP -#define NALL_CONFIG_HPP - -#include -#include -#include -#include - -namespace nall { - -class setting; - -class configuration { -public: - array list; - - bool load(const char *fn); - bool save(const char *fn) const; - void add(setting *setting_) { list.add(setting_); } -}; - -class setting { -public: - enum setting_type { - integral_type, - string_type, - } type; - - const char *name; - const char *description; - - virtual void set(const char *input) = 0; - virtual void get(string &output) const = 0; - virtual void get_default(string &output) const = 0; -}; - -class integral_setting : public setting { -public: - enum integral_type { - boolean, - decimal, - hex, - } type; - - intmax_t value; - intmax_t default_value; - - void set(const char *input) { - if(type == boolean) { value = !strcmp(input, "true"); } - if(type == decimal) { value = strdec(input); } - if(type == hex) { value = strhex(input); } - } - - void get(string &output) const { - if(type == boolean) { output = value ? "true" : "false"; } - if(type == decimal) { output = strdec(value); } - if(type == hex) { output = string() << "0x" << strhex(value); } - } - - void get_default(string &output) const { - if(type == boolean) { output = default_value ? "true" : "false"; } - if(type == decimal) { output = strdec(default_value); } - if(type == hex) { output = string() << "0x" << strhex(default_value); } - } - - operator intmax_t() const { return value; } - integral_setting& operator=(intmax_t value_) { value = value_; return *this; } - - integral_setting(const char *name_, const char *description_, integral_type type_, intmax_t value_) { - initialize(name_, description_, type_, value_); - } - - integral_setting(configuration &parent, const char *name_, const char *description_, integral_type type_, intmax_t value_) { - initialize(name_, description_, type_, value_); - parent.add(this); - } - -private: - void initialize(const char *name_, const char *description_, integral_type type_, intmax_t value_) { - setting::type = setting::integral_type; - name = name_; - description = description_; - type = type_; - value = default_value = value_; - } -}; - -class string_setting : public setting { -public: - string value; - string default_value; - - void set(const char *input) { value = input; trim(value(), "\""); } - void get(string &output) const { output = string() << "\"" << value << "\""; } - void get_default(string &output) const { output = string() << "\"" << default_value << "\""; } - - operator const char*() const { return value; } - string_setting& operator=(const char *value_) { value = value_; return *this; } - bool operator==(const char *value_) const { return value == value_; } - bool operator!=(const char *value_) const { return value != value_; } - - string_setting(const char *name_, const char *description_, const char *value_) { - initialize(name_, description_, value_); - } - - string_setting(configuration &parent, const char *name_, const char *description_, const char *value_) { - initialize(name_, description_, value_); - parent.add(this); - } - -private: - void initialize(const char *name_, const char *description_, const char *value_) { - setting::type = setting::string_type; - name = name_; - description = description_; - value = default_value = value_; - } -}; - -inline bool configuration::load(const char *fn) { - //load the config file into memory - string data; - if(!fread(data, fn)) return false; - - //split the file into lines - replace(data, "\r\n", "\n"); - qreplace(data, "\t", ""); - qreplace(data, " ", ""); - - lstring line, part, subpart; - split(line, "\n", data); - - for(unsigned i = 0; i < count(line); i++) { - if(strlen(line[i]) == 0) continue; - if(strbegin(line[i], "#")) continue; - - qsplit(part, "=", line[i]); - for(unsigned l = 0; l < list.size(); l++) { - if(part[0] == list[l]->name) { - list[l]->set(part[1]); - break; - } - } - } - - return true; -} - -inline bool configuration::save(const char *fn) const { - file fp; - if(!fp.open(fn, file::mode_write)) return false; - - for(unsigned i = 0; i < list.size(); i++) { - string data; - lstring line, part, subpart; - strcpy(data, list[i]->description); - replace(data, "\r\n", "\n"); - split(line, "\n", data); - - string temp; - for(unsigned l = 0; l < count(line); l++) { - if(line[l] != "") fp.print(string() << "# " << line[l] << "\r\n"); - } - - string default_, value_; - list[i]->get_default(default_); - fp.print(string() << "# (default = " << default_ << ")\r\n"); - list[i]->get(value_); - fp.print(string() << list[i]->name << " = " << value_ << "\r\n\r\n"); - } - - fp.close(); - return true; -} - -} //namespace nall - -#endif //ifndef NALL_CONFIG_HPP +#ifndef NALL_CONFIG_HPP +#define NALL_CONFIG_HPP + +#include +#include +#include + +namespace nall { + namespace configuration_traits { + template struct is_boolean { enum { value = false }; }; + template<> struct is_boolean { enum { value = true }; }; + + template struct is_signed { enum { value = false }; }; + template<> struct is_signed { enum { value = true }; }; + + template struct is_unsigned { enum { value = false }; }; + template<> struct is_unsigned { enum { value = true }; }; + + template struct is_string { enum { value = false }; }; + template<> struct is_string { enum { value = true }; }; + } + + class configuration { + public: + enum type_t { boolean_t, signed_t, unsigned_t, string_t, unknown_t }; + struct item_t { + uintptr_t data; + string name; + string desc; + type_t type; + + string get() { + switch(type) { + case boolean_t: return (*(bool*)data == false ? "false" : "true"); + case signed_t: return string() << (int)*(signed*)data; + case unsigned_t: return string() << (int)*(unsigned*)data; + case string_t: return string() << "\"" << *(string*)data << "\""; + } + return "???"; + } + + void set(string s) { + switch(type) { + case boolean_t: *(bool*)data = (s == "true"); break; + case signed_t: *(signed*)data = s; break; + case unsigned_t: *(unsigned*)data = s; break; + case string_t: trim(s, "\""); *(string*)data = s; break; + } + } + }; + vector list; + + template + void attach(T &data, const char *name, const char *desc = "") { + unsigned n = list.size(); + list[n].data = (uintptr_t)&data; + list[n].name = name; + list[n].desc = desc; + + if(configuration_traits::is_boolean::value) list[n].type = boolean_t; + else if(configuration_traits::is_signed::value) list[n].type = signed_t; + else if(configuration_traits::is_unsigned::value) list[n].type = unsigned_t; + else if(configuration_traits::is_string::value) list[n].type = string_t; + else list[n].type = unknown_t; + } + + bool load(const char *filename) { + string data; + if(fread(data, filename) == true) { + replace(data, "\r", ""); + lstring line; + split(line, "\n", data); + + for(unsigned i = 0; i < count(line); i++) { + int position = qstrpos(line[i], "#"); + if(position >= 0) line[i][position] = 0; + if(qstrpos(line[i], " = ") < 0) continue; + + lstring part; + qsplit(part, " = ", line[i]); + trim(part[0]); + trim(part[1]); + + for(unsigned n = 0; n < list.size(); n++) { + if(part[0] == list[n].name) { + list[n].set(part[1]); + break; + } + } + } + + return true; + } else { + return false; + } + } + + bool save(const char *filename) { + file fp; + if(fp.open(filename, file::mode_write)) { + for(unsigned i = 0; i < list.size(); i++) { + fp.print(string() << list[i].name << " = " << list[i].get() << " # " << list[i].desc << "\r\n"); + } + + fp.close(); + return true; + } else { + return false; + } + } + }; +} + +#endif diff --git a/src/lib/nall/config.txt b/src/lib/nall/config.txt new file mode 100644 index 00000000..a59bc1c9 --- /dev/null +++ b/src/lib/nall/config.txt @@ -0,0 +1,176 @@ +#ifndef NALL_CONFIG_HPP +#define NALL_CONFIG_HPP + +#include +#include +#include +#include + +namespace nall { + class setting; + + class configuration { + public: + array list; + + bool load(const char *fn); + bool save(const char *fn) const; + void add(setting *setting_) { list.add(setting_); } + }; + + class setting { + public: + enum setting_type { + integral_type, + string_type, + } type; + + const char *name; + const char *description; + + virtual void set(const char *input) = 0; + virtual void get(string &output) const = 0; + virtual void get_default(string &output) const = 0; + }; + + class integral_setting : public setting { + public: + enum integral_type { + boolean, + decimal, + hex, + } type; + + intmax_t value; + intmax_t default_value; + + void set(const char *input) { + if(type == boolean) { value = !strcmp(input, "true"); } + if(type == decimal) { value = strdec(input); } + if(type == hex) { value = strhex(input); } + } + + void get(string &output) const { + if(type == boolean) { output = value ? "true" : "false"; } + if(type == decimal) { output = strdec(value); } + if(type == hex) { output = string() << "0x" << strhex(value); } + } + + void get_default(string &output) const { + if(type == boolean) { output = default_value ? "true" : "false"; } + if(type == decimal) { output = strdec(default_value); } + if(type == hex) { output = string() << "0x" << strhex(default_value); } + } + + operator intmax_t() const { return value; } + integral_setting& operator=(intmax_t value_) { value = value_; return *this; } + + integral_setting(const char *name_, const char *description_, integral_type type_, intmax_t value_) { + initialize(name_, description_, type_, value_); + } + + integral_setting(configuration &parent, const char *name_, const char *description_, integral_type type_, intmax_t value_) { + initialize(name_, description_, type_, value_); + parent.add(this); + } + + private: + void initialize(const char *name_, const char *description_, integral_type type_, intmax_t value_) { + setting::type = setting::integral_type; + name = name_; + description = description_; + type = type_; + value = default_value = value_; + } + }; + + class string_setting : public setting { + public: + string value; + string default_value; + + void set(const char *input) { value = input; trim(value(), "\""); } + void get(string &output) const { output = string() << "\"" << value << "\""; } + void get_default(string &output) const { output = string() << "\"" << default_value << "\""; } + + operator const char*() const { return value; } + string_setting& operator=(const char *value_) { value = value_; return *this; } + bool operator==(const char *value_) const { return value == value_; } + bool operator!=(const char *value_) const { return value != value_; } + + string_setting(const char *name_, const char *description_, const char *value_) { + initialize(name_, description_, value_); + } + + string_setting(configuration &parent, const char *name_, const char *description_, const char *value_) { + initialize(name_, description_, value_); + parent.add(this); + } + + private: + void initialize(const char *name_, const char *description_, const char *value_) { + setting::type = setting::string_type; + name = name_; + description = description_; + value = default_value = value_; + } + }; + + inline bool configuration::load(const char *fn) { + //load the config file into memory + string data; + if(!fread(data, fn)) return false; + + //split the file into lines + replace(data, "\r\n", "\n"); + qreplace(data, "\t", ""); + qreplace(data, " ", ""); + + lstring line, part, subpart; + split(line, "\n", data); + + for(unsigned i = 0; i < count(line); i++) { + if(strlen(line[i]) == 0) continue; + if(strbegin(line[i], "#")) continue; + + qsplit(part, "=", line[i]); + for(unsigned l = 0; l < list.size(); l++) { + if(part[0] == list[l]->name) { + list[l]->set(part[1]); + break; + } + } + } + + return true; + } + + inline bool configuration::save(const char *fn) const { + file fp; + if(!fp.open(fn, file::mode_write)) return false; + + for(unsigned i = 0; i < list.size(); i++) { + string data; + lstring line, part, subpart; + strcpy(data, list[i]->description); + replace(data, "\r\n", "\n"); + split(line, "\n", data); + + string temp; + for(unsigned l = 0; l < count(line); l++) { + if(line[l] != "") fp.print(string() << "# " << line[l] << "\r\n"); + } + + string default_, value_; + list[i]->get_default(default_); + fp.print(string() << "# (default = " << default_ << ")\r\n"); + list[i]->get(value_); + fp.print(string() << list[i]->name << " = " << value_ << "\r\n\r\n"); + } + + fp.close(); + return true; + } +} + +#endif diff --git a/src/lib/nall/crc32.hpp b/src/lib/nall/crc32.hpp index 3e848a6e..ad36fbf6 100644 --- a/src/lib/nall/crc32.hpp +++ b/src/lib/nall/crc32.hpp @@ -4,65 +4,63 @@ #include namespace nall { + const uint32_t crc32_table[256] = { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, + 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, + 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, + 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, + 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, + 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, + 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, + 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, + 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, + 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, + 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, + 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, + 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, + 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, + 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, + 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, + 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, + 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, + 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, + 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, + 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, + 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, + 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, + 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, + 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, + 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, + 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, + 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, + 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, + 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, + 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, + 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, + 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, + 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, + 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d + }; -const uint32_t crc32_table[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, - 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, - 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c, - 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, - 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106, - 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, - 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, - 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, - 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, - 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, - 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e, - 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, - 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, - 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, - 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, - 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, - 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, - 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; - -inline uint32_t crc32_adjust(uint32_t crc32, uint8_t input) { - return ((crc32 >> 8) & 0x00ffffff) ^ crc32_table[(crc32 ^ input) & 0xff]; -} - -inline uint32_t crc32_calculate(const uint8_t *data, unsigned length) { - uint32_t crc32 = ~0; - for(unsigned i = 0; i < length; i++) { - crc32 = crc32_adjust(crc32, data[i]); + inline uint32_t crc32_adjust(uint32_t crc32, uint8_t input) { + return ((crc32 >> 8) & 0x00ffffff) ^ crc32_table[(crc32 ^ input) & 0xff]; + } + + inline uint32_t crc32_calculate(const uint8_t *data, unsigned length) { + uint32_t crc32 = ~0; + for(unsigned i = 0; i < length; i++) { + crc32 = crc32_adjust(crc32, data[i]); + } + return ~crc32; } - return ~crc32; } -} //namespace nall - -#endif //ifndef NALL_CRC32_HPP +#endif diff --git a/src/lib/nall/detect.hpp b/src/lib/nall/detect.hpp index c196237f..98c017e5 100644 --- a/src/lib/nall/detect.hpp +++ b/src/lib/nall/detect.hpp @@ -27,4 +27,4 @@ #define ARCH_MSB #endif -#endif //ifndef NALL_DETECT_HPP +#endif diff --git a/src/lib/nall/dictionary.hpp b/src/lib/nall/dictionary.hpp index b5c7ad75..02edddc4 100644 --- a/src/lib/nall/dictionary.hpp +++ b/src/lib/nall/dictionary.hpp @@ -6,70 +6,68 @@ #include namespace nall { - -class dictionary : noncopyable { -public: - string operator[](const char *input) { - for(unsigned i = 0; i < index_input.size(); i++) { - if(index_input[i] == input) return index_output[i]; - } - - //no match, use input; remove input identifier, if one exists - if(strbegin(input, "{{")) { - int pos = strpos(input, "}}"); - if(pos >= 0) { - string temp = substr(input, pos + 2); - return temp; + class dictionary : noncopyable { + public: + string operator[](const char *input) { + for(unsigned i = 0; i < index_input.size(); i++) { + if(index_input[i] == input) return index_output[i]; } + + //no match, use input; remove input identifier, if one exists + if(strbegin(input, "{{")) { + int pos = strpos(input, "}}"); + if(pos >= 0) { + string temp = substr(input, pos + 2); + return temp; + } + } + + return input; } - return input; - } + bool import(const char *filename) { + string data; + if(fread(data, filename) == false) return false; + ltrim_once(data, "\xef\xbb\xbf"); //remove UTF-8 marker, if it exists + replace(data, "\r", ""); - bool import(const char *filename) { - string data; - if(fread(data, filename) == false) return false; - ltrim_once(data, "\xef\xbb\xbf"); //remove UTF-8 marker, if it exists - 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; - 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 whitespace - trim(part[0]); - trim(part[1]); + //remove quotes + trim_once(part[0], "\""); + trim_once(part[1], "\""); - //remove quotes - trim_once(part[0], "\""); - trim_once(part[1], "\""); + unsigned n = index_input.size(); + index_input[n] = part[0]; + index_output[n] = part[1]; + } - unsigned n = index_input.size(); - index_input[n] = part[0]; - index_output[n] = part[1]; + return true; } - return true; - } + void reset() { + index_input.reset(); + index_output.reset(); + } - void reset() { - index_input.reset(); - index_output.reset(); - } + ~dictionary() { + reset(); + } - ~dictionary() { - reset(); - } + protected: + lstring index_input; + lstring index_output; + }; +} -protected: - lstring index_input; - lstring index_output; -}; - -} //namespace nall - -#endif //ifndef NALL_DICTIONARY_HPP +#endif diff --git a/src/lib/nall/endian.hpp b/src/lib/nall/endian.hpp index ccbd209c..40d15633 100644 --- a/src/lib/nall/endian.hpp +++ b/src/lib/nall/endian.hpp @@ -35,4 +35,4 @@ #define order_msb8(a,b,c,d,e,f,g,h) a,b,c,d,e,f,g,h #endif -#endif //ifndef NALL_ENDIAN_HPP +#endif diff --git a/src/lib/nall/file.hpp b/src/lib/nall/file.hpp index a5fc013f..596b74a5 100644 --- a/src/lib/nall/file.hpp +++ b/src/lib/nall/file.hpp @@ -9,212 +9,210 @@ #include namespace nall { + class file : noncopyable { + public: + enum FileMode { mode_read, mode_write, mode_readwrite, mode_writeread }; + enum SeekMode { seek_absolute, seek_relative }; -class file : noncopyable { -public: - enum FileMode { mode_read, mode_write, mode_readwrite, mode_writeread }; - enum SeekMode { seek_absolute, seek_relative }; - - uint8_t read() { - if(!fp) return 0xff; //file not open - if(file_mode == mode_write) return 0xff; //reads not permitted - if(file_offset >= file_size) return 0xff; //cannot read past end of file - buffer_sync(); - return buffer[(file_offset++) & buffer_mask]; - } - - uintmax_t readl(unsigned length = 1) { - uintmax_t data = 0; - for(int i = 0; i < length; i++) { - data |= (uintmax_t)read() << (i << 3); - } - return data; - } - - uintmax_t readm(unsigned length = 1) { - uintmax_t data = 0; - while(length--) { - data <<= 8; - data |= read(); - } - return data; - } - - void read(uint8_t *buffer, unsigned length) { - while(length--) *buffer++ = read(); - } - - void write(uint8_t data) { - if(!fp) return; //file not open - if(file_mode == mode_read) return; //writes not permitted - buffer_sync(); - buffer[(file_offset++) & buffer_mask] = data; - buffer_dirty = true; - if(file_offset > file_size) file_size = file_offset; - } - - void writel(uintmax_t data, unsigned length = 1) { - while(length--) { - write(data); - data >>= 8; - } - } - - void writem(uintmax_t data, unsigned length = 1) { - for(int i = length - 1; i >= 0; i--) { - write(data >> (i << 3)); - } - } - - void write(const uint8_t *buffer, unsigned length) { - while(length--) write(*buffer++); - } - - void print(const char *string) { - if(!string) return; - while(*string) write(*string++); - } - - void flush() { - buffer_flush(); - fflush(fp); - } - - void seek(int offset, SeekMode mode = seek_absolute) { - if(!fp) return; //file not open - buffer_flush(); - - uintmax_t req_offset = file_offset; - switch(mode) { - case seek_absolute: req_offset = offset; break; - case seek_relative: req_offset += offset; break; + uint8_t read() { + if(!fp) return 0xff; //file not open + if(file_mode == mode_write) return 0xff; //reads not permitted + if(file_offset >= file_size) return 0xff; //cannot read past end of file + buffer_sync(); + return buffer[(file_offset++) & buffer_mask]; } - if(req_offset < 0) req_offset = 0; //cannot seek before start of file - if(req_offset > file_size) { - if(file_mode == mode_read) { //cannot seek past end of file - req_offset = file_size; - } else { //pad file to requested location - file_offset = file_size; - while(file_size < req_offset) write(0x00); + uintmax_t readl(unsigned length = 1) { + uintmax_t data = 0; + for(int i = 0; i < length; i++) { + data |= (uintmax_t)read() << (i << 3); + } + return data; + } + + uintmax_t readm(unsigned length = 1) { + uintmax_t data = 0; + while(length--) { + data <<= 8; + data |= read(); + } + return data; + } + + void read(uint8_t *buffer, unsigned length) { + while(length--) *buffer++ = read(); + } + + void write(uint8_t data) { + if(!fp) return; //file not open + if(file_mode == mode_read) return; //writes not permitted + buffer_sync(); + buffer[(file_offset++) & buffer_mask] = data; + buffer_dirty = true; + if(file_offset > file_size) file_size = file_offset; + } + + void writel(uintmax_t data, unsigned length = 1) { + while(length--) { + write(data); + data >>= 8; } } - file_offset = req_offset; - } + void writem(uintmax_t data, unsigned length = 1) { + for(int i = length - 1; i >= 0; i--) { + write(data >> (i << 3)); + } + } - int offset() { - if(!fp) return -1; //file not open - return file_offset; - } + void write(const uint8_t *buffer, unsigned length) { + while(length--) write(*buffer++); + } - int size() { - if(!fp) return -1; //file not open - return file_size; - } + void print(const char *string) { + if(!string) return; + while(*string) write(*string++); + } - bool end() { - if(!fp) return true; //file not open - return file_offset >= file_size; - } + void flush() { + buffer_flush(); + fflush(fp); + } - static bool exists(const char *fn) { - #if !defined(_WIN32) - FILE *fp = fopen(fn, "rb"); - #else - FILE *fp = _wfopen(utf16(fn), L"rb"); - #endif - if(fp) { - fclose(fp); + void seek(int offset, SeekMode mode = seek_absolute) { + if(!fp) return; //file not open + buffer_flush(); + + uintmax_t req_offset = file_offset; + switch(mode) { + case seek_absolute: req_offset = offset; break; + case seek_relative: req_offset += offset; break; + } + + if(req_offset < 0) req_offset = 0; //cannot seek before start of file + if(req_offset > file_size) { + if(file_mode == mode_read) { //cannot seek past end of file + req_offset = file_size; + } else { //pad file to requested location + file_offset = file_size; + while(file_size < req_offset) write(0x00); + } + } + + file_offset = req_offset; + } + + int offset() { + if(!fp) return -1; //file not open + return file_offset; + } + + int size() { + if(!fp) return -1; //file not open + return file_size; + } + + bool end() { + if(!fp) return true; //file not open + return file_offset >= file_size; + } + + static bool exists(const char *fn) { + #if !defined(_WIN32) + FILE *fp = fopen(fn, "rb"); + #else + FILE *fp = _wfopen(utf16(fn), L"rb"); + #endif + if(fp) { + fclose(fp); + return true; + } + return false; + } + + bool open() { + return fp; + } + + bool open(const char *fn, FileMode mode) { + if(fp) return false; + + switch(file_mode = mode) { + #if !defined(_WIN32) + case mode_read: fp = fopen(fn, "rb"); break; + case mode_write: fp = fopen(fn, "wb+"); break; //need read permission for buffering + case mode_readwrite: fp = fopen(fn, "rb+"); break; + case mode_writeread: fp = fopen(fn, "wb+"); break; + #else + case mode_read: fp = _wfopen(utf16(fn), L"rb"); break; + case mode_write: fp = _wfopen(utf16(fn), L"wb+"); break; + case mode_readwrite: fp = _wfopen(utf16(fn), L"rb+"); break; + case mode_writeread: fp = _wfopen(utf16(fn), L"wb+"); break; + #endif + } + if(!fp) return false; + buffer_offset = -1; //invalidate buffer + file_offset = 0; + fseek(fp, 0, SEEK_END); + file_size = ftell(fp); + fseek(fp, 0, SEEK_SET); return true; } - return false; - } - bool open() { - return fp; - } - - bool open(const char *fn, FileMode mode) { - if(fp) return false; - - switch(file_mode = mode) { - #if !defined(_WIN32) - case mode_read: fp = fopen(fn, "rb"); break; - case mode_write: fp = fopen(fn, "wb+"); break; //need read permission for buffering - case mode_readwrite: fp = fopen(fn, "rb+"); break; - case mode_writeread: fp = fopen(fn, "wb+"); break; - #else - case mode_read: fp = _wfopen(utf16(fn), L"rb"); break; - case mode_write: fp = _wfopen(utf16(fn), L"wb+"); break; - case mode_readwrite: fp = _wfopen(utf16(fn), L"rb+"); break; - case mode_writeread: fp = _wfopen(utf16(fn), L"wb+"); break; - #endif - } - if(!fp) return false; - buffer_offset = -1; //invalidate buffer - file_offset = 0; - fseek(fp, 0, SEEK_END); - file_size = ftell(fp); - fseek(fp, 0, SEEK_SET); - return true; - } - - void close() { - if(!fp) return; - buffer_flush(); - fclose(fp); - fp = 0; - } - - file() { - memset(buffer, 0, sizeof buffer); - buffer_offset = -1; - buffer_dirty = false; - fp = 0; - file_offset = 0; - file_size = 0; - file_mode = mode_read; - } - - ~file() { - close(); - } - -private: - enum { buffer_size = 1 << 12, buffer_mask = buffer_size - 1 }; - char buffer[buffer_size]; - int buffer_offset; - bool buffer_dirty; - FILE *fp; - unsigned file_offset; - unsigned file_size; - FileMode file_mode; - - void buffer_sync() { - if(!fp) return; //file not open - if(buffer_offset != (file_offset & ~buffer_mask)) { + void close() { + if(!fp) return; buffer_flush(); - buffer_offset = file_offset & ~buffer_mask; + fclose(fp); + fp = 0; + } + + file() { + memset(buffer, 0, sizeof buffer); + buffer_offset = -1; + buffer_dirty = false; + fp = 0; + file_offset = 0; + file_size = 0; + file_mode = mode_read; + } + + ~file() { + close(); + } + + private: + enum { buffer_size = 1 << 12, buffer_mask = buffer_size - 1 }; + char buffer[buffer_size]; + int buffer_offset; + bool buffer_dirty; + FILE *fp; + unsigned file_offset; + unsigned file_size; + FileMode file_mode; + + void buffer_sync() { + if(!fp) return; //file not open + if(buffer_offset != (file_offset & ~buffer_mask)) { + buffer_flush(); + buffer_offset = file_offset & ~buffer_mask; + fseek(fp, buffer_offset, SEEK_SET); + unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask); + if(length) unsigned unused = fread(buffer, 1, length, fp); + } + } + + void buffer_flush() { + if(!fp) return; //file not open + if(file_mode == mode_read) return; //buffer cannot be written to + if(buffer_offset < 0) return; //buffer unused + if(buffer_dirty == false) return; //buffer unmodified since read fseek(fp, buffer_offset, SEEK_SET); unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask); - if(length) unsigned unused = fread(buffer, 1, length, fp); + if(length) unsigned unused = fwrite(buffer, 1, length, fp); + buffer_offset = -1; //invalidate buffer + buffer_dirty = false; } - } + }; +} - void buffer_flush() { - if(!fp) return; //file not open - if(file_mode == mode_read) return; //buffer cannot be written to - if(buffer_offset < 0) return; //buffer unused - if(buffer_dirty == false) return; //buffer unmodified since read - fseek(fp, buffer_offset, SEEK_SET); - unsigned length = (buffer_offset + buffer_size) <= file_size ? buffer_size : (file_size & buffer_mask); - if(length) unsigned unused = fwrite(buffer, 1, length, fp); - buffer_offset = -1; //invalidate buffer - buffer_dirty = false; - } -}; - -} //namespace nall - -#endif //ifndef NALL_FILE_HPP +#endif diff --git a/src/lib/nall/filemap.hpp b/src/lib/nall/filemap.hpp index bc73c49f..c73efad4 100644 --- a/src/lib/nall/filemap.hpp +++ b/src/lib/nall/filemap.hpp @@ -17,176 +17,174 @@ #endif namespace nall { + class filemap { + public: + enum filemode { mode_read, mode_write, mode_readwrite, mode_writeread }; -class filemap { -public: - enum filemode { mode_read, mode_write, mode_readwrite, mode_writeread }; + bool open(const char *filename, filemode mode) { return p_open(filename, mode); } + void close() { return p_close(); } + unsigned size() const { return p_size; } + uint8_t* handle() { return p_handle; } + const uint8_t* handle() const { return p_handle; } + filemap() : p_size(0), p_handle(0) { p_ctor(); } + ~filemap() { p_dtor(); } - bool open(const char *filename, filemode mode) { return p_open(filename, mode); } - void close() { return p_close(); } - unsigned size() const { return p_size; } - uint8_t* handle() { return p_handle; } - const uint8_t* handle() const { return p_handle; } - filemap() : p_size(0), p_handle(0) { p_ctor(); } - ~filemap() { p_dtor(); } + private: + unsigned p_size; + uint8_t *p_handle; -private: - unsigned p_size; - uint8_t *p_handle; + #if defined(_WIN32) + //============= + //MapViewOfFile + //============= - #if defined(_WIN32) - // - // MapViewOfFile - // + HANDLE p_filehandle, p_maphandle; - HANDLE p_filehandle, p_maphandle; + bool p_open(const char *filename, filemode mode) { + int desired_access, creation_disposition, flprotect, map_access; - bool p_open(const char *filename, filemode mode) { - int desired_access, creation_disposition, flprotect, map_access; + switch(mode) { + default: return false; + case mode_read: + desired_access = GENERIC_READ; + creation_disposition = OPEN_EXISTING; + flprotect = PAGE_READONLY; + map_access = FILE_MAP_READ; + break; + case mode_write: + //write access requires read access + desired_access = GENERIC_WRITE; + creation_disposition = CREATE_ALWAYS; + flprotect = PAGE_READWRITE; + map_access = FILE_MAP_ALL_ACCESS; + break; + case mode_readwrite: + desired_access = GENERIC_READ | GENERIC_WRITE; + creation_disposition = OPEN_EXISTING; + flprotect = PAGE_READWRITE; + map_access = FILE_MAP_ALL_ACCESS; + break; + case mode_writeread: + desired_access = GENERIC_READ | GENERIC_WRITE; + creation_disposition = CREATE_NEW; + flprotect = PAGE_READWRITE; + map_access = FILE_MAP_ALL_ACCESS; + break; + } - switch(mode) { - default: return false; - case mode_read: - desired_access = GENERIC_READ; - creation_disposition = OPEN_EXISTING; - flprotect = PAGE_READONLY; - map_access = FILE_MAP_READ; - break; - case mode_write: - //write access requires read access - desired_access = GENERIC_WRITE; - creation_disposition = CREATE_ALWAYS; - flprotect = PAGE_READWRITE; - map_access = FILE_MAP_ALL_ACCESS; - break; - case mode_readwrite: - desired_access = GENERIC_READ | GENERIC_WRITE; - creation_disposition = OPEN_EXISTING; - flprotect = PAGE_READWRITE; - map_access = FILE_MAP_ALL_ACCESS; - break; - case mode_writeread: - desired_access = GENERIC_READ | GENERIC_WRITE; - creation_disposition = CREATE_NEW; - flprotect = PAGE_READWRITE; - map_access = FILE_MAP_ALL_ACCESS; - break; + p_filehandle = CreateFileW(utf16(filename), desired_access, FILE_SHARE_READ, NULL, + creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL); + if(p_filehandle == INVALID_HANDLE_VALUE) return false; + + p_size = GetFileSize(p_filehandle, NULL); + + p_maphandle = CreateFileMapping(p_filehandle, NULL, flprotect, 0, p_size, NULL); + if(p_maphandle == INVALID_HANDLE_VALUE) { + CloseHandle(p_filehandle); + p_filehandle = INVALID_HANDLE_VALUE; + return false; + } + + p_handle = (uint8_t*)MapViewOfFile(p_maphandle, map_access, 0, 0, p_size); + return p_handle; } - p_filehandle = CreateFileW(utf16(filename), desired_access, FILE_SHARE_READ, NULL, - creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL); - if(p_filehandle == INVALID_HANDLE_VALUE) return false; + void p_close() { + if(p_handle) { + UnmapViewOfFile(p_handle); + p_handle = 0; + } - p_size = GetFileSize(p_filehandle, NULL); + if(p_maphandle != INVALID_HANDLE_VALUE) { + CloseHandle(p_maphandle); + p_maphandle = INVALID_HANDLE_VALUE; + } - p_maphandle = CreateFileMapping(p_filehandle, NULL, flprotect, 0, p_size, NULL); - if(p_maphandle == INVALID_HANDLE_VALUE) { - CloseHandle(p_filehandle); + if(p_filehandle != INVALID_HANDLE_VALUE) { + CloseHandle(p_filehandle); + p_filehandle = INVALID_HANDLE_VALUE; + } + } + + void p_ctor() { p_filehandle = INVALID_HANDLE_VALUE; - return false; + p_maphandle = INVALID_HANDLE_VALUE; } - p_handle = (uint8_t*)MapViewOfFile(p_maphandle, map_access, 0, 0, p_size); - return p_handle; - } - - void p_close() { - if(p_handle) { - UnmapViewOfFile(p_handle); - p_handle = 0; + void p_dtor() { + close(); } - if(p_maphandle != INVALID_HANDLE_VALUE) { - CloseHandle(p_maphandle); - p_maphandle = INVALID_HANDLE_VALUE; + #else + //==== + //mmap + //==== + + int p_fd; + + bool p_open(const char *filename, filemode mode) { + int open_flags, mmap_flags; + + switch(mode) { + default: return false; + case mode_read: + open_flags = O_RDONLY; + mmap_flags = PROT_READ; + break; + case mode_write: + open_flags = O_RDWR | O_CREAT; //mmap() requires read access + mmap_flags = PROT_WRITE; + break; + case mode_readwrite: + open_flags = O_RDWR; + mmap_flags = PROT_READ | PROT_WRITE; + break; + case mode_writeread: + open_flags = O_RDWR | O_CREAT; + mmap_flags = PROT_READ | PROT_WRITE; + break; + } + + p_fd = ::open(filename, open_flags); + if(p_fd < 0) return false; + + struct stat p_stat; + fstat(p_fd, &p_stat); + p_size = p_stat.st_size; + + p_handle = (uint8_t*)mmap(0, p_size, mmap_flags, MAP_SHARED, p_fd, 0); + if(p_handle == MAP_FAILED) { + p_handle = 0; + ::close(p_fd); + p_fd = -1; + return false; + } + + return p_handle; } - if(p_filehandle != INVALID_HANDLE_VALUE) { - CloseHandle(p_filehandle); - p_filehandle = INVALID_HANDLE_VALUE; - } - } + void p_close() { + if(p_handle) { + munmap(p_handle, p_size); + p_handle = 0; + } - void p_ctor() { - p_filehandle = INVALID_HANDLE_VALUE; - p_maphandle = INVALID_HANDLE_VALUE; - } - - void p_dtor() { - close(); - } - - #else - // - // mmap - // - - int p_fd; - - bool p_open(const char *filename, filemode mode) { - int open_flags, mmap_flags; - - switch(mode) { - default: return false; - case mode_read: - open_flags = O_RDONLY; - mmap_flags = PROT_READ; - break; - case mode_write: - open_flags = O_RDWR | O_CREAT; //mmap() requires read access - mmap_flags = PROT_WRITE; - break; - case mode_readwrite: - open_flags = O_RDWR; - mmap_flags = PROT_READ | PROT_WRITE; - break; - case mode_writeread: - open_flags = O_RDWR | O_CREAT; - mmap_flags = PROT_READ | PROT_WRITE; - break; + if(p_fd >= 0) { + ::close(p_fd); + p_fd = -1; + } } - p_fd = ::open(filename, open_flags); - if(p_fd < 0) return false; - - struct stat p_stat; - fstat(p_fd, &p_stat); - p_size = p_stat.st_size; - - p_handle = (uint8_t*)mmap(0, p_size, mmap_flags, MAP_SHARED, p_fd, 0); - if(p_handle == MAP_FAILED) { - p_handle = 0; - ::close(p_fd); - p_fd = -1; - return false; - } - - return p_handle; - } - - void p_close() { - if(p_handle) { - munmap(p_handle, p_size); - p_handle = 0; - } - - if(p_fd >= 0) { - ::close(p_fd); + void p_ctor() { p_fd = -1; } - } - void p_ctor() { - p_fd = -1; - } + void p_dtor() { + p_close(); + } - void p_dtor() { - p_close(); - } + #endif + }; +} - #endif -}; - -} //namespace nall - -#endif //ifndef NALL_FILEMAP_HPP +#endif diff --git a/src/lib/nall/function.hpp b/src/lib/nall/function.hpp index 2e10b6ea..9e90cb1d 100644 --- a/src/lib/nall/function.hpp +++ b/src/lib/nall/function.hpp @@ -8,7 +8,7 @@ #define TN typename namespace nall { -template class function; + template class function; } //parameters = 0 @@ -102,85 +102,83 @@ template class function; //function implementation template class namespace nall { + template + class function { + private: + struct base1 { virtual void func1(PL) {} }; + struct base2 { virtual void func2(PL) {} }; + struct derived : base1, virtual base2 {}; -template -class function { -private: - struct base1 { virtual void func1(PL) {} }; - struct base2 { virtual void func2(PL) {} }; - struct derived : base1, virtual base2 {}; - - struct data_t { - R (*fn_call)(const data_t& cat(PL)); - union { - R (*fn_global)(PL); - struct { - R (derived::*fn_member)(PL); - void *object; + struct data_t { + R (*fn_call)(const data_t& cat(PL)); + union { + R (*fn_global)(PL); + struct { + R (derived::*fn_member)(PL); + void *object; + }; }; - }; - } data; + } data; - static R fn_call_global(const data_t &d cat(PL)) { - return d.fn_global(CL); + static R fn_call_global(const data_t &d cat(PL)) { + return d.fn_global(CL); + } + + template + static R fn_call_member(const data_t &d cat(PL)) { + return (((C*)d.object)->*((R (C::*&)(PL))d.fn_member))(CL); + } + + public: + R operator()(PL) const { return data.fn_call(data cat(CL)); } + operator bool() const { return data.fn_call; } + + function() { data.fn_call = 0; } + + function(R (*fn)(PL)) { + data.fn_call = &fn_call_global; + data.fn_global = fn; + } + + template + function(R (C::*fn)(PL), C *obj) { + data.fn_call = &fn_call_member; + (R (C::*&)(PL))data.fn_member = fn; + assert(sizeof data.fn_member >= sizeof fn); + data.object = obj; + } + + template + function(R (C::*fn)(PL) const, C *obj) { + data.fn_call = &fn_call_member; + (R (C::*&)(PL))data.fn_member = (R (C::*&)(PL))fn; + assert(sizeof data.fn_member >= sizeof fn); + data.object = obj; + } + + function &operator=(const function &source) { memcpy(&data, &source.data, sizeof(data_t)); return *this; } + function(const function &source) { memcpy(&data, &source.data, sizeof(data_t)); } + }; + + template + function bind(R (*fn)(PL)) { + return function(fn); } - template - static R fn_call_member(const data_t &d cat(PL)) { - return (((C*)d.object)->*((R (C::*&)(PL))d.fn_member))(CL); + template + function bind(R (C::*fn)(PL), C *obj) { + return function(fn, obj); } -public: - R operator()(PL) const { return data.fn_call(data cat(CL)); } - operator bool() const { return data.fn_call; } - - function() { data.fn_call = 0; } - - function(R (*fn)(PL)) { - data.fn_call = &fn_call_global; - data.fn_global = fn; - } - - template - function(R (C::*fn)(PL), C *obj) { - data.fn_call = &fn_call_member; - (R (C::*&)(PL))data.fn_member = fn; - assert(sizeof data.fn_member >= sizeof fn); - data.object = obj; - } - - template - function(R (C::*fn)(PL) const, C *obj) { - data.fn_call = &fn_call_member; - (R (C::*&)(PL))data.fn_member = (R (C::*&)(PL))fn; - assert(sizeof data.fn_member >= sizeof fn); - data.object = obj; - } - - function &operator=(const function &source) { memcpy(&data, &source.data, sizeof(data_t)); return *this; } - function(const function &source) { memcpy(&data, &source.data, sizeof(data_t)); } -}; - -template -function bind(R (*fn)(PL)) { - return function(fn); + template + function bind(R (C::*fn)(PL) const, C *obj) { + return function(fn, obj); + } } -template -function bind(R (C::*fn)(PL), C *obj) { - return function(fn, obj); -} - -template -function bind(R (C::*fn)(PL) const, C *obj) { - return function(fn, obj); -} - -} //namespace nall - #undef cat #undef TL #undef PL #undef CL -#endif //ifndef NALL_FUNCTION_HPP +#endif diff --git a/src/lib/nall/input.hpp b/src/lib/nall/input.hpp index 4c147ca5..e6dd4741 100644 --- a/src/lib/nall/input.hpp +++ b/src/lib/nall/input.hpp @@ -8,167 +8,165 @@ #include namespace nall { - -struct keyboard { - enum { - none, - escape, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, - print_screen, scroll_lock, pause, tilde, - num_1, num_2, num_3, num_4, num_5, num_6, num_7, num_8, num_9, num_0, - dash, equal, backspace, - insert, delete_, home, end, page_up, page_down, - a, b, c, d, e, f, g, h, i, j, k, l, m, - n, o, p, q, r, s, t, u, v, w, x, y, z, - lbracket, rbracket, backslash, semicolon, apostrophe, comma, period, slash, - pad_1, pad_2, pad_3, pad_4, pad_5, pad_6, pad_7, pad_8, pad_9, pad_0, - point, enter, add, subtract, multiply, divide, - num_lock, caps_lock, - up, down, left, right, - tab, return_, spacebar, - lctrl, rctrl, lalt, ralt, lshift, rshift, lsuper, rsuper, menu, - limit, - }; -}; - -struct mouse { - enum { buttons = 8 }; - - enum { - none = keyboard::limit, - x, y, z, - button, - limit = button + buttons, - }; -}; - -template struct joypad { - enum { axes = 8 }; - enum { buttons = 96 }; - - enum { - none = joypad::limit, - up, down, left, right, - axis, - button = axis + axes, - limit = button + buttons, - }; -}; - -template<> struct joypad<-1> { - enum { count = 16 }; - enum { axes = 8 }; - enum { buttons = 96 }; - - enum { - none, - up, down, left, right, - axis, - button = axis + axes, - length = button + buttons - none, //number of syms per joypad - limit = mouse::limit, + struct keyboard { + enum { + none, + escape, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, + print_screen, scroll_lock, pause, tilde, + num_1, num_2, num_3, num_4, num_5, num_6, num_7, num_8, num_9, num_0, + dash, equal, backspace, + insert, delete_, home, end, page_up, page_down, + a, b, c, d, e, f, g, h, i, j, k, l, m, + n, o, p, q, r, s, t, u, v, w, x, y, z, + lbracket, rbracket, backslash, semicolon, apostrophe, comma, period, slash, + pad_1, pad_2, pad_3, pad_4, pad_5, pad_6, pad_7, pad_8, pad_9, pad_0, + point, enter, add, subtract, multiply, divide, + num_lock, caps_lock, + up, down, left, right, + tab, return_, spacebar, + lctrl, rctrl, lalt, ralt, lshift, rshift, lsuper, rsuper, menu, + limit, + }; }; - static uint16_t index(unsigned joypad_number, unsigned joypad_enum) { - if(joypad_number >= count) return keyboard::none; - return limit + joypad_number * length + joypad_enum; - } -}; + struct mouse { + enum { buttons = 8 }; -enum { input_limit = joypad::count - 1>::limit }; + enum { + none = keyboard::limit, + x, y, z, + button, + limit = button + buttons, + }; + }; -static const char sym_table[][64] = { - //keyboard - "none", - "escape", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", - "print_screen", "scroll_lock", "pause", "tilde", - "num_1", "num_2", "num_3", "num_4", "num_5", "num_6", "num_7", "num_8", "num_9", "num_0", - "dash", "equal", "backspace", - "insert", "delete", "home", "end", "page_up", "page_down", - "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", - "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", - "lbracket", "rbracket", "backslash", "semicolon", "apostrophe", "comma", "period", "slash", - "pad_1", "pad_2", "pad_3", "pad_4", "pad_5", "pad_6", "pad_7", "pad_8", "pad_9", "pad_0", - "point", "enter", "add", "subtract", "multiply", "divide", - "num_lock", "caps_lock", - "up", "down", "left", "right", - "tab", "return", "spacebar", - "lctrl", "rctrl", "lalt", "ralt", "lshift", "rshift", "lsuper", "rsuper", "menu", - "keyboard.limit", + template struct joypad { + enum { axes = 8 }; + enum { buttons = 96 }; - //mouse - "mouse.x", "mouse.y", "mouse.z", - "mouse.button00", "mouse.button01", "mouse.button02", "mouse.button03", - "mouse.button04", "mouse.button05", "mouse.button06", "mouse.button07", - "mouse.limit", -}; + enum { + none = joypad::limit, + up, down, left, right, + axis, + button = axis + axes, + limit = button + buttons, + }; + }; -static const char* input_find(uint16_t key) { - if(key < mouse::limit) return sym_table[key]; + template<> struct joypad<-1> { + enum { count = 16 }; + enum { axes = 8 }; + enum { buttons = 96 }; - static char buffer[64]; - for(unsigned j = 0; j < 16; j++) { - if(key == joypad<>::index(j, joypad<>::up)) { sprintf(buffer, "joypad%.2d.up", j); return buffer; } - if(key == joypad<>::index(j, joypad<>::down)) { sprintf(buffer, "joypad%.2d.down", j); return buffer; } - if(key == joypad<>::index(j, joypad<>::left)) { sprintf(buffer, "joypad%.2d.left", j); return buffer; } - if(key == joypad<>::index(j, joypad<>::right)) { sprintf(buffer, "joypad%.2d.right", j); return buffer; } + enum { + none, + up, down, left, right, + axis, + button = axis + axes, + length = button + buttons - none, //number of syms per joypad + limit = mouse::limit, + }; - if(key >= joypad<>::index(j, joypad<>::axis + 0) - && key < joypad<>::index(j, joypad<>::axis + joypad<>::axes)) { - sprintf(buffer, "joypad%.2d.axis%.2d", j, key - joypad<>::index(j, joypad<>::axis)); - return buffer; + static uint16_t index(unsigned joypad_number, unsigned joypad_enum) { + if(joypad_number >= count) return keyboard::none; + return limit + joypad_number * length + joypad_enum; + } + }; + + enum { input_limit = joypad::count - 1>::limit }; + + static const char sym_table[][64] = { + //keyboard + "none", + "escape", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", + "print_screen", "scroll_lock", "pause", "tilde", + "num_1", "num_2", "num_3", "num_4", "num_5", "num_6", "num_7", "num_8", "num_9", "num_0", + "dash", "equal", "backspace", + "insert", "delete", "home", "end", "page_up", "page_down", + "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", + "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", + "lbracket", "rbracket", "backslash", "semicolon", "apostrophe", "comma", "period", "slash", + "pad_1", "pad_2", "pad_3", "pad_4", "pad_5", "pad_6", "pad_7", "pad_8", "pad_9", "pad_0", + "point", "enter", "add", "subtract", "multiply", "divide", + "num_lock", "caps_lock", + "up", "down", "left", "right", + "tab", "return", "spacebar", + "lctrl", "rctrl", "lalt", "ralt", "lshift", "rshift", "lsuper", "rsuper", "menu", + "keyboard.limit", + + //mouse + "mouse.x", "mouse.y", "mouse.z", + "mouse.button00", "mouse.button01", "mouse.button02", "mouse.button03", + "mouse.button04", "mouse.button05", "mouse.button06", "mouse.button07", + "mouse.limit", + }; + + static const char* input_find(uint16_t key) { + if(key < mouse::limit) return sym_table[key]; + + static char buffer[64]; + for(unsigned j = 0; j < 16; j++) { + if(key == joypad<>::index(j, joypad<>::up)) { sprintf(buffer, "joypad%.2d.up", j); return buffer; } + if(key == joypad<>::index(j, joypad<>::down)) { sprintf(buffer, "joypad%.2d.down", j); return buffer; } + if(key == joypad<>::index(j, joypad<>::left)) { sprintf(buffer, "joypad%.2d.left", j); return buffer; } + if(key == joypad<>::index(j, joypad<>::right)) { sprintf(buffer, "joypad%.2d.right", j); return buffer; } + + if(key >= joypad<>::index(j, joypad<>::axis + 0) + && key < joypad<>::index(j, joypad<>::axis + joypad<>::axes)) { + sprintf(buffer, "joypad%.2d.axis%.2d", j, key - joypad<>::index(j, joypad<>::axis)); + return buffer; + } + + if(key >= joypad<>::index(j, joypad<>::button + 0) + && key < joypad<>::index(j, joypad<>::button + joypad<>::buttons)) { + sprintf(buffer, "joypad%.2d.button%.2d", j, key - joypad<>::index(j, joypad<>::button)); + return buffer; + } } - if(key >= joypad<>::index(j, joypad<>::button + 0) - && key < joypad<>::index(j, joypad<>::button + joypad<>::buttons)) { - sprintf(buffer, "joypad%.2d.button%.2d", j, key - joypad<>::index(j, joypad<>::button)); - return buffer; + return "none"; + } + + static char* input_find(char *out, uint16_t key) { + strcpy(out, input_find(key)); + return out; + } + + static uint16_t input_find(const char *key) { + for(unsigned i = 0; i < mouse::limit; i++) { + if(!strcmp(sym_table[i], key)) return i; } - } - return "none"; -} - -static char* input_find(char *out, uint16_t key) { - strcpy(out, input_find(key)); - return out; -} - -static uint16_t input_find(const char *key) { - for(unsigned i = 0; i < mouse::limit; i++) { - if(!strcmp(sym_table[i], key)) return i; - } - - if(memcmp(key, "joypad", 6)) return keyboard::none; - key += 6; - if(!*key || !*(key + 1)) return keyboard::none; - uint8_t j = (*key - '0') * 10 + (*(key + 1) - '0'); - if(j > 15) return keyboard::none; - - key += 2; - if(!strcmp(key, ".up")) return joypad<>::index(j, joypad<>::up); - if(!strcmp(key, ".down")) return joypad<>::index(j, joypad<>::down); - if(!strcmp(key, ".left")) return joypad<>::index(j, joypad<>::left); - if(!strcmp(key, ".right")) return joypad<>::index(j, joypad<>::right); - - if(!memcmp(key, ".axis", 5)) { - key += 5; + if(memcmp(key, "joypad", 6)) return keyboard::none; + key += 6; if(!*key || !*(key + 1)) return keyboard::none; - uint8_t axis = (*key - '0') * 10 + (*(key + 1) - '0'); - if(axis >= joypad<>::axes) return keyboard::none; - return joypad<>::index(j, joypad<>::axis + axis); - } + uint8_t j = (*key - '0') * 10 + (*(key + 1) - '0'); + if(j > 15) return keyboard::none; - if(!memcmp(key, ".button", 7)) { - key += 7; - if(!*key || !*(key + 1)) return keyboard::none; - uint8_t button = (*key - '0') * 10 + (*(key + 1) - '0'); - if(button >= joypad<>::buttons) return keyboard::none; - return joypad<>::index(j, joypad<>::button + button); - } + key += 2; + if(!strcmp(key, ".up")) return joypad<>::index(j, joypad<>::up); + if(!strcmp(key, ".down")) return joypad<>::index(j, joypad<>::down); + if(!strcmp(key, ".left")) return joypad<>::index(j, joypad<>::left); + if(!strcmp(key, ".right")) return joypad<>::index(j, joypad<>::right); - return keyboard::none; + if(!memcmp(key, ".axis", 5)) { + key += 5; + if(!*key || !*(key + 1)) return keyboard::none; + uint8_t axis = (*key - '0') * 10 + (*(key + 1) - '0'); + if(axis >= joypad<>::axes) return keyboard::none; + return joypad<>::index(j, joypad<>::axis + axis); + } + + if(!memcmp(key, ".button", 7)) { + key += 7; + if(!*key || !*(key + 1)) return keyboard::none; + uint8_t button = (*key - '0') * 10 + (*(key + 1) - '0'); + if(button >= joypad<>::buttons) return keyboard::none; + return joypad<>::index(j, joypad<>::button + button); + } + + return keyboard::none; + } } -} //namespace nall - -#endif //ifndef NALL_INPUT_HPP +#endif diff --git a/src/lib/nall/lzss.hpp b/src/lib/nall/lzss.hpp index 0073460c..202bc814 100644 --- a/src/lib/nall/lzss.hpp +++ b/src/lib/nall/lzss.hpp @@ -6,78 +6,76 @@ #include namespace nall { + class lzss { + public: + static bool encode(uint8_t *&output, unsigned &outlength, const uint8_t *input, unsigned inlength) { + output = new(zeromemory) uint8_t[inlength * 9 / 8 + 9]; -class lzss { -public: - static bool encode(uint8_t *&output, unsigned &outlength, const uint8_t *input, unsigned inlength) { - output = new(zeromemory) uint8_t[inlength * 9 / 8 + 9]; + unsigned i = 0, o = 0; + while(i < inlength) { + unsigned flagoffset = o++; + uint8_t flag = 0x00; - unsigned i = 0, o = 0; - while(i < inlength) { - unsigned flagoffset = o++; - uint8_t flag = 0x00; + for(unsigned b = 0; b < 8 && i < inlength; b++) { + unsigned longest = 0, pointer; + for(unsigned index = 1; index < 4096; index++) { + unsigned count = 0; + while(true) { + if(count >= 15 + 3) break; //verify pattern match is not longer than max length + if(i + count >= inlength) break; //verify pattern match does not read past end of input + if(i + count < index) break; //verify read is not before start of input + if(input[i + count] != input[i + count - index]) break; //verify pattern still matches + count++; + } - for(unsigned b = 0; b < 8 && i < inlength; b++) { - unsigned longest = 0, pointer; - for(unsigned index = 1; index < 4096; index++) { - unsigned count = 0; - while(true) { - if(count >= 15 + 3) break; //verify pattern match is not longer than max length - if(i + count >= inlength) break; //verify pattern match does not read past end of input - if(i + count < index) break; //verify read is not before start of input - if(input[i + count] != input[i + count - index]) break; //verify pattern still matches - count++; + if(count > longest) { + longest = count; + pointer = index; + } } - if(count > longest) { - longest = count; - pointer = index; + if(longest < 3) output[o++] = input[i++]; + else { + flag |= 1 << b; + uint16_t x = ((longest - 3) << 12) + pointer; + output[o++] = x; + output[o++] = x >> 8; + i += longest; } } - if(longest < 3) output[o++] = input[i++]; - else { - flag |= 1 << b; - uint16_t x = ((longest - 3) << 12) + pointer; - output[o++] = x; - output[o++] = x >> 8; - i += longest; + output[flagoffset] = flag; + } + + outlength = o; + return true; + } + + static bool decode(uint8_t *&output, const uint8_t *input, unsigned length) { + output = new(zeromemory) uint8_t[length]; + + unsigned i = 0, o = 0; + while(o < length) { + uint8_t flag = input[i++]; + + for(unsigned b = 0; b < 8 && o < length; b++) { + if(!(flag & (1 << b))) output[o++] = input[i++]; + else { + uint16_t offset = input[i++]; + offset += input[i++] << 8; + uint16_t lookuplength = (offset >> 12) + 3; + offset &= 4095; + for(unsigned index = 0; index < lookuplength && o + index < length; index++) { + output[o + index] = output[o + index - offset]; + } + o += lookuplength; + } } } - output[flagoffset] = flag; + return true; } + }; +} - outlength = o; - return true; - } - - static bool decode(uint8_t *&output, const uint8_t *input, unsigned length) { - output = new(zeromemory) uint8_t[length]; - - unsigned i = 0, o = 0; - while(o < length) { - uint8_t flag = input[i++]; - - for(unsigned b = 0; b < 8 && o < length; b++) { - if(!(flag & (1 << b))) output[o++] = input[i++]; - else { - uint16_t offset = input[i++]; - offset += input[i++] << 8; - uint16_t lookuplength = (offset >> 12) + 3; - offset &= 4095; - for(unsigned index = 0; index < lookuplength && o + index < length; index++) { - output[o + index] = output[o + index - offset]; - } - o += lookuplength; - } - } - } - - return true; - } -}; - -} //namespace nall - -#endif //ifndef NALL_LZSS_HPP +#endif diff --git a/src/lib/nall/modulo.hpp b/src/lib/nall/modulo.hpp deleted file mode 100644 index 472056fd..00000000 --- a/src/lib/nall/modulo.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef NALL_MODULO_HPP -#define NALL_MODULO_HPP - -#include - -namespace nall { - -template -class modulo_array { -public: - inline T operator[](int index) const { - return buffer[size + index]; - } - - inline T read(int index) const { - return buffer[size + index]; - } - - inline void write(unsigned index, const T value) { - buffer[index] = - buffer[index + size] = - buffer[index + size + size] = value; - } - - modulo_array() { - buffer = new(zeromemory) T[size * 3]; - } - - ~modulo_array() { - delete[] buffer; - } - -private: - T *buffer; -}; - -} //namespace nall - -#endif //ifndef NALL_MODULO_HPP diff --git a/src/lib/nall/moduloarray.hpp b/src/lib/nall/moduloarray.hpp new file mode 100644 index 00000000..30e09777 --- /dev/null +++ b/src/lib/nall/moduloarray.hpp @@ -0,0 +1,36 @@ +#ifndef NALL_MODULO_HPP +#define NALL_MODULO_HPP + +#include + +namespace nall { + template class modulo_array { + public: + inline T operator[](int index) const { + return buffer[size + index]; + } + + inline T read(int index) const { + return buffer[size + index]; + } + + inline void write(unsigned index, const T value) { + buffer[index] = + buffer[index + size] = + buffer[index + size + size] = value; + } + + modulo_array() { + buffer = new(zeromemory) T[size * 3]; + } + + ~modulo_array() { + delete[] buffer; + } + + private: + T *buffer; + }; +} + +#endif diff --git a/src/lib/nall/new.hpp b/src/lib/nall/new.hpp index 62bf64fb..abc2ca59 100644 --- a/src/lib/nall/new.hpp +++ b/src/lib/nall/new.hpp @@ -6,11 +6,9 @@ #include namespace nall { - -struct zeromemory_t {}; -static zeromemory_t zeromemory; - -} //namespace nall + struct zeromemory_t {}; + static zeromemory_t zeromemory; +} inline void* operator new[](size_t size, const nall::zeromemory_t&) throw(std::bad_alloc) { void *p = new uint8_t[size]; @@ -24,4 +22,4 @@ inline void* operator new[](size_t size, const std::nothrow_t&, const nall::zero return p; } -#endif //ifndef NALL_NEW_HPP +#endif diff --git a/src/lib/nall/platform.hpp b/src/lib/nall/platform.hpp index ec02d5fa..bdae675c 100644 --- a/src/lib/nall/platform.hpp +++ b/src/lib/nall/platform.hpp @@ -5,6 +5,8 @@ //standard platform headers //========================= +#include + #include #include #include @@ -70,4 +72,4 @@ #define alwaysinline inline #endif -#endif //ifndef NALL_PLATFORM_HPP +#endif diff --git a/src/lib/nall/priorityqueue.hpp b/src/lib/nall/priorityqueue.hpp new file mode 100644 index 00000000..3daccfab --- /dev/null +++ b/src/lib/nall/priorityqueue.hpp @@ -0,0 +1,94 @@ +#ifndef NALL_PRIORITYQUEUE_HPP +#define NALL_PRIORITYQUEUE_HPP + +#include +#include +#include + +namespace nall { + template void priority_queue_nocallback(type_t) {} + + //priority queue implementation using binary min-heap array; + //does not require normalize() function. + //O(1) find (tick) + //O(log n) insert (enqueue) + //O(log n) remove (dequeue) + template class priority_queue : noncopyable { + public: + inline void tick(unsigned ticks) { + basecounter += ticks; + while(heapsize && gte(basecounter, heap[0].counter)) callback(dequeue()); + } + + //counter is relative to current time (eg enqueue(64, ...) fires in 64 ticks); + //counter cannot exceed std::numeric_limits::max() >> 1. + void enqueue(unsigned counter, type_t event) { + unsigned child = heapsize++; + counter += basecounter; + + while(child) { + unsigned parent = (child - 1) >> 1; + if(gte(counter, heap[parent].counter)) break; + + heap[child].counter = heap[parent].counter; + heap[child].event = heap[parent].event; + child = parent; + } + + heap[child].counter = counter; + heap[child].event = event; + } + + type_t dequeue() { + type_t event(heap[0].event); + unsigned parent = 0; + unsigned counter = heap[--heapsize].counter; + + while(true) { + unsigned child = (parent << 1) + 1; + if(child >= heapsize) break; + if(child + 1 < heapsize && gte(heap[child].counter, heap[child + 1].counter)) child++; + if(gte(heap[child].counter, counter)) break; + + heap[parent].counter = heap[child].counter; + heap[parent].event = heap[child].event; + parent = child; + } + + heap[parent].counter = counter; + heap[parent].event = heap[heapsize].event; + return event; + } + + void reset() { + basecounter = 0; + heapsize = 0; + } + + priority_queue(unsigned size, function callback_ = &priority_queue_nocallback) + : callback(callback_) { + heap = new heap_t[size]; + reset(); + } + + ~priority_queue() { + delete[] heap; + } + + private: + function callback; + unsigned basecounter; + unsigned heapsize; + struct heap_t { + unsigned counter; + type_t event; + } *heap; + + //return true if x is greater than or equal to y + inline bool gte(unsigned x, unsigned y) { + return x - y < (std::numeric_limits::max() >> 1); + } + }; +} + +#endif diff --git a/src/lib/nall/serial.hpp b/src/lib/nall/serial.hpp index 706ebfb5..6f5cf6d6 100644 --- a/src/lib/nall/serial.hpp +++ b/src/lib/nall/serial.hpp @@ -9,74 +9,72 @@ #include namespace nall { - -class serial { -public: - //-1 on error, otherwise return bytes read - int read(uint8_t *data, unsigned length) { - if(port_open == false) return -1; - return ::read(port, (void*)data, length); - } - - //-1 on error, otherwise return bytes written - int write(const uint8_t *data, unsigned length) { - if(port_open == false) return -1; - return ::write(port, (void*)data, length); - } - - bool open(const char *portname, unsigned rate) { - close(); - - port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); - if(port == -1) return false; - - if(ioctl(port, TIOCEXCL) == -1) { close(); return false; } - if(fcntl(port, F_SETFL, 0) == -1) { close(); return false; } - if(tcgetattr(port, &original_attr) == -1) { close(); return false; } - - termios attr = original_attr; - cfmakeraw(&attr); - cfsetspeed(&attr, rate); - - attr.c_lflag &=~ (ECHO | ECHONL | ISIG | ICANON | IEXTEN); - attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY); - attr.c_iflag |= (IGNBRK | IGNPAR); - attr.c_oflag &=~ (OPOST); - attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB); - attr.c_cflag |= (CS8 | CREAD | CLOCAL); - attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0; - - if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; } - return port_open = true; - } - - void close() { - if(port != -1) { - tcdrain(port); - if(port_open == true) { - tcsetattr(port, TCSANOW, &original_attr); - port_open = false; - } - ::close(port); - port = -1; + class serial { + public: + //-1 on error, otherwise return bytes read + int read(uint8_t *data, unsigned length) { + if(port_open == false) return -1; + return ::read(port, (void*)data, length); } - } - serial() { - port = -1; - port_open = false; - } + //-1 on error, otherwise return bytes written + int write(const uint8_t *data, unsigned length) { + if(port_open == false) return -1; + return ::write(port, (void*)data, length); + } - ~serial() { - close(); - } + bool open(const char *portname, unsigned rate) { + close(); -private: - int port; - bool port_open; - termios original_attr; -}; + port = ::open(portname, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); + if(port == -1) return false; -} //namespace nall + if(ioctl(port, TIOCEXCL) == -1) { close(); return false; } + if(fcntl(port, F_SETFL, 0) == -1) { close(); return false; } + if(tcgetattr(port, &original_attr) == -1) { close(); return false; } -#endif //ifndef NALL_SERIAL_HPP + termios attr = original_attr; + cfmakeraw(&attr); + cfsetspeed(&attr, rate); + + attr.c_lflag &=~ (ECHO | ECHONL | ISIG | ICANON | IEXTEN); + attr.c_iflag &=~ (BRKINT | PARMRK | INPCK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY); + attr.c_iflag |= (IGNBRK | IGNPAR); + attr.c_oflag &=~ (OPOST); + attr.c_cflag &=~ (CSIZE | CSTOPB | PARENB); + attr.c_cflag |= (CS8 | CREAD | CLOCAL); + attr.c_cc[VTIME] = attr.c_cc[VMIN] = 0; + + if(tcsetattr(port, TCSANOW, &attr) == -1) { close(); return false; } + return port_open = true; + } + + void close() { + if(port != -1) { + tcdrain(port); + if(port_open == true) { + tcsetattr(port, TCSANOW, &original_attr); + port_open = false; + } + ::close(port); + port = -1; + } + } + + serial() { + port = -1; + port_open = false; + } + + ~serial() { + close(); + } + + private: + int port; + bool port_open; + termios original_attr; + }; +} + +#endif diff --git a/src/lib/nall/sort.hpp b/src/lib/nall/sort.hpp index 53e30575..23c317a5 100644 --- a/src/lib/nall/sort.hpp +++ b/src/lib/nall/sort.hpp @@ -18,47 +18,45 @@ //(* which is also O(n log n) in the average case.) namespace nall { + template + void sort(T list[], unsigned length) { + if(length <= 1) return; //nothing to sort -template -void sort(T list[], unsigned length) { - if(length <= 1) return; //nothing to sort - - //use insertion sort to quickly sort smaller blocks - if(length < 64) { - for(unsigned i = 0; i < length; i++) { - unsigned min = i; - for(unsigned j = i + 1; j < length; j++) { - if(list[j] < list[min]) min = j; + //use insertion sort to quickly sort smaller blocks + if(length < 64) { + for(unsigned i = 0; i < length; i++) { + unsigned min = i; + for(unsigned j = i + 1; j < length; j++) { + if(list[j] < list[min]) min = j; + } + if(min != i) swap(list[i], list[min]); } - if(min != i) swap(list[i], list[min]); + return; } - return; - } - //split list in half and recursively sort both - unsigned middle = length / 2; - sort(list, middle); - sort(list + middle, length - middle); + //split list in half and recursively sort both + unsigned middle = length / 2; + sort(list, middle); + sort(list + middle, length - middle); - //left and right are sorted here; perform merge sort - T *buffer = new T[length]; - unsigned offset = 0; - unsigned left = 0; - unsigned right = middle; - while(left < middle && right < length) { - if(list[left] < list[right]) { - buffer[offset++] = list[left++]; - } else { - buffer[offset++] = list[right++]; + //left and right are sorted here; perform merge sort + T *buffer = new T[length]; + unsigned offset = 0; + unsigned left = 0; + unsigned right = middle; + while(left < middle && right < length) { + if(list[left] < list[right]) { + buffer[offset++] = list[left++]; + } else { + buffer[offset++] = list[right++]; + } } - } - while(left < middle) buffer[offset++] = list[left++]; - while(right < length) buffer[offset++] = list[right++]; + while(left < middle) buffer[offset++] = list[left++]; + while(right < length) buffer[offset++] = list[right++]; - for(unsigned i = 0; i < length; i++) list[i] = buffer[i]; - delete[] buffer; + for(unsigned i = 0; i < length; i++) list[i] = buffer[i]; + delete[] buffer; + } } -} //namespace nall - -#endif //ifndef NALL_SORT_HPP +#endif diff --git a/src/lib/nall/static.hpp b/src/lib/nall/static.hpp index 14e42bac..00c3664c 100644 --- a/src/lib/nall/static.hpp +++ b/src/lib/nall/static.hpp @@ -2,20 +2,16 @@ #define NALL_STATIC_HPP namespace nall { + template struct static_assert; + template<> struct static_assert {}; -template struct static_assert; -template<> struct static_assert {}; + template struct static_if { + typedef true_type type; + }; -template -struct static_if { - typedef true_type type; -}; + template struct static_if { + typedef false_type type; + }; +} -template -struct static_if { - typedef false_type type; -}; - -} //namespace nall - -#endif //ifndef NALL_STATIC_HPP +#endif diff --git a/src/lib/nall/stdint.hpp b/src/lib/nall/stdint.hpp index ba58bda2..7e2c7a46 100644 --- a/src/lib/nall/stdint.hpp +++ b/src/lib/nall/stdint.hpp @@ -30,17 +30,15 @@ #endif namespace nall { + static static_assert int8_t_assert; + static static_assert int16_t_assert; + static static_assert int32_t_assert; + static static_assert int64_t_assert; -static static_assert int8_t_assert; -static static_assert int16_t_assert; -static static_assert int32_t_assert; -static static_assert int64_t_assert; + static static_assert uint8_t_assert; + static static_assert uint16_t_assert; + static static_assert uint32_t_assert; + static static_assert uint64_t_assert; +} -static static_assert uint8_t_assert; -static static_assert uint16_t_assert; -static static_assert uint32_t_assert; -static static_assert uint64_t_assert; - -} //namespace nall - -#endif //ifndef NALL_STDINT_HPP +#endif diff --git a/src/lib/nall/string.cpp b/src/lib/nall/string.cpp index f1818bd4..565cbc7c 100644 --- a/src/lib/nall/string.cpp +++ b/src/lib/nall/string.cpp @@ -17,4 +17,4 @@ #include #include -#endif //ifndef NALL_STRING_CPP +#endif diff --git a/src/lib/nall/string.hpp b/src/lib/nall/string.hpp index 46b9b575..d1748a4a 100644 --- a/src/lib/nall/string.hpp +++ b/src/lib/nall/string.hpp @@ -51,46 +51,44 @@ char* rtrim_once(char *str, const char *key = " "); char* trim_once (char *str, const char *key = " "); namespace nall { + class string { + public: + char *data; + size_t size; -class string { -public: - char *data; - size_t size; + void reserve(size_t size_); - void reserve(size_t size_); + operator int() const; + operator const char*() const; + char* operator()(); + char& operator[](int); - operator int() const; - operator const char*() const; - char* operator()(); - char& operator[](int); + string& operator=(int num); + string& operator=(double num); + string& operator=(const char *str); + string& operator=(const string &str); + string& operator<<(int num); + string& operator<<(double num); + string& operator<<(const char *str); + string& operator<<(const string& str); - string& operator=(int num); - string& operator=(double num); - string& operator=(const char *str); - string& operator=(const string &str); - string& operator<<(int num); - string& operator<<(double num); - string& operator<<(const char *str); - string& operator<<(const string& str); + bool operator==(const char *str) const; + bool operator!=(const char *str) const; + bool operator< (const char *str) const; + bool operator<=(const char *str) const; + bool operator> (const char *str) const; + bool operator>=(const char *str) const; - bool operator==(const char *str) const; - bool operator!=(const char *str) const; - bool operator< (const char *str) const; - bool operator<=(const char *str) const; - bool operator> (const char *str) const; - bool operator>=(const char *str) const; + string(); + string(int num); + string(double num); + string(const char *source); + string(const string &source); + ~string(); + }; - string(); - string(int num); - string(double num); - string(const char *source); - string(const string &source); - ~string(); -}; - -typedef vector lstring; - -} //namespace nall + typedef vector lstring; +} size_t count(nall::lstring&); int find(nall::lstring &str, const char *key); @@ -118,4 +116,4 @@ nall::string& ltrim_once(nall::string &str, const char *key = " "); nall::string& rtrim_once(nall::string &str, const char *key = " "); nall::string& trim_once (nall::string &str, const char *key = " "); -#endif //ifndef NALL_STRING_HPP +#endif diff --git a/src/lib/nall/string/class.cpp b/src/lib/nall/string/class.cpp index efb6586f..9a159741 100644 --- a/src/lib/nall/string/class.cpp +++ b/src/lib/nall/string/class.cpp @@ -229,4 +229,4 @@ bool fread(nall::string &str, const char *filename) { return true; } -#endif //ifdef NALL_STRING_CPP +#endif diff --git a/src/lib/nall/string/compare.cpp b/src/lib/nall/string/compare.cpp index 081a05d7..168063a2 100644 --- a/src/lib/nall/string/compare.cpp +++ b/src/lib/nall/string/compare.cpp @@ -96,4 +96,4 @@ bool striend(const char *str, const char *key) { return true; } -#endif //ifdef NALL_STRING_CPP +#endif diff --git a/src/lib/nall/string/convert.cpp b/src/lib/nall/string/convert.cpp index 51152375..46744638 100644 --- a/src/lib/nall/string/convert.cpp +++ b/src/lib/nall/string/convert.cpp @@ -252,4 +252,4 @@ size_t strdouble(char *str, double value, size_t length /* = 0 */) { return length + 1; } -#endif //ifdef NALL_STRING_CPP +#endif diff --git a/src/lib/nall/string/match.cpp b/src/lib/nall/string/match.cpp index c73df02a..186ed198 100644 --- a/src/lib/nall/string/match.cpp +++ b/src/lib/nall/string/match.cpp @@ -68,4 +68,4 @@ bool match(const char *p, const char *s) { } } -#endif //ifdef NALL_STRING_CPP +#endif diff --git a/src/lib/nall/string/math.cpp b/src/lib/nall/string/math.cpp index 3dabde3b..31835b10 100644 --- a/src/lib/nall/string/math.cpp +++ b/src/lib/nall/string/math.cpp @@ -156,4 +156,4 @@ bool strmath(const char *s, int &result) { } } -#endif //ifdef NALL_STRING_CPP +#endif diff --git a/src/lib/nall/string/replace.cpp b/src/lib/nall/string/replace.cpp index b29e02d9..34acf7c8 100644 --- a/src/lib/nall/string/replace.cpp +++ b/src/lib/nall/string/replace.cpp @@ -87,4 +87,4 @@ nall::string &qreplace(nall::string &str, const char *key, const char *token) { return str; } -#endif //ifdef NALL_STRING_CPP +#endif diff --git a/src/lib/nall/string/split.cpp b/src/lib/nall/string/split.cpp index b68b5c13..7905dfa0 100644 --- a/src/lib/nall/string/split.cpp +++ b/src/lib/nall/string/split.cpp @@ -48,4 +48,4 @@ void qsplit(nall::lstring &dest, const char *key, const char *src, size_t limit) strcpy(dest[split_count++], src + lp); } -#endif //ifdef NALL_STRING_CPP +#endif diff --git a/src/lib/nall/string/strl.cpp b/src/lib/nall/string/strl.cpp index a140fbc9..c23f652f 100644 --- a/src/lib/nall/string/strl.cpp +++ b/src/lib/nall/string/strl.cpp @@ -44,4 +44,4 @@ size_t strlcat(char *dest, const char *src, size_t length) { return dlength + (s - src); //return length of resulting string, sans null terminator } -#endif //ifdef NALL_STRING_CPP +#endif diff --git a/src/lib/nall/string/trim.cpp b/src/lib/nall/string/trim.cpp index 861500e4..1c5e5bd3 100644 --- a/src/lib/nall/string/trim.cpp +++ b/src/lib/nall/string/trim.cpp @@ -32,4 +32,4 @@ char* trim_once(char *str, const char *key) { return ltrim_once(rtrim_once(str, key), key); } -#endif //ifdef NALL_STRING_CPP +#endif diff --git a/src/lib/nall/traits.hpp b/src/lib/nall/traits.hpp index 168e90d3..96320200 100644 --- a/src/lib/nall/traits.hpp +++ b/src/lib/nall/traits.hpp @@ -2,89 +2,93 @@ #define NALL_TRAITS_HPP namespace nall { + //== + //is + //== -/* is */ + template struct is_integral { enum { value = false }; }; + template<> struct is_integral { enum { value = true }; }; + template<> struct is_integral { enum { value = true }; }; + template<> struct is_integral { enum { value = true }; }; + template<> struct is_integral { enum { value = true }; }; + template<> struct is_integral { enum { value = true }; }; + template<> struct is_integral { enum { value = true }; }; + template<> struct is_integral { enum { value = true }; }; + template<> struct is_integral { enum { value = true }; }; + template<> struct is_integral { enum { value = true }; }; + template<> struct is_integral { enum { value = true }; }; + template<> struct is_integral { enum { value = true }; }; + template<> struct is_integral { enum { value = true }; }; + template<> struct is_integral { enum { value = true }; }; -template struct is_integral { enum { value = false }; }; -template<> struct is_integral { enum { value = true }; }; -template<> struct is_integral { enum { value = true }; }; -template<> struct is_integral { enum { value = true }; }; -template<> struct is_integral { enum { value = true }; }; -template<> struct is_integral { enum { value = true }; }; -template<> struct is_integral { enum { value = true }; }; -template<> struct is_integral { enum { value = true }; }; -template<> struct is_integral { enum { value = true }; }; -template<> struct is_integral { enum { value = true }; }; -template<> struct is_integral { enum { value = true }; }; -template<> struct is_integral { enum { value = true }; }; -template<> struct is_integral { enum { value = true }; }; -template<> struct is_integral { enum { value = true }; }; + template struct is_floating_point { enum { value = false }; }; + template<> struct is_floating_point { enum { value = true }; }; + template<> struct is_floating_point { enum { value = true }; }; + template<> struct is_floating_point { enum { value = true }; }; -template struct is_floating_point { enum { value = false }; }; -template<> struct is_floating_point { enum { value = true }; }; -template<> struct is_floating_point { enum { value = true }; }; -template<> struct is_floating_point { enum { value = true }; }; + template struct is_void { enum { value = false }; }; + template<> struct is_void { enum { value = true }; }; -template struct is_void { enum { value = false }; }; -template<> struct is_void { enum { value = true }; }; + template struct is_arithmetic { + enum { value = is_integral::value || is_floating_point::value }; + }; -template struct is_arithmetic { - enum { value = is_integral::value || is_floating_point::value }; -}; + template struct is_fundamental { + enum { value = is_integral::value || is_floating_point::value || is_void::value }; + }; -template struct is_fundamental { - enum { value = is_integral::value || is_floating_point::value || is_void::value }; -}; + template struct is_compound { + enum { value = !is_fundamental::value }; + }; -template struct is_compound { - enum { value = !is_fundamental::value }; -}; + template struct is_array { enum { value = false }; }; + template struct is_array { enum { value = true }; }; + template struct is_array { enum { value = true }; }; -template struct is_array { enum { value = false }; }; -template struct is_array { enum { value = true }; }; -template struct is_array { enum { value = true }; }; + template struct is_const { enum { value = false }; }; + template struct is_const { enum { value = true }; }; + template struct is_const { enum { value = true }; }; -template struct is_const { enum { value = false }; }; -template struct is_const { enum { value = true }; }; -template struct is_const { enum { value = true }; }; + template struct is_pointer { enum { value = false }; }; + template struct is_pointer { enum { value = true }; }; -template struct is_pointer { enum { value = false }; }; -template struct is_pointer { enum { value = true }; }; + template struct is_reference { enum { value = false }; }; + template struct is_reference { enum { value = true }; }; -template struct is_reference { enum { value = false }; }; -template struct is_reference { enum { value = true }; }; + template struct is_same { enum { value = false }; }; + template struct is_same { enum { value = true }; }; -template struct is_same { enum { value = false }; }; -template struct is_same { enum { value = true }; }; + //=== + //add + //=== -/* add */ + template struct add_const { typedef const T type; }; + template struct add_const { typedef const T type; }; + template struct add_const { typedef const T& type; }; -template struct add_const { typedef const T type; }; -template struct add_const { typedef const T type; }; -template struct add_const { typedef const T& type; }; + template struct add_pointer { typedef T* type; }; + template struct add_pointer { typedef T** type; }; -template struct add_pointer { typedef T* type; }; -template struct add_pointer { typedef T** type; }; + template struct add_reference { typedef T& type; }; + template struct add_reference { typedef T& type; }; -template struct add_reference { typedef T& type; }; -template struct add_reference { typedef T& type; }; + //====== + //remove + //====== -/* remove */ + template struct remove_const { typedef T type; }; + template struct remove_const { typedef T type; }; + template struct remove_const { typedef T type; }; -template struct remove_const { typedef T type; }; -template struct remove_const { typedef T type; }; -template struct remove_const { typedef T type; }; + template struct remove_extent { typedef T type; }; + template struct remove_extent { typedef T type; }; + template struct remove_extent { typedef T type; }; -template struct remove_extent { typedef T type; }; -template struct remove_extent { typedef T type; }; -template struct remove_extent { typedef T type; }; + template struct remove_pointer { typedef T type; }; + template struct remove_pointer { typedef T type; }; -template struct remove_pointer { typedef T type; }; -template struct remove_pointer { typedef T type; }; + template struct remove_reference { typedef T type; }; + template struct remove_reference { typedef T type; }; +} -template struct remove_reference { typedef T type; }; -template struct remove_reference { typedef T type; }; - -} //namespace nall - -#endif //ifndef NALL_TRAITS_HPP +#endif diff --git a/src/lib/nall/ups.hpp b/src/lib/nall/ups.hpp index 737e8527..610e3646 100644 --- a/src/lib/nall/ups.hpp +++ b/src/lib/nall/ups.hpp @@ -10,184 +10,182 @@ #include namespace nall { + class ups { + public: + enum result { + ok, + patch_unreadable, + patch_unwritable, + patch_invalid, + input_invalid, + output_invalid, + patch_crc32_invalid, + input_crc32_invalid, + output_crc32_invalid, + }; -class ups { -public: - enum result { - ok, - patch_unreadable, - patch_unwritable, - patch_invalid, - input_invalid, - output_invalid, - patch_crc32_invalid, - input_crc32_invalid, - output_crc32_invalid, - }; + ups::result create(const char *patch_fn, const uint8_t *x_data, unsigned x_size, const uint8_t *y_data, unsigned y_size) { + if(!fp.open(patch_fn, file::mode_write)) return patch_unwritable; - ups::result create(const char *patch_fn, const uint8_t *x_data, unsigned x_size, const uint8_t *y_data, unsigned y_size) { - if(!fp.open(patch_fn, file::mode_write)) return patch_unwritable; + crc32 = ~0; + uint32_t x_crc32 = crc32_calculate(x_data, x_size); + uint32_t y_crc32 = crc32_calculate(y_data, y_size); - crc32 = ~0; - uint32_t x_crc32 = crc32_calculate(x_data, x_size); - uint32_t y_crc32 = crc32_calculate(y_data, y_size); + //header + write('U'); + write('P'); + write('S'); + write('1'); + encptr(x_size); + encptr(y_size); - //header - write('U'); - write('P'); - write('S'); - write('1'); - encptr(x_size); - encptr(y_size); + //body + unsigned max_size = max(x_size, y_size); + unsigned relative = 0; + for(unsigned i = 0; i < max_size;) { + uint8_t x = i < x_size ? x_data[i] : 0x00; + uint8_t y = i < y_size ? y_data[i] : 0x00; - //body - unsigned max_size = max(x_size, y_size); - unsigned relative = 0; - for(unsigned i = 0; i < max_size;) { - uint8_t x = i < x_size ? x_data[i] : 0x00; - uint8_t y = i < y_size ? y_data[i] : 0x00; + if(x == y) { + i++; + continue; + } - if(x == y) { - i++; - continue; + encptr(i++ - relative); + write(x ^ y); + + while(true) { + if(i >= max_size) { + write(0x00); + break; + } + + x = i < x_size ? x_data[i] : 0x00; + y = i < y_size ? y_data[i] : 0x00; + i++; + write(x ^ y); + if(x == y) break; + } + + relative = i; } - encptr(i++ - relative); - write(x ^ y); + //footer + for(unsigned i = 0; i < 4; i++) write(x_crc32 >> (i << 3)); + for(unsigned i = 0; i < 4; i++) write(y_crc32 >> (i << 3)); + uint32_t p_crc32 = ~crc32; + for(unsigned i = 0; i < 4; i++) write(p_crc32 >> (i << 3)); + fp.close(); + return ok; + } + + ups::result apply(const uint8_t *p_data, unsigned p_size, const uint8_t *x_data, unsigned x_size, uint8_t *&y_data, unsigned &y_size) { + if(p_size < 18) return patch_invalid; + p_buffer = p_data; + + crc32 = ~0; + + //header + if(read() != 'U') return patch_invalid; + if(read() != 'P') return patch_invalid; + if(read() != 'S') return patch_invalid; + if(read() != '1') return patch_invalid; + + unsigned px_size = decptr(); + unsigned py_size = decptr(); + + //mirror + if(x_size != px_size && x_size != py_size) return input_invalid; + y_size = (x_size == px_size) ? py_size : px_size; + y_data = new(zeromemory) uint8_t[y_size]; + + for(unsigned i = 0; i < x_size && i < y_size; i++) y_data[i] = x_data[i]; + for(unsigned i = x_size; i < y_size; i++) y_data[i] = 0x00; + + //body + unsigned relative = 0; + while(p_buffer < p_data + p_size - 12) { + relative += decptr(); + + while(true) { + uint8_t x = read(); + if(x && relative < y_size) { + uint8_t y = relative < x_size ? x_data[relative] : 0x00; + y_data[relative] = x ^ y; + } + relative++; + if(!x) break; + } + } + + //footer + unsigned px_crc32 = 0, py_crc32 = 0, pp_crc32 = 0; + for(unsigned i = 0; i < 4; i++) px_crc32 |= read() << (i << 3); + for(unsigned i = 0; i < 4; i++) py_crc32 |= read() << (i << 3); + uint32_t p_crc32 = ~crc32; + for(unsigned i = 0; i < 4; i++) pp_crc32 |= read() << (i << 3); + + uint32_t x_crc32 = crc32_calculate(x_data, x_size); + uint32_t y_crc32 = crc32_calculate(y_data, y_size); + + if(px_size != py_size) { + if(x_size == px_size && x_crc32 != px_crc32) return input_crc32_invalid; + if(x_size == py_size && x_crc32 != py_crc32) return input_crc32_invalid; + if(y_size == px_size && y_crc32 != px_crc32) return output_crc32_invalid; + if(y_size == py_size && y_crc32 != py_crc32) return output_crc32_invalid; + } else { + if(x_crc32 != px_crc32 && x_crc32 != py_crc32) return input_crc32_invalid; + if(y_crc32 != px_crc32 && y_crc32 != py_crc32) return output_crc32_invalid; + if(x_crc32 == y_crc32 && px_crc32 != py_crc32) return output_crc32_invalid; + if(x_crc32 != y_crc32 && px_crc32 == py_crc32) return output_crc32_invalid; + } + + if(p_crc32 != pp_crc32) return patch_crc32_invalid; + return ok; + } + + private: + file fp; + uint32_t crc32; + const uint8_t *p_buffer; + + uint8_t read() { + uint8_t n = *p_buffer++; + crc32 = crc32_adjust(crc32, n); + return n; + } + + void write(uint8_t n) { + fp.write(n); + crc32 = crc32_adjust(crc32, n); + } + + void encptr(uint64_t offset) { while(true) { - if(i >= max_size) { - write(0x00); + uint64_t x = offset & 0x7f; + offset >>= 7; + if(offset == 0) { + write(0x80 | x); break; } - - x = i < x_size ? x_data[i] : 0x00; - y = i < y_size ? y_data[i] : 0x00; - i++; - write(x ^ y); - if(x == y) break; + write(x); + offset--; } - - relative = i; } - //footer - for(unsigned i = 0; i < 4; i++) write(x_crc32 >> (i << 3)); - for(unsigned i = 0; i < 4; i++) write(y_crc32 >> (i << 3)); - uint32_t p_crc32 = ~crc32; - for(unsigned i = 0; i < 4; i++) write(p_crc32 >> (i << 3)); - - fp.close(); - return ok; - } - - ups::result apply(const uint8_t *p_data, unsigned p_size, const uint8_t *x_data, unsigned x_size, uint8_t *&y_data, unsigned &y_size) { - if(p_size < 18) return patch_invalid; - p_buffer = p_data; - - crc32 = ~0; - - //header - if(read() != 'U') return patch_invalid; - if(read() != 'P') return patch_invalid; - if(read() != 'S') return patch_invalid; - if(read() != '1') return patch_invalid; - - unsigned px_size = decptr(); - unsigned py_size = decptr(); - - //mirror - if(x_size != px_size && x_size != py_size) return input_invalid; - y_size = (x_size == px_size) ? py_size : px_size; - y_data = new(zeromemory) uint8_t[y_size]; - - for(unsigned i = 0; i < x_size && i < y_size; i++) y_data[i] = x_data[i]; - for(unsigned i = x_size; i < y_size; i++) y_data[i] = 0x00; - - //body - unsigned relative = 0; - while(p_buffer < p_data + p_size - 12) { - relative += decptr(); - + uint64_t decptr() { + uint64_t offset = 0, shift = 1; while(true) { uint8_t x = read(); - if(x && relative < y_size) { - uint8_t y = relative < x_size ? x_data[relative] : 0x00; - y_data[relative] = x ^ y; - } - relative++; - if(!x) break; + offset += (x & 0x7f) * shift; + if(x & 0x80) break; + shift <<= 7; + offset += shift; } + return offset; } + }; +} - //footer - unsigned px_crc32 = 0, py_crc32 = 0, pp_crc32 = 0; - for(unsigned i = 0; i < 4; i++) px_crc32 |= read() << (i << 3); - for(unsigned i = 0; i < 4; i++) py_crc32 |= read() << (i << 3); - uint32_t p_crc32 = ~crc32; - for(unsigned i = 0; i < 4; i++) pp_crc32 |= read() << (i << 3); - - uint32_t x_crc32 = crc32_calculate(x_data, x_size); - uint32_t y_crc32 = crc32_calculate(y_data, y_size); - - if(px_size != py_size) { - if(x_size == px_size && x_crc32 != px_crc32) return input_crc32_invalid; - if(x_size == py_size && x_crc32 != py_crc32) return input_crc32_invalid; - if(y_size == px_size && y_crc32 != px_crc32) return output_crc32_invalid; - if(y_size == py_size && y_crc32 != py_crc32) return output_crc32_invalid; - } else { - if(x_crc32 != px_crc32 && x_crc32 != py_crc32) return input_crc32_invalid; - if(y_crc32 != px_crc32 && y_crc32 != py_crc32) return output_crc32_invalid; - if(x_crc32 == y_crc32 && px_crc32 != py_crc32) return output_crc32_invalid; - if(x_crc32 != y_crc32 && px_crc32 == py_crc32) return output_crc32_invalid; - } - - if(p_crc32 != pp_crc32) return patch_crc32_invalid; - return ok; - } - -private: - file fp; - uint32_t crc32; - const uint8_t *p_buffer; - - uint8_t read() { - uint8_t n = *p_buffer++; - crc32 = crc32_adjust(crc32, n); - return n; - } - - void write(uint8_t n) { - fp.write(n); - crc32 = crc32_adjust(crc32, n); - } - - void encptr(uint64_t offset) { - while(true) { - uint64_t x = offset & 0x7f; - offset >>= 7; - if(offset == 0) { - write(0x80 | x); - break; - } - write(x); - offset--; - } - } - - uint64_t decptr() { - uint64_t offset = 0, shift = 1; - while(true) { - uint8_t x = read(); - offset += (x & 0x7f) * shift; - if(x & 0x80) break; - shift <<= 7; - offset += shift; - } - return offset; - } -}; - -} //namespace nall - -#endif //ifndef NALL_UPS_HPP +#endif diff --git a/src/lib/nall/utf8.hpp b/src/lib/nall/utf8.hpp index aedcbfdd..ad23fb73 100644 --- a/src/lib/nall/utf8.hpp +++ b/src/lib/nall/utf8.hpp @@ -8,64 +8,64 @@ #if defined(_WIN32) +#undef NOMINMAX +#define NOMINMAX #include namespace nall { + //UTF-8 to UTF-16 + class utf16 { + public: + operator wchar_t*() { + return buffer; + } -//UTF-8 to UTF-16 -class utf16 { -public: - operator wchar_t*() { - return buffer; - } + operator const wchar_t*() const { + 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(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; + } - ~utf16() { - delete[] buffer; - } + private: + wchar_t *buffer; + }; -private: - wchar_t *buffer; -}; + //UTF-16 to UTF-8 + class utf8 { + public: + operator char*() { + return buffer; + } -//UTF-16 to UTF-8 -class utf8 { -public: - operator char*() { - return buffer; - } + operator const char*() const { + 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(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; + } - ~utf8() { - delete[] buffer; - } + private: + char *buffer; + }; +} -private: - char *buffer; -}; +#endif //if defined(_WIN32) -} //namespace nall - -#endif //if defined(_WIN32) - -#endif //ifndef NALL_UTF8_HPP +#endif diff --git a/src/lib/nall/utility.hpp b/src/lib/nall/utility.hpp index 6d5cfd7e..14d3f873 100644 --- a/src/lib/nall/utility.hpp +++ b/src/lib/nall/utility.hpp @@ -2,29 +2,28 @@ #define NALL_UTILITY_HPP namespace nall { + template + inline void swap(T &x, T &y) { + T temp(x); + x = y; + y = temp; + } -template inline void swap(T &x, T &y) { - T temp = x; - x = y; - y = temp; + template + struct base_from_member { + T value; + base_from_member(T value_) : value(value_) {} + }; + + class noncopyable { + protected: + noncopyable() {} + ~noncopyable() {} + + private: + noncopyable(const noncopyable&); + const noncopyable& operator=(const noncopyable&); + }; } -template -struct base_from_member { - T value; - base_from_member(T value_) : value(value_) {} -}; - -class noncopyable { -protected: - noncopyable() {} - ~noncopyable() {} - -private: - noncopyable(const noncopyable&); - const noncopyable& operator=(const noncopyable&); -}; - -} //namespace nall - -#endif //ifndef NALL_UTILITY_HPP +#endif diff --git a/src/lib/nall/varint.hpp b/src/lib/nall/varint.hpp index 72eef460..cc3bb17c 100644 --- a/src/lib/nall/varint.hpp +++ b/src/lib/nall/varint.hpp @@ -6,89 +6,87 @@ #include namespace nall { - -template class uint_t { -private: - enum { bytes = (bits + 7) >> 3 }; //minimum number of bytes needed to store value - typedef typename static_if< - sizeof(int) >= bytes, - unsigned int, - typename static_if< - sizeof(long) >= bytes, - unsigned long, + template class uint_t { + private: + enum { bytes = (bits + 7) >> 3 }; //minimum number of bytes needed to store value + typedef typename static_if< + sizeof(int) >= bytes, + unsigned int, typename static_if< - sizeof(long long) >= bytes, - unsigned long long, - void + sizeof(long) >= bytes, + unsigned long, + typename static_if< + sizeof(long long) >= bytes, + unsigned long long, + void + >::type >::type - >::type - >::type T; - static_assert::value> uint_assert; - T data; + >::type T; + static_assert::value> uint_assert; + T data; -public: - inline operator T() const { return data; } - inline T operator ++(int) { T r = data; data = uclip(data + 1); return r; } - inline T operator --(int) { T r = data; data = uclip(data - 1); return r; } - inline T operator ++() { return data = uclip(data + 1); } - inline T operator --() { return data = uclip(data - 1); } - inline T operator =(const T i) { return data = uclip(i); } - inline T operator |=(const T i) { return data = uclip(data | i); } - inline T operator ^=(const T i) { return data = uclip(data ^ i); } - inline T operator &=(const T i) { return data = uclip(data & i); } - inline T operator<<=(const T i) { return data = uclip(data << i); } - inline T operator>>=(const T i) { return data = uclip(data >> i); } - inline T operator +=(const T i) { return data = uclip(data + i); } - inline T operator -=(const T i) { return data = uclip(data - i); } - inline T operator *=(const T i) { return data = uclip(data * i); } - inline T operator /=(const T i) { return data = uclip(data / i); } - inline T operator %=(const T i) { return data = uclip(data % i); } + public: + inline operator T() const { return data; } + inline T operator ++(int) { T r = data; data = uclip(data + 1); return r; } + inline T operator --(int) { T r = data; data = uclip(data - 1); return r; } + inline T operator ++() { return data = uclip(data + 1); } + inline T operator --() { return data = uclip(data - 1); } + inline T operator =(const T i) { return data = uclip(i); } + inline T operator |=(const T i) { return data = uclip(data | i); } + inline T operator ^=(const T i) { return data = uclip(data ^ i); } + inline T operator &=(const T i) { return data = uclip(data & i); } + inline T operator<<=(const T i) { return data = uclip(data << i); } + inline T operator>>=(const T i) { return data = uclip(data >> i); } + inline T operator +=(const T i) { return data = uclip(data + i); } + inline T operator -=(const T i) { return data = uclip(data - i); } + inline T operator *=(const T i) { return data = uclip(data * i); } + inline T operator /=(const T i) { return data = uclip(data / i); } + inline T operator %=(const T i) { return data = uclip(data % i); } - inline uint_t() : data(0) {} - inline uint_t(const T i) : data(uclip(i)) {} -}; + inline uint_t() : data(0) {} + inline uint_t(const T i) : data(uclip(i)) {} + }; -template class int_t { -private: - enum { bytes = (bits + 7) >> 3 }; //minimum number of bytes needed to store value - typedef typename static_if< - sizeof(int) >= bytes, - signed int, - typename static_if< - sizeof(long) >= bytes, - signed long, + template class int_t { + private: + enum { bytes = (bits + 7) >> 3 }; //minimum number of bytes needed to store value + typedef typename static_if< + sizeof(int) >= bytes, + signed int, typename static_if< - sizeof(long long) >= bytes, - signed long long, - void + sizeof(long) >= bytes, + signed long, + typename static_if< + sizeof(long long) >= bytes, + signed long long, + void + >::type >::type - >::type - >::type T; - static_assert::value> int_assert; - T data; + >::type T; + static_assert::value> int_assert; + T data; -public: - inline operator T() const { return data; } - inline T operator ++(int) { T r = data; data = sclip(data + 1); return r; } - inline T operator --(int) { T r = data; data = sclip(data - 1); return r; } - inline T operator ++() { return data = sclip(data + 1); } - inline T operator --() { return data = sclip(data - 1); } - inline T operator =(const T i) { return data = sclip(i); } - inline T operator |=(const T i) { return data = sclip(data | i); } - inline T operator ^=(const T i) { return data = sclip(data ^ i); } - inline T operator &=(const T i) { return data = sclip(data & i); } - inline T operator<<=(const T i) { return data = sclip(data << i); } - inline T operator>>=(const T i) { return data = sclip(data >> i); } - inline T operator +=(const T i) { return data = sclip(data + i); } - inline T operator -=(const T i) { return data = sclip(data - i); } - inline T operator *=(const T i) { return data = sclip(data * i); } - inline T operator /=(const T i) { return data = sclip(data / i); } - inline T operator %=(const T i) { return data = sclip(data % i); } + public: + inline operator T() const { return data; } + inline T operator ++(int) { T r = data; data = sclip(data + 1); return r; } + inline T operator --(int) { T r = data; data = sclip(data - 1); return r; } + inline T operator ++() { return data = sclip(data + 1); } + inline T operator --() { return data = sclip(data - 1); } + inline T operator =(const T i) { return data = sclip(i); } + inline T operator |=(const T i) { return data = sclip(data | i); } + inline T operator ^=(const T i) { return data = sclip(data ^ i); } + inline T operator &=(const T i) { return data = sclip(data & i); } + inline T operator<<=(const T i) { return data = sclip(data << i); } + inline T operator>>=(const T i) { return data = sclip(data >> i); } + inline T operator +=(const T i) { return data = sclip(data + i); } + inline T operator -=(const T i) { return data = sclip(data - i); } + inline T operator *=(const T i) { return data = sclip(data * i); } + inline T operator /=(const T i) { return data = sclip(data / i); } + inline T operator %=(const T i) { return data = sclip(data % i); } - inline int_t() : data(0) {} - inline int_t(const T i) : data(sclip(i)) {} -}; + inline int_t() : data(0) {} + inline int_t(const T i) : data(sclip(i)) {} + }; +} -} //namespace nall - -#endif //ifndef NALL_VARINT_HPP +#endif diff --git a/src/lib/nall/vector.hpp b/src/lib/nall/vector.hpp index 699f5e1b..ca12b806 100644 --- a/src/lib/nall/vector.hpp +++ b/src/lib/nall/vector.hpp @@ -3,160 +3,160 @@ #include #include +#include +#include namespace nall { + //linear_vector + //memory: O(capacity * 2) + // + //linear_vector uses placement new + manual destructor calls to create a + //contiguous block of memory for all objects. accessing individual elements + //is fast, though resizing the array incurs significant overhead. + //reserve() overhead is reduced from quadratic time to amortized constant time + //by resizing twice as much as requested. + // + //if objects hold memory address references to themselves (introspection), a + //valid copy constructor will be needed to keep pointers valid. -//linear_vector -//memory: O(capacity * 2) -// -//linear_vector uses placement new + manual destructor calls to create a -//contiguous block of memory for all objects. accessing individual elements -//is fast, though resizing the array incurs significant overhead. -//reserve() overhead is reduced from quadratic time to amortized constant time -//by resizing twice as much as requested. -// -//if objects hold memory address references to themselves (introspection), a -//valid copy constructor will be needed to keep pointers valid. + template class linear_vector : noncopyable { + protected: + T *pool; + unsigned poolsize, objectsize; -template class linear_vector { -protected: - T *pool; - unsigned poolsize, objectsize; + public: + unsigned size() const { return objectsize; } + unsigned capacity() const { return poolsize; } -public: - unsigned size() const { return objectsize; } - unsigned capacity() const { return poolsize; } + void reset() { + if(pool) { + for(unsigned i = 0; i < objectsize; i++) pool[i].~T(); + free(pool); + } + pool = 0; + poolsize = 0; + objectsize = 0; + } - void reset() { - if(pool) { + void reserve(unsigned newsize) { + newsize = bit::round(newsize); //round to nearest power of two (for amortized growth) + + T *poolcopy = (T*)malloc(newsize * sizeof(T)); + for(unsigned i = 0; i < min(objectsize, newsize); i++) new(poolcopy + i) T(pool[i]); for(unsigned i = 0; i < objectsize; i++) pool[i].~T(); free(pool); - } - pool = 0; - poolsize = 0; - objectsize = 0; - } - - void reserve(unsigned newsize) { - newsize <<= 1; //amortized constant growth - - T *poolcopy = (T*)malloc(newsize * sizeof(T)); - for(unsigned i = 0; i < min(objectsize, newsize); i++) new(poolcopy + i) T(pool[i]); - for(unsigned i = 0; i < objectsize; i++) pool[i].~T(); - free(pool); - pool = poolcopy; - poolsize = newsize; - objectsize = min(objectsize, newsize); - } - - void resize(unsigned newsize) { - if(newsize > poolsize) reserve(newsize); - - if(newsize < objectsize) { - //vector is shrinking; destroy excess objects - for(unsigned i = newsize; i < objectsize; i++) pool[i].~T(); - } else if(newsize > objectsize) { - //vector is expanding; allocate new objects - for(unsigned i = objectsize; i < newsize; i++) new(pool + i) T; + pool = poolcopy; + poolsize = newsize; + objectsize = min(objectsize, newsize); } - objectsize = newsize; - } + void resize(unsigned newsize) { + if(newsize > poolsize) reserve(newsize); - void add(const T data) { - if(objectsize + 1 > poolsize) reserve(objectsize + 1); - new(pool + objectsize++) T(data); - } + if(newsize < objectsize) { + //vector is shrinking; destroy excess objects + for(unsigned i = newsize; i < objectsize; i++) pool[i].~T(); + } else if(newsize > objectsize) { + //vector is expanding; allocate new objects + for(unsigned i = objectsize; i < newsize; i++) new(pool + i) T; + } - inline T& operator[](unsigned index) { - if(index >= objectsize) resize(index + 1); - return pool[index]; - } - - inline const T& operator[](unsigned index) const { - if(index >= objectsize) throw "vector[] out of bounds"; - return pool[index]; - } - - linear_vector() : pool(0), poolsize(0), objectsize(0) {} - ~linear_vector() { reset(); } -}; - -//pointer_vector -//memory: O(1) -// -//pointer_vector keeps an array of pointers to each vector object. this adds -//significant overhead to individual accesses, but allows for optimal memory -//utilization. -// -//by guaranteeing that the base memory address of each objects never changes, -//this avoids the need for an object to have a valid copy constructor. - -template class pointer_vector { -protected: - T **pool; - unsigned poolsize, objectsize; - -public: - unsigned size() const { return objectsize; } - unsigned capacity() const { return poolsize; } - - void reset() { - if(pool) { - for(unsigned i = 0; i < objectsize; i++) { if(pool[i]) delete pool[i]; } - free(pool); - } - pool = 0; - poolsize = 0; - objectsize = 0; - } - - void reserve(unsigned newsize) { - newsize <<= 1; //amortized constant growth - - for(unsigned i = newsize; i < objectsize; i++) { - if(pool[i]) { delete pool[i]; pool[i] = 0; } + objectsize = newsize; } - pool = (T**)realloc(pool, newsize * sizeof(T*)); - for(unsigned i = poolsize; i < newsize; i++) pool[i] = 0; - poolsize = newsize; - objectsize = min(objectsize, newsize); - } - - void resize(unsigned newsize) { - if(newsize > poolsize) reserve(newsize); - - for(unsigned i = newsize; i < objectsize; i++) { - if(pool[i]) { delete pool[i]; pool[i] = 0; } + void add(const T data) { + if(objectsize + 1 > poolsize) reserve(objectsize + 1); + new(pool + objectsize++) T(data); } - objectsize = newsize; - } + inline T& operator[](unsigned index) { + if(index >= objectsize) resize(index + 1); + return pool[index]; + } - void add(const T data) { - if(objectsize + 1 > poolsize) reserve(objectsize + 1); - pool[objectsize++] = new T(data); - } + inline const T& operator[](unsigned index) const { + if(index >= objectsize) throw "vector[] out of bounds"; + return pool[index]; + } - inline T& operator[](unsigned index) { - if(index >= objectsize) resize(index + 1); - if(!pool[index]) pool[index] = new T; - return *pool[index]; - } + linear_vector() : pool(0), poolsize(0), objectsize(0) {} + ~linear_vector() { reset(); } + }; - inline const T& operator[](unsigned index) const { - if(index >= objectsize || !pool[index]) throw "vector[] out of bounds"; - return *pool[index]; - } + //pointer_vector + //memory: O(1) + // + //pointer_vector keeps an array of pointers to each vector object. this adds + //significant overhead to individual accesses, but allows for optimal memory + //utilization. + // + //by guaranteeing that the base memory address of each objects never changes, + //this avoids the need for an object to have a valid copy constructor. - pointer_vector() : pool(0), poolsize(0), objectsize(0) {} - ~pointer_vector() { reset(); } -}; + template class pointer_vector : noncopyable { + protected: + T **pool; + unsigned poolsize, objectsize; -//default vector type -template class vector : public linear_vector {}; - -} //namespace nall + public: + unsigned size() const { return objectsize; } + unsigned capacity() const { return poolsize; } -#endif //ifndef NALL_VECTOR_HPP + void reset() { + if(pool) { + for(unsigned i = 0; i < objectsize; i++) { if(pool[i]) delete pool[i]; } + free(pool); + } + pool = 0; + poolsize = 0; + objectsize = 0; + } + + void reserve(unsigned newsize) { + newsize = bit::round(newsize); //round to nearest power of two (for amortized growth) + + for(unsigned i = newsize; i < objectsize; i++) { + if(pool[i]) { delete pool[i]; pool[i] = 0; } + } + + pool = (T**)realloc(pool, newsize * sizeof(T*)); + for(unsigned i = poolsize; i < newsize; i++) pool[i] = 0; + poolsize = newsize; + objectsize = min(objectsize, newsize); + } + + void resize(unsigned newsize) { + if(newsize > poolsize) reserve(newsize); + + for(unsigned i = newsize; i < objectsize; i++) { + if(pool[i]) { delete pool[i]; pool[i] = 0; } + } + + objectsize = newsize; + } + + void add(const T data) { + if(objectsize + 1 > poolsize) reserve(objectsize + 1); + pool[objectsize++] = new T(data); + } + + inline T& operator[](unsigned index) { + if(index >= objectsize) resize(index + 1); + if(!pool[index]) pool[index] = new T; + return *pool[index]; + } + + inline const T& operator[](unsigned index) const { + if(index >= objectsize || !pool[index]) throw "vector[] out of bounds"; + return *pool[index]; + } + + pointer_vector() : pool(0), poolsize(0), objectsize(0) {} + ~pointer_vector() { reset(); } + }; + + //default vector type + template class vector : public linear_vector {}; +} + +#endif diff --git a/src/lib/ruby/input/directinput.cpp b/src/lib/ruby/input/directinput.cpp index 0d4b80ad..ac9777fc 100644 --- a/src/lib/ruby/input/directinput.cpp +++ b/src/lib/ruby/input/directinput.cpp @@ -1,3 +1,4 @@ +#define DIRECTINPUT_VERSION 0x0800 #include #include diff --git a/src/lib/sync.bat b/src/lib/sync.bat index 88362bdd..47175d6e 100644 --- a/src/lib/sync.bat +++ b/src/lib/sync.bat @@ -9,3 +9,8 @@ mkdir ruby xcopy /E ..\..\..\nall nall xcopy /E ..\..\..\hiro hiro xcopy /E ..\..\..\ruby ruby + +del hiro\test* +del hiro\cc.* +del ruby\test* +del ruby\cc.* diff --git a/src/lib/tool/opgen_switch.cpp b/src/lib/tool/opgen_switch.cpp index eb6cfbde..80da12e1 100644 --- a/src/lib/tool/opgen_switch.cpp +++ b/src/lib/tool/opgen_switch.cpp @@ -3,8 +3,8 @@ using namespace nall; FILE *fp; -string data; -lstring line, part, subpart, output_op; +string data, output_op; +lstring line, part, subpart; struct OpList { string name; @@ -89,7 +89,7 @@ void gen_op() { void gen_end() { string t; for(unsigned i = 0; i < op_count; i++) { - t = output_op[0]; + t = output_op; replace(t, "$$", op_list[i].name); replace(t, "$0", op_list[i].arg[0]); replace(t, "$1", op_list[i].arg[1]); @@ -103,12 +103,14 @@ void gen_end() { } } -void generate(char *dest, char *src) { +void generate(const char *dest, const char *src) { fread(data, src); replace(data, "\r\n", "\n"); split(line, "\n", data); fp = fopen(dest, "wb"); + string header = CLASS_NAME; + fprintf(fp, "#ifdef %s_CPP\n\n", (const char*)strupper(header)); //inclusion guard line_num = 0; while(line_num < count(line)) { @@ -120,5 +122,6 @@ void generate(char *dest, char *src) { gen_end(); } + fprintf(fp, "#endif\n"); fclose(fp); } diff --git a/src/memory/smemory/smemory.cpp b/src/memory/smemory/smemory.cpp index cf201e67..a9ffce6a 100644 --- a/src/memory/smemory/smemory.cpp +++ b/src/memory/smemory/smemory.cpp @@ -1,4 +1,6 @@ #include <../base.hpp> +#include <../chip/chip.hpp> +#include <../cart/cart.hpp> #define SMEMORY_CPP #include "mapper/system.cpp" @@ -7,7 +9,7 @@ void sBus::power() { for(unsigned i = 0x2000; i <= 0x5fff; i++) memory::mmio.map(i, memory::mmio_unmapped); - for(unsigned i = 0; i < memory::wram.size(); i++) memory::wram[i] = config::cpu.wram_init_value; + for(unsigned i = 0; i < memory::wram.size(); i++) memory::wram[i] = snes.config.cpu.wram_init_value; reset(); } diff --git a/src/ppu/bppu/bppu.cpp b/src/ppu/bppu/bppu.cpp index 6ab44586..d5481f3c 100644 --- a/src/ppu/bppu/bppu.cpp +++ b/src/ppu/bppu/bppu.cpp @@ -40,22 +40,22 @@ void bPPU::add_clocks(unsigned clocks) { void bPPU::scanline() { snes.scanline(); - line.y = ivcounter(); + line = ivcounter(); - if(line.y == 0) { + if(line == 0) { //RTO flag reset regs.time_over = false; regs.range_over = false; } - if(line.y == 1) { + if(line == 1) { //mosaic reset for(int bg = BG1; bg <= BG4; bg++) regs.bg_y[bg] = 1; regs.mosaic_countdown = regs.mosaic_size + 1; regs.mosaic_countdown--; } else { for(int bg = BG1; bg <= BG4; bg++) { - if(!regs.mosaic_enabled[bg] || !regs.mosaic_countdown) regs.bg_y[bg] = line.y; + if(!regs.mosaic_enabled[bg] || !regs.mosaic_countdown) regs.bg_y[bg] = line; } if(!regs.mosaic_countdown) regs.mosaic_countdown = regs.mosaic_size + 1; regs.mosaic_countdown--; @@ -68,7 +68,7 @@ void bPPU::render_scanline() { if(status.render_output == false) return; #endif - if(line.y >= 1 && line.y < (!overscan() ? 225 : 240)) { + if(line >= 1 && line < (!overscan() ? 225 : 240)) { render_line_oam_rto(); render_line(); } diff --git a/src/ppu/bppu/bppu.hpp b/src/ppu/bppu/bppu.hpp index bdce2a3b..5e2f2135 100644 --- a/src/ppu/bppu/bppu.hpp +++ b/src/ppu/bppu/bppu.hpp @@ -4,18 +4,15 @@ public: void add_clocks(unsigned clocks); uint8 region; + unsigned line; enum { NTSC = 0, PAL = 1 }; enum { BG1 = 0, BG2 = 1, BG3 = 2, BG4 = 3, OAM = 4, BACK = 5, COL = 5 }; enum { SC_32x32 = 0, SC_64x32 = 1, SC_32x64 = 2, SC_64x64 = 3 }; - struct { - uint y; - } line; - struct { bool interlace; - bool overscan; + bool overscan; } display; struct { @@ -153,9 +150,9 @@ public: uint16 oam_tdaddr; } cache; - alwaysinline bool interlace() { return display.interlace; } - alwaysinline bool overscan() { return display.overscan; } - alwaysinline bool hires() { return (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6); } + alwaysinline bool interlace() const { return display.interlace; } + alwaysinline bool overscan() const { return display.overscan; } + alwaysinline bool hires() const { return (regs.pseudo_hires || regs.bg_mode == 5 || regs.bg_mode == 6); } uint16 get_vram_address(); uint8 vram_mmio_read (uint16 addr); @@ -230,8 +227,8 @@ public: uint8 mmio_r213e(); //STAT77 uint8 mmio_r213f(); //STAT78 - uint8 mmio_read(uint addr); - void mmio_write(uint addr, uint8 data); + uint8 mmio_read(unsigned addr); + void mmio_write(unsigned addr, uint8 data); void latch_counters(); diff --git a/src/ppu/bppu/bppu_mmio.cpp b/src/ppu/bppu/bppu_mmio.cpp index d3276e16..8b8945f3 100644 --- a/src/ppu/bppu/bppu_mmio.cpp +++ b/src/ppu/bppu/bppu_mmio.cpp @@ -737,7 +737,7 @@ uint8 r = 0x00; return regs.ppu2_mdr; } -uint8 bPPU::mmio_read(uint addr) { +uint8 bPPU::mmio_read(unsigned addr) { scheduler.sync_cpuppu(); switch(addr & 0xffff) { @@ -777,7 +777,7 @@ uint8 bPPU::mmio_read(uint addr) { return cpu.regs.mdr; } -void bPPU::mmio_write(uint addr, uint8 data) { +void bPPU::mmio_write(unsigned addr, uint8 data) { scheduler.sync_cpuppu(); switch(addr & 0xffff) { diff --git a/src/ppu/bppu/bppu_render_addsub.cpp b/src/ppu/bppu/bppu_render_addsub.cpp index e47ad811..447aa4e1 100644 --- a/src/ppu/bppu/bppu_render_addsub.cpp +++ b/src/ppu/bppu/bppu_render_addsub.cpp @@ -1,21 +1,19 @@ #ifdef BPPU_CPP - -/***** - * Color Addition / Subtraction - * Thanks to blargg for the optimized algorithms - *****/ + +//color addition / subtraction +//thanks go to blargg for the optimized algorithms inline uint16 bPPU::addsub(uint32 x, uint32 y, bool halve) { if(!regs.color_mode) { if(!halve) { - uint sum = x + y; - uint carry = (sum - ((x ^ y) & 0x0421)) & 0x8420; + unsigned sum = x + y; + unsigned carry = (sum - ((x ^ y) & 0x0421)) & 0x8420; return (sum - carry) | (carry - (carry >> 5)); } else { return (x + y - ((x ^ y) & 0x0421)) >> 1; } } else { - uint diff = x - y + 0x8420; - uint borrow = (diff - ((x ^ y) & 0x8420)) & 0x8420; + unsigned diff = x - y + 0x8420; + unsigned borrow = (diff - ((x ^ y) & 0x8420)) & 0x8420; if(!halve) { return (diff - borrow) & (borrow - (borrow >> 5)); } else { @@ -24,4 +22,4 @@ inline uint16 bPPU::addsub(uint32 x, uint32 y, bool halve) { } } -#endif //ifdef BPPU_CPP +#endif diff --git a/src/ppu/bppu/bppu_render_bg.cpp b/src/ppu/bppu/bppu_render_bg.cpp index 3a2b022a..0bf63d7a 100644 --- a/src/ppu/bppu/bppu_render_bg.cpp +++ b/src/ppu/bppu/bppu_render_bg.cpp @@ -2,8 +2,8 @@ //called once at the start of every rendered scanline void bPPU::update_bg_info() { - uint hires = (regs.bg_mode == 5 || regs.bg_mode == 6); - uint width = (!hires) ? 256 : 512; + unsigned hires = (regs.bg_mode == 5 || regs.bg_mode == 6); + unsigned width = (!hires) ? 256 : 512; for(int bg = 0; bg < 4; bg++) { bg_info[bg].th = (regs.bg_tilesize[bg]) ? 4 : 3; @@ -71,7 +71,7 @@ void bPPU::render_line_bg(uint8 bg, uint8 color_depth, uint8 pri0_pos, uint8 pri uint16 tile_mask = 0x0fff >> color_depth; //0x0fff, 0x07ff, 0x03ff //4 + color_depth = >>(4-6) -- / {16, 32, 64 } bytes/tile //index is a tile number count to add to base tile number - uint tiledata_index = regs.bg_tdaddr[bg] >> (4 + color_depth); + unsigned tiledata_index = regs.bg_tdaddr[bg] >> (4 + color_depth); uint8 *bg_td = bg_tiledata[color_depth]; uint8 *bg_td_state = bg_tiledata_state[color_depth]; @@ -85,8 +85,8 @@ void bPPU::render_line_bg(uint8 bg, uint8 color_depth, uint8 pri0_pos, uint8 pri uint16 hscroll = regs.bg_hofs[bg]; uint16 vscroll = regs.bg_vofs[bg]; - uint hires = (regs.bg_mode == 5 || regs.bg_mode == 6); - uint width = (!hires) ? 256 : 512; + unsigned hires = (regs.bg_mode == 5 || regs.bg_mode == 6); + unsigned width = (!hires) ? 256 : 512; if(hires) { hscroll <<= 1; @@ -95,13 +95,13 @@ void bPPU::render_line_bg(uint8 bg, uint8 color_depth, uint8 pri0_pos, uint8 pri uint16 *mtable = mosaic_table[(regs.mosaic_enabled[bg]) ? regs.mosaic_size : 0]; - uint16 hval, vval; - uint16 t, tile_pri, tile_num; - uint8 pal_index, pal_num; - uint8 *tile_ptr; - uint xpos, ypos; - uint16 hoffset, voffset, opt_x, col; - bool mirror_x, mirror_y; + uint16 hval, vval; + uint16 t, tile_pri, tile_num; + uint8 pal_index, pal_num; + uint8 *tile_ptr; + unsigned xpos, ypos; + uint16 hoffset, voffset, opt_x, col; + bool mirror_x, mirror_y; const bool is_opt_mode = (regs.bg_mode == 2 || regs.bg_mode == 4 || regs.bg_mode == 6); build_window_tables(bg); diff --git a/src/ppu/bppu/bppu_render_line.cpp b/src/ppu/bppu/bppu_render_line.cpp index 43400ba6..47f734b9 100644 --- a/src/ppu/bppu/bppu_render_line.cpp +++ b/src/ppu/bppu/bppu_render_line.cpp @@ -85,7 +85,7 @@ inline uint16 bPPU::get_pixel_swap(uint32 x) { } inline void bPPU::render_line_output() { - uint16 *ptr = (uint16*)output + (line.y * 1024) + + uint16 *ptr = (uint16*)output + (line * 1024) + ((interlace() && ifield()) ? 512 : 0); uint16 *luma_b = light_table_b [regs.display_brightness]; uint16 *luma_gr = light_table_gr[regs.display_brightness]; @@ -131,7 +131,7 @@ inline void bPPU::render_line_output() { } inline void bPPU::render_line_clear() { - uint16 *ptr = (uint16*)output + (line.y * 1024) + + uint16 *ptr = (uint16*)output + (line * 1024) + ((interlace() && ifield()) ? 512 : 0); uint16 width = (!regs.pseudo_hires && regs.bg_mode != 5 && regs.bg_mode != 6) ? 256 : 512; memset(ptr, 0, width * 2 * sizeof(uint16)); diff --git a/src/ppu/bppu/bppu_render_mode7.cpp b/src/ppu/bppu/bppu_render_mode7.cpp index 18de21f0..4134b51c 100644 --- a/src/ppu/bppu/bppu_render_mode7.cpp +++ b/src/ppu/bppu/bppu_render_mode7.cpp @@ -46,7 +46,7 @@ void bPPU::render_line_mode7(uint8 bg, uint8 pri0_pos, uint8 pri1_pos) { uint8 *wt_main = window[bg].main; uint8 *wt_sub = window[bg].sub; - int32 y = (regs.mode7_vflip == false) ? (line.y) : (255 - line.y); + int32 y = (regs.mode7_vflip == false ? line : 255 - line); uint16 *mtable_x, *mtable_y; if(bg == BG1) { diff --git a/src/ppu/bppu/bppu_render_oam.cpp b/src/ppu/bppu/bppu_render_oam.cpp index 5394fa73..ee0e9042 100644 --- a/src/ppu/bppu/bppu_render_oam.cpp +++ b/src/ppu/bppu/bppu_render_oam.cpp @@ -58,15 +58,15 @@ bool bPPU::is_sprite_on_scanline() { if(spr->x > 256 && (spr->x + spr->width - 1) < 512) return false; int spr_height = (regs.oam_interlace == false) ? (spr->height) : (spr->height >> 1); - if(line.y >= spr->y && line.y < (spr->y + spr_height)) return true; - if((spr->y + spr_height) >= 256 && line.y < ((spr->y + spr_height) & 255)) return true; + if(line >= spr->y && line < (spr->y + spr_height)) return true; + if((spr->y + spr_height) >= 256 && line < ((spr->y + spr_height) & 255)) return true; return false; } void bPPU::load_oam_tiles() { uint16 tile_width = spr->width >> 3; int x = spr->x; - int y = line.y - spr->y; + int y = line - spr->y; if(regs.oam_interlace == true) { y <<= 1; } @@ -96,21 +96,21 @@ void bPPU::load_oam_tiles() { chry &= 15; chry <<= 4; - for(uint tx = 0; tx < tile_width; tx++) { - uint sx = (x + (tx << 3)) & 511; + for(unsigned tx = 0; tx < tile_width; tx++) { + unsigned sx = (x + (tx << 3)) & 511; //ignore sprites that are offscreen, x==256 is a special case that loads all tiles in OBJ if(x != 256 && sx >= 256 && (sx + 7) < 512) continue; if(regs.oam_tilecount++ > 34) break; - uint n = regs.oam_tilecount - 1; + unsigned n = regs.oam_tilecount - 1; oam_tilelist[n].x = sx; oam_tilelist[n].y = y; oam_tilelist[n].pri = spr->priority; oam_tilelist[n].pal = 128 + (spr->palette << 4); oam_tilelist[n].hflip = spr->hflip; - uint mx = (spr->hflip == false) ? tx : ((tile_width - 1) - tx); - uint pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5); + unsigned mx = (spr->hflip == false) ? tx : ((tile_width - 1) - tx); + unsigned pos = tdaddr + ((chry + ((chrx + mx) & 15)) << 5); oam_tilelist[n].tile = (pos >> 5) & 0x07ff; } } @@ -124,12 +124,12 @@ void bPPU::render_oam_tile(int tile_num) { render_bg_tile(COLORDEPTH_16, t->tile); } - uint sx = t->x; + unsigned sx = t->x; uint8 *tile_ptr = (uint8*)oam_td + (t->tile << 6) + ((t->y & 7) << 3); - for(uint x = 0; x < 8; x++) { + for(unsigned x = 0; x < 8; x++) { sx &= 511; if(sx < 256) { - uint col = *(tile_ptr + ((t->hflip == false) ? x : (7 - x))); + unsigned col = *(tile_ptr + ((t->hflip == false) ? x : (7 - x))); if(col) { col += t->pal; oam_line_pal[sx] = col; diff --git a/src/ppu/counter.cpp b/src/ppu/counter.cpp index a61f8b62..17bdce7e 100644 --- a/src/ppu/counter.cpp +++ b/src/ppu/counter.cpp @@ -1,9 +1,9 @@ #ifdef PPU_CPP //wrappers to allow PPUcounter::tick()/tock() to be inlined -bool PPUcounter::region() { return snes.region() == SNES::NTSC ? 0 : 1; } -bool PPUcounter::interlace() { return ppu.interlace(); } -void PPUcounter::scanline() { cpu.scanline(); } +bool PPUcounter::region() const { return snes.region() == SNES::NTSC ? 0 : 1; } +bool PPUcounter::interlace() const { return ppu.interlace(); } +void PPUcounter::scanline() { cpu.scanline(); } //one PPU dot = 4 CPU clocks // @@ -14,7 +14,7 @@ void PPUcounter::scanline() { cpu.scanline(); } //dot 323 range = { 1292, 1294, 1296 } //dot 327 range = { 1310, 1312, 1314 } -uint16 PPUcounter::hdot() { +uint16 PPUcounter::hdot() const { if(region() == 0 && interlace() == false && status.vcounter == 240 && status.field == 1) { return (status.hcounter >> 2); } else { @@ -22,12 +22,12 @@ uint16 PPUcounter::hdot() { } } -uint16 PPUcounter::lineclocks() { +uint16 PPUcounter::lineclocks() const { if(region() == 0 && interlace() == false && vcounter() == 240 && status.field == 1) return 1360; return 1364; } -uint16 PPUcounter::ilineclocks() { +uint16 PPUcounter::ilineclocks() const { if(region() == 0 && interlace() == false && ivcounter() == 240 && status.field == 1) return 1360; return 1364; } @@ -47,4 +47,4 @@ void PPUcounter::reset() { } } -#endif //ifndef PPU_CPP +#endif diff --git a/src/ppu/counter.hpp b/src/ppu/counter.hpp index a38204a0..515f64ee 100644 --- a/src/ppu/counter.hpp +++ b/src/ppu/counter.hpp @@ -32,28 +32,28 @@ public: } //timing information relative to S-CPU - alwaysinline bool field () { return status.field; } - alwaysinline uint16 vcounter() { return status.vcounter; } - alwaysinline uint16 hcounter() { return status.hcounter; } - uint16 hdot(); - uint16 lineclocks(); + alwaysinline bool field () const { return status.field; } + alwaysinline uint16 vcounter() const { return status.vcounter; } + alwaysinline uint16 hcounter() const { return status.hcounter; } + uint16 hdot() const; + uint16 lineclocks() const; //timing history information relative to S-CPU - alwaysinline bool field (unsigned offset) { return history.field [(history.index - (offset >> 1)) & 2047]; } - alwaysinline uint16 vcounter(unsigned offset) { return history.vcounter[(history.index - (offset >> 1)) & 2047]; } - alwaysinline uint16 hcounter(unsigned offset) { return history.hcounter[(history.index - (offset >> 1)) & 2047]; } + alwaysinline bool field (unsigned offset) const { return history.field [(history.index - (offset >> 1)) & 2047]; } + alwaysinline uint16 vcounter(unsigned offset) const { return history.vcounter[(history.index - (offset >> 1)) & 2047]; } + alwaysinline uint16 hcounter(unsigned offset) const { return history.hcounter[(history.index - (offset >> 1)) & 2047]; } //timing information relative to S-PPU - alwaysinline bool ifield() { return history.field [(history.index - (history.ppudiff >> 1)) & 2047]; } - alwaysinline uint16 ivcounter() { return history.vcounter[(history.index - (history.ppudiff >> 1)) & 2047]; } - alwaysinline uint16 ihcounter() { return history.hcounter[(history.index - (history.ppudiff >> 1)) & 2047]; } - uint16 ilineclocks(); + alwaysinline bool ifield() const { return history.field [(history.index - (history.ppudiff >> 1)) & 2047]; } + alwaysinline uint16 ivcounter() const { return history.vcounter[(history.index - (history.ppudiff >> 1)) & 2047]; } + alwaysinline uint16 ihcounter() const { return history.hcounter[(history.index - (history.ppudiff >> 1)) & 2047]; } + uint16 ilineclocks() const; void reset(); private: - bool region(); - bool interlace(); + bool region() const; + bool interlace() const; void scanline(); struct { diff --git a/src/ppu/ppu.cpp b/src/ppu/ppu.cpp index 01528a72..2ddf84cd 100644 --- a/src/ppu/ppu.cpp +++ b/src/ppu/ppu.cpp @@ -28,7 +28,6 @@ void PPU::power() { } void PPU::reset() { - PPUcounter::reset(); memset(output, 0, 512 * 480 * sizeof(uint16)); } diff --git a/src/ppu/ppu.hpp b/src/ppu/ppu.hpp index 257aef16..a6064add 100644 --- a/src/ppu/ppu.hpp +++ b/src/ppu/ppu.hpp @@ -25,9 +25,9 @@ public: //* reported by $213f uint8 ppu2_version; - virtual bool interlace() = 0; - virtual bool overscan() = 0; - virtual bool hires() = 0; + virtual bool interlace() const = 0; + virtual bool overscan() const = 0; + virtual bool hires() const = 0; virtual void latch_counters() = 0; diff --git a/src/reader/reader.cpp b/src/reader/reader.cpp index df1dcc8c..035c7129 100644 --- a/src/reader/reader.cpp +++ b/src/reader/reader.cpp @@ -1,6 +1,7 @@ #include <../base.hpp> #define READER_CPP - + +#include "reader.hpp" #include "filereader.cpp" #if defined(GZIP_SUPPORT) diff --git a/src/smp/ssmp/core/op_misc.cpp b/src/smp/ssmp/core/op_misc.cpp index eb4360a9..a778b9e7 100644 --- a/src/smp/ssmp/core/op_misc.cpp +++ b/src/smp/ssmp/core/op_misc.cpp @@ -1,3 +1,5 @@ +#ifdef SSMP_CPP + //nop case 0x00: { op_io(); @@ -344,3 +346,4 @@ case 0x9e: { regs.p.z = (regs.a == 0); } break; +#endif diff --git a/src/smp/ssmp/core/op_mov.cpp b/src/smp/ssmp/core/op_mov.cpp index 5ebac4e1..03890394 100644 --- a/src/smp/ssmp/core/op_mov.cpp +++ b/src/smp/ssmp/core/op_mov.cpp @@ -1,3 +1,5 @@ +#ifdef SSMP_CPP + //mov_a_x case 0x7d: { op_io(); @@ -387,3 +389,4 @@ case 0xca: { op_writeaddr(dp, rd); } break; +#endif diff --git a/src/smp/ssmp/core/op_pc.cpp b/src/smp/ssmp/core/op_pc.cpp index d6f9e4b1..b9b59925 100644 --- a/src/smp/ssmp/core/op_pc.cpp +++ b/src/smp/ssmp/core/op_pc.cpp @@ -1,3 +1,5 @@ +#ifdef SSMP_CPP + //bra case 0x2f: { rd = op_readpc(); @@ -601,3 +603,4 @@ case 0x7f: { regs.pc = rd; } break; +#endif diff --git a/src/smp/ssmp/core/op_read.cpp b/src/smp/ssmp/core/op_read.cpp index 4109360d..3f8f77fd 100644 --- a/src/smp/ssmp/core/op_read.cpp +++ b/src/smp/ssmp/core/op_read.cpp @@ -1,3 +1,5 @@ +#ifdef SSMP_CPP + //adc_a_const case 0x88: { rd = op_readpc(); @@ -742,3 +744,4 @@ case 0x2a: { regs.p.c = regs.p.c | !(rd & (1 << bit)); } break; +#endif diff --git a/src/smp/ssmp/core/op_rmw.cpp b/src/smp/ssmp/core/op_rmw.cpp index 7c331626..7bba31b6 100644 --- a/src/smp/ssmp/core/op_rmw.cpp +++ b/src/smp/ssmp/core/op_rmw.cpp @@ -1,3 +1,5 @@ +#ifdef SSMP_CPP + //inc_a case 0xbc: { op_io(); @@ -260,3 +262,4 @@ case 0x1a: { regs.p.z = (rd == 0); } break; +#endif diff --git a/src/smp/ssmp/memory/memory.cpp b/src/smp/ssmp/memory/memory.cpp index 4c596021..431b87d9 100644 --- a/src/smp/ssmp/memory/memory.cpp +++ b/src/smp/ssmp/memory/memory.cpp @@ -258,12 +258,12 @@ void sSMP::op_writeaddr(uint16 addr, uint8 data) { alwaysinline uint8 sSMP::op_readdp(uint8 addr) { - return op_read((uint(regs.p.p) << 8) + addr); + return op_read((unsigned(regs.p.p) << 8) + addr); } alwaysinline void sSMP::op_writedp(uint8 addr, uint8 data) { - op_write((uint(regs.p.p) << 8) + addr, data); + op_write((unsigned(regs.p.p) << 8) + addr, data); } #endif //ifdef SSMP_CPP diff --git a/src/smp/ssmp/memory/memory.hpp b/src/smp/ssmp/memory/memory.hpp index 39ba859d..d6e36d51 100644 --- a/src/smp/ssmp/memory/memory.hpp +++ b/src/smp/ssmp/memory/memory.hpp @@ -4,9 +4,9 @@ uint8 port_read(uint8 port); void port_write(uint8 port, uint8 data); -/***** - * core SMP bus functions - *****/ + //====================== + //core SMP bus functions + //====================== uint8 op_busread(uint16 addr); void op_buswrite(uint16 addr, uint8 data); @@ -14,9 +14,9 @@ uint8 op_read(uint16 addr); void op_write(uint16 addr, uint8 data); -/***** - * helper memory addressing functions used by SMP core - *****/ + //=================================================== + //helper memory addressing functions used by SMP core + //=================================================== uint8 op_readpc(); uint8 op_readstack(); diff --git a/src/smp/ssmp/ssmp.cpp b/src/smp/ssmp/ssmp.cpp index 1f26efd2..8ec73bc1 100644 --- a/src/smp/ssmp/ssmp.cpp +++ b/src/smp/ssmp/ssmp.cpp @@ -6,8 +6,8 @@ #include "timing/timing.cpp" void sSMP::power() { - for(unsigned i = 0; i < 65536; i++) { - //SNES hardware APURAM contains pseudo-random data upon power up + for(unsigned i = 0; i < memory::apuram.size(); i++) { + //SNES hardware APURAM contains pseudo-random data upon power up (exact formula is unknown.) //memory::apuram.write(i, (i & 32) ? 0xff : 0x00); memory::apuram.write(i, 0x00); } diff --git a/src/smp/ssmp/ssmp.hpp b/src/smp/ssmp/ssmp.hpp index 2e882355..c8389b2e 100644 --- a/src/smp/ssmp/ssmp.hpp +++ b/src/smp/ssmp/ssmp.hpp @@ -2,7 +2,6 @@ class sSMP : public SMP { public: void enter(); -public: #include "core/core.hpp" #include "memory/memory.hpp" #include "timing/timing.hpp" diff --git a/src/smp/ssmp/timing/timing.cpp b/src/smp/ssmp/timing/timing.cpp index 508a2d66..80d9a794 100644 --- a/src/smp/ssmp/timing/timing.cpp +++ b/src/smp/ssmp/timing/timing.cpp @@ -1,15 +1,13 @@ #ifdef SSMP_CPP -alwaysinline -void sSMP::add_clocks(uint clocks) { +void sSMP::add_clocks(unsigned clocks) { scheduler.addclocks_smp(clocks); } -alwaysinline void sSMP::tick_timers() { t0.tick(); t1.tick(); t2.tick(); } -#endif //ifdef SSMP_CPP +#endif diff --git a/src/smp/ssmp/timing/timing.hpp b/src/smp/ssmp/timing/timing.hpp index 0f7376be..e72b39c2 100644 --- a/src/smp/ssmp/timing/timing.hpp +++ b/src/smp/ssmp/timing/timing.hpp @@ -29,6 +29,6 @@ public: sSMPTimer<128> t1; sSMPTimer< 16> t2; - void add_clocks(uint clocks); - void tick_timers(); + alwaysinline void add_clocks(unsigned clocks); + alwaysinline void tick_timers(); uint32 clocks_executed(); diff --git a/src/snes/scheduler/scheduler.cpp b/src/snes/scheduler/scheduler.cpp index 96e243d5..512e33ce 100644 --- a/src/snes/scheduler/scheduler.cpp +++ b/src/snes/scheduler/scheduler.cpp @@ -1,56 +1,56 @@ #ifdef SNES_CPP -Scheduler scheduler; - -void threadentry_cpu() { cpu.enter(); } -void threadentry_smp() { smp.enter(); } -void threadentry_ppu() { ppu.enter(); } -void threadentry_dsp() { dsp.enter(); } - -void Scheduler::enter() { - switch(clock.active) { - case THREAD_CPU: co_switch(thread_cpu); break; - case THREAD_SMP: co_switch(thread_smp); break; - case THREAD_PPU: co_switch(thread_ppu); break; - case THREAD_DSP: co_switch(thread_dsp); break; - } -} - -void Scheduler::exit() { - co_switch(thread_snes); -} - -void Scheduler::init() { - clock.cpu_freq = snes.region() == SNES::NTSC - ? config::cpu.ntsc_clock_rate - : config::cpu.pal_clock_rate; - clock.smp_freq = snes.region() == SNES::NTSC - ? config::smp.ntsc_clock_rate - : config::smp.pal_clock_rate; - - clock.active = THREAD_CPU; - clock.cpuppu = 0; - clock.cpusmp = 0; - clock.smpdsp = 0; - - if(thread_cpu) co_delete(thread_cpu); - if(thread_smp) co_delete(thread_smp); - if(thread_ppu) co_delete(thread_ppu); - if(thread_dsp) co_delete(thread_dsp); - - thread_snes = co_active(); - thread_cpu = co_create(65536 * sizeof(void*), threadentry_cpu); - thread_smp = co_create(65536 * sizeof(void*), threadentry_smp); - thread_ppu = co_create(65536 * sizeof(void*), threadentry_ppu); - thread_dsp = co_create(65536 * sizeof(void*), threadentry_dsp); -} +Scheduler scheduler; -Scheduler::Scheduler() { - thread_snes = 0; - thread_cpu = 0; - thread_smp = 0; - thread_ppu = 0; - thread_dsp = 0; -} +void threadentry_cpu() { cpu.enter(); } +void threadentry_smp() { smp.enter(); } +void threadentry_ppu() { ppu.enter(); } +void threadentry_dsp() { dsp.enter(); } + +void Scheduler::enter() { + switch(clock.active) { + case THREAD_CPU: co_switch(thread_cpu); break; + case THREAD_SMP: co_switch(thread_smp); break; + case THREAD_PPU: co_switch(thread_ppu); break; + case THREAD_DSP: co_switch(thread_dsp); break; + } +} + +void Scheduler::exit() { + co_switch(thread_snes); +} + +void Scheduler::init() { + clock.cpu_freq = snes.region() == SNES::NTSC + ? snes.config.cpu.ntsc_clock_rate + : snes.config.cpu.pal_clock_rate; + clock.smp_freq = snes.region() == SNES::NTSC + ? snes.config.smp.ntsc_clock_rate + : snes.config.smp.pal_clock_rate; + + clock.active = THREAD_CPU; + clock.cpuppu = 0; + clock.cpusmp = 0; + clock.smpdsp = 0; + + if(thread_cpu) co_delete(thread_cpu); + if(thread_smp) co_delete(thread_smp); + if(thread_ppu) co_delete(thread_ppu); + if(thread_dsp) co_delete(thread_dsp); + + thread_snes = co_active(); + thread_cpu = co_create(65536 * sizeof(void*), threadentry_cpu); + thread_smp = co_create(65536 * sizeof(void*), threadentry_smp); + thread_ppu = co_create(65536 * sizeof(void*), threadentry_ppu); + thread_dsp = co_create(65536 * sizeof(void*), threadentry_dsp); +} + +Scheduler::Scheduler() { + thread_snes = 0; + thread_cpu = 0; + thread_smp = 0; + thread_ppu = 0; + thread_dsp = 0; +} #endif //ifdef SNES_CPP diff --git a/src/snes/snes.cpp b/src/snes/snes.cpp index 3d2720a0..d10441eb 100644 --- a/src/snes/snes.cpp +++ b/src/snes/snes.cpp @@ -1,4 +1,6 @@ #include <../base.hpp> +#include <../chip/chip.hpp> +#include <../cart/cart.hpp> #define SNES_CPP SNES snes; @@ -62,8 +64,8 @@ void SNES::term() { } void SNES::power() { - snes_region = max(0, min(2, config::snes.region)); - snes_expansion = max(0, min(1, config::snes.expansion_port)); + snes_region = max(0, min(2, snes.config.region)); + snes_expansion = max(0, min(1, snes.config.expansion_port)); if(snes_region == Autodetect) { snes_region = cartridge.region() == Cartridge::NTSC ? NTSC : PAL; @@ -71,13 +73,14 @@ void SNES::power() { scheduler.init(); + ppu.PPUcounter::reset(); cpu.power(); smp.power(); dsp.power(); ppu.power(); bus.power(); - if(expansion() == ExpansionBSX) { bsxbase.power(); } + if(expansion() == ExpansionBSX) bsxbase.power(); if(cartridge.info.bsxcart) bsxcart.power(); if(cartridge.info.bsxflash) bsxflash.power(); @@ -114,8 +117,8 @@ void SNES::power() { if(cartridge.info.obc1) obc1.enable(); if(cartridge.info.st010) st010.enable(); - input.port_set_device(0, config::snes.controller_port1); - input.port_set_device(1, config::snes.controller_port2); + input.port_set_device(0, snes.config.controller_port1); + input.port_set_device(1, snes.config.controller_port2); input.update(); video.update(); } @@ -123,6 +126,7 @@ void SNES::power() { void SNES::reset() { scheduler.init(); + ppu.PPUcounter::reset(); cpu.reset(); smp.reset(); dsp.reset(); @@ -144,8 +148,8 @@ void SNES::reset() { if(cartridge.info.obc1) obc1.reset(); if(cartridge.info.st010) st010.reset(); - input.port_set_device(0, config::snes.controller_port1); - input.port_set_device(1, config::snes.controller_port2); + input.port_set_device(0, snes.config.controller_port1); + input.port_set_device(1, snes.config.controller_port2); input.update(); video.update(); } @@ -163,13 +167,39 @@ void SNES::scanline() { void SNES::frame() { } -SNES::Region SNES::region() { +SNES::Region SNES::region() const { return (SNES::Region)snes_region; } -SNES::ExpansionPortDevice SNES::expansion() { +SNES::ExpansionPortDevice SNES::expansion() const { return (SNES::ExpansionPortDevice)snes_expansion; } SNES::SNES() : snes_region(NTSC), snes_expansion(ExpansionNone) { + config.controller_port1 = Input::DeviceJoypad; + config.controller_port2 = Input::DeviceJoypad; + config.expansion_port = ExpansionBSX; + config.region = Autodetect; + + config.file.autodetect_type = false; + config.file.bypass_patch_crc32 = false; + + config.path.base = ""; + config.path.user = ""; + config.path.rom = ""; + config.path.save = ""; + config.path.patch = ""; + config.path.cheat = ""; + config.path.exportdata = ""; + config.path.bsx = ""; + config.path.st = ""; + + config.cpu.ntsc_clock_rate = 21477272; + config.cpu.pal_clock_rate = 21281370; + config.cpu.alu_mul_delay = 2; + config.cpu.alu_div_delay = 2; + config.cpu.wram_init_value = 0x55; + + config.smp.ntsc_clock_rate = 32041 * 768; + config.smp.pal_clock_rate = 32041 * 768; } diff --git a/src/snes/snes.hpp b/src/snes/snes.hpp index 78e9d337..8336046b 100644 --- a/src/snes/snes.hpp +++ b/src/snes/snes.hpp @@ -10,6 +10,37 @@ public: enum RegionAutodetect { Autodetect = 2 }; enum ExpansionPortDevice { ExpansionNone = 0, ExpansionBSX = 1 }; + struct Config { + unsigned controller_port1; + unsigned controller_port2; + unsigned expansion_port; + unsigned region; + + struct File { + bool autodetect_type; + bool bypass_patch_crc32; + } file; + + struct Path { + string base, user; + string rom, save, patch, cheat, exportdata; + string bsx, st; + } path; + + struct CPU { + unsigned ntsc_clock_rate; + unsigned pal_clock_rate; + unsigned alu_mul_delay; + unsigned alu_div_delay; + unsigned wram_init_value; + } cpu; + + struct SMP { + unsigned ntsc_clock_rate; + unsigned pal_clock_rate; + } smp; + } config; + //system functions virtual void run(); virtual void runtoframe(); @@ -24,17 +55,17 @@ public: //return *active* region / expansion port device information //settings cached upon power-on - Region region(); - ExpansionPortDevice expansion(); + Region region() const; + ExpansionPortDevice expansion() const; #include "video/video.hpp" #include "audio/audio.hpp" #include "input/input.hpp" SNES(); - virtual ~SNES() {} - -private: + virtual ~SNES() {} + +private: unsigned snes_region; unsigned snes_expansion; }; diff --git a/src/snes/tracer/tracer.cpp b/src/snes/tracer/tracer.cpp index 1eea80af..2526ed8f 100644 --- a/src/snes/tracer/tracer.cpp +++ b/src/snes/tracer/tracer.cpp @@ -1,94 +1,94 @@ #ifdef SNES_CPP -Tracer tracer; - -void tprintf(const char *s, ...) { - if(tracer.enabled() == false) { return; } - -char str[4096]; -va_list args; - va_start(args, s); - vsprintf(str, s, args); - va_end(args); - fprintf(tracer.fp, "%s\r\n", str); -} - -void Tracer::trace_cpuop() { - if(enabled() == false) { return; } - if(cpuop_enabled() == false) { return; } - if(cpu.in_opcode() == true) { return; } - - if(cpuopmask_enabled() == true) { - uint addr = cpu.regs.pc.d; - if(settings.cpuopmasktbl[addr >> 3] & 0x80 >> (addr & 7)) { return; } - settings.cpuopmasktbl[addr >> 3] |= 0x80 >> (addr & 7); - } - -char t[1024]; - cpu.disassemble_opcode(t); - fprintf(fp, "%s\r\n", t); -} - -void Tracer::trace_smpop() { - if(enabled() == false) { return; } - if(smpop_enabled() == false) { return; } - if(smp.in_opcode() == true) { return; } - - if(smpopmask_enabled() == true) { - uint addr = smp.regs.pc; - if(settings.smpopmasktbl[addr >> 3] & 0x80 >> (addr & 7)) { return; } - settings.smpopmasktbl[addr >> 3] |= 0x80 >> (addr & 7); - } - -char t[1024]; - smp.disassemble_opcode(t); - fprintf(fp, "%s\r\n", t); -} - -void Tracer::enable(bool en) { - if(en == true && enabled() == false) { - fp = fopen(config::filepath("trace.log", config::path.exportdata), "wb"); - } else if(en == false && enabled() == true) { - fclose(fp); - fp = 0; - } - - settings.enabled = en; -} - -void Tracer::cpuopmask_enable(bool en) { - if(en == true && cpuopmask_enabled() == false) { - settings.cpuopmasktbl = new(zeromemory) uint8_t[0x200000]; - } else if(en == false && cpuopmask_enabled() == true) { - delete[] settings.cpuopmasktbl; - } - - settings.cpuopmask = en; -} - -void Tracer::smpopmask_enable(bool en) { - if(en == true && smpopmask_enabled() == false) { - settings.smpopmasktbl = new(zeromemory) uint8_t[0x2000]; - } else if(en == false && smpopmask_enabled() == true) { - delete[] settings.smpopmasktbl; - } - - settings.smpopmask = en; -} - -Tracer::Tracer() { - fp = 0; - - settings.cpuop = false; - settings.cpuopmask = false; - settings.cpuopmasktbl = 0; - - settings.smpop = false; - settings.smpopmask = false; - settings.smpopmasktbl = 0; -} - -Tracer::~Tracer() { -} +Tracer tracer; + +void tprintf(const char *s, ...) { + if(tracer.enabled() == false) return; + + char str[4096]; + va_list args; + va_start(args, s); + vsprintf(str, s, args); + va_end(args); + fprintf(tracer.fp, "%s\r\n", str); +} + +void Tracer::trace_cpuop() { + if(enabled() == false) return; + if(cpuop_enabled() == false) return; + if(cpu.in_opcode() == true) return; + + if(cpuopmask_enabled() == true) { + unsigned addr = cpu.regs.pc.d; + if(settings.cpuopmasktbl[addr >> 3] & 0x80 >> (addr & 7)) return; + settings.cpuopmasktbl[addr >> 3] |= 0x80 >> (addr & 7); + } + + char t[1024]; + cpu.disassemble_opcode(t); + fprintf(fp, "%s\r\n", t); +} + +void Tracer::trace_smpop() { + if(enabled() == false) return; + if(smpop_enabled() == false) return; + if(smp.in_opcode() == true) return; + + if(smpopmask_enabled() == true) { + unsigned addr = smp.regs.pc; + if(settings.smpopmasktbl[addr >> 3] & 0x80 >> (addr & 7)) return; + settings.smpopmasktbl[addr >> 3] |= 0x80 >> (addr & 7); + } + + char t[1024]; + smp.disassemble_opcode(t); + fprintf(fp, "%s\r\n", t); +} + +void Tracer::enable(bool en) { + if(en == true && enabled() == false) { + fp = fopen(Cartridge::filepath("trace.log", snes.config.path.exportdata), "wb"); + } else if(en == false && enabled() == true) { + fclose(fp); + fp = 0; + } + + settings.enabled = en; +} + +void Tracer::cpuopmask_enable(bool en) { + if(en == true && cpuopmask_enabled() == false) { + settings.cpuopmasktbl = new(zeromemory) uint8_t[0x200000]; + } else if(en == false && cpuopmask_enabled() == true) { + delete[] settings.cpuopmasktbl; + } + + settings.cpuopmask = en; +} + +void Tracer::smpopmask_enable(bool en) { + if(en == true && smpopmask_enabled() == false) { + settings.smpopmasktbl = new(zeromemory) uint8_t[0x2000]; + } else if(en == false && smpopmask_enabled() == true) { + delete[] settings.smpopmasktbl; + } + + settings.smpopmask = en; +} + +Tracer::Tracer() { + fp = 0; + + settings.cpuop = false; + settings.cpuopmask = false; + settings.cpuopmasktbl = 0; + + settings.smpop = false; + settings.smpopmask = false; + settings.smpopmasktbl = 0; +} + +Tracer::~Tracer() { +} #endif //ifdef SNES_CPP diff --git a/src/ui/base/main.cpp b/src/ui/base/main.cpp index 9986733b..0f58b0e2 100644 --- a/src/ui/base/main.cpp +++ b/src/ui/base/main.cpp @@ -2,7 +2,7 @@ bool MainWindow::input_ready() { //allow input if main window has focus if(focused() == true) return true; //allow input if config set to never block input - if(config::input.capture_mode == 0) return true; + if(config.input.capture_mode == 0) return true; //block input return false; } @@ -35,12 +35,12 @@ uintptr_t MainWindow::event(event_t e) { if(e.widget == &menu_system_controller_port2_justifier) { event::update_controller_port2(SNES::Input::DeviceJustifier); } if(e.widget == &menu_system_controller_port2_justifiers) { event::update_controller_port2(SNES::Input::DeviceJustifiers); } - if(e.widget == &menu_system_expansion_port_none) { config::snes.expansion_port = SNES::ExpansionNone; } - if(e.widget == &menu_system_expansion_port_bsx) { config::snes.expansion_port = SNES::ExpansionBSX; } + if(e.widget == &menu_system_expansion_port_none) { snes.config.expansion_port = SNES::ExpansionNone; } + if(e.widget == &menu_system_expansion_port_bsx) { snes.config.expansion_port = SNES::ExpansionBSX; } - if(e.widget == &menu_system_region_auto) { config::snes.region = SNES::Autodetect; } - if(e.widget == &menu_system_region_ntsc) { config::snes.region = SNES::NTSC; } - if(e.widget == &menu_system_region_pal) { config::snes.region = SNES::PAL; } + if(e.widget == &menu_system_region_auto) { snes.config.region = SNES::Autodetect; } + if(e.widget == &menu_system_region_ntsc) { snes.config.region = SNES::NTSC; } + if(e.widget == &menu_system_region_pal) { snes.config.region = SNES::PAL; } if(e.widget == &menu_system_exit) { event::quit(); } @@ -80,7 +80,7 @@ uintptr_t MainWindow::event(event_t e) { if(e.widget == &menu_settings_videoframeskip_9) { event::update_frameskip(9); } if(e.widget == &menu_settings_mute) { - config::audio.mute = menu_settings_mute.checked(); + config.audio.mute = menu_settings_mute.checked(); } if(e.widget == &menu_settings_emuspeed_slowest) { event::update_emulation_speed(0); } @@ -90,13 +90,13 @@ uintptr_t MainWindow::event(event_t e) { if(e.widget == &menu_settings_emuspeed_fastest) { event::update_emulation_speed(4); } if(e.widget == &menu_settings_emuspeed_videosync) { - config::video.synchronize = menu_settings_emuspeed_videosync.checked(); - video.set(Video::Synchronize, config::video.synchronize); + config.video.synchronize = menu_settings_emuspeed_videosync.checked(); + video.set(Video::Synchronize, config.video.synchronize); } if(e.widget == &menu_settings_emuspeed_audiosync) { - config::audio.synchronize = menu_settings_emuspeed_audiosync.checked(); - audio.set(Audio::Synchronize, config::audio.synchronize); + config.audio.synchronize = menu_settings_emuspeed_audiosync.checked(); + audio.set(Audio::Synchronize, config.audio.synchronize); } if(e.widget == &menu_settings_config) { window_settings.show(); } @@ -197,7 +197,7 @@ void MainWindow::setup() { menu_system_region.attach(menu_system_region_pal.create (group, translate["{{region}}PAL"])); group.reset(); - if(config::advanced.enable == true) { + if(config.misc.show_advanced_options == true) { menu_system.attach(menu_system_sep3); menu_system.attach(menu_system_expansion_port); menu_system.attach(menu_system_region); @@ -414,14 +414,14 @@ void MainWindow::setup() { void MainWindow::sync() { event::load_video_settings(); - switch(config::snes.controller_port1) { default: + switch(snes.config.controller_port1) { default: case SNES::Input::DeviceNone: menu_system_controller_port1_none.check(); break; case SNES::Input::DeviceJoypad: menu_system_controller_port1_joypad.check(); break; case SNES::Input::DeviceMultitap: menu_system_controller_port1_multitap.check(); break; case SNES::Input::DeviceMouse: menu_system_controller_port1_mouse.check(); break; } - switch(config::snes.controller_port2) { default: + switch(snes.config.controller_port2) { default: case SNES::Input::DeviceNone: menu_system_controller_port2_none.check(); break; case SNES::Input::DeviceJoypad: menu_system_controller_port2_joypad.check(); break; case SNES::Input::DeviceMultitap: menu_system_controller_port2_multitap.check(); break; @@ -431,12 +431,12 @@ void MainWindow::sync() { case SNES::Input::DeviceJustifiers: menu_system_controller_port2_justifiers.check(); break; } - switch(config::snes.expansion_port) { default: + switch(snes.config.expansion_port) { default: case SNES::ExpansionNone: menu_system_expansion_port_none.check(); break; case SNES::ExpansionBSX: menu_system_expansion_port_bsx.check(); break; } - switch(config::snes.region) { default: + switch(snes.config.region) { default: case SNES::Autodetect: menu_system_region_auto.check(); break; case SNES::NTSC: menu_system_region_ntsc.check(); break; case SNES::PAL: menu_system_region_pal.check(); break; @@ -471,9 +471,9 @@ void MainWindow::sync() { case 4: menu_settings_videofilter_swntsc.check(); break; } - menu_settings_mute.check(config::audio.mute); + menu_settings_mute.check(config.audio.mute); - switch(config::video.frameskip) { + 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; @@ -486,7 +486,7 @@ void MainWindow::sync() { case 9: menu_settings_videoframeskip_9.check(); break; } - switch(config::system.emulation_speed) { + 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; @@ -494,6 +494,6 @@ void MainWindow::sync() { case 4: menu_settings_emuspeed_fastest.check(); break; } - menu_settings_emuspeed_videosync.check(config::video.synchronize); - menu_settings_emuspeed_audiosync.check(config::audio.synchronize); + menu_settings_emuspeed_videosync.check(config.video.synchronize); + menu_settings_emuspeed_audiosync.check(config.audio.synchronize); } diff --git a/src/ui/base/textview.cpp b/src/ui/base/textview.cpp index 021d448d..b3b84d92 100644 --- a/src/ui/base/textview.cpp +++ b/src/ui/base/textview.cpp @@ -7,7 +7,7 @@ void TextViewWindow::setup() { create(Window::AutoCenter, 415, 450); set_icon(48, 48, (uint32_t*)resource::icon48); - text.create(Editbox::Multiline | Editbox::Readonly | Editbox::HorizontalScrollNever | Editbox::VerticalScrollAlways, 405, 410); + text.create(Editbox::Multiline | Editbox::Readonly | Editbox::HorizontalScrollNever | Editbox::VerticalScrollAuto, 405, 410); ok.create(0, 100, 25, translate["{{textview}}Ok"]); attach(text, 5, 5); diff --git a/src/ui/config.cpp b/src/ui/config.cpp index e1e0ad44..818944f1 100644 --- a/src/ui/config.cpp +++ b/src/ui/config.cpp @@ -1,310 +1,263 @@ -namespace config { +#include -char bsnes_cfg[PATH_MAX] = ""; -char locale_cfg[PATH_MAX] = ""; +class bsnes_configuration : public configuration { +public: + char bsnes_cfg[PATH_MAX], locale_cfg[PATH_MAX]; -struct System { - static string_setting video, audio, input; - static integral_setting invoke_crash_handler; - static integral_setting emulation_speed; - static integral_setting gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma; -} system; + struct System { + string video, audio, input; + bool invoke_crash_handler; + unsigned emulation_speed; + } system; -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", ""); + struct Video { + unsigned mode; + bool synchronize; -integral_setting System::invoke_crash_handler(config(), "system.invoke_crash_handler", - "Do not modify this setting!\n" - "Used to detect crashes caused by initialization of video / audio / input drivers. " - "When the emulator crashes during driver initialization, this value will be left as true. " - "When true, driver selection crash handler window will appear on next start-up.", - integral_setting::boolean, false); + struct Windowed { + bool aspect_correction; + unsigned region, multiplier, hardware_filter, software_filter; + } windowed; -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%", - integral_setting::decimal, 2); + struct Fullscreen { + bool aspect_correction; + unsigned region, multiplier, hardware_filter, software_filter; + } fullscreen; -integral_setting System::gamma_ramp(config(), "system.colorfilter.gamma_ramp", - "Use precalculated TV-style gamma ramp", integral_setting::boolean, true); -integral_setting System::sepia(config(), "system.colorfilter.sepia", - "Convert color to sepia tone", integral_setting::boolean, false); -integral_setting System::grayscale(config(), "system.colorfilter.grayscale", - "Convert color to grayscale tone", integral_setting::boolean, false); -integral_setting System::invert(config(), "system.colorfilter.invert", - "Invert output image colors", integral_setting::boolean, false); -integral_setting System::contrast(config(), "system.colorfilter.contrast", - "Contrast", integral_setting::decimal, 0); -integral_setting System::brightness(config(), "system.colorfilter.brightness", - "Brightness", integral_setting::decimal, 0); -integral_setting System::gamma(config(), "system.colorfilter.gamma", - "Gamma", integral_setting::decimal, 100); + unsigned aspect_ntsc_x, aspect_ntsc_y, aspect_pal_x, aspect_pal_y; + unsigned frameskip; -struct Video { - static integral_setting mode; - static integral_setting synchronize; + unsigned contrast, brightness, gamma; + bool gamma_ramp, sepia, grayscale, invert; + bool ntsc_filter_merge_fields; + } video; - struct Windowed { - static integral_setting aspect_correction; - static integral_setting region, multiplier, hardware_filter, software_filter; - } windowed; - struct Fullscreen { - static integral_setting aspect_correction; - static integral_setting region, multiplier, hardware_filter, software_filter; - } fullscreen; - static integral_setting aspect_ntsc_x, aspect_ntsc_y, aspect_pal_x, aspect_pal_y; - static integral_setting frameskip; - static integral_setting start_in_fullscreen_mode; -} video; + struct Audio { + unsigned output_frequency, input_frequency; + unsigned latency; + unsigned volume, mute; + bool synchronize; + } audio; -//0 = windowed, 1 = fullscreen, 2 = exclusive (not implemented yet) -integral_setting Video::mode("video.mode", "Active video mode", integral_setting::decimal, 0); -integral_setting Video::synchronize(config(), "video.synchronize", "Synchronize to video refresh rate", integral_setting::boolean, false); + struct Input { + unsigned capture_mode; + bool allow_invalid_input; + unsigned analog_axis_resistance; -integral_setting Video::Windowed::aspect_correction(config(), "video.windowed.aspect_correction", - "Correct video aspect ratio.\n" - "Defaults assume display pixels are perfectly square." - "Formula: width = width * video.aspect__x / video.aspect__y", - integral_setting::boolean, true); -integral_setting Video::Windowed::region(config(), "video.windowed.region", - "Video output region:\n" - "0 = NTSC\n" - "1 = PAL", - integral_setting::decimal, 0); -integral_setting Video::Windowed::multiplier(config(), "video.windowed.multiplier", - "Video output size multiplier (1-5x)\n" - "1 = 1x (<= 320x240)\n" - "2 = 2x (<= 640x480)\n" - "etc.", - integral_setting::decimal, 2); -integral_setting Video::Windowed::hardware_filter(config(), "video.windowed.hardware_filter", - "Video hardware filter:\n" - "0 = Point\n" - "1 = Linear", - integral_setting::decimal, 1); -integral_setting Video::Windowed::software_filter(config(), "video.windowed.software_filter", - "Video software filter:\n" - "0 = None\n" - "1 = Scanline\n" - "2 = Scale2x\n" - "3 = HQ2x\n" - "4 = NTSC", - integral_setting::decimal, 0); + struct Joypad { + string up, down, left, right, a, b, x, y, l, r, select, start; + } joypad1, joypad2, + multitap1a, multitap1b, multitap1c, multitap1d, + multitap2a, multitap2b, multitap2c, multitap2d; -integral_setting Video::Fullscreen::aspect_correction(config(), "video.fullscreen.aspect_correction", "", integral_setting::boolean, true); -integral_setting Video::Fullscreen::region (config(), "video.fullscreen.region", "", integral_setting::decimal, 0); -integral_setting Video::Fullscreen::multiplier (config(), "video.fullscreen.multiplier", "", integral_setting::decimal, 2); -integral_setting Video::Fullscreen::hardware_filter (config(), "video.fullscreen.hardware_filter", "", integral_setting::decimal, 1); -integral_setting Video::Fullscreen::software_filter (config(), "video.fullscreen.software_filter", "", integral_setting::decimal, 0); + struct Mouse { + string x, y, l, r; + } mouse1, mouse2; -integral_setting Video::aspect_ntsc_x(config(), "video.aspect_ntsc_x", "", integral_setting::decimal, 54); -integral_setting Video::aspect_ntsc_y(config(), "video.aspect_ntsc_y", "", integral_setting::decimal, 47); -integral_setting Video::aspect_pal_x (config(), "video.aspect_pal_x", "", integral_setting::decimal, 32); -integral_setting Video::aspect_pal_y (config(), "video.aspect_pal_y", "", integral_setting::decimal, 23); + struct SuperScope { + string x, y, trigger, turbo, cursor, pause; + } superscope; -integral_setting Video::frameskip("video.frameskip", "Video frameskip", integral_setting::decimal, 0); -integral_setting Video::start_in_fullscreen_mode(config(), "video.start_in_fullscreen_mode", - "If true, bsnes will start in fullscreen mode, rather than windowed mode.", - integral_setting::boolean, false); + struct Justifier { + string x, y, trigger, start; + } justifier1, justifier2; -struct Audio { - static integral_setting output_frequency, input_frequency; - static integral_setting latency; - static integral_setting volume, mute; - static integral_setting synchronize; -} audio; -integral_setting Audio::output_frequency(config(), "audio.output_frequency", "Sound card audio output frequency", integral_setting::decimal, 48000); -integral_setting Audio::input_frequency(config(), "audio.input_frequency", "Emulator audio input frequency", integral_setting::decimal, 32000); -integral_setting Audio::latency(config(), "audio.latency", "Sound card latency (in ms)", integral_setting::decimal, 100); -integral_setting Audio::volume(config(), "audio.volume", "Audio volume (10 - 100)", integral_setting::decimal, 100); -integral_setting Audio::mute(config(), "audio.mute", "Mute audio playback", integral_setting::boolean, false); -integral_setting Audio::synchronize(config(), "audio.synchronize", "Synchronize to audio sample rate", integral_setting::boolean, true); + struct GUI { + string load, pause, reset, power, quit; + string speed_decrease, speed_increase; + string frameskip_decrease, frameskip_increase; + string toggle_fullscreen, toggle_menubar, toggle_statusbar; + } gui; -struct Input { - static integral_setting capture_mode; - static integral_setting allow_invalid_input; - static integral_setting analog_axis_resistance; + struct Debugger { + string export_memory; + string toggle_cputrace, toggle_cputracemask; + string toggle_smptrace, toggle_smptracemask; + } debugger; + } input; - struct Joypad1 { static string_setting up, down, left, right, a, b, x, y, l, r, select, start; } joypad1; - struct Joypad2 { static string_setting up, down, left, right, a, b, x, y, l, r, select, start; } joypad2; + struct Misc { + bool start_in_fullscreen_mode; + unsigned window_opacity; + unsigned cheat_autosort; + bool show_advanced_options; + } misc; - struct Multitap1A { static string_setting up, down, left, right, a, b, x, y, l, r, select, start; } multitap1a; - struct Multitap1B { static string_setting up, down, left, right, a, b, x, y, l, r, select, start; } multitap1b; - struct Multitap1C { static string_setting up, down, left, right, a, b, x, y, l, r, select, start; } multitap1c; - struct Multitap1D { static string_setting up, down, left, right, a, b, x, y, l, r, select, start; } multitap1d; - struct Multitap2A { static string_setting up, down, left, right, a, b, x, y, l, r, select, start; } multitap2a; - struct Multitap2B { static string_setting up, down, left, right, a, b, x, y, l, r, select, start; } multitap2b; - struct Multitap2C { static string_setting up, down, left, right, a, b, x, y, l, r, select, start; } multitap2c; - struct Multitap2D { static string_setting up, down, left, right, a, b, x, y, l, r, select, start; } multitap2d; + bsnes_configuration() { + //======== + //external + //======== - struct Mouse1 { static string_setting x, y, l, r; } mouse1; - struct Mouse2 { static string_setting x, y, l, r; } mouse2; + attach(snes.config.controller_port1 = SNES::Input::DeviceJoypad, "snes.controller_port1"); + attach(snes.config.controller_port2 = SNES::Input::DeviceJoypad, "snes.controller_port2"); + attach(snes.config.expansion_port = SNES::ExpansionBSX, "snes.expansion_port"); + attach(snes.config.region = SNES::Autodetect, "snes.region"); - struct SuperScope { static string_setting x, y, trigger, turbo, cursor, pause; } superscope; - struct Justifier1 { static string_setting x, y, trigger, start; } justifier1; - struct Justifier2 { static string_setting x, y, trigger, start; } justifier2; + attach(snes.config.file.autodetect_type = false, "file.autodetect_type", "Detect filetype by header, rather than file extension"); + attach(snes.config.file.bypass_patch_crc32 = false, "file.bypass_patch_crc32", "Apply UPS patches even when checksum match fails"); - struct GUI { - static string_setting load; - 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; - } gui; + attach(snes.config.path.rom = "", "path.rom"); + attach(snes.config.path.save = "", "path.save"); + attach(snes.config.path.patch = "", "path.patch"); + attach(snes.config.path.cheat = "", "path.cheat"); + attach(snes.config.path.exportdata = "", "path.exportdata"); + attach(snes.config.path.bsx = "", "path.bsx"); + attach(snes.config.path.st = "", "path.st"); - struct Debugger { - static string_setting export_memory; - static string_setting toggle_cputrace; - static string_setting toggle_cputracemask; - static string_setting toggle_smptrace; - static string_setting toggle_smptracemask; - } debugger; -} input; + attach(snes.config.cpu.ntsc_clock_rate = 21477272, "cpu.ntsc_clock_rate"); + attach(snes.config.cpu.pal_clock_rate = 21281370, "cpu.pal_clock_rate"); + attach(snes.config.cpu.alu_mul_delay = 2, "cpu.alu_mul_delay"); + attach(snes.config.cpu.alu_div_delay = 2, "cpu.alu_div_delay"); + attach(snes.config.cpu.wram_init_value = 0x55, "cpu.wram_init_value"); -integral_setting Input::capture_mode(config(), "input.capture_mode", - "Capture method for input to main emulation window.\n" - "When emulation window does not have focus:\n" - "0 = Allow input\n" - "1 = Ignore input\n" - "2 = Pause emulator", - integral_setting::decimal, 2); + attach(snes.config.smp.ntsc_clock_rate = 32041 * 768, "smp.ntsc_clock_rate"); + attach(snes.config.smp.pal_clock_rate = 32041 * 768, "smp.pal_clock_rate"); -integral_setting Input::allow_invalid_input(config(), "input.allow_invalid_input", - "Allow up+down and left+right combinations (not recommended.)\n" - "This is not possible on an actual SNES controller, due to its design. " - "Enabling this option can trigger bugs in certain games.", - integral_setting::boolean, false); + //======== + //internal + //======== -integral_setting Input::analog_axis_resistance(config(), "input.analog_axis_resistance", - "Resistance required to activate analog stick in any given direction.\n" - "This value ranges from 1 (1%, virtually no resistance) to 99 (99%, near full resistance.) " - "For instance, a value of 50 means that to register 'left', the analog stick must be moved " - "50% between the center and the left.\n" - "Less resistance allows for more fluid movement; whereas more resistance helps to prevent " - "accidental movements, eg attempting to press up whilst bumping the stick slightly left.", - integral_setting::decimal, 50); + *bsnes_cfg = 0; + *locale_cfg = 0; -string_setting Input::Joypad1::up (config(), "input.joypad1.up", "", "up"); -string_setting Input::Joypad1::down (config(), "input.joypad1.down", "", "down"); -string_setting Input::Joypad1::left (config(), "input.joypad1.left", "", "left"); -string_setting Input::Joypad1::right (config(), "input.joypad1.right", "", "right"); -string_setting Input::Joypad1::a (config(), "input.joypad1.a", "", "x"); -string_setting Input::Joypad1::b (config(), "input.joypad1.b", "", "z"); -string_setting Input::Joypad1::x (config(), "input.joypad1.x", "", "s"); -string_setting Input::Joypad1::y (config(), "input.joypad1.y", "", "a"); -string_setting Input::Joypad1::l (config(), "input.joypad1.l", "", "d"); -string_setting Input::Joypad1::r (config(), "input.joypad1.r", "", "c"); -string_setting Input::Joypad1::select(config(), "input.joypad1.select", "", "rshift"); -string_setting Input::Joypad1::start (config(), "input.joypad1.start", "", "return"); + attach(system.video = "", "system.video", "Video hardware interface"); + attach(system.audio = "", "system.audio", "Audio hardware interface"); + attach(system.input = "", "system.input", "Input hardware interface"); -string_setting Input::Joypad2::up (config(), "input.joypad2.up", "", "t"); -string_setting Input::Joypad2::down (config(), "input.joypad2.down", "", "g"); -string_setting Input::Joypad2::left (config(), "input.joypad2.left", "", "f"); -string_setting Input::Joypad2::right (config(), "input.joypad2.right", "", "h"); -string_setting Input::Joypad2::a (config(), "input.joypad2.a", "", "k"); -string_setting Input::Joypad2::b (config(), "input.joypad2.b", "", "j"); -string_setting Input::Joypad2::x (config(), "input.joypad2.x", "", "i"); -string_setting Input::Joypad2::y (config(), "input.joypad2.y", "", "u"); -string_setting Input::Joypad2::l (config(), "input.joypad2.l", "", "o"); -string_setting Input::Joypad2::r (config(), "input.joypad2.r", "", "l"); -string_setting Input::Joypad2::select(config(), "input.joypad2.select", "", "lbracket"); -string_setting Input::Joypad2::start (config(), "input.joypad2.start", "", "rbracket"); + attach(system.invoke_crash_handler = false, "system.invoke_crash_handler", "Do not modify! Used to detect crashes caused by driver initialization"); + attach(system.emulation_speed = 2, "system.emulation_speed", "Relative speed of emulator compared to hardware"); -#define DeclMultitap(uname, lname) \ -string_setting Input::uname::up (config(), "input.multitap" lname ".up", "", "none"); \ -string_setting Input::uname::down (config(), "input.multitap" lname ".down", "", "none"); \ -string_setting Input::uname::left (config(), "input.multitap" lname ".left", "", "none"); \ -string_setting Input::uname::right (config(), "input.multitap" lname ".right", "", "none"); \ -string_setting Input::uname::a (config(), "input.multitap" lname ".a", "", "none"); \ -string_setting Input::uname::b (config(), "input.multitap" lname ".b", "", "none"); \ -string_setting Input::uname::x (config(), "input.multitap" lname ".x", "", "none"); \ -string_setting Input::uname::y (config(), "input.multitap" lname ".y", "", "none"); \ -string_setting Input::uname::l (config(), "input.multitap" lname ".l", "", "none"); \ -string_setting Input::uname::r (config(), "input.multitap" lname ".r", "", "none"); \ -string_setting Input::uname::select(config(), "input.multitap" lname ".select", "", "none"); \ -string_setting Input::uname::start (config(), "input.multitap" lname ".start", "", "none"); + video.mode = 0; + attach(video.synchronize = false, "video.synchronize", "Synchronize to video refresh rate"); -DeclMultitap(Multitap1A, "1a") -DeclMultitap(Multitap1B, "1b") -DeclMultitap(Multitap1C, "1c") -DeclMultitap(Multitap1D, "1d") -DeclMultitap(Multitap2A, "2a") -DeclMultitap(Multitap2B, "2b") -DeclMultitap(Multitap2C, "2c") -DeclMultitap(Multitap2D, "2d") + attach(video.windowed.aspect_correction = true, "video.windowed.aspect_correction"); + attach(video.windowed.region = 0, "video.windowed.region"); + attach(video.windowed.multiplier = 2, "video.windowed.multiplier"); + attach(video.windowed.hardware_filter = 1, "video.windowed.hardware_filter"); + attach(video.windowed.software_filter = 0, "video.windowed.software_filter"); -#undef DeclMultitap + attach(video.fullscreen.aspect_correction = true, "video.fullscreen.aspect_correction"); + attach(video.fullscreen.region = 0, "video.fullscreen.region"); + attach(video.fullscreen.multiplier = 2, "video.fullscreen.multiplier"); + attach(video.fullscreen.hardware_filter = 1, "video.fullscreen.hardware_filter"); + attach(video.fullscreen.software_filter = 0, "video.fullscreen.software_filter"); -string_setting Input::Mouse1::x(config(), "input.mouse1.x", "", "mouse.x"); -string_setting Input::Mouse1::y(config(), "input.mouse1.y", "", "mouse.y"); -string_setting Input::Mouse1::l(config(), "input.mouse1.l", "", "mouse.button00"); -string_setting Input::Mouse1::r(config(), "input.mouse1.r", "", "mouse.button02"); + attach(video.aspect_ntsc_x = 54, "video.aspect_ntsc_x", "NTSC TV aspect correction ratio"); + attach(video.aspect_ntsc_y = 47, "video.aspect_ntsc_y"); + attach(video.aspect_pal_x = 32, "video.aspect_pal_x", "PAL TV aspect correction ratio"); + attach(video.aspect_pal_y = 23, "video.aspect_pal_y"); -string_setting Input::Mouse2::x(config(), "input.mouse2.x", "", "mouse.x"); -string_setting Input::Mouse2::y(config(), "input.mouse2.y", "", "mouse.y"); -string_setting Input::Mouse2::l(config(), "input.mouse2.l", "", "mouse.button00"); -string_setting Input::Mouse2::r(config(), "input.mouse2.r", "", "mouse.button02"); + video.frameskip = 0; + attach(video.contrast = 0, "video.contrast"); + attach(video.brightness = 0, "video.brightness"); + attach(video.gamma = 100, "video.gamma"); -string_setting Input::SuperScope::x (config(), "input.superscope.x", "", "mouse.x"); -string_setting Input::SuperScope::y (config(), "input.superscope.y", "", "mouse.y"); -string_setting Input::SuperScope::trigger(config(), "input.superscope.trigger", "", "mouse.button00"); -string_setting Input::SuperScope::cursor (config(), "input.superscope.cursor", "", "mouse.button02"); -string_setting Input::SuperScope::turbo (config(), "input.superscope.turbo", "", "t"); -string_setting Input::SuperScope::pause (config(), "input.superscope.pause", "", "p"); + attach(video.gamma_ramp = true, "video.gamma_ramp"); + attach(video.sepia = false, "video.sepia"); + attach(video.grayscale = false, "video.grayscale"); + attach(video.invert = false, "video.invert"); + attach(video.ntsc_filter_merge_fields = true, "video.ntsc_filter_merge_fields"); -string_setting Input::Justifier1::x (config(), "input.justifier1.x", "", "mouse.x"); -string_setting Input::Justifier1::y (config(), "input.justifier1.y", "", "mouse.y"); -string_setting Input::Justifier1::trigger(config(), "input.justifier1.trigger", "", "mouse.button00"); -string_setting Input::Justifier1::start (config(), "input.justifier1.start", "", "mouse.button02"); + attach(audio.output_frequency = 48000, "audio.output_frequency"); + attach(audio.input_frequency = 32000, "audio.input_frequency"); + attach(audio.latency = 100, "audio.latency"); + attach(audio.volume = 100, "audio.volume"); + attach(audio.mute = false, "audio.mute"); + attach(audio.synchronize = true, "audio.synchronize"); -string_setting Input::Justifier2::x (config(), "input.justifier2.x", "", "none"); -string_setting Input::Justifier2::y (config(), "input.justifier2.y", "", "none"); -string_setting Input::Justifier2::trigger(config(), "input.justifier2.trigger", "", "none"); -string_setting Input::Justifier2::start (config(), "input.justifier2.start", "", "none"); + attach(input.capture_mode = 2, "input.capture_mode", "Capture method: 0 = allow, 1 = ignore, 2 = pause"); + attach(input.allow_invalid_input = false, "input.allow_invalid_input", "Allow D-pad up+down and left+right combinations (not recommended)"); + attach(input.analog_axis_resistance = 50, "input.analog_axis_resistance", "Analog stick resistance percentage; lower = less, higher = more"); -string_setting Input::GUI::load (config(), "input.gui.load", "", "none"); -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::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"); + attach(input.joypad1.up = "up", "input.joypad1.up"); + attach(input.joypad1.down = "down", "input.joypad1.down"); + attach(input.joypad1.left = "left", "input.joypad1.left"); + attach(input.joypad1.right = "right", "input.joypad1.right"); + attach(input.joypad1.a = "x", "input.joypad1.a"); + attach(input.joypad1.b = "z", "input.joypad1.b"); + attach(input.joypad1.x = "s", "input.joypad1.x"); + attach(input.joypad1.y = "a", "input.joypad1.y"); + attach(input.joypad1.l = "d", "input.joypad1.l"); + attach(input.joypad1.r = "c", "input.joypad1.r"); + attach(input.joypad1.select = "rshift", "input.joypad1.select"); + attach(input.joypad1.start = "return", "input.joypad1.start"); -string_setting Input::Debugger::export_memory (config(), "input.debugger.export_memory", "", "none"); -string_setting Input::Debugger::toggle_cputrace (config(), "input.debugger.toggle_cputrace", "", "none"); -string_setting Input::Debugger::toggle_cputracemask(config(), "input.debugger.toggle_cputracemask", "", "none"); -string_setting Input::Debugger::toggle_smptrace (config(), "input.debugger.toggle_smptrace", "", "none"); -string_setting Input::Debugger::toggle_smptracemask(config(), "input.debugger.toggle_smptracemask", "", "none"); + attach_joypad(input.joypad2, "input.joypad2"); + attach_joypad(input.multitap1a, "input.multitap1a"); + attach_joypad(input.multitap1b, "input.multitap1b"); + attach_joypad(input.multitap1c, "input.multitap1c"); + attach_joypad(input.multitap1d, "input.multitap1d"); + attach_joypad(input.multitap2a, "input.multitap2a"); + attach_joypad(input.multitap2b, "input.multitap2b"); + attach_joypad(input.multitap2c, "input.multitap2c"); + attach_joypad(input.multitap2d, "input.multitap2d"); -struct Misc { - static integral_setting cheat_autosort; - static integral_setting opacity; -} misc; + attach(input.mouse1.x = "mouse1.x", "input.mouse1.x"); + attach(input.mouse1.y = "mouse1.y", "input.mouse1.y"); + attach(input.mouse1.l = "mouse1.button00", "input.mouse1.l"); + attach(input.mouse1.r = "mouse1.button02", "input.mouse1.r"); -integral_setting Misc::cheat_autosort(config(), "misc.cheat_autosort", "Keep cheat code list sorted by description", integral_setting::boolean, false); -integral_setting Misc::opacity(config(), "misc.opacity", "Opacity of user interface windows", integral_setting::decimal, 100); + attach(input.mouse2.x = "mouse2.x", "input.mouse2.x"); + attach(input.mouse2.y = "mouse2.y", "input.mouse2.y"); + attach(input.mouse2.l = "mouse2.button00", "input.mouse2.l"); + attach(input.mouse2.r = "mouse2.button02", "input.mouse2.r"); -struct Advanced { - static integral_setting enable; -} advanced; + attach(input.superscope.x = "mouse.x", "input.superscope.x"); + attach(input.superscope.y = "mouse.y", "input.superscope.y"); + attach(input.superscope.trigger = "mouse.button00", "input.superscope.trigger"); + attach(input.superscope.cursor = "mouse.button02", "input.superscope.cursor"); + attach(input.superscope.turbo = "t", "input.superscope.turbo"); + attach(input.superscope.pause = "p", "input.superscope.pause"); -integral_setting Advanced::enable(config(), "advanced.enable", "Enable advanced, developer-oriented UI options", integral_setting::boolean, false); + attach(input.justifier1.x = "mouse.x", "input.justifier1.x"); + attach(input.justifier1.y = "mouse.y", "input.justifier1.y"); + attach(input.justifier1.trigger = "mouse.button00", "input.justifier1.trigger"); + attach(input.justifier1.start = "mouse.button02", "input.justifier1.start"); -} //namespace config + attach(input.justifier2.x = "none", "input.justifier2.x"); + attach(input.justifier2.y = "none", "input.justifier2.y"); + attach(input.justifier2.trigger = "none", "input.justifier2.trigger"); + attach(input.justifier2.start = "none", "input.justifier2.start"); + + attach(input.gui.load = "none", "input.gui.load"); + attach(input.gui.pause = "f12", "input.gui.pause"); + attach(input.gui.reset = "none", "input.gui.reset"); + attach(input.gui.power = "none", "input.gui.power"); + attach(input.gui.quit = "none", "input.gui.quit"); + + attach(input.gui.speed_decrease = "divide", "input.gui.speed_decrease"); + attach(input.gui.speed_increase = "multiply", "input.gui.speed_increase"); + attach(input.gui.frameskip_decrease = "subtract", "input.gui.frameskip_decrease"); + attach(input.gui.frameskip_increase = "add", "input.gui.frameskip_increase"); + + attach(input.gui.toggle_fullscreen = "f11", "input.gui.toggle_fullscreen"); + attach(input.gui.toggle_menubar = "escape", "input.gui.toggle_menubar"); + attach(input.gui.toggle_statusbar = "escape", "input.gui.toggle_statusbar"); + + attach(input.debugger.export_memory = "none", "input.debugger.export_memory"); + attach(input.debugger.toggle_cputrace = "none", "input.debugger.toggle_cputrace"); + attach(input.debugger.toggle_cputracemask = "none", "input.debugger.toggle_cputracemask"); + attach(input.debugger.toggle_smptrace = "none", "input.debugger.toggle_smptrace"); + attach(input.debugger.toggle_smptracemask = "none", "input.debugger.toggle_smptracemask"); + + attach(misc.start_in_fullscreen_mode = false, "misc.start_in_fullscreen_mode"); + attach(misc.window_opacity = 100, "misc.window_opacity", "Translucency percentage of helper windows (50%-100%)"); + attach(misc.cheat_autosort = false, "misc.cheat_autosort"); + attach(misc.show_advanced_options = false, "misc.show_advanced_options", "Enable developer-oriented GUI options"); + } + + void attach_joypad(Input::Joypad &joypad, const char *name) { + attach(joypad.up = "none", string() << name << ".up"); + attach(joypad.down = "none", string() << name << ".down"); + attach(joypad.left = "none", string() << name << ".left"); + attach(joypad.right = "none", string() << name << ".right"); + attach(joypad.a = "none", string() << name << ".a"); + attach(joypad.b = "none", string() << name << ".b"); + attach(joypad.x = "none", string() << name << ".x"); + attach(joypad.y = "none", string() << name << ".y"); + attach(joypad.l = "none", string() << name << ".l"); + attach(joypad.r = "none", string() << name << ".r"); + attach(joypad.select = "none", string() << name << ".select"); + attach(joypad.start = "none", string() << name << ".start"); + } +} config; diff --git a/src/ui/event/debugger.cpp b/src/ui/event/debugger.cpp index 5066abef..ee76b868 100644 --- a/src/ui/event/debugger.cpp +++ b/src/ui/event/debugger.cpp @@ -1,23 +1,23 @@ void export_memory() { file fp; - fp.open(config::filepath("wram.bin", config::path.exportdata), file::mode_write); + fp.open(Cartridge::filepath("wram.bin", snes.config.path.exportdata), file::mode_write); for(unsigned i = 0; i < memory::wram.size(); i++) fp.write(memory::wram[i]); fp.close(); - fp.open(config::filepath("apuram.bin", config::path.exportdata), file::mode_write); + fp.open(Cartridge::filepath("apuram.bin", snes.config.path.exportdata), file::mode_write); for(unsigned i = 0; i < memory::apuram.size(); i++) fp.write(memory::apuram[i]); fp.close(); - fp.open(config::filepath("vram.bin", config::path.exportdata), file::mode_write); + fp.open(Cartridge::filepath("vram.bin", snes.config.path.exportdata), file::mode_write); for(unsigned i = 0; i < memory::vram.size(); i++) fp.write(memory::vram[i]); fp.close(); - fp.open(config::filepath("oam.bin", config::path.exportdata), file::mode_write); + fp.open(Cartridge::filepath("oam.bin", snes.config.path.exportdata), file::mode_write); for(unsigned i = 0; i < memory::oam.size(); i++) fp.write(memory::oam[i]); fp.close(); - fp.open(config::filepath("cgram.bin", config::path.exportdata), file::mode_write); + fp.open(Cartridge::filepath("cgram.bin", snes.config.path.exportdata), file::mode_write); for(unsigned i = 0; i < memory::cgram.size(); i++) fp.write(memory::cgram[i]); fp.close(); diff --git a/src/ui/event/event.cpp b/src/ui/event/event.cpp index e3f60663..15279460 100644 --- a/src/ui/event/event.cpp +++ b/src/ui/event/event.cpp @@ -11,7 +11,7 @@ void input_event(uint16_t code) { if(window_main.focused()) { if(code == inputuigeneral.load.code) load_cart(); if(code == inputuigeneral.pause.code) { - app.pause = !app.pause; //toggle pause state + app.pause = !app.pause; //toggle pause state if(app.pause) { audio.clear(); if(cartridge.loaded()) status.update(); @@ -21,16 +21,16 @@ void input_event(uint16_t code) { if(code == inputuigeneral.power.code) modify_system_state(PowerCycle); if(code == inputuigeneral.quit.code) quit(); if(code == inputuigeneral.speed_decrease.code) { - update_emulation_speed(config::system.emulation_speed - 1); + update_emulation_speed(config.system.emulation_speed - 1); } if(code == inputuigeneral.speed_increase.code) { - update_emulation_speed(config::system.emulation_speed + 1); + update_emulation_speed(config.system.emulation_speed + 1); } if(code == inputuigeneral.frameskip_decrease.code) { - update_frameskip(config::video.frameskip - 1); + update_frameskip(config.video.frameskip - 1); } if(code == inputuigeneral.frameskip_increase.code) { - update_frameskip(config::video.frameskip + 1); + update_frameskip(config.video.frameskip + 1); } if(code == inputuigeneral.toggle_fullscreen.code) toggle_fullscreen(); if(code == inputuigeneral.toggle_menubar.code) toggle_menubar(); @@ -46,11 +46,11 @@ void input_event(uint16_t code) { void acquire() { if(cartridge.loaded() == true) { - if(config::snes.controller_port1 == SNES::Input::DeviceMouse - || config::snes.controller_port2 == SNES::Input::DeviceMouse - || config::snes.controller_port2 == SNES::Input::DeviceSuperScope - || config::snes.controller_port2 == SNES::Input::DeviceJustifier - || config::snes.controller_port2 == SNES::Input::DeviceJustifiers + if(snes.config.controller_port1 == SNES::Input::DeviceMouse + || snes.config.controller_port2 == SNES::Input::DeviceMouse + || snes.config.controller_port2 == SNES::Input::DeviceSuperScope + || snes.config.controller_port2 == SNES::Input::DeviceJustifier + || snes.config.controller_port2 == SNES::Input::DeviceJustifiers ) input.acquire(); } } @@ -60,79 +60,79 @@ void unacquire() { } void load_video_settings() { - video_settings.mode = config::video.mode; - video_settings.synchronize = config::video.synchronize; + video_settings.mode = config.video.mode; + video_settings.synchronize = config.video.synchronize; switch(video_settings.mode) { default: case 0: { //windowed - video_settings.aspect_correction = config::video.windowed.aspect_correction; - video_settings.region = config::video.windowed.region; - video_settings.multiplier = config::video.windowed.multiplier; - video_settings.hardware_filter = config::video.windowed.hardware_filter; - video_settings.software_filter = config::video.windowed.software_filter; + video_settings.aspect_correction = config.video.windowed.aspect_correction; + video_settings.region = config.video.windowed.region; + video_settings.multiplier = config.video.windowed.multiplier; + video_settings.hardware_filter = config.video.windowed.hardware_filter; + video_settings.software_filter = config.video.windowed.software_filter; } break; case 1: { //fullscreen - video_settings.aspect_correction = config::video.fullscreen.aspect_correction; - video_settings.region = config::video.fullscreen.region; - video_settings.multiplier = config::video.fullscreen.multiplier; - video_settings.hardware_filter = config::video.fullscreen.hardware_filter; - video_settings.software_filter = config::video.fullscreen.software_filter; + video_settings.aspect_correction = config.video.fullscreen.aspect_correction; + video_settings.region = config.video.fullscreen.region; + video_settings.multiplier = config.video.fullscreen.multiplier; + video_settings.hardware_filter = config.video.fullscreen.hardware_filter; + video_settings.software_filter = config.video.fullscreen.software_filter; } break; } } void update_aspect_correction(bool aspect_correction) { - switch(config::video.mode) { default: - case 0: config::video.windowed.aspect_correction = aspect_correction; break; - case 1: config::video.fullscreen.aspect_correction = aspect_correction; break; + switch(config.video.mode) { default: + case 0: config.video.windowed.aspect_correction = aspect_correction; break; + case 1: config.video.fullscreen.aspect_correction = aspect_correction; break; } update_video_settings(); } -void update_multiplier(uint multiplier) { - switch(config::video.mode) { default: - case 0: config::video.windowed.multiplier = multiplier; break; - case 1: config::video.fullscreen.multiplier = multiplier; break; +void update_multiplier(unsigned multiplier) { + switch(config.video.mode) { default: + case 0: config.video.windowed.multiplier = multiplier; break; + case 1: config.video.fullscreen.multiplier = multiplier; break; } update_video_settings(); } -void update_region(uint region) { - switch(config::video.mode) { default: - case 0: config::video.windowed.region = region; break; - case 1: config::video.fullscreen.region = region; break; +void update_region(unsigned region) { + switch(config.video.mode) { default: + case 0: config.video.windowed.region = region; break; + case 1: config.video.fullscreen.region = region; break; } update_video_settings(); } -void update_hardware_filter(uint hardware_filter) { - switch(config::video.mode) { default: - case 0: config::video.windowed.hardware_filter = hardware_filter; break; - case 1: config::video.fullscreen.hardware_filter = hardware_filter; break; +void update_hardware_filter(unsigned hardware_filter) { + switch(config.video.mode) { default: + case 0: config.video.windowed.hardware_filter = hardware_filter; break; + case 1: config.video.fullscreen.hardware_filter = hardware_filter; break; } update_video_settings(); } -void update_software_filter(uint software_filter) { - switch(config::video.mode) { default: - case 0: config::video.windowed.software_filter = software_filter; break; - case 1: config::video.fullscreen.software_filter = software_filter; break; +void update_software_filter(unsigned software_filter) { + switch(config.video.mode) { default: + case 0: config.video.windowed.software_filter = software_filter; break; + case 1: config.video.fullscreen.software_filter = software_filter; break; } update_video_settings(); } void update_frameskip(int speed) { - config::video.frameskip = max(0, min(9, speed)); + config.video.frameskip = max(0, min(9, speed)); window_main.sync(); } void update_emulation_speed(int speed) { - config::system.emulation_speed = speed = max(0, min(4, speed)); + config.system.emulation_speed = speed = max(0, min(4, speed)); double scale[] = { 0.50, 0.75, 1.00, 1.50, 2.00 }; - unsigned outfreq = config::audio.output_frequency; - unsigned infreq = config::audio.input_frequency * scale[speed] + 0.5; + unsigned outfreq = config.audio.output_frequency; + unsigned infreq = config.audio.input_frequency * scale[speed] + 0.5; audio.set(Audio::Resample, outfreq != infreq); //only resample when necessary audio.set(Audio::ResampleOutputFrequency, outfreq); @@ -238,23 +238,24 @@ void modify_system_state(system_state_t state) { ? window_main.menu_system_power_on.check() : window_main.menu_system_power_off.check(); window_cheat_editor.refresh(); + if(cartridge.loaded() == false) window_cheat_code_editor.hide(); } void update_controller_port1(int device) { - unsigned current_device = config::snes.controller_port1; + unsigned current_device = snes.config.controller_port1; if(device != current_device) { - snes.input.port_set_device(0, config::snes.controller_port1 = device); + snes.input.port_set_device(0, snes.config.controller_port1 = device); } window_main.sync(); } void update_controller_port2(int device) { - unsigned current_device = config::snes.controller_port2; + unsigned current_device = snes.config.controller_port2; if(device != current_device) { - snes.input.port_set_device(1, config::snes.controller_port2 = device); + snes.input.port_set_device(1, snes.config.controller_port2 = device); } window_main.sync(); @@ -273,9 +274,9 @@ void update_video_settings() { if(video_settings.aspect_correction == true) { double scalar; if(mode == SNES::Video::ModeNTSC) { - scalar = (double)config::video.aspect_ntsc_x / (double)config::video.aspect_ntsc_y; + scalar = (double)config.video.aspect_ntsc_x / (double)config.video.aspect_ntsc_y; } else { - scalar = (double)config::video.aspect_pal_x / (double)config::video.aspect_pal_y; + scalar = (double)config.video.aspect_pal_x / (double)config.video.aspect_pal_y; } width = (unsigned)((double)width * (double)scalar); } @@ -309,6 +310,7 @@ void update_video_settings() { window_main.move(window_main.view, (viewwidth - width) / 2, (viewheight - height) / 2); window_main.view.resize(width, height); + //update software filter mode libfilter::FilterInterface::FilterType filter; switch(video_settings.software_filter) { default: case 0: filter = libfilter::FilterInterface::Direct; break; @@ -317,8 +319,8 @@ void update_video_settings() { case 3: filter = libfilter::FilterInterface::HQ2x; break; case 4: filter = libfilter::FilterInterface::NTSC; break; } - libfilter::filter.set(filter); + snes.video.set_mode(mode); video.set(Video::Synchronize, video_settings.synchronize); video.set(Video::Filter, video_settings.hardware_filter); @@ -327,22 +329,24 @@ void update_video_settings() { void update_opacity() { //convert opacity from 50-100 (percentage) to 128-255 (8-bit alpha) - unsigned opacity = max(50, min(100, config::misc.opacity)); + unsigned opacity = max(50, min(100, config.misc.window_opacity)); opacity = unsigned(256.0 / 100.0 * opacity); opacity = max(128, min(255, opacity)); - window_settings.set_opacity(opacity); - window_input_capture.set_opacity(opacity); - window_bsxloader.set_opacity(opacity); - window_stloader.set_opacity(opacity); window_about.set_opacity(opacity); + window_bsxloader.set_opacity(opacity); + window_cheat_code_editor.set_opacity(opacity); + window_input_capture.set_opacity(opacity); + window_settings.set_opacity(opacity); + window_stloader.set_opacity(opacity); + window_textview.set_opacity(opacity); } void toggle_fullscreen() { - if(config::video.mode != 1) { //switch to fullscreen mode if not already in it - config::video.mode = 1; + if(config.video.mode != 1) { //switch to fullscreen mode if not already in it + config.video.mode = 1; } else { //switch to windowed mode if already in fullscreen mode - config::video.mode = 0; + config.video.mode = 0; } update_video_settings(); } @@ -364,7 +368,7 @@ bool load_cart(char *fn) { lstring dir; strcpy(fn, ""); - strcpy(dir[0], config::path.rom); + strcpy(dir[0], snes.config.path.rom); replace(dir[0], "\\", "/"); if(strlen(dir[0]) && !strend(dir[0], "/")) strcat(dir[0], "/"); @@ -372,7 +376,7 @@ bool load_cart(char *fn) { if(strbegin(dir[0], "./")) { ltrim(dir[0], "./"); strcpy(dir[1], dir[0]); - strcpy(dir[0], config::path.base); + strcpy(dir[0], snes.config.path.base); strcat(dir[0], dir[1]); } @@ -429,7 +433,7 @@ void load_image(const char *filename) { case Cartridge::TypeBSX: { window_bsxloader.mode = BSXLoaderWindow::ModeBSX; window_bsxloader.set_text(translate["Load BS-X Cartridge"]); - window_bsxloader.tbase.set_text(config::path.bsx); + window_bsxloader.tbase.set_text(snes.config.path.bsx); window_bsxloader.tslot.set_text(filename); window_bsxloader.load.focus(); window_bsxloader.focus(); @@ -444,7 +448,7 @@ void load_image(const char *filename) { } break; case Cartridge::TypeSufamiTurbo: { - window_stloader.tbase.set_text(config::path.st); + window_stloader.tbase.set_text(snes.config.path.st); window_stloader.tslotA.set_text(filename); window_stloader.tslotB.set_text(""); window_stloader.load.focus(); @@ -497,12 +501,15 @@ void unload_cart() { void quit() { app.term = true; - window_textview.hide(); - window_about.hide(); - window_settings.hide(); - window_bsxloader.hide(); - window_stloader.hide(); window_main.hide(); + + window_about.hide(); + window_bsxloader.hide(); + window_cheat_code_editor.hide(); + window_input_capture.hide(); + window_settings.hide(); + window_stloader.hide(); + window_textview.hide(); } }; diff --git a/src/ui/event/event.hpp b/src/ui/event/event.hpp index 38717c45..29c6147d 100644 --- a/src/ui/event/event.hpp +++ b/src/ui/event/event.hpp @@ -8,21 +8,21 @@ void acquire(); void unacquire(); struct VideoSettings { - uint mode; + unsigned mode; bool synchronize; bool aspect_correction; - uint region; - uint multiplier; - uint hardware_filter; - uint software_filter; + unsigned region; + unsigned multiplier; + unsigned hardware_filter; + unsigned software_filter; } video_settings; void load_video_settings(); void update_aspect_correction(bool); -void update_multiplier(uint); -void update_region(uint); -void update_hardware_filter(uint); -void update_software_filter(uint); +void update_multiplier(unsigned); +void update_region(unsigned); +void update_hardware_filter(unsigned); +void update_software_filter(unsigned); void update_frameskip(int); void update_emulation_speed(int); diff --git a/src/ui/inputdevices.cpp b/src/ui/inputdevices.cpp index 3156e7e3..8342f39c 100644 --- a/src/ui/inputdevices.cpp +++ b/src/ui/inputdevices.cpp @@ -34,12 +34,12 @@ struct InputCode { struct InputObject { enum Type { Button, Axis } type; const char *name; - string_setting &setting; + string &setting; uint16_t code; int16_t state; - void bind() { code = input_find(setting); } - InputObject(Type t, const char *n, string_setting &s) : type(t), name(n), setting(s) {} + void bind() { code = input_find((const char*)setting); } + InputObject(Type t, const char *n, string &s) : type(t), name(n), setting(s) {} }; struct InputGroup { @@ -96,6 +96,13 @@ struct Joypad : InputDevice { InputObject l, r, select, start; int16_t state(unsigned index) { + if(config.input.allow_invalid_input == false) { + //SNES D-pads have central pivot point, making up+down or left+right combinations impossible. + //some software programs rely on this, and will crash if these combinations are allowed. + if(index == SNES::Input::JoypadDown && up.state ) return 0; + if(index == SNES::Input::JoypadRight && left.state) return 0; + } + switch(index) { case SNES::Input::JoypadUp: return up.state; case SNES::Input::JoypadDown: return down.state; @@ -115,9 +122,9 @@ struct Joypad : InputDevice { Joypad( SNES::Input::DeviceID id, bool port, const char *name, - string_setting &up_t, string_setting &down_t, string_setting &left_t, string_setting &right_t, - string_setting &a_t, string_setting &b_t, string_setting &x_t, string_setting &y_t, - string_setting &l_t, string_setting &r_t, string_setting &select_t, string_setting &start_t + string &up_t, string &down_t, string &left_t, string &right_t, + string &a_t, string &b_t, string &x_t, string &y_t, + string &l_t, string &r_t, string &select_t, string &start_t ) : InputDevice(id, port, name), up (InputObject::Button, "Up", up_t), @@ -155,8 +162,7 @@ struct Mouse : InputDevice { Mouse( SNES::Input::DeviceID id, bool port, const char *name, - string_setting &x_t, string_setting &y_t, - string_setting &left_t, string_setting &right_t + string &x_t, string &y_t, string &left_t, string &right_t ) : InputDevice(id, port, name), x (InputObject::Axis, "X-axis", x_t), @@ -186,8 +192,7 @@ struct SuperScope : InputDevice { SuperScope( SNES::Input::DeviceID id, bool port, const char *name, - string_setting &x_t, string_setting &y_t, - string_setting &trigger_t, string_setting &cursor_t, string_setting &turbo_t, string_setting &pause_t + string &x_t, string &y_t, string &trigger_t, string &cursor_t, string &turbo_t, string &pause_t ) : InputDevice(id, port, name), x (InputObject::Axis, "X-axis", x_t), @@ -218,8 +223,7 @@ struct Justifier : InputDevice { Justifier( SNES::Input::DeviceID id, bool port, const char *name, - string_setting &x_t, string_setting &y_t, - string_setting &trigger_t, string_setting &start_t + string &x_t, string &y_t, string &trigger_t, string &start_t ) : InputDevice(id, port, name), x (InputObject::Axis, "X-axis", x_t), @@ -263,101 +267,101 @@ struct InputDevicePool { Joypad joypad1( SNES::Input::DeviceIDJoypad1, InputDevice::Port1, "Joypad", -config::input.joypad1.up, config::input.joypad1.down, config::input.joypad1.left, config::input.joypad1.right, -config::input.joypad1.a, config::input.joypad1.b, config::input.joypad1.x, config::input.joypad1.y, -config::input.joypad1.l, config::input.joypad1.r, config::input.joypad1.select, config::input.joypad1.start +config.input.joypad1.up, config.input.joypad1.down, config.input.joypad1.left, config.input.joypad1.right, +config.input.joypad1.a, config.input.joypad1.b, config.input.joypad1.x, config.input.joypad1.y, +config.input.joypad1.l, config.input.joypad1.r, config.input.joypad1.select, config.input.joypad1.start ); Joypad joypad2( SNES::Input::DeviceIDJoypad2, InputDevice::Port2, "Joypad", -config::input.joypad2.up, config::input.joypad2.down, config::input.joypad2.left, config::input.joypad2.right, -config::input.joypad2.a, config::input.joypad2.b, config::input.joypad2.x, config::input.joypad2.y, -config::input.joypad2.l, config::input.joypad2.r, config::input.joypad2.select, config::input.joypad2.start +config.input.joypad2.up, config.input.joypad2.down, config.input.joypad2.left, config.input.joypad2.right, +config.input.joypad2.a, config.input.joypad2.b, config.input.joypad2.x, config.input.joypad2.y, +config.input.joypad2.l, config.input.joypad2.r, config.input.joypad2.select, config.input.joypad2.start ); Joypad multitap1a( SNES::Input::DeviceIDMultitap1A, InputDevice::Port1, "Multitap - Port 1", -config::input.multitap1a.up, config::input.multitap1a.down, config::input.multitap1a.left, config::input.multitap1a.right, -config::input.multitap1a.a, config::input.multitap1a.b, config::input.multitap1a.x, config::input.multitap1a.y, -config::input.multitap1a.l, config::input.multitap1a.r, config::input.multitap1a.select, config::input.multitap1a.start +config.input.multitap1a.up, config.input.multitap1a.down, config.input.multitap1a.left, config.input.multitap1a.right, +config.input.multitap1a.a, config.input.multitap1a.b, config.input.multitap1a.x, config.input.multitap1a.y, +config.input.multitap1a.l, config.input.multitap1a.r, config.input.multitap1a.select, config.input.multitap1a.start ); Joypad multitap1b( SNES::Input::DeviceIDMultitap1B, InputDevice::Port1, "Multitap - Port 2", -config::input.multitap1b.up, config::input.multitap1b.down, config::input.multitap1b.left, config::input.multitap1b.right, -config::input.multitap1b.a, config::input.multitap1b.b, config::input.multitap1b.x, config::input.multitap1b.y, -config::input.multitap1b.l, config::input.multitap1b.r, config::input.multitap1b.select, config::input.multitap1b.start +config.input.multitap1b.up, config.input.multitap1b.down, config.input.multitap1b.left, config.input.multitap1b.right, +config.input.multitap1b.a, config.input.multitap1b.b, config.input.multitap1b.x, config.input.multitap1b.y, +config.input.multitap1b.l, config.input.multitap1b.r, config.input.multitap1b.select, config.input.multitap1b.start ); Joypad multitap1c( SNES::Input::DeviceIDMultitap1C, InputDevice::Port1, "Multitap - Port 3", -config::input.multitap1c.up, config::input.multitap1c.down, config::input.multitap1c.left, config::input.multitap1c.right, -config::input.multitap1c.a, config::input.multitap1c.b, config::input.multitap1c.x, config::input.multitap1c.y, -config::input.multitap1c.l, config::input.multitap1c.r, config::input.multitap1c.select, config::input.multitap1c.start +config.input.multitap1c.up, config.input.multitap1c.down, config.input.multitap1c.left, config.input.multitap1c.right, +config.input.multitap1c.a, config.input.multitap1c.b, config.input.multitap1c.x, config.input.multitap1c.y, +config.input.multitap1c.l, config.input.multitap1c.r, config.input.multitap1c.select, config.input.multitap1c.start ); Joypad multitap1d( SNES::Input::DeviceIDMultitap1D, InputDevice::Port1, "Multitap - Port 4", -config::input.multitap1d.up, config::input.multitap1d.down, config::input.multitap1d.left, config::input.multitap1d.right, -config::input.multitap1d.a, config::input.multitap1d.b, config::input.multitap1d.x, config::input.multitap1d.y, -config::input.multitap1d.l, config::input.multitap1d.r, config::input.multitap1d.select, config::input.multitap1d.start +config.input.multitap1d.up, config.input.multitap1d.down, config.input.multitap1d.left, config.input.multitap1d.right, +config.input.multitap1d.a, config.input.multitap1d.b, config.input.multitap1d.x, config.input.multitap1d.y, +config.input.multitap1d.l, config.input.multitap1d.r, config.input.multitap1d.select, config.input.multitap1d.start ); Joypad multitap2a( SNES::Input::DeviceIDMultitap2A, InputDevice::Port2, "Multitap - Port 1", -config::input.multitap2a.up, config::input.multitap2a.down, config::input.multitap2a.left, config::input.multitap2a.right, -config::input.multitap2a.a, config::input.multitap2a.b, config::input.multitap2a.x, config::input.multitap2a.y, -config::input.multitap2a.l, config::input.multitap2a.r, config::input.multitap2a.select, config::input.multitap2a.start +config.input.multitap2a.up, config.input.multitap2a.down, config.input.multitap2a.left, config.input.multitap2a.right, +config.input.multitap2a.a, config.input.multitap2a.b, config.input.multitap2a.x, config.input.multitap2a.y, +config.input.multitap2a.l, config.input.multitap2a.r, config.input.multitap2a.select, config.input.multitap2a.start ); Joypad multitap2b( SNES::Input::DeviceIDMultitap2B, InputDevice::Port2, "Multitap - Port 2", -config::input.multitap2b.up, config::input.multitap2b.down, config::input.multitap2b.left, config::input.multitap2b.right, -config::input.multitap2b.a, config::input.multitap2b.b, config::input.multitap2b.x, config::input.multitap2b.y, -config::input.multitap2b.l, config::input.multitap2b.r, config::input.multitap2b.select, config::input.multitap2b.start +config.input.multitap2b.up, config.input.multitap2b.down, config.input.multitap2b.left, config.input.multitap2b.right, +config.input.multitap2b.a, config.input.multitap2b.b, config.input.multitap2b.x, config.input.multitap2b.y, +config.input.multitap2b.l, config.input.multitap2b.r, config.input.multitap2b.select, config.input.multitap2b.start ); Joypad multitap2c( SNES::Input::DeviceIDMultitap2C, InputDevice::Port2, "Multitap - Port 3", -config::input.multitap2c.up, config::input.multitap2c.down, config::input.multitap2c.left, config::input.multitap2c.right, -config::input.multitap2c.a, config::input.multitap2c.b, config::input.multitap2c.x, config::input.multitap2c.y, -config::input.multitap2c.l, config::input.multitap2c.r, config::input.multitap2c.select, config::input.multitap2c.start +config.input.multitap2c.up, config.input.multitap2c.down, config.input.multitap2c.left, config.input.multitap2c.right, +config.input.multitap2c.a, config.input.multitap2c.b, config.input.multitap2c.x, config.input.multitap2c.y, +config.input.multitap2c.l, config.input.multitap2c.r, config.input.multitap2c.select, config.input.multitap2c.start ); Joypad multitap2d( SNES::Input::DeviceIDMultitap2D, InputDevice::Port2, "Multitap - Port 4", -config::input.multitap2d.up, config::input.multitap2d.down, config::input.multitap2d.left, config::input.multitap2d.right, -config::input.multitap2d.a, config::input.multitap2d.b, config::input.multitap2d.x, config::input.multitap2d.y, -config::input.multitap2d.l, config::input.multitap2d.r, config::input.multitap2d.select, config::input.multitap2d.start +config.input.multitap2d.up, config.input.multitap2d.down, config.input.multitap2d.left, config.input.multitap2d.right, +config.input.multitap2d.a, config.input.multitap2d.b, config.input.multitap2d.x, config.input.multitap2d.y, +config.input.multitap2d.l, config.input.multitap2d.r, config.input.multitap2d.select, config.input.multitap2d.start ); Mouse mouse1( SNES::Input::DeviceIDMouse1, InputDevice::Port1, "Mouse", -config::input.mouse1.x, config::input.mouse1.y, config::input.mouse1.l, config::input.mouse1.r +config.input.mouse1.x, config.input.mouse1.y, config.input.mouse1.l, config.input.mouse1.r ); Mouse mouse2( SNES::Input::DeviceIDMouse2, InputDevice::Port2, "Mouse", -config::input.mouse2.x, config::input.mouse2.y, config::input.mouse2.l, config::input.mouse2.r +config.input.mouse2.x, config.input.mouse2.y, config.input.mouse2.l, config.input.mouse2.r ); SuperScope superscope( SNES::Input::DeviceIDSuperScope, InputDevice::Port2, "Super Scope", -config::input.superscope.x, config::input.superscope.y, -config::input.superscope.trigger, config::input.superscope.cursor, -config::input.superscope.turbo, config::input.superscope.pause +config.input.superscope.x, config.input.superscope.y, +config.input.superscope.trigger, config.input.superscope.cursor, +config.input.superscope.turbo, config.input.superscope.pause ); Justifier justifier1( SNES::Input::DeviceIDJustifier1, InputDevice::Port2, "Justifier 1", -config::input.justifier1.x, config::input.justifier1.y, -config::input.justifier1.trigger, config::input.justifier1.start +config.input.justifier1.x, config.input.justifier1.y, +config.input.justifier1.trigger, config.input.justifier1.start ); Justifier justifier2( SNES::Input::DeviceIDJustifier2, InputDevice::Port2, "Justifier 2", -config::input.justifier2.x, config::input.justifier2.y, -config::input.justifier2.trigger, config::input.justifier2.start +config.input.justifier2.x, config.input.justifier2.y, +config.input.justifier2.trigger, config.input.justifier2.start ); InputDevicePool::InputDevicePool() { diff --git a/src/ui/inputui.cpp b/src/ui/inputui.cpp index 368bd9d8..49c16a1a 100644 --- a/src/ui/inputui.cpp +++ b/src/ui/inputui.cpp @@ -14,18 +14,18 @@ struct InputUIGeneral : InputGroup { InputUIGeneral() : InputGroup("General"), - load (InputObject::Button, "Load cartridge", config::input.gui.load), - pause (InputObject::Button, "Pause emulation", config::input.gui.pause), - reset (InputObject::Button, "Reset system", config::input.gui.reset), - power (InputObject::Button, "Power cycle system", config::input.gui.power), - quit (InputObject::Button, "Exit emulator", config::input.gui.quit), - speed_decrease (InputObject::Button, "Decrease emulation speed", config::input.gui.speed_decrease), - speed_increase (InputObject::Button, "Increase emulation speed", config::input.gui.speed_increase), - frameskip_decrease(InputObject::Button, "Decrease frameskip rate", config::input.gui.frameskip_decrease), - frameskip_increase(InputObject::Button, "Increase frameskip rate", config::input.gui.frameskip_increase), - toggle_fullscreen (InputObject::Button, "Toggle fullscreen mode", config::input.gui.toggle_fullscreen), - toggle_menubar (InputObject::Button, "Toggle menubar", config::input.gui.toggle_menubar), - toggle_statusbar (InputObject::Button, "Toggle statusbar", config::input.gui.toggle_statusbar) + load (InputObject::Button, "Load cartridge", config.input.gui.load), + pause (InputObject::Button, "Pause emulation", config.input.gui.pause), + reset (InputObject::Button, "Reset system", config.input.gui.reset), + power (InputObject::Button, "Power cycle system", config.input.gui.power), + quit (InputObject::Button, "Exit emulator", config.input.gui.quit), + speed_decrease (InputObject::Button, "Decrease emulation speed", config.input.gui.speed_decrease), + speed_increase (InputObject::Button, "Increase emulation speed", config.input.gui.speed_increase), + frameskip_decrease(InputObject::Button, "Decrease frameskip rate", config.input.gui.frameskip_decrease), + frameskip_increase(InputObject::Button, "Increase frameskip rate", config.input.gui.frameskip_increase), + toggle_fullscreen (InputObject::Button, "Toggle fullscreen mode", config.input.gui.toggle_fullscreen), + toggle_menubar (InputObject::Button, "Toggle menubar", config.input.gui.toggle_menubar), + toggle_statusbar (InputObject::Button, "Toggle statusbar", config.input.gui.toggle_statusbar) { attach(load); attach(pause); attach(reset); attach(power); attach(quit); attach(speed_decrease); attach(speed_increase); @@ -43,11 +43,11 @@ struct InputUIDebug : InputGroup { InputUIDebug() : InputGroup("Debugger"), - export_memory (InputObject::Button, "Export memory", config::input.debugger.export_memory), - toggle_cputrace (InputObject::Button, "Toggle S-CPU tracing", config::input.debugger.toggle_cputrace), - toggle_cputracemask(InputObject::Button, "Toggle S-CPU trace mask", config::input.debugger.toggle_cputracemask), - toggle_smptrace (InputObject::Button, "Toggle S-SMP tracing", config::input.debugger.toggle_smptrace), - toggle_smptracemask(InputObject::Button, "Toggle S-SMP trace mask", config::input.debugger.toggle_smptracemask) + export_memory (InputObject::Button, "Export memory", config.input.debugger.export_memory), + toggle_cputrace (InputObject::Button, "Toggle S-CPU tracing", config.input.debugger.toggle_cputrace), + toggle_cputracemask(InputObject::Button, "Toggle S-CPU trace mask", config.input.debugger.toggle_cputracemask), + toggle_smptrace (InputObject::Button, "Toggle S-SMP tracing", config.input.debugger.toggle_smptrace), + toggle_smptracemask(InputObject::Button, "Toggle S-SMP trace mask", config.input.debugger.toggle_smptracemask) { attach(export_memory); attach(toggle_cputrace); attach(toggle_cputracemask); diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp index 3329f654..16e05f68 100644 --- a/src/ui/interface.cpp +++ b/src/ui/interface.cpp @@ -24,15 +24,15 @@ void SNESInterface::video_refresh(uint16_t *data, unsigned pitch, unsigned *line } } - if(config::video.frameskip == 0) { + if(config.video.frameskip == 0) { ppu.enable_renderer(true); } else { frameskip_counter++; - frameskip_counter %= config::video.frameskip + 1; + frameskip_counter %= config.video.frameskip + 1; if(frameskip_counter == 0) { //randomize which frame of set will be rendered, //helps with two-frame animations (such as blinking) - frameskip_offset = rand() % (config::video.frameskip + 1); + frameskip_offset = rand() % (config.video.frameskip + 1); } ppu.enable_renderer(frameskip_counter == frameskip_offset); } @@ -41,7 +41,7 @@ void SNESInterface::video_refresh(uint16_t *data, unsigned pitch, unsigned *line //audio void SNESInterface::audio_sample(uint16 l_sample, uint16 r_sample) { - if(config::audio.mute == true) { + if(config.audio.mute == true) { l_sample = 0; r_sample = 0; } @@ -67,14 +67,15 @@ int16_t SNESInterface::input_poll(unsigned deviceid, unsigned id) { void SNESInterface::init() { input_manager.bind(); libfilter::colortable.set_format(libfilter::Colortable::RGB888); - libfilter::colortable.set_contrast(config::system.contrast); - libfilter::colortable.set_brightness(config::system.brightness); - libfilter::colortable.set_gamma(config::system.gamma); - libfilter::colortable.enable_gamma_ramp(config::system.gamma_ramp); - libfilter::colortable.enable_sepia(config::system.sepia); - libfilter::colortable.enable_grayscale(config::system.grayscale); - libfilter::colortable.enable_invert(config::system.invert); + libfilter::colortable.set_contrast(config.video.contrast); + libfilter::colortable.set_brightness(config.video.brightness); + libfilter::colortable.set_gamma(config.video.gamma); + libfilter::colortable.enable_gamma_ramp(config.video.gamma_ramp); + libfilter::colortable.enable_sepia(config.video.sepia); + libfilter::colortable.enable_grayscale(config.video.grayscale); + libfilter::colortable.enable_invert(config.video.invert); libfilter::colortable.update(); + libfilter::filter_ntsc.adjust(0, 0, 0, 0, 0, config.video.ntsc_filter_merge_fields); } void SNESInterface::term() { diff --git a/src/ui/loader/bsxloader.cpp b/src/ui/loader/bsxloader.cpp index f04fadc5..e443c84e 100644 --- a/src/ui/loader/bsxloader.cpp +++ b/src/ui/loader/bsxloader.cpp @@ -4,7 +4,7 @@ uintptr_t BSXLoaderWindow::close(event_t) { } uintptr_t BSXLoaderWindow::bbase_tick(event_t) { -char fn[PATH_MAX]; + char fn[PATH_MAX]; if(event::load_cart(fn) == true) tbase.set_text(fn); return true; } @@ -15,7 +15,7 @@ uintptr_t BSXLoaderWindow::cbase_tick(event_t) { } uintptr_t BSXLoaderWindow::bslot_tick(event_t) { -char fn[PATH_MAX]; + char fn[PATH_MAX]; if(event::load_cart(fn) == true) tslot.set_text(fn); return true; } @@ -26,12 +26,12 @@ uintptr_t BSXLoaderWindow::cslot_tick(event_t) { } uintptr_t BSXLoaderWindow::load_tick(event_t) { -char base[PATH_MAX], slot[PATH_MAX]; + char base[PATH_MAX], slot[PATH_MAX]; tbase.get_text(base, PATH_MAX); tslot.get_text(slot, PATH_MAX); if(mode == ModeBSX) { - config::path.bsx = base; + snes.config.path.bsx = base; event::load_cart_bsx(base, slot); } else if(mode == ModeBSC) { event::load_cart_bsc(base, slot); diff --git a/src/ui/loader/stloader.cpp b/src/ui/loader/stloader.cpp index a31349ed..b48a5f94 100644 --- a/src/ui/loader/stloader.cpp +++ b/src/ui/loader/stloader.cpp @@ -4,7 +4,7 @@ uintptr_t STLoaderWindow::close(event_t) { } uintptr_t STLoaderWindow::bbase_tick(event_t) { -char fn[PATH_MAX]; + char fn[PATH_MAX]; if(event::load_cart(fn) == true) tbase.set_text(fn); return true; } @@ -15,7 +15,7 @@ uintptr_t STLoaderWindow::cbase_tick(event_t) { } uintptr_t STLoaderWindow::bslotA_tick(event_t) { -char fn[PATH_MAX]; + char fn[PATH_MAX]; if(event::load_cart(fn) == true) tslotA.set_text(fn); return true; } @@ -26,7 +26,7 @@ uintptr_t STLoaderWindow::cslotA_tick(event_t) { } uintptr_t STLoaderWindow::bslotB_tick(event_t) { -char fn[PATH_MAX]; + char fn[PATH_MAX]; if(event::load_cart(fn) == true) tslotB.set_text(fn); return true; } @@ -37,12 +37,12 @@ uintptr_t STLoaderWindow::cslotB_tick(event_t) { } uintptr_t STLoaderWindow::load_tick(event_t) { -char base[PATH_MAX], slotA[PATH_MAX], slotB[PATH_MAX]; + char base[PATH_MAX], slotA[PATH_MAX], slotB[PATH_MAX]; tbase.get_text(base, PATH_MAX); tslotA.get_text(slotA, PATH_MAX); tslotB.get_text(slotB, PATH_MAX); - config::path.st = base; + snes.config.path.st = base; event::load_cart_st(base, slotA, slotB); tbase.set_text(""); diff --git a/src/ui/main.cpp b/src/ui/main.cpp index ba4418da..13d5bb76 100644 --- a/src/ui/main.cpp +++ b/src/ui/main.cpp @@ -1,4 +1,5 @@ #include <../base.hpp> +#include <../cart/cart.hpp> #include "main.hpp" #include "config.cpp" @@ -35,16 +36,16 @@ void get_paths(const char *image) { } if(strend(temp, "/") == false) strcat(temp, "/"); - config::path.base = temp; + snes.config.path.base = temp; } else { - config::path.base = ""; + snes.config.path.base = ""; } if(userpath(temp)) { if(strend(temp, "/") == false) strcat(temp, "/"); - config::path.user = temp; + snes.config.path.user = temp; } else { - config::path.user = ""; + snes.config.path.user = ""; } } @@ -52,26 +53,26 @@ void set_config_filenames() { char filename[PATH_MAX]; //locate bsnes.cfg - strcpy(filename, config::path.base); + strcpy(filename, snes.config.path.base); strcat(filename, "bsnes.cfg"); if(!file::exists(filename)) { - strcpy(filename, config::path.user); + strcpy(filename, snes.config.path.user); strcat(filename, ".bsnes"); mkdir(filename); strcat(filename, "/bsnes.cfg"); } - strcpy(config::bsnes_cfg, filename); + strcpy(config.bsnes_cfg, filename); //locate locale.cfg - strcpy(filename, config::path.base); + strcpy(filename, snes.config.path.base); strcat(filename, "locale.cfg"); if(!file::exists(filename)) { - strcpy(filename, config::path.user); + strcpy(filename, snes.config.path.user); strcat(filename, ".bsnes"); mkdir(filename); strcat(filename, "/locale.cfg"); } - strcpy(config::locale_cfg, filename); + strcpy(config.locale_cfg, filename); } void run() { @@ -79,7 +80,7 @@ void run() { status.update(); input_manager.refresh(); - if(config::input.capture_mode == 2) { + if(config.input.capture_mode == 2) { bool inactive = (window_main.focused() == false); if(app.autopause == false && inactive == true) { app.autopause = true; @@ -102,13 +103,13 @@ int hiromain(int argc, const char *const argv[]) { get_paths(argv[0]); set_config_filenames(); - config::config().load(config::bsnes_cfg); - if(file::exists(config::bsnes_cfg) == false) { + config.load(config.bsnes_cfg); + if(file::exists(config.bsnes_cfg) == false) { //in case program crashes on first run, save config file //settings, so that they can be modified by hand ... - config::config().save(config::bsnes_cfg); + config.save(config.bsnes_cfg); } - translate.import(config::locale_cfg); + translate.import(config.locale_cfg); ui_init(); if(app.term == false) { @@ -118,7 +119,7 @@ int hiromain(int argc, const char *const argv[]) { event::unload_cart(); } - config::config().save(config::bsnes_cfg); + config.save(config.bsnes_cfg); snes.term(); ui_term(); return 0; diff --git a/src/ui/settings/advanced.cpp b/src/ui/settings/advanced.cpp index c1e33e99..c4ea45e5 100644 --- a/src/ui/settings/advanced.cpp +++ b/src/ui/settings/advanced.cpp @@ -1,49 +1,40 @@ -uintptr_t AdvancedWindow::list_change(event_t) { - int pos = list.get_selection(); - edit_val.enable(pos >= 0); - set_val.enable(pos >= 0); - set_def.enable(pos >= 0); - if(pos >= 0) { - unsigned i = lookup[pos]; - string default_; - config::config().list[i]->get_default(default_); - desc.set_text(string() - << "(" << translate["{{advanced}}Default"] << " = " << default_ << ")\n" - << config::config().list[i]->description); - string value_; - config::config().list[i]->get(value_); - edit_val.set_text(value_); +uintptr_t AdvancedWindow::list_activate(event_t) { + int item = list.get_selection(); + if(item >= 0) { + //if item is integral_setting::boolean, toggle its state + if(config.list[lookup[item]].type == configuration::boolean_t) { + *(bool*)config.list[lookup[item]].data = *(bool*)config.list[lookup[item]].data ? false : true; + update(item); + } } return true; } -uintptr_t AdvancedWindow::setval_tick(event_t) { - char t[4096]; - edit_val.get_text(t, sizeof t); - update(list.get_selection(), t); +uintptr_t AdvancedWindow::list_change(event_t) { + int item = list.get_selection(); + edit.enable(item >= 0); + set.enable (item >= 0); + edit.set_text(item >= 0 ? config.list[lookup[item]].get() : translate[""]); return true; } -uintptr_t AdvancedWindow::setdef_tick(event_t) { - update(list.get_selection(), 0); +uintptr_t AdvancedWindow::set_tick(event_t) { + int item = list.get_selection(); + if(item >= 0) { + char value[4096]; + edit.get_text(value, sizeof value); + config.list[lookup[item]].set(value); + update(item); + } return true; } -void AdvancedWindow::update(uint pos, const char *data) { - unsigned i = lookup[pos]; - string default_; - config::config().list[i]->get_default(default_); - config::config().list[i]->set(data ? data : (const char*)default_); - string value_; - config::config().list[i]->get(value_); - edit_val.set_text(value_); - list.set_item(pos, string() - << config::config().list[i]->name - << (value_ == default_ ? "" : " (*)") - << "\t" - << (config::config().list[i]->type == setting::string_type ? translate["string"] : translate["integer"]) - << "\t" - << value_ +void AdvancedWindow::update(unsigned item) { + edit.set_text(config.list[lookup[item]].get()); + list.set_item(item, string() + << config.list[lookup[item]].name << "\t" + << config.list[lookup[item]].get() << "\t" + << config.list[lookup[item]].desc ); list.autosize_columns(); } @@ -51,8 +42,8 @@ void AdvancedWindow::update(uint pos, const char *data) { void AdvancedWindow::load() { lookup.reset(); - for(unsigned i = 0; i < config::config().list.size(); i++) { - string name = config::config().list[i]->name; + for(unsigned i = 0; i < config.list.size(); i++) { + string name = config.list[i].name; //blacklist (omit/hide options that can be configured through the standard UI) if(name == "snes.expansion_port") continue; @@ -60,11 +51,15 @@ void AdvancedWindow::load() { if(strbegin(name, "system.")) continue; if(strbegin(name, "path.")) continue; if(strbegin(name, "snes.controller_port")) continue; - if(strpos(name, "colorfilter.") >= 0) continue; if(name == "system.emulation_speed") continue; if(strbegin(name, "video.windowed.")) continue; if(strbegin(name, "video.fullscreen.")) continue; if(name == "video.synchronize") continue; + if(name == "video.contrast") continue; + if(name == "video.brightness") continue; + if(name == "video.gamma") continue; + if(name == "video.gamma_ramp") continue; + if(name == "video.ntsc_filter_merge_fields") continue; if(strbegin(name, "audio.")) continue; if(name == "input.capture_mode") continue; if(strbegin(name, "input.joypad")) continue; @@ -76,16 +71,10 @@ void AdvancedWindow::load() { if(strbegin(name, "input.debugger")) continue; if(name == "misc.cheat_autosort") continue; - string value_, default_; - config::config().list[i]->get(value_); - config::config().list[i]->get_default(default_); list.add_item(string() - << name - << (value_ == default_ ? "" : " (*)") - << "\t" - << (config::config().list[i]->type == setting::string_type ? translate["string"] : translate["integer"]) - << "\t" - << value_ + << name << "\t" + << config.list[i].get() << "\t" + << config.list[i].desc ); lookup.add(i); } @@ -94,29 +83,23 @@ void AdvancedWindow::load() { void AdvancedWindow::setup() { create(0, 451, 370); - list.create(Listbox::Header | Listbox::VerticalScrollAlways, - 451, 263, string() << translate["Name"] << "\t" << translate["Type"] << "\t" << translate["Value"]); - desc.create(Editbox::Multiline | Editbox::HorizontalScrollNever | Editbox::VerticalScrollAlways | Editbox::Readonly, - 451, 72, translate[""]); - edit_val.create(0, 241, 25, translate[""]); - set_val.create (0, 100, 25, translate["{{advanced}}Set"]); - set_def.create (0, 100, 25, translate["{{advanced}}Default"]); + list.create(Listbox::Header | Listbox::VerticalScrollAlways, 451, 340, + string() << translate["Name"] << "\t" << translate["Value"] << "\t" << translate["Description"]); + edit.create(0, 346, 25, translate[""]); + set.create (0, 100, 25, translate["{{advanced}}Set"]); unsigned y = 0; - attach(list, 0, y); y += 263 + 5; - attach(desc, 0, y); y += 72 + 5; - attach(edit_val, 0, y); - attach(set_val, 246, y); - attach(set_def, 351, y); y += 25 + 5; + attach(list, 0, y); y += 340 + 5; + attach(edit, 0, y); + attach(set, 351, y); load(); list.autosize_columns(); - edit_val.disable(); - set_val.disable(); - set_def.disable(); + edit.disable(); + set.disable(); - list.on_change = bind(&AdvancedWindow::list_change, this); - set_val.on_tick = bind(&AdvancedWindow::setval_tick, this); - set_def.on_tick = bind(&AdvancedWindow::setdef_tick, this); + list.on_activate = bind(&AdvancedWindow::list_activate, this); + list.on_change = bind(&AdvancedWindow::list_change, this); + set.on_tick = bind(&AdvancedWindow::set_tick, this); } diff --git a/src/ui/settings/advanced.hpp b/src/ui/settings/advanced.hpp index f0423230..10cb04b5 100644 --- a/src/ui/settings/advanced.hpp +++ b/src/ui/settings/advanced.hpp @@ -1,16 +1,15 @@ class AdvancedWindow : public Window { public: Listbox list; - Editbox desc; - Editbox edit_val; - Button set_val; - Button set_def; - + Editbox edit; + Button set; + array lookup; - void update(uint pos, const char *data); + void update(unsigned item); void load(); void setup(); + + uintptr_t list_activate(event_t); uintptr_t list_change(event_t); - uintptr_t setval_tick(event_t); - uintptr_t setdef_tick(event_t); + uintptr_t set_tick(event_t); } window_advanced; diff --git a/src/ui/settings/audiosettings.cpp b/src/ui/settings/audiosettings.cpp index 347ee8f7..e01f9c76 100644 --- a/src/ui/settings/audiosettings.cpp +++ b/src/ui/settings/audiosettings.cpp @@ -1,14 +1,14 @@ uintptr_t AudioSettingsWindow::volume_change(event_t) { - config::audio.volume = 25 + cvolume.get_selection() * 25; - audio.set(Audio::Volume, config::audio.volume); + config.audio.volume = 25 + cvolume.get_selection() * 25; + audio.set(Audio::Volume, config.audio.volume); sync_ui(); return true; } uintptr_t AudioSettingsWindow::latency_change(event_t) { - config::audio.latency = 20 + clatency.get_selection() * 20; - audio.set(Audio::Latency, config::audio.latency); + config.audio.latency = 20 + clatency.get_selection() * 20; + audio.set(Audio::Latency, config.audio.latency); sync_ui(); return true; @@ -16,41 +16,41 @@ uintptr_t AudioSettingsWindow::latency_change(event_t) { uintptr_t AudioSettingsWindow::frequency_change(event_t) { switch(cfrequency.get_selection()) { - case 0: config::audio.output_frequency = 32000; break; - case 1: config::audio.output_frequency = 44100; break; default: - case 2: config::audio.output_frequency = 48000; break; - case 3: config::audio.output_frequency = 96000; break; + case 0: config.audio.output_frequency = 32000; break; + case 1: config.audio.output_frequency = 44100; break; default: + case 2: config.audio.output_frequency = 48000; break; + case 3: config.audio.output_frequency = 96000; break; } - audio.set(Audio::Frequency, config::audio.output_frequency); - event::update_emulation_speed(config::system.emulation_speed); + audio.set(Audio::Frequency, config.audio.output_frequency); + event::update_emulation_speed(config.system.emulation_speed); sync_ui(); return true; } uintptr_t AudioSettingsWindow::skew_change(event_t) { - config::audio.input_frequency = sskew.get_position() + 32000 - 200; - event::update_emulation_speed(config::system.emulation_speed); + config.audio.input_frequency = sskew.get_position() + 32000 - 200; + event::update_emulation_speed(config.system.emulation_speed); sync_ui(); return true; } void AudioSettingsWindow::sync_ui() { - cvolume.set_selection((config::audio.volume - 25) / 25); + cvolume.set_selection((config.audio.volume - 25) / 25); unsigned position; - if(config::audio.output_frequency <= 32000) position = 0; - else if(config::audio.output_frequency <= 44100) position = 1; - else if(config::audio.output_frequency <= 48000) position = 2; + if(config.audio.output_frequency <= 32000) position = 0; + else if(config.audio.output_frequency <= 44100) position = 1; + else if(config.audio.output_frequency <= 48000) position = 2; else position = 3; cfrequency.set_selection(position); - clatency.set_selection((config::audio.latency - 20) / 20); + clatency.set_selection((config.audio.latency - 20) / 20); - lskew.set_text(string() << translate["{{audio}}Frequency adjust:"] << " " << (int)config::audio.input_frequency << "hz"); - sskew.set_position(config::audio.input_frequency - 32000 + 200); + lskew.set_text(string() << translate["{{audio}}Frequency adjust:"] << " " << (int)config.audio.input_frequency << "hz"); + sskew.set_position(config.audio.input_frequency - 32000 + 200); } void AudioSettingsWindow::setup() { @@ -62,7 +62,7 @@ void AudioSettingsWindow::setup() { cvolume.add_item( "50%"); cvolume.add_item( "75%"); cvolume.add_item("100%"); - if(config::advanced.enable == true) { + if(config.misc.show_advanced_options == true) { cvolume.add_item("125%"); cvolume.add_item("150%"); cvolume.add_item("175%"); @@ -74,7 +74,7 @@ void AudioSettingsWindow::setup() { cfrequency.add_item("32Khz"); cfrequency.add_item("44.1Khz"); cfrequency.add_item("48Khz"); - if(config::advanced.enable == true) { + if(config.misc.show_advanced_options == true) { cfrequency.add_item("96Khz"); } @@ -86,7 +86,7 @@ void AudioSettingsWindow::setup() { clatency.add_item( "80ms"); clatency.add_item("100ms"); clatency.add_item("120ms"); - if(config::advanced.enable == true) { + if(config.misc.show_advanced_options == true) { clatency.add_item("140ms"); clatency.add_item("160ms"); } diff --git a/src/ui/settings/cheateditor.cpp b/src/ui/settings/cheateditor.cpp index 6568bac8..37b1c029 100644 --- a/src/ui/settings/cheateditor.cpp +++ b/src/ui/settings/cheateditor.cpp @@ -1,86 +1,75 @@ +//================= +//CheatEditorWindow +//================= + void CheatEditorWindow::setup() { create(0, 451, 370); - list.create(Listbox::Header | Listbox::VerticalScrollAlways, 451, 287, + list.create(Listbox::Header | Listbox::VerticalScrollAlways, 451, 317, string() << translate["Status"] << "\t" << translate["Code"] << "\t" << translate["Description"]); autosort.create (0, 451, 18, translate["Keep cheat code list sorted by description"]); add_code.create (0, 147, 25, translate["Add Code"]); - toggle_code.create(0, 147, 25, translate["Toggle Status"]); + edit_code.create (0, 147, 25, translate["Edit Code"]); delete_code.create(0, 147, 25, translate["Delete Code"]); - code.create(0, 147, 25, translate[""]); - desc.create(0, 299, 25, translate[""]); unsigned y = 0; - attach(list, 0, y); y += 287 + 5; + attach(list, 0, y); y += 317 + 5; attach(autosort, 0, y); y += 18 + 5; attach(add_code, 0, y); - attach(toggle_code, 152, y); + attach(edit_code, 152, y); attach(delete_code, 304, y); y += 25 + 5; - attach(code, 0, y); - attach(desc, 152, y); y += 25 + 5; - autosort.check(config::misc.cheat_autosort); + autosort.check(config.misc.cheat_autosort); list.on_activate = bind(&CheatEditorWindow::toggle_code_state, this); list.on_change = bind(&CheatEditorWindow::list_change, this); autosort.on_tick = bind(&CheatEditorWindow::autosort_tick, this); - code.on_change = bind(&CheatEditorWindow::code_input, this); add_code.on_tick = bind(&CheatEditorWindow::add_tick, this); - toggle_code.on_tick = bind(&CheatEditorWindow::toggle_code_state, this); + edit_code.on_tick = bind(&CheatEditorWindow::edit_tick, this); delete_code.on_tick = bind(&CheatEditorWindow::delete_tick, this); - refresh(); + sync_ui(); + window_cheat_code_editor.setup(); +} + +void CheatEditorWindow::sync_ui() { + add_code.enable(cartridge.loaded()); + edit_code.enable(cartridge.loaded() && list.get_selection() >= 0); + delete_code.enable(cartridge.loaded() && list.get_selection() >= 0); +} + +string CheatEditorWindow::read_code(unsigned index) { + string s; + + Cheat::cheat_t item; + cheat.get(index, item); + s << (item.enabled ? translate["Enabled"] : translate["Disabled"]) << "\t"; + + lstring line; + split(line, "+", item.code); + if(count(line) > 1) line[0] << "+..."; + s << line[0] << "\t"; + + split(line, "\n", item.desc); + if(count(line) > 1) line[0] << " ..."; + s << line[0]; + + return s; } void CheatEditorWindow::refresh() { + if(config.misc.cheat_autosort == true) cheat.sort(); + list.reset(); - if(config::misc.cheat_autosort == true) cheat.sort(); - - for(unsigned i = 0; i < cheat.count(); i++) { - Cheat::cheat_t cheatcode; - cheat.get(i, cheatcode); - list.add_item(string() - << (cheatcode.enabled ? translate["Enabled"] : translate["Disabled"]) << "\t" - << cheatcode.code << "\t" - << cheatcode.desc); - } - + for(unsigned i = 0; i < cheat.count(); i++) list.add_item(read_code(i)); list.autosize_columns(); - //enable controls only if cartridge is loaded - bool loaded = cartridge.loaded(); - if(loaded == false) { - code.set_text(translate[""]); - desc.set_text(translate[""]); - } - code.enable(loaded); - desc.enable(loaded); - - add_code.enable(loaded && is_code_valid()); - toggle_code.disable(); //no list item will be selected; - delete_code.disable(); //so there's nothing to toggle / delete. -} - -bool CheatEditorWindow::is_code_valid() { - //input - char s_code[16]; - code.get_text(s_code, sizeof s_code); - //output - unsigned addr; - uint8_t data; - Cheat::type_t type; - return cheat.decode(s_code, addr, data, type); -} - -//enable "Add Code" button only when cheat code is valid -uintptr_t CheatEditorWindow::code_input(event_t) { - add_code.enable(is_code_valid()); - return true; + sync_ui(); } uintptr_t CheatEditorWindow::autosort_tick(event_t) { - config::misc.cheat_autosort = autosort.checked(); - if(config::misc.cheat_autosort == true) refresh(); + config.misc.cheat_autosort = autosort.checked(); + if(config.misc.cheat_autosort == true) refresh(); return true; } @@ -88,30 +77,32 @@ uintptr_t CheatEditorWindow::toggle_code_state(event_t) { int index = list.get_selection(); if(index >= 0 && index < cheat.count()) { cheat.enabled(index) ? cheat.disable(index) : cheat.enable(index); - Cheat::cheat_t cheatcode; - cheat.get(index, cheatcode); - list.set_item(index, string() - << (cheatcode.enabled ? translate["Enabled"] : translate["Disabled"]) << "\t" - << cheatcode.code << "\t" - << cheatcode.desc); + list.set_item(index, read_code(index)); } return true; } -//enables "Toggle Code" / "Delete Code" buttons when a code is selected +//enables "Edit Code" / "Delete Code" buttons when a code is selected uintptr_t CheatEditorWindow::list_change(event_t) { int index = list.get_selection(); - toggle_code.enable(index >= 0); + edit_code.enable(index >= 0); delete_code.enable(index >= 0); return true; } uintptr_t CheatEditorWindow::add_tick(event_t) { - char s_code[1024], s_desc[1024]; - code.get_text(s_code, sizeof s_code); - desc.get_text(s_desc, sizeof s_desc); - cheat.add(false, s_code, s_desc); //param 0 = false, meaning new codes are disabled by default - refresh(); + add_code.disable(); + edit_code.disable(); + delete_code.disable(); + window_cheat_code_editor.show(false); + return true; +} + +uintptr_t CheatEditorWindow::edit_tick(event_t) { + add_code.disable(); + edit_code.disable(); + delete_code.disable(); + window_cheat_code_editor.show(true, list.get_selection()); return true; } @@ -123,3 +114,125 @@ uintptr_t CheatEditorWindow::delete_tick(event_t) { } return true; } + +//===================== +//CheatCodeEditorWindow +//===================== + +uintptr_t CheatCodeEditorWindow::close(event_t) { + hide(); + window_cheat_editor.sync_ui(); + return false; +} + +uintptr_t CheatCodeEditorWindow::validate(event_t) { + char s_codes[1024]; + codes.get_text(s_codes, sizeof s_codes); + + string s_code = s_codes; + strtr(s_code, " ,;&|\t\n", "+++++++"); + while(strpos(s_code, "++") >= 0) replace(s_code, "++", "+"); + trim(s_code, "+"); + + Cheat::cheat_t item; + bool valid = cheat.decode(s_code, item); + + lvalid.set_text(valid ? "" : translate["Cheat code is invalid."]); + ok.enable(valid); + return true; +} + +uintptr_t CheatCodeEditorWindow::ok_tick(event_t) { + char s_desc[1024], s_codes[1024]; + description.get_text(s_desc, sizeof s_desc); + codes.get_text(s_codes, sizeof s_codes); + + string s_code = s_codes; + strtr(s_code, " ,;&|\t\n", "+++++++"); + while(strpos(s_code, "++") >= 0) replace(s_code, "++", "+"); + trim(s_code, "+"); + + if(active_mode == false) { + //add a new code + cheat.add(enabled.checked(), s_code, s_desc); + } else { + //modify an existing code + cheat.edit(active_code, enabled.checked(), s_code, s_desc); + } + + hide(); + window_cheat_editor.refresh(); + return true; +} + +uintptr_t CheatCodeEditorWindow::cancel_tick(event_t) { + hide(); + window_cheat_editor.sync_ui(); + return true; +} + +uintptr_t CheatCodeEditorWindow::clear_tick(event_t) { + description.set_text(""); + codes.set_text(""); + enabled.check(false); + return true; +} + +void CheatCodeEditorWindow::show(bool editmode, unsigned codenumber) { + active_mode = editmode; + active_code = codenumber; + + if(active_mode == false) { + set_text(translate["Add new cheat code"]); + description.set_text(""); + codes.set_text(""); + enabled.check(false); + } else { + Cheat::cheat_t item; + cheat.get(active_code, item); + + set_text(translate["Modify existing cheat code"]); + description.set_text(item.desc); + string s = item.code; + replace(s, "+", " + "); + codes.set_text(s); + enabled.check(item.enabled); + } + + enabled.focus(); + validate(event_t(event_t::Change)); + Window::show(); +} + +void CheatCodeEditorWindow::setup() { + create(Window::AutoCenter, 395, 235); + set_icon(48, 48, (uint32_t*)resource::icon48); + + ldescription.create(0, 385, 18, translate["Description:"]); + description.create(Editbox::Multiline | Editbox::HorizontalScrollNever, 385, 65); + lcodes.create(0, 385, 18, translate["Enter one or more cheat codes below:"]); + codes.create(Editbox::Multiline | Editbox::HorizontalScrollNever, 385, 65); + enabled.create(0, 190, 18, translate["Enable this cheat code"]); + lvalid.create(0, 190, 18); + ok.create(0, 125, 25, translate["Ok"]); + cancel.create(0, 125, 25, translate["Cancel"]); + clear.create(0, 125, 25, translate["Clear"]); + + unsigned y = 5; + attach(ldescription, 5, y); y += 18; + attach(description, 5, y); y += 65 + 5; + attach(lcodes, 5, y); y += 18; + attach(codes, 5, y); y += 65 + 5; + attach(enabled, 5, y); + attach(lvalid, 200, y); y += 18 + 5; + attach(ok, 5, y); + attach(cancel, 135, y); + attach(clear, 265, y); y += 25 + 5; + lvalid.disable(); + + on_close = bind(&CheatCodeEditorWindow::close, this); + codes.on_change = bind(&CheatCodeEditorWindow::validate, this); + ok.on_tick = bind(&CheatCodeEditorWindow::ok_tick, this); + cancel.on_tick = bind(&CheatCodeEditorWindow::cancel_tick, this); + clear.on_tick = bind(&CheatCodeEditorWindow::clear_tick, this); +} diff --git a/src/ui/settings/cheateditor.hpp b/src/ui/settings/cheateditor.hpp index 7d2c92ec..81c5882c 100644 --- a/src/ui/settings/cheateditor.hpp +++ b/src/ui/settings/cheateditor.hpp @@ -1,21 +1,48 @@ +//main editor window for all codes class CheatEditorWindow : public Window { public: Listbox list; Checkbox autosort; Button add_code; - Button toggle_code; + Button edit_code; Button delete_code; - Editbox code; - Editbox desc; + void sync_ui(); void setup(); + + string read_code(unsigned index); void refresh(); - bool is_code_valid(); uintptr_t toggle_code_state(event_t); uintptr_t list_change(event_t); - uintptr_t code_input(event_t); uintptr_t autosort_tick(event_t); uintptr_t add_tick(event_t); + uintptr_t edit_tick(event_t); uintptr_t delete_tick(event_t); } window_cheat_editor; + +//individual cheat code editor +class CheatCodeEditorWindow : public Window { +public: + Label ldescription; + Editbox description; + Label lcodes; + Editbox codes; + Checkbox enabled; + Label lvalid; + Button ok; + Button cancel; + Button clear; + + bool active_mode; + unsigned active_code; + + void show(bool editmode, unsigned codenumber = 0); + void setup(); + + uintptr_t close(event_t); + uintptr_t validate(event_t); + uintptr_t ok_tick(event_t); + uintptr_t cancel_tick(event_t); + uintptr_t clear_tick(event_t); +} window_cheat_code_editor; diff --git a/src/ui/settings/driverselect.cpp b/src/ui/settings/driverselect.cpp index fb5f0ec3..54611141 100644 --- a/src/ui/settings/driverselect.cpp +++ b/src/ui/settings/driverselect.cpp @@ -1,21 +1,21 @@ uintptr_t DriverSelectWindow::video_change(event_t) { lstring part; split(part, ";", video.driver_list()); - config::system.video = part[cvideo.get_selection()]; + config.system.video = part[cvideo.get_selection()]; return true; } uintptr_t DriverSelectWindow::audio_change(event_t) { lstring part; split(part, ";", audio.driver_list()); - config::system.audio = part[caudio.get_selection()]; + config.system.audio = part[caudio.get_selection()]; return true; } uintptr_t DriverSelectWindow::input_change(event_t) { lstring part; split(part, ";", input.driver_list()); - config::system.input = part[cinput.get_selection()]; + config.system.input = part[cinput.get_selection()]; return true; } @@ -36,7 +36,7 @@ void DriverSelectWindow::setup() { split(part, ";", video.driver_list()); for(unsigned i = 0; i < count(part); i++) { cvideo.add_item(translate[string() << "{{videodriver}}" << part[i]]); - if(part[i] == config::system.video) cvideo.set_selection(i); + if(part[i] == config.system.video) cvideo.set_selection(i); } laudio.create(0, 147, 18, translate["Audio driver:"]); @@ -45,7 +45,7 @@ void DriverSelectWindow::setup() { split(part, ";", audio.driver_list()); for(unsigned i = 0; i < count(part); i++) { caudio.add_item(translate[string() << "{{audiodriver}}" << part[i]]); - if(part[i] == config::system.audio) caudio.set_selection(i); + if(part[i] == config.system.audio) caudio.set_selection(i); } linput.create(0, 147, 18, translate["Input driver:"]); @@ -54,7 +54,7 @@ void DriverSelectWindow::setup() { split(part, ";", input.driver_list()); for(unsigned i = 0; i < count(part); i++) { cinput.add_item(translate[string() << "{{inputdriver}}" << part[i]]); - if(part[i] == config::system.input) cinput.set_selection(i); + if(part[i] == config.system.input) cinput.set_selection(i); } video_caps.create(0, 451, 18); @@ -85,17 +85,17 @@ void DriverSelectWindow::setup() { restart_message.create(0, 451, 36, translate["Note: bsnes must be restarted for changes to take effect."]); - bool crashed = config::system.invoke_crash_handler; + bool crashed = config.system.invoke_crash_handler; string t = translate["Capabilities of active video driver ($):"]; - replace(t, "$", config::system.video); + replace(t, "$", config.system.video); video_caps.set_text(t); video_sync.check(video.cap(Video::Synchronize)); video_filter.check(video.cap(Video::Filter)); t = translate["Capabilities of active audio driver ($):"]; - replace(t, "$", config::system.audio); + replace(t, "$", config.system.audio); audio_caps.set_text(t); audio_sync.check(audio.cap(Audio::Synchronize)); @@ -103,7 +103,7 @@ void DriverSelectWindow::setup() { audio_latency.check(audio.cap(Audio::Latency)); t = translate["Capabilities of active input driver ($):"]; - replace(t, "$", config::system.input); + replace(t, "$", config.system.input); input_caps.set_text(t); input_keyboard.check(input.cap(Input::KeyboardSupport)); diff --git a/src/ui/settings/inputconfig.cpp b/src/ui/settings/inputconfig.cpp index e0162b7d..3fd0cf5a 100644 --- a/src/ui/settings/inputconfig.cpp +++ b/src/ui/settings/inputconfig.cpp @@ -49,9 +49,9 @@ void InputConfigWindow::setup() { setkey.on_tick = bind(&InputConfigWindow::set_tick, this); clrkey.on_tick = bind(&InputConfigWindow::clr_tick, this); - if(config::input.capture_mode == 1) capture_focus.check(); - else if(config::input.capture_mode == 2) capture_pause.check(); - else config::input.capture_mode = 0; //capture_always + if(config.input.capture_mode == 1) capture_focus.check(); + else if(config.input.capture_mode == 2) capture_pause.check(); + else config.input.capture_mode = 0; //capture_always refresh_list(); window_input_capture.setup(); @@ -75,7 +75,7 @@ InputGroup* InputConfigWindow::get_group() { return device; } else { //user interface - switch(index) { + switch(index) { default: case 0: return &inputuigeneral; case 1: return &inputuidebugger; } @@ -150,9 +150,9 @@ void InputConfigWindow::refresh_list() { } uintptr_t InputConfigWindow::capture_change(event_t e) { - if(e.widget == &capture_always) config::input.capture_mode = 0; - if(e.widget == &capture_focus) config::input.capture_mode = 1; - if(e.widget == &capture_pause) config::input.capture_mode = 2; + if(e.widget == &capture_always) config.input.capture_mode = 0; + if(e.widget == &capture_focus) config.input.capture_mode = 1; + if(e.widget == &capture_pause) config.input.capture_mode = 2; return true; } @@ -250,6 +250,8 @@ uintptr_t InputCaptureWindow::close(event_t) { void InputCaptureWindow::setup() { create(Window::AutoCenter, 382, 206, translate["bsnes Key Capture"]); + set_icon(48, 48, (uint32_t*)resource::icon48); + label.create(0, 340, 18); canvas.create(0, 372, 178); memcpy(canvas.buffer(), resource::controller, 372 * 178 * 4); diff --git a/src/ui/settings/inputconfig.hpp b/src/ui/settings/inputconfig.hpp index e9a1e892..3db7735a 100644 --- a/src/ui/settings/inputconfig.hpp +++ b/src/ui/settings/inputconfig.hpp @@ -35,7 +35,7 @@ public: bool waiting; bool locked; - uint index; + unsigned index; void assign(uint16_t code); void show(); diff --git a/src/ui/settings/pathsettings.cpp b/src/ui/settings/pathsettings.cpp index ae6fc7f6..40908289 100644 --- a/src/ui/settings/pathsettings.cpp +++ b/src/ui/settings/pathsettings.cpp @@ -5,14 +5,14 @@ uintptr_t PathSettingsWindow::selectpath_rom(event_t) { char t[PATH_MAX]; if(hiro().folder_select(&window_settings, t) == true) { - config::path.rom = t; + snes.config.path.rom = t; update_paths(); } return true; } uintptr_t PathSettingsWindow::defaultpath_rom(event_t) { - config::path.rom = ""; + snes.config.path.rom = ""; update_paths(); return true; } @@ -24,14 +24,14 @@ uintptr_t PathSettingsWindow::defaultpath_rom(event_t) { uintptr_t PathSettingsWindow::selectpath_save(event_t) { char t[PATH_MAX]; if(hiro().folder_select(&window_settings, t) == true) { - config::path.save = t; + snes.config.path.save = t; update_paths(); } return true; } uintptr_t PathSettingsWindow::defaultpath_save(event_t) { - config::path.save = ""; + snes.config.path.save = ""; update_paths(); return true; } @@ -43,14 +43,14 @@ uintptr_t PathSettingsWindow::defaultpath_save(event_t) { uintptr_t PathSettingsWindow::selectpath_patch(event_t) { char t[PATH_MAX]; if(hiro().folder_select(&window_settings, t) == true) { - config::path.patch = t; + snes.config.path.patch = t; update_paths(); } return true; } uintptr_t PathSettingsWindow::defaultpath_patch(event_t) { - config::path.patch = ""; + snes.config.path.patch = ""; update_paths(); return true; } @@ -62,14 +62,14 @@ uintptr_t PathSettingsWindow::defaultpath_patch(event_t) { uintptr_t PathSettingsWindow::selectpath_cheat(event_t) { char t[PATH_MAX]; if(hiro().folder_select(&window_settings, t) == true) { - config::path.cheat = t; + snes.config.path.cheat = t; update_paths(); } return true; } uintptr_t PathSettingsWindow::defaultpath_cheat(event_t) { - config::path.cheat = ""; + snes.config.path.cheat = ""; update_paths(); return true; } @@ -81,14 +81,14 @@ uintptr_t PathSettingsWindow::defaultpath_cheat(event_t) { uintptr_t PathSettingsWindow::selectpath_export(event_t) { char t[PATH_MAX]; if(hiro().folder_select(&window_settings, t) == true) { - config::path.exportdata = t; + snes.config.path.exportdata = t; update_paths(); } return true; } uintptr_t PathSettingsWindow::defaultpath_export(event_t) { - config::path.exportdata = ""; + snes.config.path.exportdata = ""; update_paths(); return true; } @@ -98,19 +98,19 @@ uintptr_t PathSettingsWindow::defaultpath_export(event_t) { //============== void PathSettingsWindow::update_paths() { - if(config::path.rom != "") rompath.set_text(config::path.rom); + if(snes.config.path.rom != "") rompath.set_text(snes.config.path.rom); else rompath.set_text(translate[""]); - if(config::path.save != "") savepath.set_text(config::path.save); + if(snes.config.path.save != "") savepath.set_text(snes.config.path.save); else savepath.set_text(translate[""]); - if(config::path.patch != "") patchpath.set_text(config::path.patch); + if(snes.config.path.patch != "") patchpath.set_text(snes.config.path.patch); else patchpath.set_text(translate[""]); - if(config::path.cheat != "") cheatpath.set_text(config::path.cheat); + if(snes.config.path.cheat != "") cheatpath.set_text(snes.config.path.cheat); else cheatpath.set_text(translate[""]); - if(config::path.exportdata != "") exportpath.set_text(config::path.exportdata); + if(snes.config.path.exportdata != "") exportpath.set_text(snes.config.path.exportdata); else exportpath.set_text(translate[""]); } diff --git a/src/ui/settings/settings.cpp b/src/ui/settings/settings.cpp index 44373c6b..60cbcf2e 100644 --- a/src/ui/settings/settings.cpp +++ b/src/ui/settings/settings.cpp @@ -8,7 +8,7 @@ void SettingsWindow::setup() { panel_list.add_item(translate["Audio"]); panel_list.add_item(translate["Input"]); panel_list.add_item(translate["Paths"]); - panel_list.add_item(translate["Cheat Codes"]); + panel_list.add_item(translate["Cheat Codes"]); panel_list.add_item(translate["Advanced"]); attach(panel_list, 5, 5); @@ -25,8 +25,8 @@ void SettingsWindow::setup() { //if emulator crashed on last run, default to driver select window and disable list selection, //otherwise default to input configuration (most frequently used panel) - panel_list.set_selection(config::system.invoke_crash_handler == true ? 0 : 3); - panel_list.enable(config::system.invoke_crash_handler == false); + panel_list.set_selection(config.system.invoke_crash_handler == true ? 0 : 3); + panel_list.enable(config.system.invoke_crash_handler == false); list_change(event_t(event_t::Change)); } diff --git a/src/ui/settings/videosettings.cpp b/src/ui/settings/videosettings.cpp index 633bf798..8bf5c69d 100644 --- a/src/ui/settings/videosettings.cpp +++ b/src/ui/settings/videosettings.cpp @@ -1,123 +1,102 @@ void VideoSettingsWindow::setup() { create(0, 451, 370); - lcontrast.create (0, 451, 18); - contrast.create (0, 451, 30, 191); - lbrightness.create(0, 451, 18); - brightness.create (0, 451, 30, 191); - lgamma.create (0, 451, 18); - gamma.create (0, 451, 30, 191); - gamma_ramp.create (0, 223, 18, translate["Gamma ramp"]); - sepia.create (0, 223, 18, translate["Sepia"]); - grayscale.create (0, 223, 18, translate["Grayscale"]); - invert.create (0, 223, 18, translate["Invert colors"]); - sync_ui(); + lcontrast.create (0, 451, 18); + contrast.create (0, 451, 30, 191); + lbrightness.create (0, 451, 18); + brightness.create (0, 451, 30, 191); + lgamma.create (0, 451, 18); + gamma.create (0, 451, 30, 191); + gamma_ramp.create (0, 223, 18, translate["Simulate TV gamma ramp"]); + merge_fields.create(0, 223, 18, translate["Merge fields for NTSC filter"]); unsigned y = 0; - attach(lcontrast, 0, y); y += 18; - attach(contrast, 0, y); y += 30; - attach(lbrightness, 0, y); y += 18; - attach(brightness, 0, y); y += 30; - attach(lgamma, 0, y); y += 18; - attach(gamma, 0, y); y += 30; + attach(lcontrast, 0, y); y += 18; + attach(contrast, 0, y); y += 30; + attach(lbrightness, 0, y); y += 18; + attach(brightness, 0, y); y += 30; + attach(lgamma, 0, y); y += 18; + attach(gamma, 0, y); y += 30; - attach(gamma_ramp, 0, y); - attach(sepia, 228, y); y += 18; - attach(grayscale, 0, y); - attach(invert, 228, y); y += 18 + 5; + attach(gamma_ramp, 0, y); + attach(merge_fields, 228, y); y += 18; contrast.on_change = bind(&VideoSettingsWindow::contrast_change, this); brightness.on_change = bind(&VideoSettingsWindow::brightness_change, this); gamma.on_change = bind(&VideoSettingsWindow::gamma_change, this); gamma_ramp.on_tick = bind(&VideoSettingsWindow::gammaramp_tick, this); - sepia.on_tick = bind(&VideoSettingsWindow::sepia_tick, this); - grayscale.on_tick = bind(&VideoSettingsWindow::grayscale_tick, this); - invert.on_tick = bind(&VideoSettingsWindow::invert_tick, this); + merge_fields.on_tick = bind(&VideoSettingsWindow::merge_fields_tick, this); + + sync_ui(); } //update all UI controls to match config file values ... void VideoSettingsWindow::sync_ui() { - contrast.set_position(config::system.contrast + 95); + contrast.set_position(config.video.contrast + 95); lcontrast.set_text(string() << translate["Contrast adjust"] << ": " - << ((int)config::system.contrast > 0 ? "+" : "") - << (int)config::system.contrast << "%"); - brightness.set_position(config::system.brightness + 95); + << ((int)config.video.contrast > 0 ? "+" : "") + << (int)config.video.contrast << "%"); + brightness.set_position(config.video.brightness + 95); lbrightness.set_text(string() << translate["Brightness adjust"] << ": " - << ((int)config::system.brightness > 0 ? "+" : "") - << (int)config::system.brightness << "%"); - gamma.set_position(config::system.gamma - 5); + << ((int)config.video.brightness > 0 ? "+" : "") + << (int)config.video.brightness << "%"); + gamma.set_position(config.video.gamma - 5); lgamma.set_text(string() << translate["Gamma adjust"] << ": " - << ((int)config::system.gamma > 100 ? "+" : "") - << (int)(config::system.gamma - 100) << "%"); - gamma_ramp.check(config::system.gamma_ramp); - sepia.check(config::system.sepia); - grayscale.check(config::system.grayscale); - invert.check(config::system.invert); + << ((int)config.video.gamma > 100 ? "+" : "") + << (int)(config.video.gamma - 100) << "%"); - libfilter::colortable.set_contrast(config::system.contrast); - libfilter::colortable.set_brightness(config::system.brightness); - libfilter::colortable.set_gamma(config::system.gamma); - libfilter::colortable.enable_gamma_ramp(config::system.gamma_ramp); - libfilter::colortable.enable_sepia(config::system.sepia); - libfilter::colortable.enable_grayscale(config::system.grayscale); - libfilter::colortable.enable_invert(config::system.invert); + gamma_ramp.check(config.video.gamma_ramp); + merge_fields.check(config.video.ntsc_filter_merge_fields); + + libfilter::colortable.set_contrast(config.video.contrast); + libfilter::colortable.set_brightness(config.video.brightness); + libfilter::colortable.set_gamma(config.video.gamma); + libfilter::colortable.enable_gamma_ramp(config.video.gamma_ramp); + libfilter::colortable.enable_sepia(config.video.sepia); + libfilter::colortable.enable_grayscale(config.video.grayscale); + libfilter::colortable.enable_invert(config.video.invert); libfilter::colortable.update(); } uintptr_t VideoSettingsWindow::contrast_change(event_t) { - if(config::system.contrast != contrast.get_position() - 95) { - config::system.contrast = contrast.get_position() - 95; + if(config.video.contrast != contrast.get_position() - 95) { + config.video.contrast = contrast.get_position() - 95; sync_ui(); } return true; } uintptr_t VideoSettingsWindow::brightness_change(event_t) { - if(config::system.brightness != brightness.get_position() - 95) { - config::system.brightness = brightness.get_position() - 95; + if(config.video.brightness != brightness.get_position() - 95) { + config.video.brightness = brightness.get_position() - 95; sync_ui(); } return true; } uintptr_t VideoSettingsWindow::gamma_change(event_t) { - if(config::system.gamma != gamma.get_position() + 5) { - config::system.gamma = gamma.get_position() + 5; + if(config.video.gamma != gamma.get_position() + 5) { + config.video.gamma = gamma.get_position() + 5; sync_ui(); } return true; } uintptr_t VideoSettingsWindow::gammaramp_tick(event_t) { - if(config::system.gamma_ramp != gamma_ramp.checked()) { - config::system.gamma_ramp = gamma_ramp.checked(); + if(config.video.gamma_ramp != gamma_ramp.checked()) { + config.video.gamma_ramp = gamma_ramp.checked(); sync_ui(); } return true; } -uintptr_t VideoSettingsWindow::sepia_tick(event_t) { - if(config::system.sepia != sepia.checked()) { - config::system.sepia = sepia.checked(); - sync_ui(); - } - return true; -} - -uintptr_t VideoSettingsWindow::grayscale_tick(event_t) { - if(config::system.grayscale != grayscale.checked()) { - config::system.grayscale = grayscale.checked(); - sync_ui(); - } - return true; -} - -uintptr_t VideoSettingsWindow::invert_tick(event_t) { - if(config::system.invert != invert.checked()) { - config::system.invert = invert.checked(); +uintptr_t VideoSettingsWindow::merge_fields_tick(event_t) { + if(config.video.ntsc_filter_merge_fields != merge_fields.checked()) { + config.video.ntsc_filter_merge_fields = merge_fields.checked(); + libfilter::filter_ntsc.adjust(0, 0, 0, 0, 0, config.video.ntsc_filter_merge_fields); sync_ui(); } return true; diff --git a/src/ui/settings/videosettings.hpp b/src/ui/settings/videosettings.hpp index b27881f0..09be3112 100644 --- a/src/ui/settings/videosettings.hpp +++ b/src/ui/settings/videosettings.hpp @@ -8,9 +8,7 @@ public: Slider gamma; Checkbox gamma_ramp; - Checkbox sepia; - Checkbox grayscale; - Checkbox invert; + Checkbox merge_fields; void setup(); void sync_ui(); @@ -18,8 +16,7 @@ public: uintptr_t contrast_change(event_t); uintptr_t brightness_change(event_t); uintptr_t gamma_change(event_t); + uintptr_t gammaramp_tick(event_t); - uintptr_t sepia_tick(event_t); - uintptr_t grayscale_tick(event_t); - uintptr_t invert_tick(event_t); + uintptr_t merge_fields_tick(event_t); } window_video_settings; diff --git a/src/ui/status.cpp b/src/ui/status.cpp index c46c66b1..599ad43f 100644 --- a/src/ui/status.cpp +++ b/src/ui/status.cpp @@ -25,7 +25,7 @@ void Status::update() { ppu.status.frames_updated = false; unsigned max_framerate = snes.region() == SNES::NTSC ? 60 : 50; - switch(config::system.emulation_speed) { + switch(config.system.emulation_speed) { case 0: max_framerate = unsigned(0.50 * max_framerate); break; case 1: max_framerate = unsigned(0.75 * max_framerate); break; case 2: max_framerate = unsigned(1.00 * max_framerate); break; diff --git a/src/ui/ui.cpp b/src/ui/ui.cpp index de0f6a3e..100e89af 100644 --- a/src/ui/ui.cpp +++ b/src/ui/ui.cpp @@ -21,14 +21,14 @@ void ui_init() { resource::init(); //ruby can initialize with "", but driver selection window needs active driver name - if(config::system.video == "") config::system.video = video.default_driver(); - if(config::system.audio == "") config::system.audio = audio.default_driver(); - if(config::system.input == "") config::system.input = input.default_driver(); + if(config.system.video == "") config.system.video = video.default_driver(); + if(config.system.audio == "") config.system.audio = audio.default_driver(); + if(config.system.input == "") config.system.input = input.default_driver(); - if(config::system.invoke_crash_handler == false) { - video.driver(config::system.video); - audio.driver(config::system.audio); - input.driver(config::system.input); + if(config.system.invoke_crash_handler == false) { + video.driver(config.system.video); + audio.driver(config.system.audio); + input.driver(config.system.input); } window_main.setup(); @@ -47,11 +47,11 @@ void ui_init() { window_advanced.setup(); window_settings.setup(); - config::video.mode = (config::video.start_in_fullscreen_mode == false) ? 0 : 1; + config.video.mode = (config.misc.start_in_fullscreen_mode == false ? 0 : 1); event::update_opacity(); - event::update_video_settings(); //call first time to resize main window and update menubar + event::update_video_settings(); //call first time to resize main window and update menubar - if(config::system.invoke_crash_handler == true) { + if(config.system.invoke_crash_handler == true) { //application crashed during driver setup on last run ... //allow selection of new drivers, and then exit emulator. window_settings.show(); @@ -59,7 +59,7 @@ void ui_init() { while(hiro().pending()) hiro().run(); usleep(20 * 1000); } - config::system.invoke_crash_handler = false; + config.system.invoke_crash_handler = false; event::quit(); return; } @@ -68,21 +68,21 @@ void ui_init() { while(hiro().pending()) hiro().run(); //detect crashes during driver initialization - config::system.invoke_crash_handler = true; - config::config().save(config::bsnes_cfg); + config.system.invoke_crash_handler = true; + config.save(config.bsnes_cfg); video.set(Video::Handle, window_main.view.handle()); - video.set(Video::Synchronize, config::video.synchronize); + video.set(Video::Synchronize, config.video.synchronize); audio.set(Audio::Handle, window_main.handle()); - audio.set(Audio::Synchronize, config::audio.synchronize); - audio.set(Audio::Volume, config::audio.volume); - audio.set(Audio::Frequency, config::audio.output_frequency); - audio.set(Audio::Latency, config::audio.latency); + audio.set(Audio::Synchronize, config.audio.synchronize); + audio.set(Audio::Volume, config.audio.volume); + audio.set(Audio::Frequency, config.audio.output_frequency); + audio.set(Audio::Latency, config.audio.latency); input.set(Input::Handle, window_main.handle()); - input.set(Input::AnalogAxisResistance, config::input.analog_axis_resistance); + input.set(Input::AnalogAxisResistance, config.input.analog_axis_resistance); //sets Audio::Resample, Audio::ResampleOutputFrequency and Audio::ResampleInputFrequency - event::update_emulation_speed(config::system.emulation_speed); + event::update_emulation_speed(config.system.emulation_speed); video.init(); audio.init(); @@ -92,10 +92,10 @@ void ui_init() { audio.clear(); //if code has reached this point, driver initialized successfully - config::system.invoke_crash_handler = false; - config::config().save(config::bsnes_cfg); + config.system.invoke_crash_handler = false; + config.save(config.bsnes_cfg); - event::update_video_settings(); //call second time to update video class settings + event::update_video_settings(); //call second time to update video class settings //UI setup complete, hook input callbacks snesinterface.input_ready = bind(&MainWindow::input_ready, &window_main); diff --git a/test_hdma.smc b/test_hdma.smc deleted file mode 100644 index f6ad7f2f..00000000 Binary files a/test_hdma.smc and /dev/null differ diff --git a/test_hdmasync.smc b/test_hdmasync.smc deleted file mode 100644 index c98bb433..00000000 Binary files a/test_hdmasync.smc and /dev/null differ diff --git a/test_hdmatiming.smc b/test_hdmatiming.smc deleted file mode 100644 index 74ef35e2..00000000 Binary files a/test_hdmatiming.smc and /dev/null differ diff --git a/test_irq.smc b/test_irq.smc deleted file mode 100644 index 40c8df20..00000000 Binary files a/test_irq.smc and /dev/null differ diff --git a/test_irq4200.smc b/test_irq4200.smc deleted file mode 100644 index 830d1234..00000000 Binary files a/test_irq4200.smc and /dev/null differ diff --git a/test_irq4209.smc b/test_irq4209.smc deleted file mode 100644 index 19201d34..00000000 Binary files a/test_irq4209.smc and /dev/null differ diff --git a/test_irqb.smc b/test_irqb.smc deleted file mode 100644 index c9de8575..00000000 Binary files a/test_irqb.smc and /dev/null differ diff --git a/test_nmi.smc b/test_nmi.smc deleted file mode 100644 index 90804d11..00000000 Binary files a/test_nmi.smc and /dev/null differ