Update to bsnes v039 release.

Changelog:
    - Recovered ~10% speed loss from last release via S-CPU IRQ timing optimizations
    - Implemented O(1) binary-heap priority queue for event scheduling
    - Fixed a bug where BS-X slotted carts were never mapping SRAM
    - Fixed a bug where invalid controller input was always being allowed
    - Fixed all compilation warnings with GCC 4.3 and Visual C++ 9.0
    - Added advanced options to control S-CPU ALU hardware delays
    - S-RTC and SPC7110 timers updated to handle time_t overflow (Y2k38) gracefully
    - Cheat codes can now have multiple codes per entry, and multiple lines per description
    - Rewrote config file parser; removed config/ class from emulator core
    - Windows: added 256x256 image to program icon set
    - Linux: fixed Xorg keysym mapping, key names should show correctly in all cases now
    - UI: updated video panel, added fullscreen-on-startup and NTSC merge fields options
    - UI: simplified audio panel
    - UI: boolean options on advanced panel can be toggled via double-click
    - Lots of code cleanup, especially for S-CPU IRQ handling and nall template library
This commit is contained in:
byuu 2009-01-18 10:21:22 +00:00
parent 1a6de37454
commit 67318297dd
189 changed files with 4541 additions and 4285 deletions

BIN
bsnes.exe

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
irq.smc

Binary file not shown.

BIN
nmi.smc

Binary file not shown.

View File

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

View File

@ -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 <nall/algorithm.hpp>
#include <nall/array.hpp>
#include <nall/bit.hpp>
#include <nall/config.hpp>
#include <nall/detect.hpp>
#include <nall/endian.hpp>
#include <nall/file.hpp>
#include <nall/function.hpp>
#include <nall/modulo.hpp>
#include <nall/moduloarray.hpp>
#include <nall/new.hpp>
#include <nall/platform.hpp>
#include <nall/sort.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
#include <nall/utility.hpp>
@ -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"

View File

@ -1,9 +1,12 @@
#include <../base.hpp>
#define CART_CPP
#include <nall/crc32.hpp>
#include <../base.hpp>
#include <../chip/chip.hpp>
#include <../reader/reader.hpp>
#define CART_CPP
#include <nall/crc32.hpp>
#include <nall/ups.hpp>
#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];
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -47,4 +47,4 @@ bool Cartridge::load_ram(const char *filename, uint8_t *&data, unsigned size, ui
return true;
}
#endif //ifdef CART_CPP
#endif

View File

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

View File

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

View File

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

View File

@ -1,13 +1,21 @@
#include <../base.hpp>
#include <nall/sort.hpp>
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;
}

View File

@ -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<unsigned> addr;
array<uint8_t> 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<cheat_t> 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;

View File

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

View File

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

View File

@ -15,7 +15,7 @@ void BSXBase::reset() {
memset(&regs, 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

View File

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

View File

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

View File

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

View File

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

View File

@ -184,4 +184,4 @@ const int16 Cx4::CosTable[512] = {
32610, 32647, 32679, 32706, 32728, 32745, 32758, 32765
};
#endif //ifdef CX4_CPP
#endif

View File

@ -243,4 +243,4 @@ uint8 bit = 0x80;
}
}
#endif //ifdef CX4_CPP
#endif

View File

@ -220,4 +220,4 @@ uint16 mask2 = 0x3f3f;
}
}
#endif //ifdef CX4_CPP
#endif

View File

@ -223,4 +223,4 @@ void Cx4::op89() {
str(1, 0xffffff);
}
#endif //ifdef CX4_CPP
#endif

View File

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

View File

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

View File

@ -1622,4 +1622,4 @@ const int16 Dsp1::SinTable[256] = {
//////////////////////////////////////////////////////////////////
#endif //ifdef DSP1_CPP
#endif

View File

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

View File

@ -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();

View File

@ -174,4 +174,4 @@ uint8 pixelarray[512];
}
}
#endif //ifdef DSP2_CPP
#endif

View File

@ -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();

View File

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

View File

@ -1143,4 +1143,4 @@ void InitDSP3()
DSP3_Reset();
}
#endif //ifdef DSP3_CPP
#endif

View File

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

View File

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

View File

@ -2147,4 +2147,4 @@ void DSP4GetByte()
}
}
#endif //ifdef DSP4_CPP
#endif

View File

@ -1,4 +1,6 @@
#include <../base.hpp>
#include <../cart/cart.hpp>
#include "obc1.hpp"
void OBC1::init() {}
void OBC1::enable() {}

View File

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

View File

@ -448,4 +448,4 @@ SDD1emu::SDD1emu() :
///////////////////////////////////////////////////////////
#endif //ifdef SDD1_CPP
#endif

View File

@ -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<time_t>::max() - rtc_time + current_time + 1); //compensate for overflow
if(diff > std::numeric_limits<time_t>::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);

View File

@ -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();

View File

@ -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<time_t>::max() - rtc_time + current_time + 1); //compensate for overflow
if(diff > std::numeric_limits<time_t>::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) {

View File

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

View File

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

View File

@ -258,4 +258,4 @@ int16 x1, y1;
writew(0x0012, y1);
}
#endif //ifdef ST010_CPP
#endif

View File

@ -1 +1 @@
@make platform=win compiler=mingw32-gcc clean
@mingw32-make platform=win compiler=mingw32-gcc clean

View File

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

View File

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

View File

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

View File

@ -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();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
/*****

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -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();

View File

@ -1,8 +1,8 @@
#include <../base.hpp>
#include <../base.hpp>
#define SCPU_CPP
#include "deltaqueue.cpp"
deltaqueue delta;
#include <nall/priorityqueue.hpp>
priority_queue<unsigned> 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();

View File

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

View File

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

View File

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

View File

@ -25,4 +25,4 @@ void sCPU::run_auto_joypad_poll() {
status.joy4h = joy4 >> 8;
}
#endif //ifdef SCPU_CPP
#endif

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

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

View File

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

View File

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

View File

@ -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();
};

View File

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

View File

@ -13,12 +13,14 @@
#define NOMINMAX
#define _NO_OLDNAMES
#define mkdir _mkdir
#define UNICODE
#include <windows.h>
#include <commctrl.h>
#include <io.h>
#include <direct.h>
#include <shlobj.h>
#undef mkdir
#include <nall/algorithm.hpp>
using nall::min;

View File

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

View File

@ -1,27 +1,23 @@
#ifndef NALL_ALGORITHM_HPP
#define NALL_ALGORITHM_HPP
namespace nall {
#undef min
#undef max
template<typename T, typename U>
T min(const T& t, const U& u) {
return t < u ? t : u;
namespace nall {
template<typename T, typename U> T min(const T& t, const U& u) {
return t < u ? t : u;
}
template<typename T, typename U> 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<typename T, typename U>
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

View File

@ -6,71 +6,69 @@
#include <nall/traits.hpp>
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<typename T> any& operator=(const T& value_) {
typedef typename static_if<
is_array<T>::value,
typename remove_extent<typename add_const<T>::type>::type*,
T
>::type auto_t;
template<typename T> any& operator=(const T& value_) {
typedef typename static_if<
is_array<T>::value,
typename remove_extent<typename add_const<T>::type>::type*,
T
>::type auto_t;
if(type() == typeid(auto_t)) {
static_cast<holder<auto_t>*>(container)->value = (auto_t)value_;
} else {
if(container) delete container;
container = new holder<auto_t>((auto_t)value_);
}
if(type() == typeid(auto_t)) {
static_cast<holder<auto_t>*>(container)->value = (auto_t)value_;
} else {
if(container) delete container;
container = new holder<auto_t>((auto_t)value_);
return *this;
}
return *this;
}
any() : container(0) {}
template<typename T> any(const T& value_) : container(0) { operator=(value_); }
any() : container(0) {}
template<typename T> 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<typename T> struct holder : placeholder {
T value;
const std::type_info& type() const { return typeid(T); }
holder(const T& value_) : value(value_) {}
};
template<typename T> struct holder : placeholder {
T value;
const std::type_info& type() const { return typeid(T); }
holder(const T& value_) : value(value_) {}
template<typename T> friend T any_cast(any&);
template<typename T> friend T any_cast(const any&);
template<typename T> friend T* any_cast(any*);
template<typename T> friend const T* any_cast(const any*);
};
template<typename T> friend T any_cast(any&);
template<typename T> friend T any_cast(const any&);
template<typename T> friend T* any_cast(any*);
template<typename T> friend const T* any_cast(const any*);
};
template<typename T> T any_cast(any &value) {
typedef typename remove_reference<T>::type nonref;
if(value.type() != typeid(nonref)) throw;
return static_cast<any::holder<nonref>*>(value.container)->value;
}
template<typename T> T any_cast(any &value) {
typedef typename remove_reference<T>::type nonref;
if(value.type() != typeid(nonref)) throw;
return static_cast<any::holder<nonref>*>(value.container)->value;
template<typename T> T any_cast(const any &value) {
typedef const typename remove_reference<T>::type nonref;
if(value.type() != typeid(nonref)) throw;
return static_cast<any::holder<nonref>*>(value.container)->value;
}
template<typename T> T* any_cast(any *value) {
if(!value || value->type() != typeid(T)) return 0;
return &static_cast<any::holder<T>*>(value->container)->value;
}
template<typename T> const T* any_cast(const any *value) {
if(!value || value->type() != typeid(T)) return 0;
return &static_cast<any::holder<T>*>(value->container)->value;
}
}
template<typename T> T any_cast(const any &value) {
typedef const typename remove_reference<T>::type nonref;
if(value.type() != typeid(nonref)) throw;
return static_cast<any::holder<nonref>*>(value.container)->value;
}
template<typename T> T* any_cast(any *value) {
if(!value || value->type() != typeid(T)) return 0;
return &static_cast<any::holder<T>*>(value->container)->value;
}
template<typename T> const T* any_cast(const any *value) {
if(!value || value->type() != typeid(T)) return 0;
return &static_cast<any::holder<T>*>(value->container)->value;
}
} //namespace nall
#endif //ifndef NALL_ANY_HPP
#endif

View File

@ -3,92 +3,87 @@
#include <stdlib.h>
#include <nall/algorithm.hpp>
#include <nall/bit.hpp>
namespace nall {
//dynamic vector array
//neither constructor nor destructor is ever invoked;
//thus, this should only be used for POD objects.
template<typename T> 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<typename T> 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

View File

@ -1,94 +1,92 @@
#ifndef NALL_BASE64_HPP
#define NALL_BASE64_HPP
#include <string.h>
#include <nall/new.hpp>
#include <nall/stdint.hpp>
#include <stdio.h>
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

View File

@ -2,27 +2,50 @@
#define NALL_BIT_HPP
namespace nall {
template<int bits> inline unsigned uclamp(const unsigned x) {
enum { y = (1U << bits) - 1 };
return y + ((x - y) & -(x < y)); //min(x, y);
}
template<int bits> inline unsigned uclamp(const unsigned x) {
enum { y = (1U << bits) - 1 };
return y + ((x - y) & -(x < y)); //min(x, y);
template<int bits> inline unsigned uclip(const unsigned x) {
enum { m = (1U << bits) - 1 };
return (x & m);
}
template<int bits> 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<int bits> 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<typename T> inline T lowest(const T x) {
return x & -x;
}
//clear_lowest(0b1110) == 0b1100
template<typename T> inline T clear_lowest(const T x) {
return x & (x - 1);
}
//set_lowest(0b0101) == 0b0111
template<typename T> 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<int bits> inline unsigned uclip(const unsigned x) {
enum { m = (1U << bits) - 1 };
return (x & m);
}
template<int bits> 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<int bits> 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

View File

@ -1,178 +1,114 @@
#ifndef NALL_CONFIG_HPP
#define NALL_CONFIG_HPP
#include <nall/array.hpp>
#include <nall/file.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
namespace nall {
class setting;
class configuration {
public:
array<setting*> 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 <nall/file.hpp>
#include <nall/string.hpp>
#include <nall/vector.hpp>
namespace nall {
namespace configuration_traits {
template<typename T> struct is_boolean { enum { value = false }; };
template<> struct is_boolean<bool> { enum { value = true }; };
template<typename T> struct is_signed { enum { value = false }; };
template<> struct is_signed<signed> { enum { value = true }; };
template<typename T> struct is_unsigned { enum { value = false }; };
template<> struct is_unsigned<unsigned> { enum { value = true }; };
template<typename T> struct is_string { enum { value = false }; };
template<> struct is_string<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<item_t> list;
template<typename T>
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<T>::value) list[n].type = boolean_t;
else if(configuration_traits::is_signed<T>::value) list[n].type = signed_t;
else if(configuration_traits::is_unsigned<T>::value) list[n].type = unsigned_t;
else if(configuration_traits::is_string<T>::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

176
src/lib/nall/config.txt Normal file
View File

@ -0,0 +1,176 @@
#ifndef NALL_CONFIG_HPP
#define NALL_CONFIG_HPP
#include <nall/array.hpp>
#include <nall/file.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>
namespace nall {
class setting;
class configuration {
public:
array<setting*> 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

View File

@ -4,65 +4,63 @@
#include <nall/stdint.hpp>
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

View File

@ -27,4 +27,4 @@
#define ARCH_MSB
#endif
#endif //ifndef NALL_DETECT_HPP
#endif

View File

@ -6,70 +6,68 @@
#include <nall/utility.hpp>
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

View File

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

View File

@ -9,212 +9,210 @@
#include <nall/utility.hpp>
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

View File

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

View File

@ -8,7 +8,7 @@
#define TN typename
namespace nall {
template<typename T> class function;
template<typename T> class function;
}
//parameters = 0
@ -102,85 +102,83 @@ template<typename T> class function;
//function implementation template class
namespace nall {
template<TL>
class function<R (PL)> {
private:
struct base1 { virtual void func1(PL) {} };
struct base2 { virtual void func2(PL) {} };
struct derived : base1, virtual base2 {};
template<TL>
class function<R (PL)> {
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<typename C>
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<typename C>
function(R (C::*fn)(PL), C *obj) {
data.fn_call = &fn_call_member<C>;
(R (C::*&)(PL))data.fn_member = fn;
assert(sizeof data.fn_member >= sizeof fn);
data.object = obj;
}
template<typename C>
function(R (C::*fn)(PL) const, C *obj) {
data.fn_call = &fn_call_member<C>;
(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<TL>
function<R (PL)> bind(R (*fn)(PL)) {
return function<R (PL)>(fn);
}
template<typename C>
static R fn_call_member(const data_t &d cat(PL)) {
return (((C*)d.object)->*((R (C::*&)(PL))d.fn_member))(CL);
template<typename C, TL>
function<R (PL)> bind(R (C::*fn)(PL), C *obj) {
return function<R (PL)>(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<typename C>
function(R (C::*fn)(PL), C *obj) {
data.fn_call = &fn_call_member<C>;
(R (C::*&)(PL))data.fn_member = fn;
assert(sizeof data.fn_member >= sizeof fn);
data.object = obj;
}
template<typename C>
function(R (C::*fn)(PL) const, C *obj) {
data.fn_call = &fn_call_member<C>;
(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<TL>
function<R (PL)> bind(R (*fn)(PL)) {
return function<R (PL)>(fn);
template<typename C, TL>
function<R (PL)> bind(R (C::*fn)(PL) const, C *obj) {
return function<R (PL)>(fn, obj);
}
}
template<typename C, TL>
function<R (PL)> bind(R (C::*fn)(PL), C *obj) {
return function<R (PL)>(fn, obj);
}
template<typename C, TL>
function<R (PL)> bind(R (C::*fn)(PL) const, C *obj) {
return function<R (PL)>(fn, obj);
}
} //namespace nall
#undef cat
#undef TL
#undef PL
#undef CL
#endif //ifndef NALL_FUNCTION_HPP
#endif

View File

@ -8,167 +8,165 @@
#include <nall/stdint.hpp>
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<int number = -1> struct joypad {
enum { axes = 8 };
enum { buttons = 96 };
enum {
none = joypad<number - 1>::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<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<int number = -1> 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<number - 1>::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<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

View File

@ -6,78 +6,76 @@
#include <nall/stdint.hpp>
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

View File

@ -1,39 +0,0 @@
#ifndef NALL_MODULO_HPP
#define NALL_MODULO_HPP
#include <nall/new.hpp>
namespace nall {
template<typename T, int size>
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

View File

@ -0,0 +1,36 @@
#ifndef NALL_MODULO_HPP
#define NALL_MODULO_HPP
#include <nall/new.hpp>
namespace nall {
template<typename T, int size> 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

View File

@ -6,11 +6,9 @@
#include <nall/stdint.hpp>
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

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