Update to bsnes v019 release.

I´m releasing bsnes v0.019 today. This version contains Bandai Sufami Turbo support, new IRQ emulation code, and some various bugfixes.
Unfortunately, this release is not entirely cause for celebration. Due to fatal errors in Microsoft´s "enterprise class" c++ compiler package, I am no longer able to compile bsnes with profile guided optimizations. I have tested v0.018 with and without these optimizations, and the difference is a 40% speedup when PGO is used, even more significant than I had previously believed. However, bsnes has now become too complex for Visual C++ to handle. Unfortunately, there is nothing I can do about this, except wait for Microsoft to fix their compiler.
(Warning: this paragraph contains personal opinions, skip it if you can´t handle that) As if this wasn´t enough, I´m now doing my best to wean my dependence from Microsoft´s line of operating systems, as I´m particularly concerned about the black box nature of Vista and its´ DRM control mechanisms. This isn´t a road I wish to begin traveling down, and thusly have no interest in upgrading to future versions of Windows. Therefore, as of late, I´ve been writing a UI wrapper that will allow me to code applications that are truly platform independent. The biggest goal for this library is to design a GUI for bsnes that runs virtually identically on both Windows and Linux/BSD. This is mostly complete, however there were many tricks I used in bsnes using the win32 API that I simply cannot do with GTK+ on Linux/BSD, such as the memory editor window subclassing. I will be porting bsnes to use this new UI wrapper, and in turn this will lessen the attractiveness / functionality of the bsnes UI to a certain degree.
Perhaps the most devastating news is that I am still contemplating the idea of designing a dot-based PPU renderer for bsnes. As if the loss of PGO wasn´t bad enough, this will likely eat away an unimaginable level of performance as well. I can only estimate the speed loss being between 100-500%. Yes, it will be that bad. And despite weeks of planning, I cannot think of a way to allow a scanline-based and dot-based renderer to coexist as selectable options, given their massive differences in implementation.
And let´s not even joke about SA-1 or SuperFX support ... those processors are each four to eight times more powerful than the SNES´ main CPU.
All of these speed losses will basically make bsnes mostly irrelevant as an alternative to ZSNES, SNES9x et al. Although I believe I really came close to a viable alternative with v0.018, I know that I cannot both create a mainstream emulator, as well as keep with my original goal to emulate the SNES as accurately as possible.
The past few months have been very tough for me; trying to decide which of the above two goals to pursue. I´ve still not absolutely made up my mind. But for now, I´ve been sitting on a mostly untouched version of bsnes for the last few months, and have decided to release it to the public, profile guided optimizations be damned.
I´m once again asking for help, if anyone can figure out why bsnes won´t compile with PGO support, please let me know. I´d very much like to get one last PGO build of bsnes released before starting on a dot-based PPU renderer. But given the usual response I get from these requests for help, I´d suggest no one getting their hopes up that bsnes will ever be as fast as it once was again.
The new version can be downloaded at the usual place. I´m leaving v0.018 up, as it may very well be the last stable, fast version of bsnes ever released.
This commit is contained in:
byuu 2007-01-01 21:04:34 +00:00
parent add0f74387
commit 1ebdb69516
130 changed files with 2281 additions and 1758 deletions

Binary file not shown.

Binary file not shown.

BIN
cart.db

Binary file not shown.

View File

@ -1,5 +1,5 @@
bsnes
Version 0.018
Version 0.019
Author: byuu
@ -14,29 +14,6 @@ http://byuu.org/
Please see license.txt for important licensing information.
Known Bugs
----------
Koushien 2 (J):
- Severity: critical
- Issue: game periodically crashes
- Cause: unknown, possibly S-SMP related
Mega lo Mania (J):
- Severity: minor
- Issue: horizontal line flickering during intro
- Cause: caching of OAM occurs too early. Not fixable without dot-based PPU core
Street Racer (J):
- Severity: minor
- Issue: track sometimes flickers every several frames
- Cause: unknown, possibly timing related
Unirally (J), Uniracers (U, E):
- Severity: critical
- Issue: 2-player mode sprites do not display at the correct positions
- Cause: mid-frame OAM writes. Not fixable without dot-based PPU core
Known Limitations
-----------------
S-CPU
@ -108,9 +85,6 @@ BS-X Flashcart
Flash cartridge used by BS-X, as well as some standalone games by
Asciisoft
Bandai Sufami Turbo
Special cartloader to play some Bandai games
Super Gameboy
Cartridge passthrough used for playing Gameboy games

View File

@ -1,4 +1,4 @@
#define BSNES_VERSION "0.018.04"
#define BSNES_VERSION "0.019"
#define BSNES_TITLE "bsnes v" BSNES_VERSION
#define MEMCORE bMemBus
@ -34,6 +34,7 @@
#endif
#include "lib/libbase.h"
#include "lib/libsort.h"
#include "lib/libco_x86.h"
#include "lib/libarray.h"
#include "lib/libvector.h"

View File

@ -1,9 +1,20 @@
#include "../base.h"
#include "database.cpp"
#include "cart_file.cpp"
#include "cart_header.cpp"
Cartridge cartridge;
void Cartridge::read_dbi() {
#include "cart_normal.cpp"
#include "cart_st.cpp"
#include "cart_stdual.cpp"
void Cartridge::load_begin(uint cart_type) {
if(loaded() == true)return;
info.type = cart_type;
info.srtc = false;
info.sdd1 = false;
info.c4 = false;
@ -13,372 +24,89 @@ void Cartridge::read_dbi() {
info.dsp1_mapper = 0;
info.header_index = 0x7fc0;
info.header_index = 0xffc0;
info.mapper = PCB;
strcpy(info.name, dbi.name);
strcpy(info.pcb, dbi.pcb);
strcpy(info.name, "");
strcpy(info.pcb, "");
info.region = NTSC;
info.cart_mmio = false;
info.rom_size = dbi.rom;
info.ram_size = dbi.ram;
}
info.rom_size = 0;
info.ram_size = 0;
void Cartridge::read_header() {
info.srtc = false;
info.sdd1 = false;
info.c4 = false;
info.dsp1 = false;
info.dsp2 = false;
info.obc1 = false;
info.dsp1_mapper = 0;
if(info.header_index == 0x7fc0 && info.rom_size >= 0x401000) {
info.mapper = EXLOROM;
strcpy(info.pcb, "UNL-EXLOROM");
} else if(info.header_index == 0x7fc0 && rom[info.header_index + MAPPER] == 0x32) {
info.mapper = EXLOROM;
strcpy(info.pcb, "UNL-EXLOROM");
} else if(info.header_index == 0x7fc0) {
info.mapper = LOROM;
strcpy(info.pcb, "UNL-LOROM");
} else if(info.header_index == 0xffc0) {
info.mapper = HIROM;
strcpy(info.pcb, "UNL-HIROM");
} else { //info.header_index == 0x40ffc0
info.mapper = EXHIROM;
strcpy(info.pcb, "UNL-EXHIROM");
}
uint8 mapper = rom[info.header_index + MAPPER];
uint8 rom_type = rom[info.header_index + ROM_TYPE];
if(mapper == 0x35 && rom_type == 0x55) {
info.srtc = true;
}
if(mapper == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
info.sdd1 = true;
}
if(mapper == 0x20 && rom_type == 0xf3) {
info.c4 = true;
}
if((mapper == 0x20 || mapper == 0x21) && rom_type == 0x03) {
info.dsp1 = true;
}
if(mapper == 0x30 && rom_type == 0x05) {
info.dsp1 = true;
}
if(mapper == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
info.dsp1 = true;
}
if(info.dsp1 == true) {
if((mapper & 0x2f) == 0x20 && info.rom_size <= 0x100000) {
info.dsp1_mapper = DSP1_LOROM_1MB;
} else if((mapper & 0x2f) == 0x20) {
info.dsp1_mapper = DSP1_LOROM_2MB;
} else if((mapper & 0x2f) == 0x21) {
info.dsp1_mapper = DSP1_HIROM;
}
}
if(mapper == 0x20 && rom_type == 0x05) {
info.dsp2 = true;
}
if(mapper == 0x30 && rom_type == 0x25) {
info.obc1 = true;
}
info.cart_mmio = info.c4 | info.dsp1 | info.dsp2 | info.obc1;
if(rom[info.header_index + SRAM_SIZE] & 7) {
info.ram_size = 1024 << (rom[info.header_index + SRAM_SIZE] & 7);
} else {
info.ram_size = 0;
}
memcpy(&info.name, &rom[info.header_index + CART_NAME], 21);
info.name[21] = 0;
for(int i = 0; i < 22; i++) {
if(info.name[i] & 0x80) {
info.name[i] = '?';
}
file.count = 0;
for(int i = 0; i < 8; i++) {
strcpy(file.rom_name[i], "");
strcpy(file.ram_name[i], "");
file.rom_size[i] = 0;
file.ram_size[i] = 0;
file.rom_data[i] = 0;
file.ram_data[i] = 0;
}
}
void Cartridge::find_header() {
int32 score_lo = 0,
score_hi = 0,
score_ex = 0;
void Cartridge::load(const char *rom_fn) {
if(!rom_fn || !*rom_fn)return;
if(info.rom_size < 0x010000) {
//cart too small to be anything but lorom
info.header_index = 0x007fc0;
return;
}
if((rom[0x7fc0 + MAPPER] & ~0x10) == 0x20)score_lo++;
if((rom[0xffc0 + MAPPER] & ~0x10) == 0x21)score_hi++;
if(rom[0x7fc0 + ROM_TYPE] < 0x08)score_lo++;
if(rom[0xffc0 + ROM_TYPE] < 0x08)score_hi++;
if(rom[0x7fc0 + ROM_SIZE] < 0x10)score_lo++;
if(rom[0xffc0 + ROM_SIZE] < 0x10)score_hi++;
if(rom[0x7fc0 + SRAM_SIZE] < 0x08)score_lo++;
if(rom[0xffc0 + SRAM_SIZE] < 0x08)score_hi++;
if(rom[0x7fc0 + REGION] < 14)score_lo++;
if(rom[0xffc0 + REGION] < 14)score_hi++;
if(rom[0x7fc0 + LICENSE] < 3)score_lo++;
if(rom[0xffc0 + LICENSE] < 3)score_hi++;
if(rom[0x7fc0 + RESH] & 0x80)score_lo += 2;
if(rom[0xffc0 + RESH] & 0x80)score_hi += 2;
uint16 cksum, icksum;
cksum = rom[0x7fc0 + CKSUM] | (rom[0x7fc0 + CKSUM + 1] << 8);
icksum = rom[0x7fc0 + ICKSUM] | (rom[0x7fc0 + ICKSUM + 1] << 8);
if((cksum + icksum) == 0xffff && (cksum != 0) && (icksum != 0)) {
score_lo += 8;
}
cksum = rom[0xffc0 + CKSUM] | (rom[0xffc0 + CKSUM + 1] << 8);
icksum = rom[0xffc0 + ICKSUM] | (rom[0xffc0 + ICKSUM + 1] << 8);
if((cksum + icksum) == 0xffff && (cksum != 0) && (icksum != 0)) {
score_hi += 8;
}
if(info.rom_size < 0x401000) {
score_ex = 0;
} else {
if(rom[0x7fc0 + MAPPER] == 0x32)score_lo++;
else score_ex += 16;
}
if(score_lo >= score_hi && score_lo >= score_ex) {
info.header_index = 0x007fc0;
} else if(score_hi >= score_ex) {
info.header_index = 0x00ffc0;
} else {
info.header_index = 0x40ffc0;
}
}
void Cartridge::load_sram() {
if(info.ram_size == 0) {
sram = 0;
return;
}
FileReader ff(sram_fn);
if(!ff.ready()) {
sram = (uint8*)malloc(info.ram_size);
memset(sram, 0xff, info.ram_size);
return;
}
sram = ff.read(info.ram_size);
}
void Cartridge::save_sram() {
if(info.ram_size == 0)return;
FileWriter ff(sram_fn);
if(!ff.ready())return;
ff.write(sram, info.ram_size);
}
void Cartridge::load_rom(Reader &rf) {
uint size = rf.size();
bool header = ((size & 0x7fff) == 512);
info.rom_size = size - (header ? 512 : 0);
if(info.rom_size & 0x7fff) {
info.rom_size += 0x8000 - (info.rom_size & 0x7fff);
}
uint8 *base_rom = rf.read(info.rom_size + (header ? 512 : 0));
if(header) {
memcpy(rom_header, base_rom, 512);
} else {
memset(rom_header, 0x00, 512);
}
rom = (uint8*)malloc(info.rom_size);
memcpy(rom, base_rom + (header ? 512 : 0), info.rom_size);
SafeFree(base_rom);
info.crc32 = 0xffffffff;
for(int32 i = 0; i < info.rom_size; i++) {
info.crc32 = crc32_adjust(info.crc32, rom[i]);
}
info.crc32 = ~info.crc32;
}
void Cartridge::patch_rom(Reader &rf) {
UPS<ramfile, ramfile, ramfile> ups;
uint patchsize = rf.size();
uint8 *patchdata = rf.read();
fopen(ups.original, 0, file::mode_writeread);
fopen(ups.modified, 0, file::mode_writeread);
fopen(ups.patch.fp, 0, file::mode_writeread);
fwrite(ups.original, rom, info.rom_size);
fwrite(ups.patch.fp, patchdata, patchsize);
if(ups.apply() == true) {
info.crc32 = ups.modified_crc32;
info.rom_size = ups.modified_filesize;
rom = (uint8*)realloc(rom, info.rom_size);
fseek(ups.modified, 0, file::seek_start);
fread(ups.modified, rom, info.rom_size);
}
}
bool Cartridge::load(const char *fn) {
if(cart_loaded == true)return false;
if(strlen(fn) < 3)return false;
dprintf("* Loading \"%s\"...", fn);
strcpy(rom_fn, fn);
switch(Reader::detect(rom_fn)) {
case Reader::RF_NORMAL: {
FileReader ff(rom_fn);
if(!ff.ready()) {
alert("Error loading image file (%s)!", rom_fn);
return false;
}
load_rom(ff);
} break;
#ifdef GZIP_SUPPORT
case Reader::RF_GZ: {
GZReader gf(rom_fn);
if(!gf.ready()) {
alert("Error loading image file (%s)!", rom_fn);
return false;
}
load_rom(gf);
} break;
case Reader::RF_ZIP: {
ZipReader zf(rom_fn);
load_rom(zf);
} break;
#endif
#ifdef JMA_SUPPORT
case Reader::RF_JMA: {
try {
JMAReader jf(rom_fn);
load_rom(jf);
} catch(JMA::jma_errors jma_error) {
alert("Error loading image file (%s)!", rom_fn);
return false;
}
} break;
#endif
}
//remove ROM extension
strcpy(sram_fn, fn);
char fn[4096], ram_fn[4096];
strcpy(fn, rom_fn);
//correct folder slashes
for(int i = strlen(fn) - 1; i >= 0; i--) {
if(sram_fn[i] == '.') {
sram_fn[i] = 0;
if(fn[i] == '\\')fn[i] = '/';
}
uint i = file.count++;
strcpy(file.rom_name[i], fn);
strcpy(fn, rom_fn);
//remove ROM extension
for(int i = strlen(fn) - 1; i >= 0; i--) {
if(fn[i] == '.') {
fn[i] = 0;
break;
}
}
//add SRAM extension
strcat(sram_fn, ".");
strcat(sram_fn, config::fs.save_ext.sget());
if(i == 0) {
strcpy(file.patch_name, fn);
strcat(file.patch_name, ".ups");
}
strcpy(fn, strptr(config::file_updatepath(fn, config::path.save)));
if(i == 0) {
strcpy(file.cheat_name, fn);
strcat(file.cheat_name, ".cht");
}
strcpy(file.ram_name[i], fn);
strcat(file.ram_name[i], ".");
strcat(file.ram_name[i], config::path.save_ext);
}
stringarray save_path;
strcpy(save_path, config::fs.save_path.sget());
replace(save_path, "\\", "/");
if(strlen(save_path) && !strend(save_path, "/")) { strcat(save_path, "/"); }
if(strlen(save_path) != 0) {
//override default path (current directory)
stringarray new_fn, parts;
strcpy(new_fn, sram_fn);
replace(new_fn, "\\", "/");
split(parts, "/", new_fn);
//add new SRAM path
strcpy(new_fn, save_path);
//append fs.base_path if fs.sram_path is not fully-qualified path
if(strbegin(new_fn, "./") == true) {
strltrim(new_fn, "./");
strcpy(new_fn[1], new_fn[0]);
strcpy(new_fn[0], config::fs.base_path.sget());
strcat(new_fn[0], new_fn[1]);
}
//finally, append SRAM file name
strcat(new_fn, parts[count(parts) - 1]);
strcpy(sram_fn, strptr(new_fn));
bool Cartridge::load_end() {
for(int i = 0; i < file.count; i++) {
load_file(file.rom_name[i], file.rom_data[i], file.rom_size[i]);
}
//load cheat file if it exists
strcpy(cheat_fn, sram_fn);
strrtrim(cheat_fn, config::fs.save_ext.sget());
strrtrim(cheat_fn, ".");
strcat(cheat_fn, ".cht");
if(fexists(cheat_fn) == true) {
FileReader ff(cheat_fn);
cheat.load(ff);
if(fexists(file.cheat_name) == true) {
cheat.clear();
cheat.load(file.cheat_name);
}
//load patch file if it exists
strcpy(patch_fn, sram_fn);
strrtrim(patch_fn, config::fs.save_ext.sget());
strrtrim(patch_fn, ".");
strcat(patch_fn, ".ups");
if(fexists(patch_fn) == true) {
FileReader ff(patch_fn);
patch_rom(ff);
switch(info.type) {
case CART_NORMAL: {
load_rom_normal();
load_ram_normal();
} break;
case CART_ST: {
load_rom_st();
load_ram_st();
} break;
case CART_STDUAL: {
load_rom_stdual();
load_ram_stdual();
} break;
}
#ifdef GZIP_SUPPORT
else {
strrtrim(patch_fn, ".ups");
strcat(patch_fn, ".upz");
if(fexists(patch_fn) == true) {
ZipReader zf(patch_fn);
patch_rom(zf);
}
}
#endif
if(read_database() == true) {
read_dbi();
} else {
find_header();
read_header();
}
load_sram();
cart_loaded = true;
r_mem->load_cart();
return true;
}
@ -388,13 +116,23 @@ bool Cartridge::unload() {
r_mem->unload_cart();
if(sram) { save_sram(); }
SafeFree(rom);
SafeFree(sram);
switch(info.type) {
case CART_NORMAL: {
save_ram_normal();
} break;
case CART_ST: {
save_ram_st();
} break;
case CART_STDUAL: {
save_ram_stdual();
} break;
}
if(cheat.count() > 0 || fexists(cheat_fn)) {
FileWriter ff(cheat_fn);
cheat.save(ff);
SafeFree(rom);
SafeFree(ram);
if(cheat.count() > 0 || fexists(file.cheat_name) == true) {
cheat.save(file.cheat_name);
cheat.clear();
}
@ -407,8 +145,8 @@ Cartridge::Cartridge() {
cart_loaded = false;
rom = 0;
sram = 0;
rom = 0;
ram = 0;
}
Cartridge::~Cartridge() {

View File

@ -15,10 +15,15 @@ db_item dbi;
//
bool cart_loaded;
char rom_fn[4096], sram_fn[4096], cheat_fn[4096], patch_fn[4096];
enum {
CART_NORMAL,
CART_ST,
CART_STDUAL,
};
uint8 rom_header[512], *rom, *sram;
bool cart_loaded;
uint8 rom_header[512], *rom, *ram;
enum {
//header fields
@ -26,7 +31,7 @@ enum {
MAPPER = 0x15,
ROM_TYPE = 0x16,
ROM_SIZE = 0x17,
SRAM_SIZE = 0x18,
RAM_SIZE = 0x18,
REGION = 0x19,
LICENSE = 0x1a,
VERSION = 0x1b,
@ -53,6 +58,17 @@ enum {
};
struct {
uint count;
char cheat_name[4096], patch_name[4096];
char rom_name[8][4096], ram_name[8][4096];
uint rom_size[8], ram_size[8];
uint8 *rom_data[8], *ram_data[8];
} file;
struct {
uint type;
//cart information
uint32 crc32;
char name[128];
char pcb[32];
@ -78,15 +94,28 @@ struct {
uint header_index;
} info;
void load_rom(Reader &rf);
void patch_rom(Reader &rf);
void load_sram();
void save_sram();
void read_dbi();
bool load_file(const char *fn, uint8 *&data, uint &size);
bool save_file(const char *fn, uint8 *data, uint size);
void load_rom_normal();
void load_ram_normal();
void save_ram_normal();
void load_rom_st();
void load_ram_st();
void save_ram_st();
void load_rom_stdual();
void load_ram_stdual();
void save_ram_stdual();
void find_header();
void read_header();
bool loaded() { return cart_loaded; }
bool load(const char *fn);
void load_begin(uint cart_type);
void load(const char *rom_fn);
bool load_end();
bool unload();
Cartridge();

61
src/cart/cart_file.cpp Normal file
View File

@ -0,0 +1,61 @@
bool Cartridge::load_file(const char *fn, uint8 *&data, uint &size) {
dprintf("* Loading \"%s\"...", fn);
if(fexists(fn) == false) {
return false;
}
switch(Reader::detect(fn)) {
case Reader::RF_NORMAL: {
FileReader ff(fn);
if(!ff.ready()) {
alert("Error loading image file (%s)!", fn);
return false;
}
size = ff.size();
data = ff.read();
} break;
#ifdef GZIP_SUPPORT
case Reader::RF_GZ: {
GZReader gf(fn);
if(!gf.ready()) {
alert("Error loading image file (%s)!", fn);
return false;
}
size = gf.size();
data = gf.read();
} break;
case Reader::RF_ZIP: {
ZipReader zf(fn);
size = zf.size();
data = zf.read();
} break;
#endif
#ifdef JMA_SUPPORT
case Reader::RF_JMA: {
try {
JMAReader jf(fn);
size = jf.size();
data = jf.read();
} catch(JMA::jma_errors jma_error) {
alert("Error loading image file (%s)!", fn);
return false;
}
} break;
#endif
}
return true;
}
bool Cartridge::save_file(const char *fn, uint8 *data, uint size) {
FileWriter ff(fn);
if(!ff.ready())return false;
ff.write(data, size);
return true;
}

149
src/cart/cart_header.cpp Normal file
View File

@ -0,0 +1,149 @@
void Cartridge::read_header() {
info.srtc = false;
info.sdd1 = false;
info.c4 = false;
info.dsp1 = false;
info.dsp2 = false;
info.obc1 = false;
info.dsp1_mapper = 0;
if(info.header_index == 0x7fc0 && info.rom_size >= 0x401000) {
info.mapper = EXLOROM;
strcpy(info.pcb, "UNL-EXLOROM");
} else if(info.header_index == 0x7fc0 && rom[info.header_index + MAPPER] == 0x32) {
info.mapper = EXLOROM;
strcpy(info.pcb, "UNL-EXLOROM");
} else if(info.header_index == 0x7fc0) {
info.mapper = LOROM;
strcpy(info.pcb, "UNL-LOROM");
} else if(info.header_index == 0xffc0) {
info.mapper = HIROM;
strcpy(info.pcb, "UNL-HIROM");
} else { //info.header_index == 0x40ffc0
info.mapper = EXHIROM;
strcpy(info.pcb, "UNL-EXHIROM");
}
uint8 mapper = rom[info.header_index + MAPPER];
uint8 rom_type = rom[info.header_index + ROM_TYPE];
if(mapper == 0x35 && rom_type == 0x55) {
info.srtc = true;
}
if(mapper == 0x32 && (rom_type == 0x43 || rom_type == 0x45)) {
info.sdd1 = true;
}
if(mapper == 0x20 && rom_type == 0xf3) {
info.c4 = true;
}
if((mapper == 0x20 || mapper == 0x21) && rom_type == 0x03) {
info.dsp1 = true;
}
if(mapper == 0x30 && rom_type == 0x05) {
info.dsp1 = true;
}
if(mapper == 0x31 && (rom_type == 0x03 || rom_type == 0x05)) {
info.dsp1 = true;
}
if(info.dsp1 == true) {
if((mapper & 0x2f) == 0x20 && info.rom_size <= 0x100000) {
info.dsp1_mapper = DSP1_LOROM_1MB;
} else if((mapper & 0x2f) == 0x20) {
info.dsp1_mapper = DSP1_LOROM_2MB;
} else if((mapper & 0x2f) == 0x21) {
info.dsp1_mapper = DSP1_HIROM;
}
}
if(mapper == 0x20 && rom_type == 0x05) {
info.dsp2 = true;
}
if(mapper == 0x30 && rom_type == 0x25) {
info.obc1 = true;
}
info.cart_mmio = info.c4 | info.dsp1 | info.dsp2 | info.obc1;
if(rom[info.header_index + RAM_SIZE] & 7) {
info.ram_size = 1024 << (rom[info.header_index + RAM_SIZE] & 7);
} else {
info.ram_size = 0;
}
memcpy(&info.name, &rom[info.header_index + CART_NAME], 21);
info.name[21] = 0;
for(int i = 0; i < 22; i++) {
if(info.name[i] & 0x80) {
info.name[i] = '?';
}
}
}
void Cartridge::find_header() {
int32 score_lo = 0,
score_hi = 0,
score_ex = 0;
if(info.rom_size < 0x010000) {
//cart too small to be anything but lorom
info.header_index = 0x007fc0;
return;
}
if((rom[0x7fc0 + MAPPER] & ~0x10) == 0x20)score_lo++;
if((rom[0xffc0 + MAPPER] & ~0x10) == 0x21)score_hi++;
if(rom[0x7fc0 + ROM_TYPE] < 0x08)score_lo++;
if(rom[0xffc0 + ROM_TYPE] < 0x08)score_hi++;
if(rom[0x7fc0 + ROM_SIZE] < 0x10)score_lo++;
if(rom[0xffc0 + ROM_SIZE] < 0x10)score_hi++;
if(rom[0x7fc0 + RAM_SIZE] < 0x08)score_lo++;
if(rom[0xffc0 + RAM_SIZE] < 0x08)score_hi++;
if(rom[0x7fc0 + REGION] < 14)score_lo++;
if(rom[0xffc0 + REGION] < 14)score_hi++;
if(rom[0x7fc0 + LICENSE] < 3)score_lo++;
if(rom[0xffc0 + LICENSE] < 3)score_hi++;
if(rom[0x7fc0 + RESH] & 0x80)score_lo += 2;
if(rom[0xffc0 + RESH] & 0x80)score_hi += 2;
uint16 cksum, icksum;
cksum = rom[0x7fc0 + CKSUM] | (rom[0x7fc0 + CKSUM + 1] << 8);
icksum = rom[0x7fc0 + ICKSUM] | (rom[0x7fc0 + ICKSUM + 1] << 8);
if((cksum + icksum) == 0xffff && (cksum != 0) && (icksum != 0)) {
score_lo += 8;
}
cksum = rom[0xffc0 + CKSUM] | (rom[0xffc0 + CKSUM + 1] << 8);
icksum = rom[0xffc0 + ICKSUM] | (rom[0xffc0 + ICKSUM + 1] << 8);
if((cksum + icksum) == 0xffff && (cksum != 0) && (icksum != 0)) {
score_hi += 8;
}
if(info.rom_size < 0x401000) {
score_ex = 0;
} else {
if(rom[0x7fc0 + MAPPER] == 0x32)score_lo++;
else score_ex += 16;
}
if(score_lo >= score_hi && score_lo >= score_ex) {
info.header_index = 0x007fc0;
} else if(score_hi >= score_ex) {
info.header_index = 0x00ffc0;
} else {
info.header_index = 0x40ffc0;
}
}

66
src/cart/cart_normal.cpp Normal file
View File

@ -0,0 +1,66 @@
void Cartridge::load_rom_normal() {
uint size = 0;
for(int i = 0; i < file.count; i++) {
size += file.rom_size[i] - (((file.rom_size[i] & 0x7fff) == 512) ? 512 : 0);
}
info.rom_size = size;
rom = (uint8*)malloc(info.rom_size);
memset(rom, 0, info.rom_size);
uint offset = 0;
for(int i = 0; i < file.count; i++) {
uint8 *data = file.rom_data[i] + (((file.rom_size[i] & 0x7fff) == 512) ? 512 : 0);
uint size = file.rom_size[i] - (((file.rom_size[i] & 0x7fff) == 512) ? 512 : 0);
memcpy(rom + offset, data, size);
offset += size;
safe_free(file.rom_data[i]);
}
info.crc32 = crc32_calculate(rom, info.rom_size);
if(read_database() == true) {
info.srtc = false;
info.sdd1 = false;
info.c4 = false;
info.dsp1 = false;
info.dsp2 = false;
info.obc1 = false;
info.dsp1_mapper = 0;
info.header_index = 0xffc0;
info.mapper = PCB;
strcpy(info.name, dbi.name);
strcpy(info.pcb, dbi.pcb);
info.region = NTSC;
info.cart_mmio = false;
info.rom_size = dbi.rom;
info.ram_size = dbi.ram;
} else {
find_header();
read_header();
}
}
void Cartridge::load_ram_normal() {
if(info.ram_size == 0) {
ram = 0;
return;
}
ram = (uint8*)malloc(info.ram_size);
memset(ram, 0xff, info.ram_size);
if(load_file(file.ram_name[0], file.ram_data[0], file.ram_size[0]) == true) {
memcpy(ram, file.ram_data[0], min(info.ram_size, file.ram_size[0]));
safe_free(file.ram_data[0]);
}
}
void Cartridge::save_ram_normal() {
if(info.ram_size == 0)return;
save_file(file.ram_name[0], ram, info.ram_size);
}

45
src/cart/cart_st.cpp Normal file
View File

@ -0,0 +1,45 @@
void Cartridge::load_rom_st() {
uint8 *data;
uint size;
string bios = config::file_updatepath("stbios.bin", config::path.bios);
info.rom_size = 0x200000;
rom = (uint8*)malloc(info.rom_size);
memset(rom, 0, info.rom_size);
load_file(strptr(bios), data, size);
memcpy(rom, data, min(size, 0x040000));
safe_free(data);
memcpy(rom + 0x100000, file.rom_data[0], min(file.rom_size[0], 0x100000));
safe_free(file.rom_data[0]);
//
strcpy(info.name, "???");
strcpy(info.pcb, "STC-SOLO");
info.mapper = PCB;
info.region = NTSC;
info.rom_size = 0x200000;
info.ram_size = 0x020000;
//
info.crc32 = crc32_calculate(rom + 0x100000, file.rom_size[0]);
if(read_database() == true) {
strcpy(info.name, dbi.name);
}
}
void Cartridge::load_ram_st() {
ram = (uint8*)malloc(info.ram_size);
memset(ram, 0xff, info.ram_size);
if(load_file(file.ram_name[0], file.ram_data[0], file.ram_size[0]) == true) {
memcpy(ram, file.ram_data[0], min(file.ram_size[0], 0x020000));
safe_free(file.ram_data[0]);
}
}
void Cartridge::save_ram_st() {
save_file(file.ram_name[0], ram, 0x020000);
}

66
src/cart/cart_stdual.cpp Normal file
View File

@ -0,0 +1,66 @@
void Cartridge::load_rom_stdual() {
uint8 *data;
uint size;
string bios = config::file_updatepath("stbios.bin", config::path.bios);
info.rom_size = 0x300000;
rom = (uint8*)malloc(info.rom_size);
memset(rom, 0, info.rom_size);
load_file(strptr(bios), data, size);
memcpy(rom, data, min(size, 0x040000));
safe_free(data);
memcpy(rom + 0x100000, file.rom_data[0], min(file.rom_size[0], 0x100000));
safe_free(file.rom_data[0]);
memcpy(rom + 0x200000, file.rom_data[1], min(file.rom_size[1], 0x100000));
safe_free(file.rom_data[1]);
char name_a[4096], name_b[4096];
strcpy(name_a, "???");
strcpy(name_b, "???");
//
info.mapper = PCB;
info.region = NTSC;
info.rom_size = 0x300000;
info.ram_size = 0x040000;
//
info.crc32 = crc32_calculate(rom + 0x100000, file.rom_size[0]);
if(read_database() == true) {
strcpy(name_a, dbi.name);
}
info.crc32 = crc32_calculate(rom + 0x200000, file.rom_size[1]);
if(read_database() == true) {
strcpy(name_b, dbi.name);
}
//
info.crc32 = 0;
strcpy(info.name, name_a);
strcat(info.name, " + ");
strcat(info.name, name_b);
strcpy(info.pcb, "STC-DUAL");
}
void Cartridge::load_ram_stdual() {
ram = (uint8*)malloc(info.ram_size);
memset(ram, 0xff, info.ram_size);
if(load_file(file.ram_name[0], file.ram_data[0], file.ram_size[0]) == true) {
memcpy(ram + 0x000000, file.ram_data[0], min(file.ram_size[0], 0x020000));
safe_free(file.ram_data[0]);
}
if(load_file(file.ram_name[1], file.ram_data[1], file.ram_size[1]) == true) {
memcpy(ram + 0x020000, file.ram_data[1], min(file.ram_size[1], 0x020000));
safe_free(file.ram_data[1]);
}
}
void Cartridge::save_ram_stdual() {
save_file(file.ram_name[0], ram + 0x000000, 0x020000);
save_file(file.ram_name[1], ram + 0x020000, 0x020000);
}

Binary file not shown.

View File

@ -1,32 +1,98 @@
[0xbb5c4238]
name = "Bishoujo Senshi Sailor Moon Sailor Stars - Fuwa Fuwa Panic 2 (Japan)"
pcb = "STC-????"
rom = 8mbit
ram = 32kbit
[0x8eb753f3]
name = "Crayon Shin-chan - Nagagutsu Dobon!! (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x7aedd703]
name = "Der Langrisser (Japan) [!]"
pcb = "SHVC-1A3M-30"
rom = 16mbit
ram = 64kbit
[0x35f9eecc]
name = "Der Langrisser (Japan) (V1.1)"
pcb = "SHVC-1A3M-30" ;unverified (guess)
rom = 16mbit
ram = 64kbit
[0x19bdcb19]
name = "Derby Stallion '96 (Japan) [!]"
pcb = "BSC-1A5M-01"
rom = 24mbit
ram = 256kbit
[0x4296500d]
name = "Gegege no Kitarou - Youkai Donjara (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 16kbit
[0x14c66fca]
name = "Gekisou Sentai Car Rangers (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x32b2b3dd]
name = "Poi Poi Ninja World (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x9684526d]
name = "Romancing SaGa (Japan) (V1.1) [!]"
pcb = "SHVC-1A3B-12"
rom = 8mbit
ram = 64kbit
[0x675b6382]
name = "RPG Tsukuru 2 (Japan)"
pcb = "BSC-1A7M-01" ;unverified
rom = 16mbit
ram = 512kbit
[0xafd74dcb]
name = "SD Gundam Generation A - Ichinen Sensouki (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x48ecae44]
name = "SD Gundam Generation B - Grips Senki (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x72b4235f]
name = "SD Gundam Generation C - Axis Senki (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x792d884c]
name = "SD Gundam Generation D - Babylonia Kenkoku Senki (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0xefd3a865]
name = "SD Gundam Generation E - Zanskar Senki (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0xc5dfa8fd]
name = "SD Gundam Generation F - Colony Kakutouki (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x43ad5a45]
name = "SD Ultra Battle - Seven Densetsu (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0x04939d14]
name = "SD Ultra Battle - Ultra Densetsu (Japan)"
pcb = "STC-????"
rom = 4mbit
ram = 8kbit
[0xa5c0045e]
name = "Secret of Evermore (USA) [!]"

View File

@ -8,7 +8,7 @@
FILE *fp;
uint decode_size(substring &str) {
uint decode_size(string &str) {
//hex encoding
if(strbegin(str, "0x")) {
strltrim(str, "0x");
@ -31,8 +31,8 @@ uint decode_size(substring &str) {
return strdec(str);
}
void build_block(substring &block) {
string line, hashpart, part;
void build_block(string &block) {
stringarray line, hashpart, part;
split(line, "\n", block);
if(strbegin(line[0], "[") == false) {
@ -58,26 +58,26 @@ db_item dbi;
strset(line[i], pos, 0);
}
if(strmatch(line[i], ""))continue;
if(line[i] == "")continue;
split(part, "=", line[i]);
strunquote(part[1]);
if(strmatch(part[0], "name")) {
if(part[0] == "name") {
strncpy(dbi.name, strptr(part[1]), 128);
dbi.name[128] = 0;
}
if(strmatch(part[0], "pcb")) {
if(part[0] == "pcb") {
strncpy(dbi.pcb, strptr(part[1]), 32);
dbi.pcb[31] = 0;
}
if(strmatch(part[0], "rom")) {
if(part[0] == "rom") {
dbi.rom = decode_size(part[1]);
}
if(strmatch(part[0], "ram")) {
if(part[0] == "ram") {
dbi.ram = decode_size(part[1]);
}
}
@ -89,7 +89,7 @@ db_item dbi;
}
void build_database() {
string data, block;
stringarray data, block;
if(strfread(data, "cartdb.txt") == false)return;
fp = fopen("cart.db", "wb");

View File

@ -268,7 +268,8 @@ void Cheat::disable(uint32 n) {
* cheat file manipulation routines
*****/
bool Cheat::load(Reader &rf) {
bool Cheat::load(const char *fn) {
FileReader rf(fn);
if(!rf.ready())return false;
uint8 *raw_data = rf.read();
@ -299,7 +300,8 @@ stringarray data, line;
return true;
}
bool Cheat::save(Writer &wf) {
bool Cheat::save(const char *fn) {
FileWriter wf(fn);
if(!wf.ready())return false;
string data;

View File

@ -38,8 +38,8 @@ public:
bool enabled(uint32 n);
void enable (uint32 n);
void disable(uint32 n);
bool load(Reader &rf);
bool save(Writer &wf);
bool load(const char *fn);
bool save(const char *fn);
void clear();
Cheat();

View File

@ -10,34 +10,34 @@ void OBC1::power() {
}
void OBC1::reset() {
memset(cartridge.sram, 0xff, 0x2000);
status.baseptr = (cartridge.sram[0x1ff5] & 1) ? 0x1800 : 0x1c00;
status.address = (cartridge.sram[0x1ff6] & 0x7f);
status.shift = (cartridge.sram[0x1ff6] & 3) << 1;
memset(cartridge.ram, 0xff, 0x2000);
status.baseptr = (cartridge.ram[0x1ff5] & 1) ? 0x1800 : 0x1c00;
status.address = (cartridge.ram[0x1ff6] & 0x7f);
status.shift = (cartridge.ram[0x1ff6] & 3) << 1;
}
uint8 OBC1::read(uint16 addr) {
addr &= 0x1fff;
if((addr & 0x1ff8) != 0x1ff0) {
return cartridge.sram[addr];
return cartridge.ram[addr];
}
switch(addr) {
case 0x1ff0:
return cartridge.sram[status.baseptr + (status.address << 2) + 0];
return cartridge.ram[status.baseptr + (status.address << 2) + 0];
case 0x1ff1:
return cartridge.sram[status.baseptr + (status.address << 2) + 1];
return cartridge.ram[status.baseptr + (status.address << 2) + 1];
case 0x1ff2:
return cartridge.sram[status.baseptr + (status.address << 2) + 2];
return cartridge.ram[status.baseptr + (status.address << 2) + 2];
case 0x1ff3:
return cartridge.sram[status.baseptr + (status.address << 2) + 3];
return cartridge.ram[status.baseptr + (status.address << 2) + 3];
case 0x1ff4:
return cartridge.sram[status.baseptr + (status.address >> 2) + 0x200];
return cartridge.ram[status.baseptr + (status.address >> 2) + 0x200];
case 0x1ff5:
case 0x1ff6:
case 0x1ff7:
return cartridge.sram[addr];
return cartridge.ram[addr];
}
//never used, blocks compiler warning
@ -48,40 +48,40 @@ void OBC1::write(uint16 addr, uint8 data) {
addr &= 0x1fff;
if((addr & 0x1ff8) != 0x1ff0) {
cartridge.sram[addr] = data;
cartridge.ram[addr] = data;
return;
}
switch(addr) {
case 0x1ff0:
cartridge.sram[status.baseptr + (status.address << 2) + 0] = data;
cartridge.ram[status.baseptr + (status.address << 2) + 0] = data;
break;
case 0x1ff1:
cartridge.sram[status.baseptr + (status.address << 2) + 1] = data;
cartridge.ram[status.baseptr + (status.address << 2) + 1] = data;
break;
case 0x1ff2:
cartridge.sram[status.baseptr + (status.address << 2) + 2] = data;
cartridge.ram[status.baseptr + (status.address << 2) + 2] = data;
break;
case 0x1ff3:
cartridge.sram[status.baseptr + (status.address << 2) + 3] = data;
cartridge.ram[status.baseptr + (status.address << 2) + 3] = data;
break;
case 0x1ff4: {
uint8 temp;
temp = cartridge.sram[status.baseptr + (status.address >> 2) + 0x200];
temp = cartridge.ram[status.baseptr + (status.address >> 2) + 0x200];
temp = (temp & ~(3 << status.shift)) | ((data & 3) << status.shift);
cartridge.sram[status.baseptr + (status.address >> 2) + 0x200] = temp;
cartridge.ram[status.baseptr + (status.address >> 2) + 0x200] = temp;
} break;
case 0x1ff5:
status.baseptr = (data & 1) ? 0x1800 : 0x1c00;
cartridge.sram[addr] = data;
cartridge.ram[addr] = data;
break;
case 0x1ff6:
status.address = (data & 0x7f);
status.shift = (data & 3) << 1;
cartridge.sram[addr] = data;
cartridge.ram[addr] = data;
break;
case 0x1ff7:
cartridge.sram[addr] = data;
cartridge.ram[addr] = data;
break;
}
}

View File

@ -2,24 +2,52 @@ Config config_file;
namespace config {
Setting FS::base_path(0, "fs.base_path",
"Directory that bsnes resides in", "");
Setting FS::rom_path(&config_file, "fs.rom_path",
"Default path to look for ROM files in (\"\" = use default directory)", "");
Setting FS::save_path(&config_file, "fs.save_path",
"Default path for all save RAM and cheat files (\"\" = use current directory)", "");
string file_updatepath(const char *req_file, const char *req_path) {
string file(req_file);
replace(file, "\\", "/");
if(!req_path || strlen(req_path) == 0) { return file; }
Setting FS::save_ext(&config_file, "fs.save_ext",
string path(req_path);
replace(path, "\\", "/");
if(!strend(path, "/")) { strcat(path, "/"); }
if(strbegin(path, "./")) {
strltrim(path, "./");
string temp;
strcpy(temp, config::path.base);
strcat(temp, path);
strcpy(path, temp);
}
stringarray part;
split(part, "/", file);
strcat(path, part[count(part) - 1]);
return path;
}
Setting Path::base(0, "fs.base_path",
"Path that bsnes resides in", "");
Setting Path::rom(&config_file, "path.rom",
"Default path to look for ROM files in (\"\" = use default directory)", "");
Setting Path::save(&config_file, "path.save",
"Default path for all save RAM and cheat files (\"\" = use current directory)", "");
Setting Path::bios(&config_file, "path.bios",
"Path where BIOS file(s) are located\n"
"Supported BIOS files:\n"
"stbios.bin - Bandai Sufami Turbo"
"", "./bios");
Setting Path::save_ext(&config_file, "path.save_ext",
"Extension to be used for all save RAM files", "srm");
Setting SNES::gamma_ramp(&config_file, "snes.colorfilter.gamma_ramp",
"Use precalculated TV-style gamma ramp", true, Setting::TRUE_FALSE);
"Use precalculated TV-style gamma ramp", true, Setting::BOOL);
Setting SNES::sepia(&config_file, "snes.colorfilter.sepia",
"Convert color to sepia tone", false, Setting::TRUE_FALSE);
"Convert color to sepia tone", false, Setting::BOOL);
Setting SNES::grayscale(&config_file, "snes.colorfilter.grayscale",
"Convert color to grayscale tone", false, Setting::TRUE_FALSE);
"Convert color to grayscale tone", false, Setting::BOOL);
Setting SNES::invert(&config_file, "snes.colorfilter.invert",
"Invert output image colors", false, Setting::TRUE_FALSE);
"Invert output image colors", false, Setting::BOOL);
Setting SNES::contrast(&config_file, "snes.colorfilter.contrast",
"Contrast", 0, Setting::DEC);
Setting SNES::brightness(&config_file, "snes.colorfilter.brightness",
@ -30,10 +58,10 @@ Setting SNES::gamma(&config_file, "snes.colorfilter.gamma",
Setting SNES::ntsc_merge_fields(&config_file, "snes.ntsc_merge_fields",
"Merge fields in NTSC video filter\n"
"Set to true if using filter at any refresh rate other than 60hz\n"
"", true, Setting::TRUE_FALSE);
"", true, Setting::BOOL);
Setting SNES::mute(&config_file, "snes.mute", "Mutes SNES audio output when enabled",
false, Setting::TRUE_FALSE);
false, Setting::BOOL);
Setting SNES::controller_port0(&config_file, "snes.controller_port_1",
"Controller attached to SNES port 1", ::SNES::DEVICEID_JOYPAD1, Setting::DEC);
@ -43,31 +71,37 @@ Setting SNES::controller_port1(&config_file, "snes.controller_port_2",
Setting CPU::ntsc_clock_rate(&config_file, "cpu.ntsc_clock_rate",
"NTSC S-CPU clock rate (in hz)", 21477272, Setting::DEC);
Setting CPU::pal_clock_rate(&config_file, "cpu.pal_clock_rate",
"PAL S-CPU clock rate (in hz)", 21241370, Setting::DEC);
"PAL S-CPU clock rate (in hz)", 21281370, Setting::DEC);
Setting CPU::hdma_enable(0, "cpu.hdma_enable",
"Enable HDMA effects", true, Setting::TRUE_FALSE);
"Enable HDMA effects", true, Setting::BOOL);
Setting SMP::ntsc_clock_rate(&config_file, "smp.ntsc_clock_rate",
"NTSC S-SMP clock rate (in hz)", 24576000, Setting::DEC);
"NTSC S-SMP clock rate (in hz)", 24606720, Setting::DEC);
Setting SMP::pal_clock_rate(&config_file, "smp.pal_clock_rate",
"PAL S-SMP clock rate (in hz)", 24576000, Setting::DEC);
"PAL S-SMP clock rate (in hz)", 24606720, Setting::DEC);
Setting PPU::render_scanline_position(&config_file, "ppu.render_scanline_position",
Setting PPU::Hack::render_scanline_position(&config_file, "ppu.hack.render_scanline_position",
"Approximate HCLOCK position to render at for scanline-based renderers",
256, Setting::DEC);
Setting PPU::opt_enable(0, "ppu.opt_enable", "Enable offset-per-tile effects", true, Setting::TRUE_FALSE);
512, Setting::DEC);
Setting PPU::Hack::obj_cache(&config_file, "ppu.hack.obj_cache",
"Cache OAM OBJ attributes one scanline before rendering\n"
"This is technically closer to the actual operation of the SNES,\n"
"but can cause problems in many games if enabled",
false, Setting::BOOL);
Setting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::bg1_pri1_enable(0, "ppu.bg1_pri1_enable", "Enable BG1 Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::bg2_pri0_enable(0, "ppu.bg2_pri0_enable", "Enable BG2 Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::bg2_pri1_enable(0, "ppu.bg2_pri1_enable", "Enable BG2 Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::bg3_pri0_enable(0, "ppu.bg3_pri0_enable", "Enable BG3 Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::bg3_pri1_enable(0, "ppu.bg3_pri1_enable", "Enable BG3 Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::bg4_pri0_enable(0, "ppu.bg4_pri0_enable", "Enable BG4 Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::bg4_pri1_enable(0, "ppu.bg4_pri1_enable", "Enable BG4 Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::oam_pri0_enable(0, "ppu.oam_pri0_enable", "Enable OAM Priority 0", true, Setting::TRUE_FALSE);
Setting PPU::oam_pri1_enable(0, "ppu.oam_pri1_enable", "Enable OAM Priority 1", true, Setting::TRUE_FALSE);
Setting PPU::oam_pri2_enable(0, "ppu.oam_pri2_enable", "Enable OAM Priority 2", true, Setting::TRUE_FALSE);
Setting PPU::oam_pri3_enable(0, "ppu.oam_pri3_enable", "Enable OAM Priority 3", true, Setting::TRUE_FALSE);
Setting PPU::opt_enable(0, "ppu.opt_enable", "Enable offset-per-tile effects", true, Setting::BOOL);
Setting PPU::bg1_pri0_enable(0, "ppu.bg1_pri0_enable", "Enable BG1 Priority 0", true, Setting::BOOL);
Setting PPU::bg1_pri1_enable(0, "ppu.bg1_pri1_enable", "Enable BG1 Priority 1", true, Setting::BOOL);
Setting PPU::bg2_pri0_enable(0, "ppu.bg2_pri0_enable", "Enable BG2 Priority 0", true, Setting::BOOL);
Setting PPU::bg2_pri1_enable(0, "ppu.bg2_pri1_enable", "Enable BG2 Priority 1", true, Setting::BOOL);
Setting PPU::bg3_pri0_enable(0, "ppu.bg3_pri0_enable", "Enable BG3 Priority 0", true, Setting::BOOL);
Setting PPU::bg3_pri1_enable(0, "ppu.bg3_pri1_enable", "Enable BG3 Priority 1", true, Setting::BOOL);
Setting PPU::bg4_pri0_enable(0, "ppu.bg4_pri0_enable", "Enable BG4 Priority 0", true, Setting::BOOL);
Setting PPU::bg4_pri1_enable(0, "ppu.bg4_pri1_enable", "Enable BG4 Priority 1", true, Setting::BOOL);
Setting PPU::oam_pri0_enable(0, "ppu.oam_pri0_enable", "Enable OAM Priority 0", true, Setting::BOOL);
Setting PPU::oam_pri1_enable(0, "ppu.oam_pri1_enable", "Enable OAM Priority 1", true, Setting::BOOL);
Setting PPU::oam_pri2_enable(0, "ppu.oam_pri2_enable", "Enable OAM Priority 2", true, Setting::BOOL);
Setting PPU::oam_pri3_enable(0, "ppu.oam_pri3_enable", "Enable OAM Priority 3", true, Setting::BOOL);
};

View File

@ -2,10 +2,12 @@ extern Config config_file;
namespace config {
extern struct FS {
static Setting base_path, rom_path, save_path;
string file_updatepath(const char *, const char *);
extern struct Path {
static Setting base, rom, save, bios;
static Setting save_ext;
} fs;
} path;
extern struct SNES {
static Setting gamma_ramp, sepia, grayscale, invert, contrast, brightness, gamma;
@ -25,9 +27,12 @@ extern struct SMP {
} smp;
extern struct PPU {
static Setting render_scanline_position;
static Setting opt_enable;
struct Hack {
static Setting render_scanline_position;
static Setting obj_cache;
} hack;
static Setting opt_enable;
static Setting bg1_pri0_enable, bg1_pri1_enable;
static Setting bg2_pri0_enable, bg2_pri1_enable;
static Setting bg3_pri0_enable, bg3_pri1_enable;

View File

@ -2,7 +2,6 @@
class CPU : public MMIO {
public:
thread_t thread;
virtual void enter() = 0;
public:

View File

@ -58,9 +58,7 @@ cop(0x02, 0xfff4, 0xfff5, 0xffe4, 0xffe5) {
stp(0xdb) {
1:op_io();
2:last_cycle();
while(1) {
op_io();
}
while(1) { op_io(); }
}
wai(0xcb) {
@ -77,9 +75,9 @@ wai(0xcb) {
xce(0xfb) {
1:last_cycle();
op_io();
bool c = regs.p.c;
bool carry = regs.p.c;
regs.p.c = regs.e;
regs.e = c;
regs.e = carry;
if(regs.e) {
regs.p |= 0x30;
regs.s.h = 0x01;

View File

@ -98,9 +98,7 @@ case 0x02: {
case 0xdb: {
op_io();
last_cycle();
while(1) {
op_io();
}
while(1) { op_io(); }
} break;
//wai
@ -119,9 +117,9 @@ case 0xcb: {
case 0xfb: {
last_cycle();
op_io();
bool c = regs.p.c;
bool carry = regs.p.c;
regs.p.c = regs.e;
regs.e = c;
regs.e = carry;
if(regs.e) {
regs.p |= 0x30;
regs.s.h = 0x01;

View File

@ -5,11 +5,11 @@ iny(0xc8, regs.p.x, y) {
op_io();
if($1) {
regs.$2.l++;
regs.p.n = bool(regs.$2.l & 0x80);
regs.p.n = !!(regs.$2.l & 0x80);
regs.p.z = (regs.$2.l == 0);
} else {
regs.$2.w++;
regs.p.n = bool(regs.$2.w & 0x8000);
regs.p.n = !!(regs.$2.w & 0x8000);
regs.p.z = (regs.$2.w == 0);
}
}
@ -21,11 +21,11 @@ dey(0x88, regs.p.x, y) {
op_io();
if($1) {
regs.$2.l--;
regs.p.n = bool(regs.$2.l & 0x80);
regs.p.n = !!(regs.$2.l & 0x80);
regs.p.z = (regs.$2.l == 0);
} else {
regs.$2.w--;
regs.p.n = bool(regs.$2.w & 0x8000);
regs.p.n = !!(regs.$2.w & 0x8000);
regs.p.z = (regs.$2.w == 0);
}
}
@ -34,14 +34,14 @@ asl(0x0a) {
1:last_cycle();
op_io();
if(regs.p.m) {
regs.p.c = bool(regs.a.l & 0x80);
regs.p.c = !!(regs.a.l & 0x80);
regs.a.l <<= 1;
regs.p.n = bool(regs.a.l & 0x80);
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.p.c = bool(regs.a.w & 0x8000);
regs.p.c = !!(regs.a.w & 0x8000);
regs.a.w <<= 1;
regs.p.n = bool(regs.a.w & 0x8000);
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
}
@ -52,12 +52,12 @@ lsr(0x4a) {
if(regs.p.m) {
regs.p.c = regs.a.l & 1;
regs.a.l >>= 1;
regs.p.n = bool(regs.a.l & 0x80);
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.p.c = regs.a.w & 1;
regs.a.w >>= 1;
regs.p.n = bool(regs.a.w & 0x8000);
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
}
@ -67,16 +67,16 @@ rol(0x2a) {
op_io();
uint16 c = regs.p.c;
if(regs.p.m) {
regs.p.c = bool(regs.a.l & 0x80);
regs.p.c = !!(regs.a.l & 0x80);
regs.a.l <<= 1;
regs.a.l |= c;
regs.p.n = bool(regs.a.l & 0x80);
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.p.c = bool(regs.a.w & 0x8000);
regs.p.c = !!(regs.a.w & 0x8000);
regs.a.w <<= 1;
regs.a.w |= c;
regs.p.n = bool(regs.a.w & 0x8000);
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
}
@ -90,14 +90,14 @@ ror(0x6a) {
regs.p.c = regs.a.l & 1;
regs.a.l >>= 1;
regs.a.l |= c;
regs.p.n = bool(regs.a.l & 0x80);
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
c = (regs.p.c)?0x8000:0;
regs.p.c = regs.a.w & 1;
regs.a.w >>= 1;
regs.a.w |= c;
regs.p.n = bool(regs.a.w & 0x8000);
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
}

View File

@ -4,11 +4,11 @@ case 0x1a: {
op_io();
if(regs.p.m) {
regs.a.l++;
regs.p.n = bool(regs.a.l & 0x80);
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.a.w++;
regs.p.n = bool(regs.a.w & 0x8000);
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;
@ -19,11 +19,11 @@ case 0xe8: {
op_io();
if(regs.p.x) {
regs.x.l++;
regs.p.n = bool(regs.x.l & 0x80);
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
} else {
regs.x.w++;
regs.p.n = bool(regs.x.w & 0x8000);
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
} break;
@ -34,11 +34,11 @@ case 0xc8: {
op_io();
if(regs.p.x) {
regs.y.l++;
regs.p.n = bool(regs.y.l & 0x80);
regs.p.n = !!(regs.y.l & 0x80);
regs.p.z = (regs.y.l == 0);
} else {
regs.y.w++;
regs.p.n = bool(regs.y.w & 0x8000);
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
}
} break;
@ -49,11 +49,11 @@ case 0x3a: {
op_io();
if(regs.p.m) {
regs.a.l--;
regs.p.n = bool(regs.a.l & 0x80);
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.a.w--;
regs.p.n = bool(regs.a.w & 0x8000);
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;
@ -64,11 +64,11 @@ case 0xca: {
op_io();
if(regs.p.x) {
regs.x.l--;
regs.p.n = bool(regs.x.l & 0x80);
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
} else {
regs.x.w--;
regs.p.n = bool(regs.x.w & 0x8000);
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
} break;
@ -79,11 +79,11 @@ case 0x88: {
op_io();
if(regs.p.x) {
regs.y.l--;
regs.p.n = bool(regs.y.l & 0x80);
regs.p.n = !!(regs.y.l & 0x80);
regs.p.z = (regs.y.l == 0);
} else {
regs.y.w--;
regs.p.n = bool(regs.y.w & 0x8000);
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
}
} break;
@ -93,14 +93,14 @@ case 0x0a: {
last_cycle();
op_io();
if(regs.p.m) {
regs.p.c = bool(regs.a.l & 0x80);
regs.p.c = !!(regs.a.l & 0x80);
regs.a.l <<= 1;
regs.p.n = bool(regs.a.l & 0x80);
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.p.c = bool(regs.a.w & 0x8000);
regs.p.c = !!(regs.a.w & 0x8000);
regs.a.w <<= 1;
regs.p.n = bool(regs.a.w & 0x8000);
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;
@ -112,12 +112,12 @@ case 0x4a: {
if(regs.p.m) {
regs.p.c = regs.a.l & 1;
regs.a.l >>= 1;
regs.p.n = bool(regs.a.l & 0x80);
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.p.c = regs.a.w & 1;
regs.a.w >>= 1;
regs.p.n = bool(regs.a.w & 0x8000);
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;
@ -128,16 +128,16 @@ case 0x2a: {
op_io();
uint16 c = regs.p.c;
if(regs.p.m) {
regs.p.c = bool(regs.a.l & 0x80);
regs.p.c = !!(regs.a.l & 0x80);
regs.a.l <<= 1;
regs.a.l |= c;
regs.p.n = bool(regs.a.l & 0x80);
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
regs.p.c = bool(regs.a.w & 0x8000);
regs.p.c = !!(regs.a.w & 0x8000);
regs.a.w <<= 1;
regs.a.w |= c;
regs.p.n = bool(regs.a.w & 0x8000);
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;
@ -152,14 +152,14 @@ case 0x6a: {
regs.p.c = regs.a.l & 1;
regs.a.l >>= 1;
regs.a.l |= c;
regs.p.n = bool(regs.a.l & 0x80);
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
} else {
c = (regs.p.c)?0x8000:0;
regs.p.c = regs.a.w & 1;
regs.a.w >>= 1;
regs.a.w |= c;
regs.p.n = bool(regs.a.w & 0x8000);
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
} break;

View File

@ -23,8 +23,8 @@ int32 r = regs.a.l + rd.l + regs.p.c;
r = regs.a.l + rd.l + regs.p.c;
regs.p.c = (r > 0xff);
}
regs.p.n = bool(r & 0x80);
regs.p.v = bool(~(regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
regs.p.n = !!(r & 0x80);
regs.p.v = !!(~(regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
regs.p.z = ((uint8)r == 0);
regs.a.l = r;
}
@ -67,135 +67,135 @@ int32 r;
r = regs.a.w + rd.w + regs.p.c;
regs.p.c = (r > 0xffff);
}
regs.p.n = bool(r & 0x8000);
regs.p.v = bool(~(regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
regs.p.n = !!(r & 0x8000);
regs.p.v = !!(~(regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.a.w = r;
}
inline void sCPU::op_and_b() {
regs.a.l &= rd.l;
regs.p.n = bool(regs.a.l & 0x80);
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
}
inline void sCPU::op_and_w() {
regs.a.w &= rd.w;
regs.p.n = bool(regs.a.w & 0x8000);
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
inline void sCPU::op_bit_b() {
regs.p.n = bool(rd.l & 0x80);
regs.p.v = bool(rd.l & 0x40);
regs.p.n = !!(rd.l & 0x80);
regs.p.v = !!(rd.l & 0x40);
regs.p.z = ((rd.l & regs.a.l) == 0);
}
inline void sCPU::op_bit_w() {
regs.p.n = bool(rd.w & 0x8000);
regs.p.v = bool(rd.w & 0x4000);
regs.p.n = !!(rd.w & 0x8000);
regs.p.v = !!(rd.w & 0x4000);
regs.p.z = ((rd.w & regs.a.w) == 0);
}
inline void sCPU::op_cmp_b() {
int32 r = regs.a.l - rd.l;
regs.p.n = bool(r & 0x80);
regs.p.n = !!(r & 0x80);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r >= 0);
}
inline void sCPU::op_cmp_w() {
int32 r = regs.a.w - rd.w;
regs.p.n = bool(r & 0x8000);
regs.p.n = !!(r & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.p.c = (r >= 0);
}
inline void sCPU::op_cpx_b() {
int32 r = regs.x.l - rd.l;
regs.p.n = bool(r & 0x80);
regs.p.n = !!(r & 0x80);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r >= 0);
}
inline void sCPU::op_cpx_w() {
int32 r = regs.x.w - rd.w;
regs.p.n = bool(r & 0x8000);
regs.p.n = !!(r & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.p.c = (r >= 0);
}
inline void sCPU::op_cpy_b() {
int32 r = regs.y.l - rd.l;
regs.p.n = bool(r & 0x80);
regs.p.n = !!(r & 0x80);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r >= 0);
}
inline void sCPU::op_cpy_w() {
int32 r = regs.y.w - rd.w;
regs.p.n = bool(r & 0x8000);
regs.p.n = !!(r & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.p.c = (r >= 0);
}
inline void sCPU::op_eor_b() {
regs.a.l ^= rd.l;
regs.p.n = bool(regs.a.l & 0x80);
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
}
inline void sCPU::op_eor_w() {
regs.a.w ^= rd.w;
regs.p.n = bool(regs.a.w & 0x8000);
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
inline void sCPU::op_lda_b() {
regs.a.l = rd.l;
regs.p.n = bool(regs.a.l & 0x80);
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
}
inline void sCPU::op_lda_w() {
regs.a.w = rd.w;
regs.p.n = bool(regs.a.w & 0x8000);
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
inline void sCPU::op_ldx_b() {
regs.x.l = rd.l;
regs.p.n = bool(regs.x.l & 0x80);
regs.p.n = !!(regs.x.l & 0x80);
regs.p.z = (regs.x.l == 0);
}
inline void sCPU::op_ldx_w() {
regs.x.w = rd.w;
regs.p.n = bool(regs.x.w & 0x8000);
regs.p.n = !!(regs.x.w & 0x8000);
regs.p.z = (regs.x.w == 0);
}
inline void sCPU::op_ldy_b() {
regs.y.l = rd.l;
regs.p.n = bool(regs.y.l & 0x80);
regs.p.n = !!(regs.y.l & 0x80);
regs.p.z = (regs.y.l == 0);
}
inline void sCPU::op_ldy_w() {
regs.y.w = rd.w;
regs.p.n = bool(regs.y.w & 0x8000);
regs.p.n = !!(regs.y.w & 0x8000);
regs.p.z = (regs.y.w == 0);
}
inline void sCPU::op_ora_b() {
regs.a.l |= rd.l;
regs.p.n = bool(regs.a.l & 0x80);
regs.p.n = !!(regs.a.l & 0x80);
regs.p.z = (regs.a.l == 0);
}
inline void sCPU::op_ora_w() {
regs.a.w |= rd.w;
regs.p.n = bool(regs.a.w & 0x8000);
regs.p.n = !!(regs.a.w & 0x8000);
regs.p.z = (regs.a.w == 0);
}
@ -221,8 +221,8 @@ int32 r;
r = regs.a.l - rd.l - !regs.p.c;
regs.p.c = (r >= 0);
}
regs.p.n = bool(r & 0x80);
regs.p.v = bool((regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
regs.p.n = !!(r & 0x80);
regs.p.v = !!((regs.a.l ^ rd.l) & (regs.a.l ^ r) & 0x80);
regs.p.z = ((uint8)r == 0);
regs.a.l = r;
}
@ -261,8 +261,8 @@ int32 r;
r = regs.a.w - rd.w - !regs.p.c;
regs.p.c = (r >= 0);
}
regs.p.n = bool(r & 0x8000);
regs.p.v = bool((regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
regs.p.n = !!(r & 0x8000);
regs.p.v = !!((regs.a.w ^ rd.w) & (regs.a.w ^ r) & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.a.w = r;
}
@ -270,89 +270,85 @@ int32 r;
//op_rmw
inline void sCPU::op_inc_b() {
rd.l++;
regs.p.n = bool(rd.l & 0x80);
regs.p.n = !!(rd.l & 0x80);
regs.p.z = (rd.l == 0);
}
inline void sCPU::op_inc_w() {
rd.w++;
regs.p.n = bool(rd.w & 0x8000);
regs.p.n = !!(rd.w & 0x8000);
regs.p.z = (rd.w == 0);
}
inline void sCPU::op_dec_b() {
rd.l--;
regs.p.n = bool(rd.l & 0x80);
regs.p.n = !!(rd.l & 0x80);
regs.p.z = (rd.l == 0);
}
inline void sCPU::op_dec_w() {
rd.w--;
regs.p.n = bool(rd.w & 0x8000);
regs.p.n = !!(rd.w & 0x8000);
regs.p.z = (rd.w == 0);
}
inline void sCPU::op_asl_b() {
regs.p.c = bool(rd.l & 0x80);
regs.p.c = !!(rd.l & 0x80);
rd.l <<= 1;
regs.p.n = bool(rd.l & 0x80);
regs.p.n = !!(rd.l & 0x80);
regs.p.z = (rd.l == 0);
}
inline void sCPU::op_asl_w() {
regs.p.c = bool(rd.w & 0x8000);
regs.p.c = !!(rd.w & 0x8000);
rd.w <<= 1;
regs.p.n = bool(rd.w & 0x8000);
regs.p.n = !!(rd.w & 0x8000);
regs.p.z = (rd.w == 0);
}
inline void sCPU::op_lsr_b() {
regs.p.c = rd.l & 1;
rd.l >>= 1;
regs.p.n = bool(rd.l & 0x80);
regs.p.n = !!(rd.l & 0x80);
regs.p.z = (rd.l == 0);
}
inline void sCPU::op_lsr_w() {
regs.p.c = rd.w & 1;
rd.w >>= 1;
regs.p.n = bool(rd.w & 0x8000);
regs.p.n = !!(rd.w & 0x8000);
regs.p.z = (rd.w == 0);
}
inline void sCPU::op_rol_b() {
uint16 c = regs.p.c;
regs.p.c = bool(rd.l & 0x80);
rd.l <<= 1;
rd.l |= c;
regs.p.n = bool(rd.l & 0x80);
uint16 carry = (uint16)regs.p.c;
regs.p.c = !!(rd.l & 0x80);
rd.l = (rd.l << 1) | carry;
regs.p.n = !!(rd.l & 0x80);
regs.p.z = (rd.l == 0);
}
inline void sCPU::op_rol_w() {
uint16 c = regs.p.c;
regs.p.c = bool(rd.w & 0x8000);
rd.w <<= 1;
rd.w |= c;
regs.p.n = bool(rd.w & 0x8000);
uint16 carry = (uint16)regs.p.c;
regs.p.c = !!(rd.w & 0x8000);
rd.w = (rd.w << 1) | carry;
regs.p.n = !!(rd.w & 0x8000);
regs.p.z = (rd.w == 0);
}
inline void sCPU::op_ror_b() {
uint16 c = (regs.p.c)?0x80:0;
uint16 carry = (uint16)regs.p.c << 7;
regs.p.c = rd.l & 1;
rd.l >>= 1;
rd.l |= c;
regs.p.n = bool(rd.l & 0x80);
rd.l = carry | (rd.l >> 1);
regs.p.n = !!(rd.l & 0x80);
regs.p.z = (rd.l == 0);
}
inline void sCPU::op_ror_w() {
uint16 c = (regs.p.c)?0x8000:0;
uint16 carry = (uint16)regs.p.c << 15;
regs.p.c = rd.w & 1;
rd.w >>= 1;
rd.w |= c;
regs.p.n = bool(rd.w & 0x8000);
rd.w = carry | (rd.w >> 1);
regs.p.n = !!(rd.w & 0x8000);
regs.p.z = (rd.w == 0);
}

View File

@ -1,3 +1,8 @@
void sCPU::dma_add_clocks(uint clocks) {
status.dma_clocks += clocks;
add_clocks(clocks);
}
/*****
* used by both DMA and HDMA
*
@ -29,8 +34,7 @@ uint8 r;
r_mem->write(abus, r);
}
status.dma_clocks += 8;
add_clocks(8);
dma_add_clocks(8);
cycle_edge();
}
@ -104,8 +108,7 @@ inline void sCPU::dma_write(uint8 i, uint8 index) {
void sCPU::dma_run() {
for(int i = 0; i < 8; i++) {
if(channel[i].dma_enabled == false)continue;
status.dma_clocks += 8;
add_clocks(8);
dma_add_clocks(8);
if(cartridge.info.sdd1 == true) {
sdd1->dma_begin(i, (channel[i].srcbank << 16) | (channel[i].srcaddr),
@ -129,7 +132,7 @@ void sCPU::dma_run() {
channel[i].dma_enabled = false;
}
counter.set(counter.irq_delay, 24);
counter.set(counter.irq_delay, 2);
}
/*****
@ -166,19 +169,19 @@ uint8 r = 0;
void sCPU::hdma_update(uint8 i) {
channel[i].hdma_line_counter = r_mem->read(hdma_addr(i));
add_clocks(8);
dma_add_clocks(8);
channel[i].hdma_completed = (channel[i].hdma_line_counter == 0);
channel[i].hdma_do_transfer = !channel[i].hdma_completed;
if(channel[i].hdma_indirect) {
channel[i].hdma_iaddr = r_mem->read(hdma_addr(i)) << 8;
add_clocks(8);
dma_add_clocks(8);
if(!channel[i].hdma_completed || hdma_active_after(i)) {
channel[i].hdma_iaddr >>= 8;
channel[i].hdma_iaddr |= r_mem->read(hdma_addr(i)) << 8;
add_clocks(8);
dma_add_clocks(8);
}
}
}
@ -188,7 +191,7 @@ static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
for(int i = 0; i < 8; i++) {
if(hdma_active(i) == false)continue;
channel[i].dma_enabled = false; //HDMA run during DMA will stop DMA mid-transfer
add_clocks(8);
dma_add_clocks(8);
if(channel[i].hdma_do_transfer) {
int xferlen = hdma_xferlen[channel[i].xfermode];
@ -197,7 +200,7 @@ static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
dma_transfer(channel[i].direction, dma_bbus(i, index),
!channel[i].hdma_indirect ? hdma_addr(i) : hdma_iaddr(i));
} else {
add_clocks(8);
dma_add_clocks(8);
cycle_edge();
}
}
@ -210,7 +213,7 @@ static uint8 hdma_xferlen[8] = { 1, 2, 2, 4, 4, 4, 2, 4 };
}
}
counter.set(counter.irq_delay, 24);
counter.set(counter.irq_delay, 2);
}
void sCPU::hdma_init_reset() {
@ -229,7 +232,7 @@ void sCPU::hdma_init() {
hdma_update(i);
}
counter.set(counter.irq_delay, 24);
counter.set(counter.irq_delay, 2);
}
/*****

View File

@ -45,6 +45,7 @@ struct {
bool hdma_do_transfer;
} channel[8];
void dma_add_clocks(uint clocks);
void dma_transfer(bool direction, uint8 bbus, uint32 abus);
uint8 dma_bbus(uint8 i, uint8 index);

View File

@ -41,7 +41,7 @@ void sCPU::mmio_w4016(uint8 data) {
status.joypad_strobe_latch = !!(data & 1);
if(status.joypad_strobe_latch == 1) {
snes->poll_input();
snes.poll_input();
}
}
@ -53,7 +53,7 @@ void sCPU::mmio_w4016(uint8 data) {
//realtime or buffered status of joypadN.b
uint8 sCPU::mmio_r4016() {
uint8 r = regs.mdr & 0xfc;
r |= (uint8)snes->port_read(0);
r |= (uint8)snes.port_read(0);
return r;
}
@ -63,43 +63,14 @@ uint8 r = regs.mdr & 0xfc;
//1-0 = Joypad serial data
uint8 sCPU::mmio_r4017() {
uint8 r = (regs.mdr & 0xe0) | 0x1c;
r |= (uint8)snes->port_read(1);
r |= (uint8)snes.port_read(1);
return r;
}
//NMITIMEN
void sCPU::mmio_w4200(uint8 data) {
status.nmi_enabled = !!(data & 0x80);
status.virq_enabled = !!(data & 0x20);
status.hirq_enabled = !!(data & 0x10);
status.auto_joypad_poll = !!(data & 0x01);
if(status.nmi_read == 0) {
if(status.nmi_line == 1 && status.nmi_enabled == 1) {
status.nmi_transition = 1;
}
status.nmi_line = !status.nmi_enabled;
}
if(status.irq_read == 0) {
if(status.irq_line == 1 && (status.virq_enabled || status.hirq_enabled)) {
status.irq_transition = 1;
}
status.irq_line = !(status.virq_enabled || status.hirq_enabled);
}
if(status.virq_enabled == true && status.hirq_enabled == false) {
status.irq_lock = false;
}
if(status.virq_enabled == false && status.hirq_enabled == false) {
status.irq_line = 1;
status.irq_read = 1;
status.irq_transition = 0;
}
update_interrupts();
counter.set(counter.irq_delay, 2);
nmitimen_update(data);
}
//WRIO
@ -144,32 +115,28 @@ void sCPU::mmio_w4206(uint8 data) {
void sCPU::mmio_w4207(uint8 data) {
status.hirq_pos = (status.hirq_pos & ~0xff) | (data);
status.hirq_pos &= 0x01ff;
update_interrupts();
irqpos_update(0x4207);
hvtime_update(0x4207);
}
//HTIMEH
void sCPU::mmio_w4208(uint8 data) {
status.hirq_pos = (status.hirq_pos & 0xff) | (data << 8);
status.hirq_pos &= 0x01ff;
update_interrupts();
irqpos_update(0x4208);
hvtime_update(0x4208);
}
//VTIMEL
void sCPU::mmio_w4209(uint8 data) {
status.virq_pos = (status.virq_pos & ~0xff) | (data);
status.virq_pos &= 0x01ff;
update_interrupts();
irqpos_update(0x4209);
hvtime_update(0x4209);
}
//VTIMEH
void sCPU::mmio_w420a(uint8 data) {
status.virq_pos = (status.virq_pos & 0xff) | (data << 8);
status.virq_pos &= 0x01ff;
update_interrupts();
irqpos_update(0x420a);
hvtime_update(0x420a);
}
//DMAEN
@ -201,12 +168,7 @@ void sCPU::mmio_w420d(uint8 data) {
//3-0 = CPU (5a22) version
uint8 sCPU::mmio_r4210() {
uint8 r = (regs.mdr & 0x70);
r |= (uint8)(!status.nmi_read) << 7;
if(!nmi_edge()) {
status.nmi_read = 1;
}
r |= (uint8)(rdnmi()) << 7;
r |= (cpu_version & 0x0f);
return r;
}
@ -216,14 +178,7 @@ uint8 r = (regs.mdr & 0x70);
//6-0 = MDR
uint8 sCPU::mmio_r4211() {
uint8 r = (regs.mdr & 0x7f);
r |= (uint8)(!status.irq_read) << 7;
if(!irq_edge()) {
status.irq_read = 1;
status.irq_line = 1;
status.irq_transition = 0;
}
r |= (uint8)(timeup()) << 7;
return r;
}

View File

@ -7,7 +7,7 @@
#include "timing/timing.cpp"
void sCPU::power() {
status.region = (bool)snes->region();
status.region = (bool)snes.region();
regs.a = regs.x = regs.y = 0x0000;
regs.s = 0x01ff;

View File

@ -16,6 +16,9 @@ struct {
} event;
struct {
uint nmi_hold;
uint irq_hold;
uint nmi_fire;
uint irq_fire;
uint irq_delay;
@ -55,6 +58,7 @@ struct {
bool interlace, interlace_field;
bool overscan;
uint16 field_lines, line_clocks;
uint16 prev_field_lines, prev_line_clocks;
uint16 vblstart;
bool line_rendered;
@ -70,15 +74,17 @@ struct {
uint16 irq_delay;
uint16 nmi_trigger_pos;
uint16 nmi_read_pos, nmi_line_pos;
bool nmi_read, nmi_line, nmi_transition;
bool nmi_lock, nmi_pending;
uint16 vnmi_trigger_pos;
bool nmi_valid;
bool nmi_line;
bool nmi_transition;
bool nmi_pending;
uint16 virq_trigger_pos, hirq_trigger_pos;
uint16 irq_read_pos, irq_line_pos;
bool irq_read, irq_line, irq_transition;
bool irq_lock, irq_pending;
bool irq_valid;
bool irq_line;
bool irq_transition;
bool irq_pending;
//dma
uint dma_counter;

View File

@ -1,8 +1,4 @@
#if defined(FAVOR_ACCURACY)
#include "irqtiming_accurate.cpp"
#elif defined(FAVOR_SPEED)
#include "irqtiming_fast.cpp"
#endif
#include "irqtiming.cpp"
bool sCPU::irq_pos_valid() {
uint vpos = status.virq_pos;
@ -21,15 +17,25 @@ uint vlimit = region_scanlines() >> 1;
return true;
}
alwaysinline bool sCPU::nmi_test() {
if(status.nmi_transition == 0)return false;
alwaysinline
bool sCPU::nmi_test() {
if(status.nmi_transition == false) { return false; }
status.nmi_transition = false;
status.nmi_transition = 0;
event.wai = false;
return true;
}
alwaysinline bool sCPU::irq_test() {
alwaysinline
bool sCPU::irq_test() {
if(status.irq_transition == false) { return false; }
status.irq_transition = false;
event.wai = false;
return (regs.p.i) ? false : true;
}
/*
if(status.irq_transition == 1)goto irq_trigger;
if(status.irq_read == 0) {
@ -51,3 +57,4 @@ irq_trigger:
event.wai = false;
return (regs.p.i) ? false : true;
}
*/

View File

@ -0,0 +1,105 @@
void sCPU::update_interrupts() {
status.vnmi_trigger_pos = status.vblstart;
if(irq_pos_valid() == true) {
status.virq_trigger_pos = status.virq_pos;
status.hirq_trigger_pos = 4 * ((status.hirq_enabled) ? (status.hirq_pos + 1) : 0);
} else {
status.virq_trigger_pos = IRQ_TRIGGER_NEVER;
status.hirq_trigger_pos = IRQ_TRIGGER_NEVER;
}
}
alwaysinline
void sCPU::poll_interrupts() {
uint vpos = status.vcounter, hpos = status.hclock;
//NMI test
timeshift_backward(2, vpos, hpos);
bool nmi_valid = (vpos >= status.vnmi_trigger_pos);
if(status.nmi_valid == false && nmi_valid == true) {
//0->1 edge sensitive transition
status.nmi_line = true;
counter.nmi_hold = 6;
} else if(status.nmi_valid == true && nmi_valid == false) {
//1->0 edge sensitive transition
status.nmi_line = false;
}
status.nmi_valid = nmi_valid;
//NMI hold
if(counter.nmi_hold) {
counter.nmi_hold -= 2;
if(counter.nmi_hold == 0) {
if(status.nmi_enabled == true) { status.nmi_transition = true; }
}
}
//IRQ test
timeshift_backward(8, vpos, hpos);
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; }
}
if(status.irq_valid == false && irq_valid == true) {
//0->1 edge sensitive transition
status.irq_line = true;
counter.irq_hold = 6;
}
status.irq_valid = irq_valid;
//IRQ hold
if(counter.irq_hold) { counter.irq_hold -= 2; }
if(status.irq_line == true && counter.irq_hold == 0) {
if(status.virq_enabled == true || status.hirq_enabled == true) { status.irq_transition = true; }
}
}
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);
//0->1 edge sensitive transition
if(nmi_enabled == false && status.nmi_enabled == true && status.nmi_line == true) {
status.nmi_transition = true;
}
//?->1 level sensitive transition
if(status.virq_enabled == true && status.hirq_enabled == false && status.irq_line == true) {
status.irq_transition = true;
}
if(status.virq_enabled == false && status.hirq_enabled == false) {
status.irq_line = false;
status.irq_transition = false;
}
update_interrupts();
counter.set(counter.irq_delay, 2);
}
void sCPU::hvtime_update(uint16 addr) {
update_interrupts();
}
bool sCPU::rdnmi() {
bool result = status.nmi_line;
if(counter.nmi_hold == 0) {
status.nmi_line = false;
}
return result;
}
bool sCPU::timeup() {
bool result = status.irq_line;
if(counter.irq_hold == 0) {
status.irq_line = false;
status.irq_transition = false;
}
return result;
}

View File

@ -1,76 +0,0 @@
void sCPU::update_interrupts() {
status.nmi_trigger_pos = (status.vcounter == status.vblstart) ? 2 : IRQ_TRIGGER_NEVER;
if(irq_pos_valid() == true) {
status.virq_trigger_pos = status.virq_pos;
status.hirq_trigger_pos = 4 * ((status.hirq_enabled) ? (status.hirq_pos + 1) : 0);
} else {
status.virq_trigger_pos = IRQ_TRIGGER_NEVER;
status.hirq_trigger_pos = IRQ_TRIGGER_NEVER;
}
}
alwaysinline void sCPU::poll_interrupts(uint clocks) {
clocks >>= 1;
while(clocks--) {
status.hclock += 2;
if(status.hclock >= status.line_clocks) { scanline(); }
//NMI tick
if(counter.nmi_fire) {
counter.nmi_fire -= 2;
if(counter.nmi_fire == 0) {
if(status.nmi_enabled == true && status.nmi_line == 1) {
status.nmi_line = 0;
status.nmi_transition = 1;
}
}
}
//IRQ tick
if(counter.irq_fire) {
counter.irq_fire -= 2;
if(counter.irq_fire == 0) {
if(status.virq_enabled == true || status.hirq_enabled == true) {
status.irq_line = 0;
status.irq_transition = 1;
}
}
}
//NMI test
if(status.hclock == status.nmi_trigger_pos) {
status.nmi_read = 0;
counter.nmi_fire = 4;
}
//IRQ test
if(status.hclock == 10) { status.irq_lock = false; }
if(status.hirq_trigger_pos == IRQ_TRIGGER_NEVER) { continue; }
if(status.virq_enabled == false && status.hirq_enabled == false) { continue; }
if(status.irq_lock == true) { continue; }
uint vpos = status.vcounter, hpos = status.hclock;
timeshift_backward(10, vpos, hpos);
bool trigger_irq = true;
if(status.virq_enabled == true && vpos != status.virq_trigger_pos)trigger_irq = false;
if(status.hirq_enabled == true && hpos != status.hirq_trigger_pos)trigger_irq = false;
if(trigger_irq == true) {
status.irq_lock = true;
status.irq_read = 0;
counter.irq_fire = 4;
}
}
}
bool sCPU::nmi_edge() { return (counter.nmi_fire != 0); }
bool sCPU::irq_edge() { return (counter.irq_fire != 0); }
void sCPU::irqpos_update(uint16 addr) {
uint vpos = status.vcounter, hpos = status.hclock;
timeshift_backward(10, vpos, hpos);
if(hpos < status.hirq_trigger_pos) { status.irq_lock = false; }
}

View File

@ -1,111 +0,0 @@
void sCPU::update_interrupts() {
status.nmi_read_pos = (status.vcounter == status.vblstart) ? 2 : IRQ_TRIGGER_NEVER;
status.nmi_line_pos = (status.vcounter == status.vblstart) ? 6 : IRQ_TRIGGER_NEVER;
if(irq_pos_valid() == false) {
status.irq_read_pos = IRQ_TRIGGER_NEVER;
status.irq_line_pos = IRQ_TRIGGER_NEVER;
return;
}
uint vpos = status.virq_pos;
uint hpos = 4 * ((status.hirq_enabled) ? (status.hirq_pos + 1) : 0);
timeshift_forward(10, vpos, hpos);
if(!status.virq_enabled || (status.virq_enabled && status.vcounter == vpos)) {
status.irq_read_pos = hpos;
} else {
status.irq_read_pos = IRQ_TRIGGER_NEVER;
}
timeshift_forward(4, vpos, hpos);
if(!status.virq_enabled || (status.virq_enabled && status.vcounter == vpos)) {
status.irq_line_pos = hpos;
} else {
status.irq_line_pos = IRQ_TRIGGER_NEVER;
}
}
alwaysinline void sCPU::poll_interrupts(uint clocks) {
if(status.hclock + clocks >= status.line_clocks) {
clocks = (status.hclock + clocks) - status.line_clocks;
poll_interrupts_range(status.line_clocks - status.hclock);
scanline();
status.irq_lock = false;
if(clocks == 0) { return; }
}
poll_interrupts_range(clocks);
status.hclock += clocks;
}
alwaysinline void sCPU::poll_interrupts_range(uint clocks) {
int start, end;
if(status.hclock == 0) {
start = -1;
end = clocks;
} else {
start = status.hclock;
end = status.hclock + clocks;
}
if(start < status.nmi_read_pos && status.nmi_read_pos <= end) {
status.nmi_read = 0;
}
if(start < status.nmi_line_pos && status.nmi_line_pos <= end) {
if(status.nmi_enabled == true) {
if(status.nmi_line == 1) {
status.nmi_transition = 1;
}
status.nmi_line = 0;
}
}
if(status.virq_enabled == false && status.hirq_enabled == false) {
return;
}
if(status.hirq_enabled == false) {
if(status.irq_lock == false) {
if(end >= status.irq_read_pos) {
status.irq_read = 0;
}
if(end >= status.irq_line_pos) {
status.irq_lock = true;
status.irq_line = 0;
status.irq_transition = 1;
}
}
} else {
if(start < status.irq_read_pos && status.irq_read_pos <= end) {
status.irq_read = 0;
}
if(start < status.irq_line_pos && status.irq_line_pos <= end) {
status.irq_lock = true;
status.irq_line = 0;
status.irq_transition = 1;
}
}
}
bool sCPU::nmi_edge() {
uint vpos = status.vcounter, hpos = status.hclock;
if(hpos == status.nmi_read_pos)return true;
timeshift_backward(2, vpos, hpos);
if(hpos == status.nmi_read_pos)return true;
return false;
}
bool sCPU::irq_edge() {
uint vpos = status.vcounter, hpos = status.hclock;
if(hpos == status.irq_read_pos)return true;
timeshift_backward(2, vpos, hpos);
if(hpos == status.irq_read_pos)return true;
return false;
}
void sCPU::irqpos_update(uint16 addr) {
if(status.hclock < status.irq_line_pos) { status.irq_lock = false; }
}

View File

@ -1,8 +1,8 @@
void sCPU::run_auto_joypad_poll() {
uint16 joy1 = 0, joy2 = 0;
for(int i = 0; i < 16; i++) {
joy1 |= (uint16)snes->port_read(0) ? (0x8000 >> i) : 0;
joy2 |= (uint16)snes->port_read(1) ? (0x8000 >> i) : 0;
joy1 |= (uint16)snes.port_read(0) ? (0x8000 >> i) : 0;
joy2 |= (uint16)snes.port_read(1) ? (0x8000 >> i) : 0;
}
status.joy1l = joy1;

View File

@ -1,6 +1,5 @@
alwaysinline void sCPU::timeshift_forward(uint clocks, uint &vtime, uint &htime) {
htime += clocks;
if(htime >= status.line_clocks) {
htime -= status.line_clocks;
if(++vtime >= status.field_lines) {
@ -13,14 +12,11 @@ alwaysinline void sCPU::timeshift_backward(uint clocks, uint &vtime, uint &htime
if(htime >= clocks) {
htime -= clocks;
} else {
htime += 1364 - clocks;
if(status.region == SNES::NTSC && status.vcounter == 241 &&
status.interlace == false && status.interlace_field == 1)htime -= 4;
htime += status.prev_line_clocks - clocks;
if(vtime > 0) {
vtime--;
} else {
vtime = status.region_scanlines;
if(status.interlace == true && status.interlace_field == 1)vtime++;
vtime = status.prev_field_lines - 1;
}
}
}

View File

@ -55,11 +55,12 @@ void sCPU::add_clocks(uint clocks) {
counter.sub(counter.irq_delay, clocks);
scheduler.addclocks_cpu(clocks);
//TODO: rename function to more descriptive term
//below function is responsible for incrementing status.hclock
//by clocks, calling scanline() when a new line is reached, and
//testing for and triggering NMIs and IRQs
poll_interrupts(clocks);
clocks >>= 1;
while(clocks--) {
status.hclock += 2;
if(status.hclock >= status.line_clocks) { scanline(); }
poll_interrupts();
}
}
void sCPU::scanline() {
@ -70,6 +71,7 @@ void sCPU::scanline() {
frame();
}
status.prev_line_clocks = status.line_clocks;
status.line_clocks = (ntsc_color_burst_phase_shift_scanline() == false) ? 1364 : 1360;
//dram refresh occurs once every scanline
@ -89,23 +91,20 @@ void sCPU::scanline() {
status.hdma_triggered = (status.vcounter <= (!overscan() ? 224 : 239)) ? false : true;
r_ppu->scanline();
snes->scanline();
snes.scanline();
update_interrupts();
if(status.auto_joypad_poll == true && status.vcounter == (!overscan() ? 227 : 242)) {
snes->poll_input();
snes.poll_input();
run_auto_joypad_poll();
}
}
void sCPU::frame() {
status.nmi_read = 1;
status.nmi_line = 1;
status.nmi_transition = 0;
status.vcounter = 0;
status.interlace_field ^= 1;
status.prev_field_lines = status.field_lines;
status.field_lines = (status.region_scanlines >> 1);
//interlaced even fields have one extra scanline
//(263+262=525 NTSC, 313+312=625 PAL)
@ -119,7 +118,7 @@ void sCPU::frame() {
}
r_ppu->frame();
snes->frame();
snes.frame();
}
/*****
@ -171,15 +170,16 @@ void sCPU::cycle_edge() {
if(status.hdmainit_triggered == false) {
if(status.hclock >= status.hdmainit_trigger_position || status.vcounter) {
status.hdmainit_triggered = true;
hdma_init_reset();
if(hdma_enabled_channels()) {
if(status.dma_state == DMASTATE_INACTIVE) {
status.dma_state = DMASTATE_DMASYNC;
status.hdmainit_pending = true;
} else {
hdma_init();
}
add_clocks(12);
hdma_init();
//if(status.dma_state == DMASTATE_INACTIVE) {
// status.dma_state = DMASTATE_DMASYNC;
// status.hdmainit_pending = true;
//} else {
// hdma_init();
//}
}
}
}
@ -188,12 +188,14 @@ void sCPU::cycle_edge() {
if(status.hclock >= 1106) {
status.hdma_triggered = true;
if(hdma_active_channels()) {
if(status.dma_state == DMASTATE_INACTIVE) {
status.dma_state = DMASTATE_DMASYNC;
status.hdma_pending = true;
} else {
hdma_run();
}
add_clocks(12);
hdma_run();
//if(status.dma_state == DMASTATE_INACTIVE) {
// status.dma_state = DMASTATE_DMASYNC;
// status.hdma_pending = true;
//} else {
// hdma_run();
//}
}
}
}
@ -221,6 +223,9 @@ void sCPU::timing_power() {
}
void sCPU::timing_reset() {
counter.nmi_hold = 0;
counter.irq_hold = 0;
counter.nmi_fire = 0;
counter.irq_fire = 0;
counter.irq_delay = 0;
@ -241,8 +246,11 @@ void sCPU::timing_reset() {
status.field_lines = status.region_scanlines >> 1;
status.line_clocks = 1364;
status.prev_field_lines = status.region_scanlines >> 1;
status.prev_line_clocks = 1364;
status.line_rendered = false;
status.line_render_position = minmax<0, 1112>((uint16)config::ppu.render_scanline_position);
status.line_render_position = minmax<0, 1112>((uint16)config::ppu.hack.render_scanline_position);
status.dram_refreshed = false;
status.dram_refresh_position = (cpu_version == 1) ? 530 : 538;
@ -254,16 +262,14 @@ void sCPU::timing_reset() {
status.irq_delay = 0;
status.nmi_read = 1;
status.nmi_line = 1;
status.nmi_transition = 0;
status.nmi_lock = false;
status.nmi_valid = false;
status.nmi_line = false;
status.nmi_transition = false;
status.nmi_pending = false;
status.irq_read = 1;
status.irq_line = 1;
status.irq_transition = 0;
status.irq_lock = false;
status.irq_valid = false;
status.irq_line = false;
status.irq_transition = false;
status.irq_pending = false;
update_interrupts();

View File

@ -31,13 +31,12 @@
//irq.cpp
enum { IRQ_TRIGGER_NEVER = 0x3fff };
void update_interrupts();
void poll_interrupts(uint clocks);
#ifdef FAVOR_SPEED
void poll_interrupts_range(uint clocks);
#endif
bool nmi_edge();
bool irq_edge();
void irqpos_update(uint16 addr);
void poll_interrupts();
void nmitimen_update(uint8 data);
void hvtime_update(uint16 addr);
bool rdnmi();
bool timeup();
bool irq_pos_valid();
bool nmi_test();
bool irq_test();

View File

@ -558,7 +558,7 @@ int32 fir_samplel, fir_sampler;
msampler = sclamp<16>(msampler);
}
return uint32( uint16(msamplel) | (uint16(msampler) << 16) );
return (uint32)( (uint16)msamplel | ((uint16)msampler << 16) );
}
bDSP::bDSP() {}

View File

@ -1,5 +1,5 @@
/*
libbase : version 0.08c ~byuu (09/28/06)
libbase : version 0.08f ~byuu (2006-11-07)
*/
#ifndef __LIBBASE
@ -9,6 +9,7 @@
//disable libc deprecation warnings in MSVC 2k5+
#pragma warning(disable:4996)
#define NOMINMAX
#define ftruncate _chsize
#define vsnprintf _vsnprintf
#endif
@ -28,7 +29,10 @@
#define alwaysinline inline
#define fastcall __attribute__((fastcall))
#else
#error "unsupported compiler"
#define noinline
#define inline inline
#define alwaysinline inline
#define fastcall
#endif
#include <stdio.h>
@ -47,6 +51,7 @@
#define TRUE !FALSE
#endif
//deprecated
#define SafeFree(__n) if(__n) { free(__n); __n = 0; }
#define SafeDelete(__n) if(__n) { delete(__n); __n = 0; }
#define SafeRelease(__n) if(__n) { __n->Release(); __n = 0; }
@ -78,14 +83,45 @@ typedef signed long long int64;
* templates
*****/
template<typename T> inline void safe_free(T &handle) {
if(handle) {
free(handle);
handle = 0;
}
}
template<typename T> inline void safe_delete(T &handle) {
if(handle) {
delete handle;
handle = 0;
}
}
template<typename T> inline void safe_release(T &handle) {
if(handle) {
handle->Release();
handle = 0;
}
}
template<typename T> inline void swap(T &x, T &y) {
T z = x;
x = y;
y = z;
}
#ifdef min
#undef min
#endif
#define min(x, y) ((x < y) ? x : y)
#ifdef max
#undef max
#endif
#define max(x, y) ((x > y) ? x : y)
template<int min, int max, typename T> inline T minmax(const T x) {
return (x < T(min)) ? T(min) : (x > T(max)) ? T(max) : x;
return (x < (T)min) ? (T)min : (x > (T)max) ? (T)max : x;
}
template<int bits> inline unsigned uclamp(const unsigned x) {
@ -243,6 +279,90 @@ typedef int_t<48, int64> int48;
* libc extensions
*****/
static uint8 fgetb(FILE *fp) { return fgetc(fp); }
static uint8 fgetlb(FILE *fp) { return fgetc(fp); }
static uint8 fgetmb(FILE *fp) { return fgetc(fp); }
static uint16 fgetlw(FILE *fp) {
return (fgetc(fp)) | (fgetc(fp) << 8);
}
static uint16 fgetmw(FILE *fp) {
return (fgetc(fp) << 8) | (fgetc(fp) << 8);
}
static uint32 fgetld(FILE *fp) {
return (fgetc(fp)) | (fgetc(fp) << 8) | (fgetc(fp) << 16) | (fgetc(fp) << 24);
}
static uint32 fgetmd(FILE *fp) {
return (fgetc(fp) << 24) | (fgetc(fp) << 16) | (fgetc(fp) << 8) | (fgetc(fp));
}
static uint64 fgetlq(FILE *fp) {
return ((uint64)fgetc(fp) << 0) | ((uint64)fgetc(fp) << 8) |
((uint64)fgetc(fp) << 16) | ((uint64)fgetc(fp) << 24) |
((uint64)fgetc(fp) << 32) | ((uint64)fgetc(fp) << 40) |
((uint64)fgetc(fp) << 48) | ((uint64)fgetc(fp) << 56);
}
static uint64 fgetmq(FILE *fp) {
return ((uint64)fgetc(fp) << 56) | ((uint64)fgetc(fp) << 48) |
((uint64)fgetc(fp) << 40) | ((uint64)fgetc(fp) << 32) |
((uint64)fgetc(fp) << 24) | ((uint64)fgetc(fp) << 16) |
((uint64)fgetc(fp) << 8) | ((uint64)fgetc(fp) << 0);
}
static void fputb(FILE *fp, uint8 data) { fputc(data, fp); }
static void fputlb(FILE *fp, uint8 data) { fputc(data, fp); }
static void fputmb(FILE *fp, uint8 data) { fputc(data, fp); }
static void fputlw(FILE *fp, uint16 data) {
fputc(data >> 0, fp);
fputc(data >> 8, fp);
}
static void fputmw(FILE *fp, uint16 data) {
fputc(data >> 8, fp);
fputc(data >> 0, fp);
}
static void fputld(FILE *fp, uint32 data) {
fputc(data >> 0, fp);
fputc(data >> 8, fp);
fputc(data >> 16, fp);
fputc(data >> 24, fp);
}
static void fputmd(FILE *fp, uint32 data) {
fputc(data >> 24, fp);
fputc(data >> 16, fp);
fputc(data >> 8, fp);
fputc(data >> 0, fp);
}
static void fputlq(FILE *fp, uint64 data) {
fputc(data >> 0, fp);
fputc(data >> 8, fp);
fputc(data >> 16, fp);
fputc(data >> 24, fp);
fputc(data >> 32, fp);
fputc(data >> 40, fp);
fputc(data >> 48, fp);
fputc(data >> 56, fp);
}
static void fputmq(FILE *fp, uint64 data) {
fputc(data >> 56, fp);
fputc(data >> 48, fp);
fputc(data >> 40, fp);
fputc(data >> 32, fp);
fputc(data >> 24, fp);
fputc(data >> 16, fp);
fputc(data >> 8, fp);
fputc(data >> 0, fp);
}
static bool fexists(const char *fn) {
FILE *fp = fopen(fn, "rb");
if(!fp)return false;
@ -270,7 +390,7 @@ uint32 size = ftell(fp);
return size;
}
inline int ftruncate(FILE *fp, long size) { return ftruncate(fileno(fp), size); }
static int ftruncate(FILE *fp, long size) { return ftruncate(fileno(fp), size); }
/*****
* crc32 calculation
@ -327,4 +447,12 @@ inline uint32 crc32_adjust(uint32 crc32, uint8 input) {
return ((crc32 >> 8) & 0x00ffffff) ^ crc32_table[(crc32 ^ input) & 0xff];
}
inline uint32 crc32_calculate(uint8 *data, uint length) {
uint32 crc32 = ~0;
for(uint i = 0; i < length; i++) {
crc32 = crc32_adjust(crc32, data[i]);
}
return ~crc32;
}
#endif

View File

@ -1,5 +1,5 @@
/*
libco_win32 : version 0.06 ~byuu (05/21/06)
libco_win32 : version 0.08 ~byuu (10/21/06)
win32-x86 implementation of libco
*/
@ -9,60 +9,62 @@
#include "libco_win32.h"
namespace libco_win32 {
bool co_enabled = false;
int co_stackptr = 0;
thread_t co_stack[4096];
void __stdcall coentry_proc(void *coentry) {
thread_p main = (thread_p)coentry;
main();
}
struct cothread_struct {
void *cohandle;
cothread_p coentry;
cothread_t colink;
};
void co_init() {
if(libco_win32::co_enabled == true)return;
libco_win32::co_enabled = true;
cothread_t __co_active = 0, __co_primary = 0;
void __stdcall co_entryproc(void *coentry) {
cothread_struct *s = static_cast<cothread_struct*>(coentry);
s->coentry();
co_exit(0);
}
cothread_t co_init() {
ConvertThreadToFiber(0);
cothread_struct *s = static_cast<cothread_struct*>(malloc(sizeof(cothread_struct)));
s->colink = 0;
s->coentry = 0;
s->cohandle = GetCurrentFiber();
__co_active = __co_primary = static_cast<cothread_t>(s);
return __co_active;
}
void co_term() {
/*****
//ConverFiberToThread() only exists on WinXP+
if(libco_win32::co_enabled == false)return;
libco_win32::co_enabled = false;
ConvertFiberToThread();
*****/
//primary fiber cannot be deleted; free memory used by handle to fiber only
free(__co_primary);
//ConvertFiberToThread(); //only exists on WinXP+
}
thread_t co_active() {
if(libco_win32::co_enabled == false)co_init();
return GetCurrentFiber();
cothread_t co_active() {
return __co_active;
}
thread_t co_create(thread_p coentry, unsigned int heapsize) {
if(libco_win32::co_enabled == false)co_init();
return CreateFiber(heapsize, libco_win32::coentry_proc, (void*)coentry);
cothread_t co_create(cothread_p coentry, unsigned int heapsize) {
cothread_struct *s = static_cast<cothread_struct*>(malloc(sizeof(cothread_struct)));
s->colink = co_active();
s->coentry = coentry;
s->cohandle = CreateFiber(heapsize + 512, co_entryproc, static_cast<void*>(s));
return static_cast<cothread_t>(s);
}
void co_delete(thread_t cothread) {
DeleteFiber(cothread);
void co_delete(cothread_t cothread) {
cothread_struct *s = static_cast<cothread_struct*>(cothread);
DeleteFiber(s->cohandle);
free(cothread);
}
void co_jump(thread_t cothread) {
SwitchToFiber(cothread);
void co_switch(cothread_t cothread) {
__co_active = cothread;
cothread_struct *s = static_cast<cothread_struct*>(cothread);
SwitchToFiber(s->cohandle);
}
void co_call(thread_t cothread) {
libco_win32::co_stack[libco_win32::co_stackptr++] = co_active();
co_jump(cothread);
}
void co_return() {
co_jump(libco_win32::co_stack[--libco_win32::co_stackptr]);
void co_exit(cothread_t cothread) {
if(cothread != 0) { co_switch(cothread); }
cothread_struct *s = static_cast<cothread_struct*>(__co_active);
co_switch(s->colink);
}

View File

@ -1,15 +1,20 @@
/*
libco_win32 : version 0.06 ~byuu (05/21/2006)
libco_win32 : version 0.08 ~byuu (10/21/2006)
*/
typedef void (*thread_t);
typedef void (*thread_p)();
#define COTHREAD_STACKSIZE_TINY 0x1000
#define COTHREAD_STACKSIZE_SMALL 0x4000
#define COTHREAD_STACKSIZE_NORMAL 0x10000
#define COTHREAD_STACKSIZE_LARGE 0x40000
#define COTHREAD_STACKSIZE_HUGE 0x100000
void co_init();
void co_term();
thread_t co_active();
thread_t co_create(thread_p coentry, unsigned int heapsize);
void co_delete(thread_t cothread);
void co_jump(thread_t cothread);
void co_call(thread_t cothread);
void co_return();
typedef void (*cothread_t);
typedef void (*cothread_p)(void);
cothread_t co_init();
void co_term();
cothread_t co_active();
cothread_t co_create(cothread_p coentry, unsigned int heapsize);
void co_delete(cothread_t cothread);
void co_switch(cothread_t cothread);
void co_exit(cothread_t cothread);

View File

@ -1,9 +1,9 @@
;*****
;libco_x86 : version 0.07 ~byuu (08/15/06)
;libco_x86 : version 0.08 ~byuu (10/21/06)
;cross-platform x86 implementation of libco
;
;context save/restore adheres to c/c++ ABI
;for x86 windows, linux and freebsd
;for x86 windows, osx, linux and freebsd
;
;context saves esp+ebp+esi+edi+ebx
;context ignores eax+ecx+edx
@ -14,8 +14,8 @@
section .data
align 4
co_initialized dd 0
co_active_context dd 0
co_primary_context dd 0
section .code
@ -31,9 +31,21 @@ section .code
%define co_active @co_active@0
%define co_create @co_create@8
%define co_delete @co_delete@4
%define co_jump @co_jump@4
%define co_call @co_call@4
%define co_return @co_return@0
%define co_switch @co_switch@4
%define co_exit @co_exit@4
%endif
%ifdef OSX86
%define malloc _malloc
%define free _free
%define co_init _co_init
%define co_term _co_term
%define co_active _co_active
%define co_create _co_create
%define co_delete _co_delete
%define co_switch _co_switch
%define co_exit _co_exit
%endif
extern malloc
@ -44,26 +56,22 @@ global co_term
global co_active
global co_create
global co_delete
global co_jump
global co_call
global co_return
global co_switch
global co_exit
;*****
;extern "C" void fastcall co_init();
;extern "C" cothread_t fastcall co_init();
;return = eax
;*****
align 16
co_init:
cmp dword[co_initialized],0 ;only run co_init once
jne .end
inc dword[co_initialized]
;create context for main thread
;create context for main cothread
mov ecx,0 ;entry point for main thread is not needed
mov edx,256 ;main thread uses default program stack
mov edx,512 ;main cothread uses default program stack
call co_create
mov dword[co_active_context],eax
.end
mov dword[co_primary_context],eax
ret
;*****
@ -72,24 +80,22 @@ co_init:
align 16
co_term:
mov ecx,dword[co_primary_context]
call co_delete
ret
;*****
;extern "C" thread_t fastcall co_active();
;extern "C" cothread_t fastcall co_active();
;return = eax
;*****
align 16
co_active:
cmp dword[co_initialized],0 ;make sure co_init has been called
jne .next
call co_init
.next:
mov eax,dword[co_active_context]
ret
;*****
;extern "C" thread_t fastcall co_create(thread_p coentry, unsigned int heapsize);
;extern "C" cothread_t fastcall co_create(cothread_p coentry, unsigned int heapsize);
;ecx = coentry
;edx = heapsize
;return = eax
@ -97,17 +103,8 @@ co_active:
align 16
co_create:
cmp dword[co_initialized],0 ;make sure co_init has been called
jne .next
push ecx
push edx
call co_init
pop edx
pop ecx
.next:
;create heap space (stack + register storage)
add edx,28 ;+8(esp+prev_call_context)+4(coentry)+16(stack_align)
add edx,512 ;+4(esp)+4(coentry)+4(colink)+256(stack_align)
push ecx
push edx
@ -119,10 +116,10 @@ co_create:
pop ecx
add edx,eax ;set edx to point to top of stack heap
and edx,0xfffffff0 ;force 16-byte alignment of stack heap
and edx,0xffffff00 ;force 256-byte alignment of stack heap
;store thread entry point + registers so that first call to co_jump will go to coentry
mov dword[edx-4],ecx ;edx=*stack,ecx=coentry
;store thread entry point + registers so that first call to co_switch will execute coentry
mov dword[edx-4],co_entrypoint ;edx=*stack
mov dword[edx-8],0
mov dword[edx-12],0
mov dword[edx-16],0
@ -130,13 +127,15 @@ co_create:
sub edx,20
;initialize context memory heap
mov dword[eax],edx ;thread_t[0-3] = stack heap pointer (esp)
mov dword[eax+4],0 ;thread_t[4-7] = (null) pointer to prev_call_context
mov dword[eax],edx ;cothread_t[ 0- 3] = stack heap pointer (esp)
mov dword[eax+4],ecx ;cothread_t[ 4- 7] = entry point
mov ecx,dword[co_active_context]
mov dword[eax+8],ecx ;cothread_t[ 8-11] = return context
ret ;return allocated memory block as thread handle
;*****
;extern "C" void fastcall co_delete(thread_t cothread);
;extern "C" void fastcall co_delete(cothread_t cothread);
;ecx = cothread
;*****
@ -148,12 +147,12 @@ co_delete:
ret
;*****
;extern "C" void fastcall co_jump(thread_t cothread);
;extern "C" void fastcall co_switch(cothread_t cothread);
;ecx = cothread
;*****
align 16
co_jump:
co_switch:
mov eax,dword[co_active_context] ;backup current context
mov dword[co_active_context],ecx ;set new active context
@ -172,50 +171,27 @@ co_jump:
ret
;*****
;extern "C" void fastcall co_call(thread_t cothread);
;extern "C" void fastcall co_exit(cothread_t cothread);
;ecx = cothread
;*****
align 16
co_call:
mov eax,dword[co_active_context] ;backup current context
mov dword[co_active_context],ecx ;set new active context
mov dword[ecx+4],eax
co_exit:
cmp ecx,0
jne co_switch
push ebp
push esi
push edi
push ebx
mov dword[eax],esp
mov esp,dword[ecx]
pop ebx
pop edi
pop esi
pop ebp
ret
;if cothread is null, switch to context that created current context
mov eax,dword[co_active_context]
mov ecx,dword[eax+8]
jmp co_switch
;*****
;extern "C" void fastcall co_return();
;void fastcall co_entrypoint();
;*****
align 16
co_return:
mov eax,dword[co_active_context] ;backup current context
mov ecx,dword[eax+4] ;restore pre-call context
mov dword[co_active_context],ecx ;set new active context
push ebp
push esi
push edi
push ebx
mov dword[eax],esp
mov esp,dword[ecx]
pop ebx
pop edi
pop esi
pop ebp
ret
co_entrypoint:
mov eax,dword[co_active_context]
call dword[eax+4]
xor ecx,ecx
jmp co_exit

View File

@ -1,15 +1,20 @@
/*
libco_x86 : version 0.06 ~byuu (05/21/2006)
libco_x86 : version 0.08 ~byuu (10/21/2006)
*/
typedef void (*thread_t);
typedef void (*thread_p)();
#define COTHREAD_STACKSIZE_TINY 0x1000
#define COTHREAD_STACKSIZE_SMALL 0x4000
#define COTHREAD_STACKSIZE_NORMAL 0x10000
#define COTHREAD_STACKSIZE_LARGE 0x40000
#define COTHREAD_STACKSIZE_HUGE 0x100000
extern "C" void fastcall co_init();
extern "C" void fastcall co_term();
extern "C" thread_t fastcall co_active();
extern "C" thread_t fastcall co_create(thread_p coentry, unsigned int heapsize);
extern "C" void fastcall co_delete(thread_t cothread);
extern "C" void fastcall co_jump(thread_t cothread);
extern "C" void fastcall co_call(thread_t cothread);
extern "C" void fastcall co_return();
typedef void (*cothread_t);
typedef void (*cothread_p)(void);
extern "C" cothread_t fastcall co_init();
extern "C" void fastcall co_term();
extern "C" cothread_t fastcall co_active();
extern "C" cothread_t fastcall co_create(cothread_p coentry, unsigned int heapsize);
extern "C" void fastcall co_delete(cothread_t cothread);
extern "C" void fastcall co_switch(cothread_t cothread);
extern "C" void fastcall co_exit(cothread_t cothread);

View File

@ -14,7 +14,7 @@ void Setting::set(uint _data) {
data = _data;
switch(type) {
case TRUE_FALSE:
case BOOL:
case ENABLED_DISABLED:
case ON_OFF:
case YES_NO:
@ -32,22 +32,20 @@ void Setting::set(uint _data) {
}
}
char *Setting::sget() {
char *Setting::strget() {
return strptr(char_data);
}
void Setting::sset(const char *_data) {
void Setting::strset(const char *_data) {
strcpy(char_data, _data);
strunquote(char_data);
}
Setting::Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type) {
int s;
if(_parent) {
_parent->add(this);
}
s = strlen(_name);
uint s = strlen(_name);
name = (char*)malloc(s + 1);
strcpy(name, _name);
@ -66,12 +64,11 @@ int s;
}
Setting::Setting(Config *_parent, char *_name, char *_desc, char *_data) {
int s;
if(_parent) {
_parent->add(this);
}
s = strlen(_name);
uint s = strlen(_name);
name = (char*)malloc(s + 1);
strcpy(name, _name);
@ -87,7 +84,7 @@ int s;
strcpy(char_data, _data);
strcpy(char_def, _data);
type = STR;
type = STRING;
}
void Config::add(Setting *setting) {
@ -95,18 +92,18 @@ void Config::add(Setting *setting) {
}
uint Config::string_to_uint(uint type, char *input) {
if(strmatch(input, "true") ||
strmatch(input, "enabled") ||
strmatch(input, "on") ||
strmatch(input, "yes")
if(!strcmp(input, "true") ||
!strcmp(input, "enabled") ||
!strcmp(input, "on") ||
!strcmp(input, "yes")
) {
return (uint)true;
}
if(strmatch(input, "false") ||
strmatch(input, "disabled") ||
strmatch(input, "off") ||
strmatch(input, "no")
if(!strcmp(input, "false") ||
!strcmp(input, "disabled") ||
!strcmp(input, "off") ||
!strcmp(input, "no")
) {
return (uint)false;
}
@ -121,7 +118,7 @@ uint Config::string_to_uint(uint type, char *input) {
char *Config::uint_to_string(uint type, uint input) {
static char output[512];
switch(type) {
case Setting::TRUE_FALSE:
case Setting::BOOL:
sprintf(output, "%s", (input & 1) ? "true" : "false");
break;
case Setting::ENABLED_DISABLED:
@ -144,7 +141,7 @@ static char output[512];
return output;
}
bool Config::load(char *fn) {
bool Config::load(const char *fn) {
FILE *fp;
fp = fopen(fn, "rb");
if(!fp)return false;
@ -172,11 +169,12 @@ char *buffer = (char*)malloc(fsize + 1);
qsplit(part, "=", line[i]);
for(int l = 0; l < list_count; l++) {
if(strmatch(list[l]->name, part[0])) {
if(!strcmp(list[l]->name, part[0])) {
if(list[l]->type != Setting::STR) {
list[l]->set(string_to_uint(list[l]->type, strptr(part[1])));
} else {
list[l]->sset(strptr(part[1]));
list[l]->strset(strptr(part[1]));
strunquote(list[l]->char_data);
}
}
}
@ -186,7 +184,7 @@ char *buffer = (char*)malloc(fsize + 1);
}
bool Config::load(string &fn) { return load(strptr(fn)); }
bool Config::save(char *fn) {
bool Config::save(const char *fn) {
FILE *fp;
fp = fopen(fn, "wb");
if(!fp)return false;
@ -198,7 +196,7 @@ FILE *fp;
for(int l = 0; l < count(line); l++) {
fprintf(fp, "# %s\r\n", strptr(line[l]));
}
if(list[i]->type != Setting::STR) {
if(list[i]->type != Setting::STRING) {
fprintf(fp, "# (default = %s)\r\n", uint_to_string(list[i]->type, list[i]->def));
fprintf(fp, "%s = %s\r\n\r\n", list[i]->name, uint_to_string(list[i]->type, list[i]->data));
} else {
@ -207,6 +205,7 @@ FILE *fp;
}
}
fclose(fp);
return true;
}
bool Config::save(string &fn) { return save(strptr(fn)); }

View File

@ -1,5 +1,5 @@
/*
libconfig : version 0.10 ~byuu (10/10/06)
libconfig : version 0.11 ~byuu (2006/11/12)
*/
#ifndef __LIBCONFIG
@ -30,16 +30,18 @@ enum {
HEX16 = 7,
HEX24 = 8,
HEX32 = 9,
STRING = 10,
STR = 10,
};
char *name, *desc;
string char_data, char_def;
virtual void toggle();
virtual uint get();
virtual void set(uint _data);
virtual char *sget();
virtual void sset(const char *_data);
virtual char *strget();
virtual void strset(const char *_data);
Setting(Config *_parent, char *_name, char *_desc, uint _data, uint _type);
Setting(Config *_parent, char *_name, char *_desc, char *_data);
@ -52,6 +54,12 @@ string char_data, char_def;
template<typename T> inline bool operator> (const T &x) { return (T)get() > x; }
template<typename T> inline bool operator<=(const T &x) { return (T)get() <= x; }
template<typename T> inline bool operator< (const T &x) { return (T)get() < x; }
inline operator char*() { return strget(); }
inline Setting &operator=(char *x) { strset(x); return *this; }
inline Setting &operator=(const char *x) { strset(x); return *this; }
inline bool operator==(const char *x) { return !strcmp(strget(), x); }
inline bool operator!=(const char *x) { return strcmp(strget(), x); }
};
class Config {
@ -67,9 +75,9 @@ char *uint_to_string(uint type, uint input);
public:
void add(Setting *setting);
bool load(char *fn);
bool load(const char *fn);
bool load(string &fn);
bool save(char *fn);
bool save(const char *fn);
bool save(string &fn);
Config();
};

View File

@ -1,5 +1,5 @@
/*
libfile : version 0.05 ~byuu (10/12/06)
libfile : version 0.05a ~byuu (10/26/06)
*/
#ifndef __LIBFILE
@ -51,10 +51,12 @@ uint32 crc32 = 0xffffffff;
inline void fread(file &s, uint8 *data, uint length) { s.read(data, length); }
inline uint8 fread(file &s) { return s.read(); }
inline uint8 fgetc(file &s) { return s.read(); }
inline uint fgetb(file &s) { return s.read(); }
inline void fwrite(file &s, uint8 *data, uint length) { s.write(data, length); }
inline void fwrite(file &s, uint8 data) { s.write(data); }
inline void fputc(file &s, uint8 data) { s.write(data); }
inline void fputc(uint8 data, file &s) { s.write(data); }
inline void fputb(file &s, uint8 data) { s.write(data); }
inline uint32 fcrc32(file &s) { return s.crc32(); }
@ -107,53 +109,53 @@ inline uint64 fgetmq(file &s) {
((uint64)fgetc(s) << 8) | ((uint64)fgetc(s) << 0);
}
inline void fputlb(file &s, uint8 data) { fputc(s, data); }
inline void fputmb(file &s, uint8 data) { fputc(s, data); }
inline void fputlb(file &s, uint8 data) { fputc(data, s); }
inline void fputmb(file &s, uint8 data) { fputc(data, s); }
inline void fputlw(file &s, uint16 data) {
fputc(s, data >> 0);
fputc(s, data >> 8);
fputc(data >> 0, s);
fputc(data >> 8, s);
}
inline void fputmw(file &s, uint16 data) {
fputc(s, data >> 8);
fputc(s, data >> 0);
fputc(data >> 8, s);
fputc(data >> 0, s);
}
inline void fputld(file &s, uint32 data) {
fputc(s, data >> 0);
fputc(s, data >> 8);
fputc(s, data >> 16);
fputc(s, data >> 24);
fputc(data >> 0, s);
fputc(data >> 8, s);
fputc(data >> 16, s);
fputc(data >> 24, s);
}
inline void fputmd(file &s, uint32 data) {
fputc(s, data >> 24);
fputc(s, data >> 16);
fputc(s, data >> 8);
fputc(s, data >> 0);
fputc(data >> 24, s);
fputc(data >> 16, s);
fputc(data >> 8, s);
fputc(data >> 0, s);
}
inline void fputlq(file &s, uint64 data) {
fputc(s, data >> 0);
fputc(s, data >> 8);
fputc(s, data >> 16);
fputc(s, data >> 24);
fputc(s, data >> 32);
fputc(s, data >> 40);
fputc(s, data >> 48);
fputc(s, data >> 56);
fputc(data >> 0, s);
fputc(data >> 8, s);
fputc(data >> 16, s);
fputc(data >> 24, s);
fputc(data >> 32, s);
fputc(data >> 40, s);
fputc(data >> 48, s);
fputc(data >> 56, s);
}
inline void fputmq(file &s, uint64 data) {
fputc(s, data >> 56);
fputc(s, data >> 48);
fputc(s, data >> 40);
fputc(s, data >> 32);
fputc(s, data >> 24);
fputc(s, data >> 16);
fputc(s, data >> 8);
fputc(s, data >> 0);
fputc(data >> 56, s);
fputc(data >> 48, s);
fputc(data >> 40, s);
fputc(data >> 32, s);
fputc(data >> 24, s);
fputc(data >> 16, s);
fputc(data >> 8, s);
fputc(data >> 0, s);
}
/*****

34
src/lib/libsort.h Normal file
View File

@ -0,0 +1,34 @@
/*
libsort : version 0.01 ~byuu (2006-11-15)
*/
#ifndef __LIBSORT
#define __LIBSORT
template<typename T>
void sort(T list[], uint length) {
for(uint d = 0; d < length; d++) {
uint min = d;
for(uint s = d + 1; s < length; s++) {
if(list[s] < list[min]) { min = s; }
}
if(min != d) {
swap(list[d], list[min]);
}
}
}
template<typename T, typename Tcmp>
void sort(T list[], uint length, Tcmp comparator) {
for(uint d = 0; d < length; d++) {
uint min = d;
for(uint s = d + 1; s < length; s++) {
if(comparator(list[s], list[min]) == true) { min = s; }
}
if(min != d) {
swap(list[d], list[min]);
}
}
}
#endif __LIBSORT

View File

@ -1,5 +1,6 @@
#include "libbase.h"
#include "libstring.h"
#include "libstring_oo.cpp"
uint count(stringarray &str) { return str.size(); }
@ -13,12 +14,6 @@ char chrupper(char c) {
return c;
}
void strresize(string &str, uint size) {
str.s = (char*)realloc(str.s, size + 1);
str.s[size] = 0;
str.size = size;
}
char *strptr(string &str) { return str.s; }
uint strlen(string &str) { return strlen(strptr(str)); }
@ -39,49 +34,41 @@ int stricmp(string &dest, const char *src) { return __stricmp(strptr(dest), src)
int stricmp(const char *dest, string &src) { return __stricmp(dest, strptr(src)); }
int stricmp(string &dest, string &src) { return __stricmp(strptr(dest), strptr(src)); }
bool strmatch(const char *dest, const char *src) { return !strcmp(dest, src); }
bool strmatch(string &dest, const char *src) { return strmatch(strptr(dest), src); }
bool strmatch(const char *dest, string &src) { return strmatch(dest, strptr(src)); }
bool strmatch(string &dest, string &src) { return strmatch(strptr(dest), strptr(src)); }
bool strimatch(const char *dest, const char *src) { return !stricmp(dest, src); }
bool strimatch(string &dest, const char *src) { return strimatch(strptr(dest), src); }
bool strimatch(const char *dest, string &src) { return strimatch(dest, strptr(src)); }
bool strimatch(string &dest, string &src) { return strimatch(strptr(dest), strptr(src)); }
void strcpy(string &dest, const char src) {
if(1 > dest.size) { strresize(dest, 1); }
dest.reserve(2);
dest.s[0] = src;
dest.s[1] = 0;
}
void strcpy(string &dest, const char *src) {
int srclen = strlen(src);
if(srclen > dest.size) { strresize(dest, srclen); }
dest.reserve(srclen);
strcpy(dest.s, src);
}
void strcpy(string &dest, string &src) { strcpy(dest, strptr(src)); }
//this differs from libc's strncpy in that it always
//appends a null terminator to the end of a copied string
void strncpy(string &dest, const char *src, uint32 length) {
int srclen = strlen(src);
//never copy more text than is in the string
if(srclen > length)srclen = length;
if(srclen > dest.size) { strresize(dest, srclen); }
strncpy(dest.s, src, srclen);
dest.s[srclen] = 0;
uint strlcpy(char *dest, const char *src, uint length) {
uint srclen = strlen(src);
length--;
if(length > srclen)length = srclen;
memcpy(dest, src, length);
dest[length] = 0;
return srclen;
}
void strncpy(string &dest, string &src, uint32 length) { strncpy(dest, strptr(src), length); }
void strset(string &dest, uint pos, uint8 c) {
if(pos > dest.size) { strresize(dest, pos); }
dest.s[pos] = c;
uint strlcpy(string &dest, const char *src, uint length) {
dest.reserve(length);
return strlcpy(strptr(dest), src, length);
}
uint strlcpy(string &dest, string &src, uint length) {
dest.reserve(length);
return strlcpy(strptr(dest), strptr(src), length);
}
void strcat(string &dest, const char src) {
int length = strlen(dest);
if(length + 1 > dest.size) { strresize(dest, length + 1); }
dest.reserve(length + 1);
dest.s[length] = src;
dest.s[length + 1] = 0;
}
@ -89,32 +76,62 @@ int length = strlen(dest);
void strcat(string &dest, const char *src) {
int srclen = strlen(src);
int destlen = strlen(dest);
if(srclen + destlen > dest.size) { strresize(dest, srclen + destlen); }
dest.reserve(srclen + destlen);
strcat(dest.s, src);
}
void strcat(string &dest, string &src) { strcat(dest, strptr(src)); }
uint strlcat(char *dest, const char *src, uint length) {
uint destlen = strlen(dest), srclen = strlen(src);
length--;
if(length > destlen + srclen)length = destlen + srclen;
memcpy(dest + destlen, src, length - destlen);
dest[length] = 0;
return destlen + srclen;
}
uint strlcat(string &dest, const char *src, uint length) {
dest.reserve(length);
return strlcat(strptr(dest), src, length);
}
uint strlcat(string &dest, string &src, uint length) {
dest.reserve(length);
return strlcat(strptr(dest), strptr(src), length);
}
string substr(string &dest, const char *src, uint start, uint length) {
string temp;
if(length == 0) {
//copy entire string
strcpy(temp, src + start);
} else {
//copy partial string
strlcpy(temp, src + start, length + 1);
}
return temp;
}
string substr(string &dest, string &src, uint start, uint length) { return substr(dest, strptr(src), start, length); }
void strinsert(string &dest, const char *src, uint pos) {
static string s;
strcpy(s, strptr(dest) + pos);
strset(dest, pos, 0);
string temp;
strcpy(temp, strptr(dest) + pos);
dest[pos] = 0;
strcat(dest, src);
strcat(dest, s);
strcat(dest, temp);
}
void strinsert(string &dest, string &src, uint pos) { strinsert(dest, strptr(src), pos); }
void strremove(string &dest, uint start, uint length) {
int destlen;
char *s;
int i, sl = strlen(dest.s);
if(start > dest.size) { strresize(dest, start); }
int i, destlen = strlen(dest);
dest.reserve(start);
if(!length) {
strset(dest, start, 0);
dest[start] = 0;
return;
}
s = dest.s;
for(i=start;i<sl;i++) { s[i] = s[i+length]; }
s[i] = 0;
for(i = start; i < destlen; i++) { dest.s[i] = dest.s[i + length]; }
dest.s[i] = 0;
}
char *strlower(char *str) {
@ -401,7 +418,7 @@ uint mask = 1000000000;
}
string &utoa(string &str, uint num) {
if(str.size < 16) { strresize(str, 16); }
str.reserve(16);
utoa(strptr(str), num);
return str;
}
@ -418,7 +435,7 @@ char *pstr = str;
}
string &itoa(string &str, uint num) {
if(str.size < 16) { strresize(str, 16); }
str.reserve(16);
itoa(strptr(str), num);
return str;
}
@ -441,7 +458,7 @@ uint mask = 28, r;
}
string &htoa(string &str, uint num) {
if(str.size < 16) { strresize(str, 16); }
str.reserve(16);
htoa(strptr(str), num);
return str;
}
@ -464,7 +481,7 @@ uint mask = 28, r;
}
string &uhtoa(string &str, uint num) {
if(str.size < 16) { strresize(str, 16); }
str.reserve(16);
uhtoa(strptr(str), num);
return str;
}
@ -485,7 +502,7 @@ uint mask = 0x80000000;
}
string &btoa(string &str, uint num) {
if(str.size < 48) { strresize(str, 48); }
str.reserve(48);
btoa(strptr(str), num);
return str;
}
@ -507,6 +524,7 @@ char *fdata = (char*)malloc(size + 1);
return true;
}
#include "libstring_int.cpp"
#include "libstring_math.cpp"
#include "libstring_split.cpp"
#include "libstring_replace.cpp"

View File

@ -1,5 +1,5 @@
/*
libstring : version 0.12 ~byuu (10/05/06)
libstring : version 0.14b ~byuu (2006/11/17)
*/
#ifndef __LIBSTRING
@ -15,10 +15,7 @@ char chrupper(char c);
uint count(stringarray &str);
void strresize(string &str, uint size);
char* strptr(string &str);
char *strptr(string &str);
uint strlen(string &str);
int strcmp(string &dest, const char *src);
@ -34,26 +31,21 @@ int stricmp(string &dest, const char *src);
int stricmp(const char *dest, string &src);
int stricmp(string &dest, string &src);
bool strmatch(const char *dest, const char *src);
bool strmatch(string &dest, const char *src);
bool strmatch(const char *dest, string &src);
bool strmatch(string &dest, string &src);
bool strimatch(const char *dest, const char *src);
bool strimatch(string &dest, const char *src);
bool strimatch(const char *dest, string &src);
bool strimatch(string &dest, string &src);
void strcpy(string &dest, const char *src);
void strcpy(string &dest, string &src);
void strncpy(string &dest, const char *src, uint32 length);
void strncpy(string &dest, string &src, uint32 length);
void strset(string &dest, uint pos, uint8 c);
uint strlcpy(char *dest, const char *src, uint length);
uint strlcpy(string &dest, const char *src, uint length);
uint strlcpy(string &dest, string &src, uint length);
void strcat(string &dest, const char src);
void strcat(string &dest, const char *src);
void strcat(string &dest, string &src);
uint strlcat(char *dest, const char *src, uint length);
uint strlcat(string &dest, const char *src, uint length);
uint strlcat(string &dest, string &src, uint length);
string substr(string &dest, const char *src, uint start = 0, uint length = 0);
string substr(string &dest, string &src, uint start = 0, uint length = 0);
void strinsert(string &dest, const char *src, uint pos);
void strinsert(string &dest, string &src, uint pos);
@ -143,6 +135,8 @@ string &btoa(string &str, uint num);
bool strfread(string &str, const char *filename);
string strfmt(const char *fmt, int num);
int strmath(const char *in_str);
int strmath(string &in_str);
@ -165,20 +159,68 @@ class string {
public:
char *s;
uint size;
void reserve(uint reqsize) {
if(reqsize > size) {
size = reqsize;
s = (char*)realloc(s, size + 1);
s[size] = 0;
}
}
void swap(string &str) {
::swap(s, str.s);
::swap(size, str.size);
}
string() {
size = 16;
s = (char*)malloc(size + 1);
*s = 0;
s[0] = 0;
}
~string() { SafeFree(s); }
void operator=(const string &p) {
SafeFree(s);
size = p.size;
string(const char *str) {
size = strlen(str);
s = (char*)malloc(size + 1);
strcpy(s, p.s);
strcpy(s, str);
}
string(string &str) {
size = strlen(str);
s = (char*)malloc(size + 1);
strcpy(s, strptr(str));
}
~string() { safe_free(s); }
const char *operator()();
char &operator[](uint);
string &operator=(int);
string &operator=(const char *);
string &operator=(string &);
string &operator+=(int);
string &operator+=(const char *);
string &operator+=(string &);
bool operator==(const char *);
bool operator==(string &);
bool operator!=(const char *);
bool operator!=(string &);
bool operator<(const char *);
bool operator<(string &);
bool operator<=(const char *);
bool operator<=(string &);
bool operator>(const char *);
bool operator>(string &);
bool operator>=(const char *);
bool operator>=(string &);
string operator+(int);
string operator+(const char *);
string operator+(string &);
};
string operator+(int, string &);
string operator+(const char *, string &);
inline void swap(string &x, string &y) { x.swap(y); }
#endif //__LIBSTRING

View File

@ -0,0 +1,5 @@
string strfmt(const char *fmt, int num) {
string temp;
sprintf(temp, fmt, num);
return temp;
}

83
src/lib/libstring_oo.cpp Normal file
View File

@ -0,0 +1,83 @@
const char *string::operator()() {
return s;
}
char &string::operator[](const uint index) {
reserve(index);
return s[index];
}
string &string::operator=(int num) {
strcpy(*this, strfmt("%d", num));
return *this;
}
string &string::operator=(const char *str) {
strcpy(*this, str);
return *this;
}
string &string::operator=(string &str) {
strcpy(*this, str);
return *this;
}
string &string::operator+=(int num) {
strcat(*this, strfmt("%d", num));
return *this;
}
string &string::operator+=(const char *str) {
strcat(*this, str);
return *this;
}
string &string::operator+=(string &str) {
strcat(*this, str);
return *this;
}
bool string::operator==(const char *str) { return strcmp(strptr(*this), str) == 0; }
bool string::operator==(string &str) { return strcmp(strptr(*this), strptr(str)) == 0; }
bool string::operator!=(const char *str) { return strcmp(strptr(*this), str) != 0; }
bool string::operator!=(string &str) { return strcmp(strptr(*this), strptr(str)) != 0; }
bool string::operator<(const char *str) { return strcmp(strptr(*this), str) < 0; }
bool string::operator<(string &str) { return strcmp(strptr(*this), strptr(str)) < 0; }
bool string::operator<=(const char *str) { return strcmp(strptr(*this), str) <= 0; }
bool string::operator<=(string &str) { return strcmp(strptr(*this), strptr(str)) <= 0; }
bool string::operator>(const char *str) { return strcmp(strptr(*this), str) > 0; }
bool string::operator>(string &str) { return strcmp(strptr(*this), strptr(str)) > 0; }
bool string::operator>=(const char *str) { return strcmp(strptr(*this), str) >= 0; }
bool string::operator>=(string &str) { return strcmp(strptr(*this), strptr(str)) >= 0; }
string string::operator+(int num) {
string temp(*this);
strcat(temp, strfmt("%d", num));
return temp;
}
string string::operator+(const char *str) {
string temp(*this);
strcat(temp, str);
return temp;
}
string string::operator+(string &str) {
string temp(*this);
strcat(temp, str);
return temp;
}
//
string operator+(int x, string &y) {
string temp(strfmt("%d", x));
strcat(temp, y);
return temp;
}
string operator+(const char *x, string &y) {
string temp(x);
strcat(temp, y);
return temp;
}

View File

@ -4,17 +4,17 @@ uint replace_count = 0, size = ssl;
char *data;
if(ksl > ssl)return str;
if(tsl > ksl) { //the new string may be longer than the old string...
for(i=0;i<=ssl-ksl;) { //so let's find out how big of a string we'll need...
for(i = 0; i <= ssl - ksl;) { //so let's find out how big of a string we'll need...
if(!memcmp(str.s + i, key, ksl)) {
replace_count++;
i += ksl;
} else i++;
}
size = ssl + ((tsl - ksl) * replace_count);
if(size > str.size)strresize(str, size);
str.reserve(size);
}
data = (char*)malloc(size + 1);
for(i=z=0;i<ssl;) {
for(i = z = 0; i < ssl;) {
if(i <= ssl - ksl) {
if(!memcmp(str.s + i, key, ksl)) {
memcpy(data + z, token, tsl);
@ -37,7 +37,7 @@ uint8 x;
char *data;
if(ksl > ssl)return str;
if(tsl > ksl) {
for(i=0;i<=ssl-ksl;) {
for(i = 0; i <= ssl - ksl;) {
x = str.s[i];
if(x == '\"' || x == '\'') {
l = i;
@ -55,10 +55,10 @@ char *data;
} else i++;
}
size = ssl + ((tsl - ksl) * replace_count);
if(size > str.size)strresize(str, size);
str.reserve(size);
}
data = (char*)malloc(size + 1);
for(i=z=0;i<ssl;) {
for(i = z = 0; i < ssl;) {
x = str.s[i];
if(x == '\"' || x == '\'') {
l = i++;

View File

@ -5,7 +5,7 @@ int ssl = strlen(src), ksl = strlen(key);
int lp = 0, split_count = 0;
for(int i = 0; i <= ssl - ksl;) {
if(!memcmp(src + i, key, ksl)) {
strncpy(dest[split_count++], src + lp, i - lp);
strlcpy(dest[split_count++], src + lp, i - lp + 1);
i += ksl;
lp = i;
} else i++;
@ -27,7 +27,7 @@ int lp = 0, split_count = 0;
if(i >= ssl)i = z;
}
if(!memcmp(src + i, key, ksl)) {
strncpy(dest[split_count++], src + lp, i - lp);
strlcpy(dest[split_count++], src + lp, i - lp + 1);
i += ksl;
lp = i;
} else i++;

View File

@ -8,7 +8,7 @@ uint length = vsprintf(str, s, args);
uint vsprintf(string &str, const char *s, va_list args) {
uint length = vsnprintf(0, 0, s, args);
strresize(str, length + 1);
str.reserve(length + 1);
return vsprintf(strptr(str), s, args);
}

View File

@ -226,33 +226,33 @@ uint ptr = 0;
template<typename FTO, typename FTM, typename FTP>
void UPS<FTO, FTM, FTP>::ptr_write(uint ptr) {
if(ptr <= 0xf7) {
fputc(patch.fp, ptr);
fputb(patch.fp, ptr);
return;
}
ptr -= 0xf8;
if(ptr <= 0xffff) {
fputc(patch.fp, 0xf8);
fputc(patch.fp, ptr);
fputc(patch.fp, ptr >> 8);
fputb(patch.fp, 0xf8);
fputb(patch.fp, ptr);
fputb(patch.fp, ptr >> 8);
return;
}
ptr -= 0x10000;
if(ptr <= 0xffffff) {
fputc(patch.fp, 0xf9);
fputc(patch.fp, ptr);
fputc(patch.fp, ptr >> 8);
fputc(patch.fp, ptr >> 16);
fputb(patch.fp, 0xf9);
fputb(patch.fp, ptr);
fputb(patch.fp, ptr >> 8);
fputb(patch.fp, ptr >> 16);
return;
}
ptr -= 0x1000000;
fputc(patch.fp, 0xfa);
fputc(patch.fp, ptr);
fputc(patch.fp, ptr >> 8);
fputc(patch.fp, ptr >> 16);
fputc(patch.fp, ptr >> 24);
fputb(patch.fp, 0xfa);
fputb(patch.fp, ptr);
fputb(patch.fp, ptr >> 8);
fputb(patch.fp, ptr >> 16);
fputb(patch.fp, ptr >> 24);
}
template<typename FTO, typename FTM, typename FTP>
@ -298,14 +298,14 @@ uint last_ptr = 0, rle_count, last_out, rep_count;
ptr_write((i - 1) - last_ptr);
//data
fputc(patch.fp, r);
fputb(patch.fp, r);
last_out = r;
rep_count = 0;
do {
r = fgetc(original) ^ fgetc(modified);
i++;
fputc(patch.fp, r);
fputb(patch.fp, r);
if(last_out != r) {
rep_count = 0;
@ -319,7 +319,7 @@ uint last_ptr = 0, rle_count, last_out, rep_count;
} while(i < largest_filesize);
ptr_write(rle_count);
if(i < largest_filesize) { fputc(patch.fp, r); }
if(i < largest_filesize) { fputb(patch.fp, r); }
rep_count = 0;
}
}
@ -331,7 +331,7 @@ uint last_ptr = 0, rle_count, last_out, rep_count;
last_ptr = i;
}
fputc(patch.fp, 0xff);
fputb(patch.fp, 0xff);
}
template<typename FTO, typename FTM, typename FTP>
@ -385,7 +385,7 @@ void UPS<FTO, FTM, FTP>::apply_linear() {
fseek(original, 0, file::seek_start);
fseek(modified, 0, file::seek_start);
for(uint i = 0; i < modified_filesize; i++) {
fputc(modified, fgetc(original));
fputb(modified, fgetc(original));
}
fseek(original, 0, file::seek_start);
@ -408,14 +408,14 @@ uint rle_count, last_in, rep_count;
if(ftell(modified) >= modified_filesize) { break; }
uint8 r = fgetc(patch.fp);
fputc(modified, r ^ fgetc(original));
fputb(modified, r ^ fgetc(original));
if(r != last_in) {
rep_count = 0;
} else {
if(++rep_count == (3 - 1)) {
rle_count = ptr_read();
while(rle_count-- && ftell(modified) < modified_filesize) {
fputc(modified, r ^ fgetc(original));
fputb(modified, r ^ fgetc(original));
}
rep_count = 0;
}

View File

@ -14,12 +14,12 @@ bool Button::Create(Window *parent_window, const char *style, int x, int y, int
stringarray part;
ParseStyleParam(style, part);
for(int i = 0; i < count(part); i++) {
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
if(!strcmp(part[i], "visible"))state.ws |= WS_VISIBLE;
if(!strcmp(part[i], "disabled"))state.ws |= WS_DISABLED;
if(strmatch(part[i], "left"))state.ws |= BS_LEFT;
if(strmatch(part[i], "center"))state.ws |= BS_CENTER;
if(strmatch(part[i], "right"))state.ws |= BS_RIGHT;
if(!strcmp(part[i], "left"))state.ws |= BS_LEFT;
if(!strcmp(part[i], "center"))state.ws |= BS_CENTER;
if(!strcmp(part[i], "right"))state.ws |= BS_RIGHT;
}
hwnd = CreateWindowEx(state.es, "BUTTON", text, state.ws,

View File

@ -20,13 +20,13 @@ bool Checkbox::Create(Window *parent_window, const char *style, int x, int y, in
stringarray part;
ParseStyleParam(style, part);
for(int i = 0; i < count(part); i++) {
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
if(!strcmp(part[i], "visible"))state.ws |= WS_VISIBLE;
if(!strcmp(part[i], "disabled"))state.ws |= WS_DISABLED;
if(strmatch(part[i], "left"))state.ws |= BS_LEFT;
if(strmatch(part[i], "center"))state.ws |= BS_CENTER;
if(strmatch(part[i], "right"))state.ws |= BS_RIGHT;
if(strmatch(part[i], "auto"))state.ws |= BS_AUTOCHECKBOX;
if(!strcmp(part[i], "left"))state.ws |= BS_LEFT;
if(!strcmp(part[i], "center"))state.ws |= BS_CENTER;
if(!strcmp(part[i], "right"))state.ws |= BS_RIGHT;
if(!strcmp(part[i], "auto"))state.ws |= BS_AUTOCHECKBOX;
}
if(!(state.ws & BS_AUTOCHECKBOX))state.ws |= BS_CHECKBOX;

View File

@ -38,13 +38,13 @@ bool Combobox::Create(Window *parent_window, const char *style, int x, int y, in
stringarray part;
ParseStyleParam(style, part);
for(int i = 0; i < count(part); i++) {
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
if(strmatch(part[i], "border"))state.ws |= WS_BORDER;
if(strmatch(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(!strcmp(part[i], "visible"))state.ws |= WS_VISIBLE;
if(!strcmp(part[i], "disabled"))state.ws |= WS_DISABLED;
if(!strcmp(part[i], "border"))state.ws |= WS_BORDER;
if(!strcmp(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(strmatch(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(strmatch(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
if(!strcmp(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(!strcmp(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
}
hwnd = CreateWindowEx(state.es, "COMBOBOX", text, state.ws,
@ -52,7 +52,7 @@ stringarray part;
parent->hwnd, (HMENU)id, GetModuleHandle(0), 0);
if(!hwnd)return false;
if(strmatch(text, "") == false) {
if(!strcmp(text, "") == false) {
stringarray t;
split(t, "|", text);
for(int i = 0; i < ::count(t); i++) {

View File

@ -74,12 +74,12 @@ void Control::GetText(char *text, uint length) {
}
void Control::SetText(const char *text, ...) {
char str[4096];
string str;
va_list args;
va_start(args, text);
vsprintf(str, text, args);
va_end(args);
SetWindowText(hwnd, str);
SetWindowText(hwnd, strptr(str));
}
Control::Control() {

View File

@ -19,18 +19,18 @@ bool Editbox::Create(Window *parent_window, const char *style, int x, int y, int
stringarray part;
ParseStyleParam(style, part);
for(int i = 0; i < count(part); i++) {
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
if(strmatch(part[i], "border"))state.ws |= WS_BORDER;
if(strmatch(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(strmatch(part[i], "vscroll"))state.ws |= WS_VSCROLL;
if(strmatch(part[i], "hscroll"))state.ws |= WS_HSCROLL;
if(!strcmp(part[i], "visible"))state.ws |= WS_VISIBLE;
if(!strcmp(part[i], "disabled"))state.ws |= WS_DISABLED;
if(!strcmp(part[i], "border"))state.ws |= WS_BORDER;
if(!strcmp(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(!strcmp(part[i], "vscroll"))state.ws |= WS_VSCROLL;
if(!strcmp(part[i], "hscroll"))state.ws |= WS_HSCROLL;
if(strmatch(part[i], "multiline"))state.ws |= ES_MULTILINE;
if(strmatch(part[i], "readonly"))state.ws |= ES_READONLY;
if(!strcmp(part[i], "multiline"))state.ws |= ES_MULTILINE;
if(!strcmp(part[i], "readonly"))state.ws |= ES_READONLY;
if(strmatch(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(strmatch(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
if(!strcmp(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(!strcmp(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
}
hwnd = CreateWindowEx(state.es, "EDIT", text, state.ws,

View File

@ -14,13 +14,13 @@ bool Groupbox::Create(Window *parent_window, const char *style, int x, int y, in
stringarray part;
ParseStyleParam(style, part);
for(int i = 0; i < count(part); i++) {
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
if(strmatch(part[i], "border"))state.ws |= WS_BORDER;
if(strmatch(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(!strcmp(part[i], "visible"))state.ws |= WS_VISIBLE;
if(!strcmp(part[i], "disabled"))state.ws |= WS_DISABLED;
if(!strcmp(part[i], "border"))state.ws |= WS_BORDER;
if(!strcmp(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(strmatch(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(strmatch(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
if(!strcmp(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(!strcmp(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
}
hwnd = CreateWindowEx(state.es, "BUTTON", text, state.ws,

View File

@ -14,18 +14,18 @@ bool Label::Create(Window *parent_window, const char *style, int x, int y, int w
stringarray part;
ParseStyleParam(style, part);
for(int i = 0; i < count(part); i++) {
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
if(strmatch(part[i], "border"))state.ws |= WS_BORDER;
if(strmatch(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(!strcmp(part[i], "visible"))state.ws |= WS_VISIBLE;
if(!strcmp(part[i], "disabled"))state.ws |= WS_DISABLED;
if(!strcmp(part[i], "border"))state.ws |= WS_BORDER;
if(!strcmp(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(strmatch(part[i], "left"))state.ws |= SS_LEFT;
if(strmatch(part[i], "center"))state.ws |= SS_CENTER;
if(strmatch(part[i], "right"))state.ws |= SS_RIGHT;
if(strmatch(part[i], "etched"))state.ws |= SS_ETCHEDFRAME;
if(!strcmp(part[i], "left"))state.ws |= SS_LEFT;
if(!strcmp(part[i], "center"))state.ws |= SS_CENTER;
if(!strcmp(part[i], "right"))state.ws |= SS_RIGHT;
if(!strcmp(part[i], "etched"))state.ws |= SS_ETCHEDFRAME;
if(strmatch(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(strmatch(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
if(!strcmp(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(!strcmp(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
}
hwnd = CreateWindowEx(state.es, "STATIC", text, state.ws,

View File

@ -38,13 +38,13 @@ bool Listbox::Create(Window *parent_window, const char *style, int x, int y, int
stringarray part;
ParseStyleParam(style, part);
for(int i = 0; i < count(part); i++) {
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
if(strmatch(part[i], "border"))state.ws |= WS_BORDER;
if(strmatch(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(!strcmp(part[i], "visible"))state.ws |= WS_VISIBLE;
if(!strcmp(part[i], "disabled"))state.ws |= WS_DISABLED;
if(!strcmp(part[i], "border"))state.ws |= WS_BORDER;
if(!strcmp(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(strmatch(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(strmatch(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
if(!strcmp(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(!strcmp(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
}
hwnd = CreateWindowEx(state.es, "LISTBOX", text, state.ws,
@ -52,7 +52,7 @@ stringarray part;
parent->hwnd, (HMENU)id, GetModuleHandle(0), 0);
if(!hwnd)return false;
if(strmatch(text, "") == false) {
if(!strcmp(text, "") == false) {
stringarray t;
split(t, "|", text);
for(int i = 0; i < ::count(t); i++) {

View File

@ -75,13 +75,13 @@ bool Listview::Create(Window *parent_window, const char *style, int x, int y, in
stringarray part;
ParseStyleParam(style, part);
for(int i = 0; i < count(part); i++) {
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
if(strmatch(part[i], "border"))state.ws |= WS_BORDER;
if(strmatch(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(!strcmp(part[i], "visible"))state.ws |= WS_VISIBLE;
if(!strcmp(part[i], "disabled"))state.ws |= WS_DISABLED;
if(!strcmp(part[i], "border"))state.ws |= WS_BORDER;
if(!strcmp(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(strmatch(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(strmatch(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
if(!strcmp(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(!strcmp(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
}
hwnd = CreateWindowEx(state.es, WC_LISTVIEW, text, state.ws,

View File

@ -20,12 +20,12 @@ bool Radiobox::Create(Window *parent_window, const char *style, int x, int y, in
stringarray part;
ParseStyleParam(style, part);
for(int i = 0; i < count(part); i++) {
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
if(!strcmp(part[i], "visible"))state.ws |= WS_VISIBLE;
if(!strcmp(part[i], "disabled"))state.ws |= WS_DISABLED;
if(strmatch(part[i], "left"))state.ws |= BS_LEFT;
if(strmatch(part[i], "center"))state.ws |= BS_CENTER;
if(strmatch(part[i], "right"))state.ws |= BS_RIGHT;
if(!strcmp(part[i], "left"))state.ws |= BS_LEFT;
if(!strcmp(part[i], "center"))state.ws |= BS_CENTER;
if(!strcmp(part[i], "right"))state.ws |= BS_RIGHT;
}
state.ws |= BS_RADIOBUTTON;

View File

@ -28,13 +28,13 @@ bool Slider::Create(Window *parent_window, const char *style, int x, int y, int
stringarray part;
ParseStyleParam(style, part);
for(int i = 0; i < count(part); i++) {
if(strmatch(part[i], "visible"))state.ws |= WS_VISIBLE;
if(strmatch(part[i], "disabled"))state.ws |= WS_DISABLED;
if(strmatch(part[i], "border"))state.ws |= WS_BORDER;
if(strmatch(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(!strcmp(part[i], "visible"))state.ws |= WS_VISIBLE;
if(!strcmp(part[i], "disabled"))state.ws |= WS_DISABLED;
if(!strcmp(part[i], "border"))state.ws |= WS_BORDER;
if(!strcmp(part[i], "raised"))state.ws |= WS_DLGFRAME;
if(strmatch(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(strmatch(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
if(!strcmp(part[i], "sunken"))state.es |= WS_EX_STATICEDGE;
if(!strcmp(part[i], "edge"))state.es |= WS_EX_CLIENTEDGE;
}
hwnd = CreateWindowEx(state.es, TRACKBAR_CLASS, text, state.ws,

View File

@ -257,20 +257,20 @@ void Window::SetStyle(const char *style) {
stringarray part;
ParseStyleParam(style, part);
for(int i = 0; i < count(part); i++) {
if(strmatch(part[i], "visible")) state.ws |= WS_VISIBLE;
if(strmatch(part[i], "popup")) state.ws |= WS_POPUP;
if(strmatch(part[i], "border")) state.ws |= WS_BORDER;
if(strmatch(part[i], "frame")) state.ws |= WS_DLGFRAME;
if(strmatch(part[i], "titlebar"))state.ws |= WS_CAPTION;
if(strmatch(part[i], "minimize"))state.ws |= WS_MINIMIZEBOX;
if(strmatch(part[i], "maximize"))state.ws |= WS_MAXIMIZEBOX;
if(!strcmp(part[i], "visible")) state.ws |= WS_VISIBLE;
if(!strcmp(part[i], "popup")) state.ws |= WS_POPUP;
if(!strcmp(part[i], "border")) state.ws |= WS_BORDER;
if(!strcmp(part[i], "frame")) state.ws |= WS_DLGFRAME;
if(!strcmp(part[i], "titlebar"))state.ws |= WS_CAPTION;
if(!strcmp(part[i], "minimize"))state.ws |= WS_MINIMIZEBOX;
if(!strcmp(part[i], "maximize"))state.ws |= WS_MAXIMIZEBOX;
if(strmatch(part[i], "topmost")) state.es |= WS_EX_TOPMOST;
if(strmatch(part[i], "layered")) state.es |= WS_EX_LAYERED;
if(strmatch(part[i], "sunken")) state.es |= WS_EX_STATICEDGE;
if(strmatch(part[i], "edge")) state.es |= WS_EX_CLIENTEDGE;
if(!strcmp(part[i], "topmost")) state.es |= WS_EX_TOPMOST;
if(!strcmp(part[i], "layered")) state.es |= WS_EX_LAYERED;
if(!strcmp(part[i], "sunken")) state.es |= WS_EX_STATICEDGE;
if(!strcmp(part[i], "edge")) state.es |= WS_EX_CLIENTEDGE;
if(strmatch(part[i], "dragmove"))state.dragmove = true;
if(!strcmp(part[i], "dragmove"))state.dragmove = true;
}
if(!hwnd)return;

View File

@ -71,7 +71,7 @@ char t[4096];
i++;
while(1) {
if(strptr(line[i])[1] == ':' || strptr(line[i])[2] == ':' || strmatch(line[i], "}"))break;
if(strptr(line[i])[1] == ':' || strptr(line[i])[2] == ':' || line[i] == "}")break;
update_line(i);
strcat(output_op, line[i]);

View File

@ -38,9 +38,9 @@ void bMemBus::load_cart() {
uint region = read(0xffd9) & 0x7f;
cartridge.info.region = (region <= 1 || region >= 13) ? Cartridge::NTSC : Cartridge::PAL;
if(cartridge.info.region == Cartridge::NTSC) {
snes->set_region(SNES::NTSC);
snes.set_region(SNES::NTSC);
} else {
snes->set_region(SNES::PAL);
snes.set_region(SNES::PAL);
}
rom_loaded = true;

View File

@ -24,7 +24,7 @@ uint ram_size = cartridge.info.ram_size;
uint addr = page << 8;
uint bank = page >> 8;
//SRAM mapping is incorrect in several games, this is the most compatible
//RAM mapping is incorrect in several games, this is the most compatible
//layout I can create using only ROM header information. Additional accuracy
//requires PCB identification.
@ -34,20 +34,20 @@ uint ram_size = cartridge.info.ram_size;
continue;
}
//HiROM SRAM region
//HiROM RAM region
//$[20-3f|a0-bf]:[6000-7fff]
if((bank & 0x7f) >= 0x20 && (bank & 0x7f) <= 0x3f && (addr & 0xe000) == 0x6000) {
if(ram_size == 0)continue;
addr = ((bank & 0x7f) - 0x20) * 0x2000 + ((addr & 0xffff) - 0x6000);
addr %= ram_size;
page_handle[page] = cartridge.sram + addr;
page_handle[page] = cartridge.ram + addr;
page_read [page] = &bMemBus::read_ram;
page_write [page] = &bMemBus::write_ram;
continue;
}
//LoROM SRAM region
//LoROM RAM region
//$[70-7f|f0-ff]:[0000-7fff]
//Note: WRAM is remapped over $[7e-7f]:[0000-ffff]
if((bank & 0x7f) >= 0x70 && (bank & 0x7f) <= 0x7f && (addr & 0x8000) == 0x0000) {
@ -57,7 +57,7 @@ uint ram_size = cartridge.info.ram_size;
addr = ((bank & 0x7f) - 0x70) * 0x8000 + (addr & 0x7fff);
addr %= ram_size;
page_handle[page] = cartridge.sram + addr;
page_handle[page] = cartridge.ram + addr;
page_read [page] = &bMemBus::read_ram;
page_write [page] = &bMemBus::write_ram;
continue;

View File

@ -1,16 +1,3 @@
uint bMemBus::mirror(uint size, uint pos) {
if(size == 0)return 0;
if(pos < size)return pos;
uint mask = 1 << 31;
while(!(pos & mask))mask >>= 1;
if(size <= (pos & mask)) {
return mirror(size, pos - mask);
} else {
return mask + mirror(size - mask, pos - mask);
}
}
bool bMemBus::cart_map_pcb(const char *pcb) {
if(!strcmp(pcb, "SHVC-1A3B-01")) { cart_map_shvc_1a3b_13(); return true; }
if(!strcmp(pcb, "SHVC-1A3B-11")) { cart_map_shvc_1a3b_13(); return true; }
@ -35,9 +22,26 @@ bool bMemBus::cart_map_pcb(const char *pcb) {
if(!strcmp(pcb, "BSC-1A7M-10")) { cart_map_bsc_1a7m_10(); return true; }
if(!strcmp(pcb, "STC-SOLO")) { cart_map_stc_solo(); return true; }
if(!strcmp(pcb, "STC-DUAL")) { cart_map_stc_dual(); return true; }
return false;
}
uint bMemBus::mirror(uint size, uint pos) {
if(size == 0)return 0;
if(pos < size)return pos;
uint mask = 1 << 31;
while(!(pos & mask))mask >>= 1;
if(size <= (pos & mask)) {
return mirror(size, pos - mask);
} else {
return mask + mirror(size - mask, pos - mask);
}
}
void bMemBus::cart_map_range(
uint mode,
uint8 bank_lo, uint8 bank_hi,
@ -59,7 +63,7 @@ uint8 page_hi = (addr_hi >> 8) & 255;
} break;
case MAP_RAM: {
data = cartridge.sram;
data = cartridge.ram;
size = cartridge.info.ram_size;
} break;

View File

@ -26,4 +26,6 @@ enum {
mapper(bsc_1a5m_01);
mapper(bsc_1a7m_01);
mapper(bsc_1a7m_10);
mapper(stc_solo);
mapper(stc_dual);
#undef mapper

View File

@ -76,3 +76,27 @@ mapper(bsc_1a7m_10) {
map(LINEAR, 0xa0, 0xbf, 0x8000, 0xffff, MAP_ROM, 0x100000);
map(LINEAR, 0xf0, 0xff, 0x0000, 0x7fff, MAP_RAM);
}
//STC-SOLO
mapper(stc_solo) {
map(LINEAR, 0x00, 0x1f, 0x8000, 0xffff, MAP_ROM, 0x000000);
map(LINEAR, 0x20, 0x3f, 0x8000, 0xffff, MAP_ROM, 0x100000);
map(LINEAR, 0x60, 0x63, 0x8000, 0xffff, MAP_RAM, 0x000000);
map(LINEAR, 0x80, 0x9f, 0x8000, 0xffff, MAP_ROM, 0x000000);
map(LINEAR, 0xa0, 0xbf, 0x8000, 0xffff, MAP_ROM, 0x100000);
map(LINEAR, 0xe0, 0xe3, 0x8000, 0xffff, MAP_RAM, 0x000000);
}
//STC-DUAL
mapper(stc_dual) {
map(LINEAR, 0x00, 0x1f, 0x8000, 0xffff, MAP_ROM, 0x000000);
map(LINEAR, 0x20, 0x3f, 0x8000, 0xffff, MAP_ROM, 0x100000);
map(LINEAR, 0x40, 0x5f, 0x8000, 0xffff, MAP_ROM, 0x200000);
map(LINEAR, 0x60, 0x63, 0x8000, 0xffff, MAP_RAM, 0x000000);
map(LINEAR, 0x70, 0x73, 0x8000, 0xffff, MAP_RAM, 0x020000);
map(LINEAR, 0x80, 0x9f, 0x8000, 0xffff, MAP_ROM, 0x000000);
map(LINEAR, 0xa0, 0xbf, 0x8000, 0xffff, MAP_ROM, 0x100000);
map(LINEAR, 0xc0, 0xdf, 0x8000, 0xffff, MAP_ROM, 0x200000);
map(LINEAR, 0xe0, 0xe3, 0x8000, 0xffff, MAP_RAM, 0x000000);
map(LINEAR, 0xf0, 0xf3, 0x8000, 0xffff, MAP_RAM, 0x020000);
}

View File

@ -65,8 +65,17 @@ void bPPU::render_scanline() {
#endif
if(line.y >= 0 && line.y < (r_cpu->overscan() ? 240 : 225)) {
if(status.render_output == true && line.y != 0) { render_line(); }
render_line_oam_rto();
if(config::ppu.hack.obj_cache == false) {
if(line.y != 0) {
render_line_oam_rto();
render_line();
}
} else {
if(line.y != 0) {
render_line();
}
render_line_oam_rto();
}
}
}
@ -81,7 +90,7 @@ void bPPU::power() {
memset(oam, 0, 544);
memset(cgram, 0, 512);
region = snes->region();
region = snes.region();
//$2100
regs.display_disabled = 1;

View File

@ -189,7 +189,7 @@ void bPPU::mmio_w210d(uint8 value) {
regs.m7_hofs = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
regs.bg_hofs[BG1] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG1] >> 8) & 7);
regs.bg_hofs[BG1] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG1] >> 8) & 7);
regs.bg_ofslatch = value;
}
@ -198,43 +198,43 @@ void bPPU::mmio_w210e(uint8 value) {
regs.m7_vofs = (value << 8) | regs.m7_latch;
regs.m7_latch = value;
regs.bg_vofs[BG1] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG1] >> 8) & 7);
regs.bg_vofs[BG1] = (value << 8) | (regs.bg_ofslatch);
regs.bg_ofslatch = value;
}
//BG2HOFS
void bPPU::mmio_w210f(uint8 value) {
regs.bg_hofs[BG2] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG2] >> 8) & 7);
regs.bg_hofs[BG2] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG2] >> 8) & 7);
regs.bg_ofslatch = value;
}
//BG2VOFS
void bPPU::mmio_w2110(uint8 value) {
regs.bg_vofs[BG2] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG2] >> 8) & 7);
regs.bg_vofs[BG2] = (value << 8) | (regs.bg_ofslatch);
regs.bg_ofslatch = value;
}
//BG3HOFS
void bPPU::mmio_w2111(uint8 value) {
regs.bg_hofs[BG3] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG3] >> 8) & 7);
regs.bg_hofs[BG3] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG3] >> 8) & 7);
regs.bg_ofslatch = value;
}
//BG3VOFS
void bPPU::mmio_w2112(uint8 value) {
regs.bg_vofs[BG3] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG3] >> 8) & 7);
regs.bg_vofs[BG3] = (value << 8) | (regs.bg_ofslatch);
regs.bg_ofslatch = value;
}
//BG4HOFS
void bPPU::mmio_w2113(uint8 value) {
regs.bg_hofs[BG4] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_hofs[BG4] >> 8) & 7);
regs.bg_hofs[BG4] = (value << 8) | (regs.bg_ofslatch & ~7) | ((regs.bg_hofs[BG4] >> 8) & 7);
regs.bg_ofslatch = value;
}
//BG4VOFS
void bPPU::mmio_w2114(uint8 value) {
regs.bg_vofs[BG4] = (value << 8) | (regs.bg_ofslatch & 0xf8) | ((regs.bg_vofs[BG4] >> 8) & 7);
regs.bg_vofs[BG4] = (value << 8) | (regs.bg_ofslatch);
regs.bg_ofslatch = value;
}

View File

@ -1,24 +1,24 @@
#define render_bg_tile_line_2bpp(mask) \
col = bool(d0 & mask) << 0; \
col += bool(d1 & mask) << 1; \
col = !!(d0 & mask) << 0; \
col += !!(d1 & mask) << 1; \
*dest++ = col
#define render_bg_tile_line_4bpp(mask) \
col = bool(d0 & mask) << 0; \
col += bool(d1 & mask) << 1; \
col += bool(d2 & mask) << 2; \
col += bool(d3 & mask) << 3; \
col = !!(d0 & mask) << 0; \
col += !!(d1 & mask) << 1; \
col += !!(d2 & mask) << 2; \
col += !!(d3 & mask) << 3; \
*dest++ = col
#define render_bg_tile_line_8bpp(mask) \
col = bool(d0 & mask) << 0; \
col += bool(d1 & mask) << 1; \
col += bool(d2 & mask) << 2; \
col += bool(d3 & mask) << 3; \
col += bool(d4 & mask) << 4; \
col += bool(d5 & mask) << 5; \
col += bool(d6 & mask) << 6; \
col += bool(d7 & mask) << 7; \
col = !!(d0 & mask) << 0; \
col += !!(d1 & mask) << 1; \
col += !!(d2 & mask) << 2; \
col += !!(d3 & mask) << 3; \
col += !!(d4 & mask) << 4; \
col += !!(d5 & mask) << 5; \
col += !!(d6 & mask) << 6; \
col += !!(d7 & mask) << 7; \
*dest++ = col
void bPPU::render_bg_tile(uint8 color_depth, uint16 tile_num) {

View File

@ -1,9 +1,10 @@
void bPPU::build_sprite_list() {
uint8 *tableA = oam, *tableB = oam + 512;
uint8 y_offset = (config::ppu.hack.obj_cache == true) ? 0 : 1;
for(int i = 0; i < 128; i++) {
uint x = bool(*tableB & (1 << ((i & 3) << 1))); //0x01, 0x04, 0x10, 0x40
bool size = bool(*tableB & (2 << ((i & 3) << 1))); //0x02, 0x08, 0x20, 0x80
uint x = !!(*tableB & (1 << ((i & 3) << 1))); //0x01, 0x04, 0x10, 0x40
bool size = !!(*tableB & (2 << ((i & 3) << 1))); //0x02, 0x08, 0x20, 0x80
switch(regs.oam_basesize) {
case 0: sprite_list[i].width = (!size) ? 8 : 16;
@ -36,10 +37,10 @@ uint8 *tableA = oam, *tableB = oam + 512;
}
sprite_list[i].x = (x << 8) + tableA[0];
sprite_list[i].y = tableA[1];
sprite_list[i].y = tableA[1] + y_offset;
sprite_list[i].character = tableA[2];
sprite_list[i].vflip = bool(tableA[3] & 0x80);
sprite_list[i].hflip = bool(tableA[3] & 0x40);
sprite_list[i].vflip = !!(tableA[3] & 0x80);
sprite_list[i].hflip = !!(tableA[3] & 0x40);
sprite_list[i].priority = (tableA[3] >> 4) & 3;
sprite_list[i].palette = (tableA[3] >> 1) & 7;
sprite_list[i].use_nameselect = tableA[3] & 1;

View File

@ -28,7 +28,7 @@ uint8 *JMAReader::read(uint32 length)
return data;
}
JMAReader::JMAReader(char *fn) : JMAFile(fn), fsize(0)
JMAReader::JMAReader(const char *fn) : JMAFile(fn), fsize(0)
{
std::vector<JMA::jma_public_file_info> file_info = JMAFile.get_files_info();
for (std::vector<JMA::jma_public_file_info>::iterator i = file_info.begin(); i != file_info.end(); i++)

View File

@ -12,6 +12,6 @@ public:
uint32 size();
uint8 *read(uint32 length = 0);
JMAReader(char *fn);
JMAReader(const char *fn);
~JMAReader() { }
};

View File

@ -8,7 +8,7 @@
#include "jmareader.cpp"
#endif
uint32 Reader::detect(char *fn) {
uint Reader::detect(const char *fn) {
int len = strlen(fn);
if(len >= 4 && !stricmp(fn + len - 3, ".gz")) {
return RF_GZ;

View File

@ -9,7 +9,7 @@ enum {
//attemps to determine filetype by extension,
//RF_NORMAL is returned on failure as a failsafe
static uint32 detect(char *fn);
static uint detect(const char *fn);
virtual uint32 size() = 0;
//return is 0 on failure, caller must deallocate memory manually

View File

@ -26,7 +26,7 @@ uint8 *ZipReader::read(uint32 length)
return data;
}
ZipReader::ZipReader(char *fn) : fsize(0)
ZipReader::ZipReader(const char *fn) : fsize(0)
{
unz_file_info cFileInfo; //Create variable to hold info for a compressed file
char cFileName[sizeof(cname)];

View File

@ -15,7 +15,7 @@ public:
uint32 size();
uint8 *read(uint32 length = 0);
ZipReader(char *fn);
ZipReader(const char *fn);
~ZipReader()
{
if (zipfile)

View File

@ -2,7 +2,6 @@
class SMP {
public:
thread_t thread;
virtual void enter() = 0;
public:

View File

@ -106,13 +106,13 @@ mov_dp_dp(0xfa) {
mov_dp_const(0x8f) {
1:rd = op_readpc();
2:dp = op_readpc();
3:op_io();
3:op_readdp(dp);
4:op_writedp(dp, rd);
}
mov_ix_a(0xc6) {
1:op_io();
2:op_io();
2:op_readdp(regs.x);
3:op_writedp(regs.x, regs.a);
}
@ -126,17 +126,18 @@ mov_dp_a(0xc4, a),
mov_dp_x(0xd8, x),
mov_dp_y(0xcb, y) {
1:dp = op_readpc();
2:op_io();
2:op_readdp(dp);
3:op_writedp(dp, regs.$1);
}
mov_dpx_a(0xd4, x, a),
mov_dpy_x(0xd9, y, x),
mov_dpx_y(0xdb, x, y) {
1:dp = op_readpc();
1:dp = op_readpc();
2:op_io();
3:op_io();
4:op_writedp(dp + regs.$1, regs.$2);
dp += regs.$1;
3:op_readdp(dp);
4:op_writedp(dp, regs.$2);
}
mov_addr_a(0xc5, a),
@ -144,7 +145,7 @@ mov_addr_x(0xc9, x),
mov_addr_y(0xcc, y) {
1:dp = op_readpc();
2:dp |= op_readpc() << 8;
3:op_io();
3:op_readaddr(dp);
4:op_writeaddr(dp, regs.$1);
}
@ -153,26 +154,29 @@ mov_addry_a(0xd6, y) {
1:dp = op_readpc();
2:dp |= op_readpc() << 8;
3:op_io();
4:op_io();
5:op_writeaddr(dp + regs.$1, regs.a);
dp += regs.$1;
4:op_readaddr(dp);
5:op_writeaddr(dp, regs.a);
}
mov_idpx_a(0xc7) {
1:sp = op_readpc() + regs.x;
1:sp = op_readpc();
2:op_io();
sp += regs.x;
3:dp = op_readdp(sp);
4:dp |= op_readdp(sp + 1) << 8;
5:op_io();
5:op_readaddr(dp);
6:op_writeaddr(dp, regs.a);
}
mov_idpy_a(0xd7) {
1:sp = op_readpc();
2:op_io();
3:dp = op_readdp(sp);
4:dp |= op_readdp(sp + 1) << 8;
5:op_io();
6:op_writeaddr(dp + regs.y, regs.a);
1:sp = op_readpc();
2:dp = op_readdp(sp);
3:dp |= op_readdp(sp + 1) << 8;
4:op_io();
dp += regs.y;
5:op_readaddr(dp);
6:op_writeaddr(dp, regs.a);
}
movw_ya_dp(0xba) {
@ -186,7 +190,7 @@ movw_ya_dp(0xba) {
movw_dp_ya(0xda) {
1:dp = op_readpc();
2:op_io();
2:op_readdp(dp);
3:op_writedp(dp, regs.a);
4:op_writedp(dp + 1, regs.y);
}

View File

@ -214,14 +214,14 @@ case 0xfa: {
case 0x8f: {
rd = op_readpc();
dp = op_readpc();
op_io();
op_readdp(dp);
op_writedp(dp, rd);
} break;
//mov_ix_a
case 0xc6: {
op_io();
op_io();
op_readdp(regs.x);
op_writedp(regs.x, regs.a);
} break;
@ -235,53 +235,56 @@ case 0xaf: {
//mov_dp_a
case 0xc4: {
dp = op_readpc();
op_io();
op_readdp(dp);
op_writedp(dp, regs.a);
} break;
//mov_dp_x
case 0xd8: {
dp = op_readpc();
op_io();
op_readdp(dp);
op_writedp(dp, regs.x);
} break;
//mov_dp_y
case 0xcb: {
dp = op_readpc();
op_io();
op_readdp(dp);
op_writedp(dp, regs.y);
} break;
//mov_dpx_a
case 0xd4: {
dp = op_readpc();
dp = op_readpc();
op_io();
op_io();
op_writedp(dp + regs.x, regs.a);
dp += regs.x;
op_readdp(dp);
op_writedp(dp, regs.a);
} break;
//mov_dpy_x
case 0xd9: {
dp = op_readpc();
dp = op_readpc();
op_io();
op_io();
op_writedp(dp + regs.y, regs.x);
dp += regs.y;
op_readdp(dp);
op_writedp(dp, regs.x);
} break;
//mov_dpx_y
case 0xdb: {
dp = op_readpc();
dp = op_readpc();
op_io();
op_io();
op_writedp(dp + regs.x, regs.y);
dp += regs.x;
op_readdp(dp);
op_writedp(dp, regs.y);
} break;
//mov_addr_a
case 0xc5: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
op_readaddr(dp);
op_writeaddr(dp, regs.a);
} break;
@ -289,7 +292,7 @@ case 0xc5: {
case 0xc9: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
op_readaddr(dp);
op_writeaddr(dp, regs.x);
} break;
@ -297,7 +300,7 @@ case 0xc9: {
case 0xcc: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
op_readaddr(dp);
op_writeaddr(dp, regs.y);
} break;
@ -306,8 +309,9 @@ case 0xd5: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
op_io();
op_writeaddr(dp + regs.x, regs.a);
dp += regs.x;
op_readaddr(dp);
op_writeaddr(dp, regs.a);
} break;
//mov_addry_a
@ -315,28 +319,31 @@ case 0xd6: {
dp = op_readpc();
dp |= op_readpc() << 8;
op_io();
op_io();
op_writeaddr(dp + regs.y, regs.a);
dp += regs.y;
op_readaddr(dp);
op_writeaddr(dp, regs.a);
} break;
//mov_idpx_a
case 0xc7: {
sp = op_readpc() + regs.x;
sp = op_readpc();
op_io();
sp += regs.x;
dp = op_readdp(sp);
dp |= op_readdp(sp + 1) << 8;
op_io();
op_readaddr(dp);
op_writeaddr(dp, regs.a);
} break;
//mov_idpy_a
case 0xd7: {
sp = op_readpc();
op_io();
sp = op_readpc();
dp = op_readdp(sp);
dp |= op_readdp(sp + 1) << 8;
op_io();
op_writeaddr(dp + regs.y, regs.a);
dp += regs.y;
op_readaddr(dp);
op_writeaddr(dp, regs.a);
} break;
//movw_ya_dp
@ -352,7 +359,7 @@ case 0xba: {
//movw_dp_ya
case 0xda: {
dp = op_readpc();
op_io();
op_readdp(dp);
op_writedp(dp, regs.a);
op_writedp(dp + 1, regs.y);
} break;

View File

@ -148,7 +148,6 @@ sbc_dp_const(0xb8, sbc, 1) {
}
addw_ya_dp(0x7a, addw),
cmpw_ya_dp(0x5a, cmpw),
subw_ya_dp(0x9a, subw) {
1:dp = op_readpc();
2:rd = op_readdp(dp);
@ -157,6 +156,13 @@ subw_ya_dp(0x9a, subw) {
regs.ya = op_$1(regs.ya, rd);
}
cmpw_ya_dp(0x5a) {
1:dp = op_readpc();
2:rd = op_readdp(dp);
3:rd |= op_readdp(dp + 1) << 8;
op_cmpw(regs.ya, rd);
}
and1_bit(0x4a, !!),
and1_notbit(0x6a, !) {
1:dp = op_readpc();

View File

@ -661,15 +661,6 @@ case 0x7a: {
regs.ya = op_addw(regs.ya, rd);
} break;
//cmpw_ya_dp
case 0x5a: {
dp = op_readpc();
rd = op_readdp(dp);
rd |= op_readdp(dp + 1) << 8;
op_io();
regs.ya = op_cmpw(regs.ya, rd);
} break;
//subw_ya_dp
case 0x9a: {
dp = op_readpc();
@ -679,6 +670,14 @@ case 0x9a: {
regs.ya = op_subw(regs.ya, rd);
} break;
//cmpw_ya_dp
case 0x5a: {
dp = op_readpc();
rd = op_readdp(dp);
rd |= op_readdp(dp + 1) << 8;
op_cmpw(regs.ya, rd);
} break;
//and1_bit
case 0x4a: {
dp = op_readpc();

View File

@ -1,32 +1,32 @@
uint8 sSMP::op_adc(uint8 x, uint8 y) {
int16 r = x + y + regs.p.c;
regs.p.n = bool(r & 0x80);
regs.p.v = bool(~(x ^ y) & (y ^ (uint8)r) & 0x80);
regs.p.h = bool((x ^ y ^ (uint8)r) & 0x10);
regs.p.n = !!(r & 0x80);
regs.p.v = !!(~(x ^ y) & (y ^ (uint8)r) & 0x80);
regs.p.h = !!((x ^ y ^ (uint8)r) & 0x10);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r > 0xff);
return r;
}
uint16 sSMP::op_addw(uint16 x, uint16 y) {
int16 r;
uint16 r;
regs.p.c = 0;
r = op_adc(x, y);
r |= op_adc(x >> 8, y >> 8) << 8;
regs.p.z = ((uint16)r == 0);
regs.p.z = (r == 0);
return r;
}
uint8 sSMP::op_and(uint8 x, uint8 y) {
x &= y;
regs.p.n = bool(x & 0x80);
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
return x;
}
uint8 sSMP::op_cmp(uint8 x, uint8 y) {
int16 r = x - y;
regs.p.n = bool(r & 0x80);
regs.p.n = !!(r & 0x80);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r >= 0);
return x;
@ -34,7 +34,7 @@ int16 r = x - y;
uint16 sSMP::op_cmpw(uint16 x, uint16 y) {
int32 r = x - y;
regs.p.n = bool(r & 0x8000);
regs.p.n = !!(r & 0x8000);
regs.p.z = ((uint16)r == 0);
regs.p.c = (r >= 0);
return x;
@ -42,22 +42,22 @@ int32 r = x - y;
uint8 sSMP::op_eor(uint8 x, uint8 y) {
x ^= y;
regs.p.n = bool(x & 0x80);
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
return x;
}
uint8 sSMP::op_or(uint8 x, uint8 y) {
x |= y;
regs.p.n = bool(x & 0x80);
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
return x;
}
uint8 sSMP::op_sbc(uint8 x, uint8 y) {
int16 r = x - y - !regs.p.c;
regs.p.n = bool(r & 0x80);
regs.p.v = bool((x ^ y) & (x ^ (uint8)r) & 0x80);
regs.p.n = !!(r & 0x80);
regs.p.v = !!((x ^ y) & (x ^ (uint8)r) & 0x80);
regs.p.h = !((x ^ y ^ (uint8)r) & 0x10);
regs.p.z = ((uint8)r == 0);
regs.p.c = (r >= 0);
@ -65,74 +65,72 @@ int16 r = x - y - !regs.p.c;
}
uint16 sSMP::op_subw(uint16 x, uint16 y) {
int16 r;
uint16 r;
regs.p.c = 1;
r = op_sbc(x, y);
r |= op_sbc(x >> 8, y >> 8) << 8;
regs.p.z = ((uint16)r == 0);
regs.p.z = (r == 0);
return r;
}
uint8 sSMP::op_inc(uint8 x) {
x++;
regs.p.n = bool(x & 0x80);
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
return x;
}
uint16 sSMP::op_incw(uint16 x) {
x++;
regs.p.n = bool(x & 0x8000);
regs.p.n = !!(x & 0x8000);
regs.p.z = (x == 0);
return x;
}
uint8 sSMP::op_dec(uint8 x) {
x--;
regs.p.n = bool(x & 0x80);
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
return x;
}
uint16 sSMP::op_decw(uint16 x) {
x--;
regs.p.n = bool(x & 0x8000);
regs.p.n = !!(x & 0x8000);
regs.p.z = (x == 0);
return x;
}
uint8 sSMP::op_asl(uint8 x) {
regs.p.c = bool(x & 0x80);
regs.p.c = !!(x & 0x80);
x <<= 1;
regs.p.n = bool(x & 0x80);
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
return x;
}
uint8 sSMP::op_lsr(uint8 x) {
regs.p.c = bool(x & 0x01);
regs.p.c = !!(x & 0x01);
x >>= 1;
regs.p.n = bool(x & 0x80);
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
return x;
}
uint8 sSMP::op_rol(uint8 x) {
uint8 c = regs.p.c;
regs.p.c = bool(x & 0x80);
x <<= 1;
x |= c;
regs.p.n = bool(x & 0x80);
uint8 carry = (uint8)regs.p.c;
regs.p.c = !!(x & 0x80);
x = (x << 1) | carry;
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
return x;
}
uint8 sSMP::op_ror(uint8 x) {
uint8 c = (regs.p.c)?0x80:0x00;
regs.p.c = bool(x & 0x01);
x >>= 1;
x |= c;
regs.p.n = bool(x & 0x80);
uint8 carry = (uint8)regs.p.c << 7;
regs.p.c = !!(x & 0x01);
x = carry | (x >> 1);
regs.p.n = !!(x & 0x80);
regs.p.z = (x == 0);
return x;
}

View File

@ -1,32 +1,35 @@
alwaysinline uint8 sSMP::ram_read(uint16 addr) {
alwaysinline
uint8 sSMP::ram_read(uint16 addr) {
if(addr < 0xffc0)return spcram[addr];
if(status.iplrom_enabled == false)return spcram[addr];
return iplrom[addr & 0x3f];
}
alwaysinline void sSMP::ram_write(uint16 addr, uint8 data) {
alwaysinline
void sSMP::ram_write(uint16 addr, uint8 data) {
//writes to $ffc0-$ffff always go to spcram, even if the iplrom is enabled
spcram[addr] = data;
}
//
alwaysinline uint8 sSMP::port_read(uint8 port) {
alwaysinline
uint8 sSMP::port_read(uint8 port) {
return spcram[0xf4 + (port & 3)];
}
alwaysinline void sSMP::port_write(uint8 port, uint8 data) {
alwaysinline
void sSMP::port_write(uint8 port, uint8 data) {
spcram[0xf4 + (port & 3)] = data;
}
//
alwaysinline uint8 sSMP::op_busread(uint16 addr) {
alwaysinline
uint8 sSMP::op_busread(uint16 addr) {
uint8 r;
if((addr & 0xfff0) == 0x00f0) {
//addr >= 0x00f0 && addr <= 0x00ff
scheduler.sync_smpcpu();
switch(addr) {
case 0xf0: { //TEST -- write-only register
@ -50,12 +53,13 @@ uint8 r;
case 0xf5: //CPUIO1
case 0xf6: //CPUIO2
case 0xf7: { //CPUIO3
scheduler.sync_smpcpu();
r = r_cpu->port_read(addr & 3);
} break;
case 0xf8: //???
case 0xf9: { //??? -- Mapped to SPCRAM
r = spcram[addr];
r = ram_read(addr);
} break;
case 0xfa: //T0TARGET
@ -93,11 +97,10 @@ uint8 r;
return r;
}
alwaysinline void sSMP::op_buswrite(uint16 addr, uint8 data) {
alwaysinline
void sSMP::op_buswrite(uint16 addr, uint8 data) {
if((addr & 0xfff0) == 0x00f0) {
//addr >= 0x00f0 && addr >= 0x00ff
scheduler.sync_smpcpu();
if(status.mmio_disabled == true)return;
switch(addr) {
@ -123,15 +126,18 @@ alwaysinline void sSMP::op_buswrite(uint16 addr, uint8 data) {
case 0xf1: { //CONTROL
status.iplrom_enabled = !!(data & 0x80);
//one-time clearing of APU port read registers,
//emulated by simulating CPU writes of 0x00
if(data & 0x20) {
r_cpu->port_write(2, 0x00);
r_cpu->port_write(3, 0x00);
}
if(data & 0x10) {
r_cpu->port_write(0, 0x00);
r_cpu->port_write(1, 0x00);
if(data & 0x30) {
//one-time clearing of APU port read registers,
//emulated by simulating CPU writes of 0x00
scheduler.sync_smpcpu();
if(data & 0x20) {
r_cpu->port_write(2, 0x00);
r_cpu->port_write(3, 0x00);
}
if(data & 0x10) {
r_cpu->port_write(0, 0x00);
r_cpu->port_write(1, 0x00);
}
}
//0->1 transistion resets timers
@ -169,12 +175,14 @@ alwaysinline void sSMP::op_buswrite(uint16 addr, uint8 data) {
case 0xf5: //CPUIO1
case 0xf6: //CPUIO2
case 0xf7: { //CPUIO3
scheduler.sync_smpcpu();
port_write(addr & 3, data);
} break;
case 0xf8: //???
case 0xf9: { //??? - Mapped to SPCRAM
spcram[addr] = data;
//$00f1.d1 (ram_writable) has no effect on these two addresses
ram_write(addr, data);
} break;
case 0xfa: { //T0TARGET
@ -220,30 +228,37 @@ void sSMP::op_write(uint16 addr, uint8 data) {
//
alwaysinline uint8 sSMP::op_readpc() {
alwaysinline
uint8 sSMP::op_readpc() {
return op_read(regs.pc++);
}
alwaysinline uint8 sSMP::op_readstack() {
alwaysinline
uint8 sSMP::op_readstack() {
return op_read(0x0100 | ++regs.sp);
}
alwaysinline void sSMP::op_writestack(uint8 data) {
alwaysinline
void sSMP::op_writestack(uint8 data) {
op_write(0x0100 | regs.sp--, data);
}
alwaysinline uint8 sSMP::op_readaddr(uint16 addr) {
alwaysinline
uint8 sSMP::op_readaddr(uint16 addr) {
return op_read(addr);
}
alwaysinline void sSMP::op_writeaddr(uint16 addr, uint8 data) {
alwaysinline
void sSMP::op_writeaddr(uint16 addr, uint8 data) {
op_write(addr, data);
}
alwaysinline uint8 sSMP::op_readdp(uint8 addr) {
alwaysinline
uint8 sSMP::op_readdp(uint8 addr) {
return op_read(((uint)regs.p.p << 8) + addr);
}
alwaysinline void sSMP::op_writedp(uint8 addr, uint8 data) {
alwaysinline
void sSMP::op_writedp(uint8 addr, uint8 data) {
op_write(((uint)regs.p.p << 8) + addr, data);
}

View File

@ -14,7 +14,8 @@ alwaysinline void sSMP::add_clocks(uint clocks) {
//1024000 / 768 = 32000 DSP ticks/second
if(++status.dsp_counter == 32) {
status.dsp_counter = 0;
snes->audio_update(r_dsp->run());
uint32 sample = r_dsp->run();
snes.audio_update( (sample & 0xffff), (sample >> 16) );
}
}
}

View File

@ -1,28 +1,26 @@
void SNES::audio_update(uint32 data) {
void SNES::audio_update(uint16 l_sample, uint16 r_sample) {
if(pcmfp) {
fputc(data, pcmfp);
fputc(data >> 8, pcmfp);
fputc(data >> 16, pcmfp);
fputc(data >> 24, pcmfp);
fputlw(pcmfp, l_sample);
fputlw(pcmfp, r_sample);
}
if(config::snes.mute == true) { l_sample = r_sample = 0x0000; }
if((bool)config::snes.mute == true)data = 0x0000;
sound_run(data);
snesinterface.audio_sample(l_sample, r_sample);
}
void SNES::log_audio_enable(const char *fn) {
char tfn[256];
int i;
if(pcmfp)log_audio_disable();
if(pcmfp) { log_audio_disable(); }
char tfn[256];
if(!fn) {
for(i=0;i<=999;i++) {
int i = 0;
while(i < 1000) {
sprintf(tfn, "audio%0.3d.wav", i);
pcmfp = fopen(tfn, "rb");
if(!pcmfp)break;
fclose(pcmfp);
pcmfp = 0;
i++;
}
if(i >= 1000)return;
} else {

View File

@ -2,11 +2,9 @@ FILE *pcmfp;
//if a filename is not specified, one will be generated
//automatically ("audio%0.3d.wav")
void log_audio_enable(const char *fn = 0);
void log_audio_disable();
void log_audio_enable(const char *fn = 0);
void log_audio_disable();
void audio_update(uint32 data);
void audio_init();
void audio_term();
virtual void sound_run(uint32 data) = 0;
void audio_update(uint16 l_sample, uint16 r_sample);
void audio_init();
void audio_term();

View File

@ -61,6 +61,8 @@ void SNES::port_set_deviceid(bool port, uint deviceid) {
}
void SNES::poll_input() {
snesinterface.input_poll();
bool *p0 = input.port0_bits;
bool *p1 = input.port1_bits;
switch(input.port0_device) {
@ -68,7 +70,7 @@ bool *p1 = input.port1_bits;
break;
default:
for(int i = 0; i < input.port0_devicebits; i++) { *p0++ = get_input_status(input.port0_deviceid, i); }
for(int i = 0; i < input.port0_devicebits; i++) { *p0++ = snesinterface.input_poll(input.port0_deviceid, i); }
break;
}
@ -77,7 +79,7 @@ bool *p1 = input.port1_bits;
break;
default:
for(int i = 0; i < input.port1_devicebits; i++) { *p1++ = get_input_status(input.port1_deviceid, i); }
for(int i = 0; i < input.port1_devicebits; i++) { *p1++ = snesinterface.input_poll(input.port1_deviceid, i); }
break;
}

View File

@ -28,13 +28,5 @@ struct {
bool port_read(bool port);
void port_set_deviceid(bool port, uint deviceid);
//The CPU calls poll_input() when the main interface should check the
//status of all joypad buttons and cache the results...
virtual void poll_input();
//...and then the CPU calls get_input_status() whenever it needs one
//of the cached button values to be returned for emulation purposes.
virtual bool get_input_status(uint8 device, uint8 button) { return false; }
virtual void input_init();
void input_init();
void poll_input();

View File

@ -0,0 +1,20 @@
/*****
* SNES Interface class
*
* Interfaces SNES core with platform-specific functionality
* (video, audio, input, ...)
*****/
class SNESInterface {
public:
bool video_lock(uint16 *&data, uint &pitch);
void video_unlock();
void video_refresh();
void audio_sample(uint16 l_sample, uint16 r_sample);
void input_poll();
bool input_poll(uint deviceid, uint button);
};
extern SNESInterface snesinterface;

View File

@ -10,23 +10,23 @@ void threadentry_smp() { r_smp->enter(); }
void Scheduler::enter() {
switch(clock.active) {
case THREAD_CPU:
co_jump(thread_cpu);
co_switch(thread_cpu);
break;
case THREAD_SMP:
co_jump(thread_smp);
co_switch(thread_smp);
break;
}
}
void Scheduler::exit() {
co_jump(thread_snes);
co_switch(thread_snes);
}
void Scheduler::init() {
clock.cpu_freq = snes->region() == SNES::NTSC ?
clock.cpu_freq = snes.region() == SNES::NTSC ?
config::cpu.ntsc_clock_rate :
config::cpu.pal_clock_rate;
clock.smp_freq = snes->region() == SNES::NTSC ?
clock.smp_freq = snes.region() == SNES::NTSC ?
config::smp.ntsc_clock_rate :
config::smp.pal_clock_rate;
@ -36,14 +36,15 @@ void Scheduler::init() {
if(thread_cpu)co_delete(thread_cpu);
if(thread_smp)co_delete(thread_smp);
thread_cpu = co_create(threadentry_cpu, 65536);
thread_smp = co_create(threadentry_smp, 65536);
thread_snes = co_active();
thread_cpu = co_create(threadentry_cpu, COTHREAD_STACKSIZE_NORMAL);
thread_smp = co_create(threadentry_smp, COTHREAD_STACKSIZE_NORMAL);
}
//
Scheduler::Scheduler() {
thread_snes = co_active();
thread_snes = 0;
thread_cpu = 0;
thread_smp = 0;
}

View File

@ -1,9 +1,9 @@
class Scheduler {
public:
thread_t thread_snes;
thread_t thread_cpu;
thread_t thread_smp;
cothread_t thread_snes;
cothread_t thread_cpu;
cothread_t thread_smp;
enum ActiveThread {
THREAD_CPU,
@ -21,25 +21,25 @@ struct {
alwaysinline void sync_cpusmp() {
if(clock.cpusmp < 0) {
clock.active = THREAD_SMP;
co_jump(thread_smp);
co_switch(thread_smp);
}
}
alwaysinline void sync_smpcpu() {
if(clock.cpusmp >= 0) {
clock.active = THREAD_CPU;
co_jump(thread_cpu);
co_switch(thread_cpu);
}
}
alwaysinline void addclocks_cpu(uint clocks) {
clock.cpusmp -= clocks * (uint64)clock.smp_freq;
if(clock.cpusmp < -(275000 * (int64)24000000))sync_cpusmp();
if(clock.cpusmp < -(250000 * (int64)20000000))sync_cpusmp();
}
alwaysinline void addclocks_smp(uint clocks) {
clock.cpusmp += clocks * (uint64)clock.cpu_freq;
if(clock.cpusmp > +(275000 * (int64)24000000))sync_smpcpu();
if(clock.cpusmp > +(250000 * (int64)20000000))sync_smpcpu();
}
void enter();

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