Compare commits

..

8 Commits
v084 ... v085

Author SHA1 Message Date
Tim Allen
ba081d309e Update to v085 release.
byuu says:

A new release for the new year.

Changelog:
fixed auto joypad polling edge case; fixes Ys 5 controls
fixed Justifier polling code; Lethal Enforcers should be fully
responsive once again
rewrote SNES S-SMP processor core (~20% code reduction)
fixed Game Boy 8x16 sprite mode; fixed some sprites in Zelda: Link's
Awakening
treat Game Boy HuC1 RAM enable flag as writable flag instead; fixes
Pokemon Card GB
created far faster XML parser; bsnes can now load XML files once again
updated to mightymo's most recent cheat code database
internal color calculations now performed at 30-bits per pixel
gamma slider now acts as fine-tuned gamma ramp option
Linux OpenGL driver will output at 30bpp on capable displays
Linux port defaults to GTK+ now instead of Qt (both are still available)
2012-01-04 00:10:46 +11:00
Tim Allen
1bf9265b7c Update to v084r08 release.
byuu says:

Okay, everything can now load XML again, including board layouts for all
three systems. New is the ability to load external Game Boy layouts (not
really that useful, but it's there.)
I'd like to aim for a v085 release soon. I've included a binary, so I'd
appreciate testing. I had to redo all of the XML mappings for every
system (I like consistency), so basically the following things need to
be tested:
* load one of every type of game for every system (every NES board type,
* every Game Boy MBC type, every SNES chip and layout type.)
* test cheat codes and the cheat database
* test pixel shaders for OpenGL and Direct3D (sepia for the win)
* test anything else for v085 release
2011-12-31 20:24:58 +11:00
Tim Allen
f947d84309 Update to v084r07 release.
byuu says:

Added the new super-fast XML parser. So far, the shaders, cheat files,
and cheat database have been updated to allow XML mode once again. Which
is sure to please Screwtape =)
So it's down to just the cartridge mapping files now, which are always
a major pain.

I still think BML is better for parsing simplicity, memory usage, disk
size, lack of red tape and speed (but horrendously bad for ease of
creating files manually), but since the base API is identical, there's
no reason not to support both. Especially since the pixel shaders have
kind of taken on a life of their own.
2011-12-30 17:41:29 +11:00
Tim Allen
0bd21185b8 Update to v084r06 release.
byuu says:

Changelog:
- fixed sprite tile masking for 8x16 mode (fixes Zelda: DX sprites)
- HuC1 flag sets RAM writable, not RAM enable (fixes Pokemon Card)
- removed within<> template, didn't turn out to be all that useful

I would be almost certain no games would break by allowing reads when it
is disabled, no game would rely on that behavior.
I prefer to be overly restrictive. Better to not allow valid behavior
than to allow invalid behavior. The latter is what gives us a dozen
broken SNES translations.
2011-12-26 21:49:48 +11:00
Tim Allen
6227974bf6 Update to v084r05 release.
(note: before the post announcing this release, there had been
a discussion of a performance optimisation that made the Super Scope
emulation a lot faster, but caused problems for the Justifier perpheral)

byuu says:

Spent a good two hours trying things to no avail.
I was trying to allow the CPU to run ahead, and sync on accesses to
$4016/4017/4201/4213, but that doesn't work because the controllers have
access to strobe IObit at will.
The codebase is really starting to get difficult to work with. I am
guessing because the days of massive development are long over, and the
code is starting to age.
Jonas' fix works 98% of the time, but there's still a few missed shots
here and there. So that's not going to work either.
So ... I give up. I've disabled the speed hack, so that it works 100% of
the time.
Did the same for the Super Scope: it may not have the same problem, but
I like consistency and don't feel like taking the chance.
This doesn't affect the mouse, since the mouse does not latch the
counters to indicate its X/Y position.
Speed hit is 92->82fps (accuracy profile), but only for Super Scope and
Justifier games.
But ... at least it works now. Slow and working is better than fast and
broken.

I appreciate the help in researching the issue, Jonas and krom.

Also pulled in phoenix/Makefile, which simplifies ui/Makefile.
Linux port defaults to GTK+ now. I can't get QGtkStyle to look good on
Debian.
2011-12-18 14:19:45 +11:00
Tim Allen
ea95eaca3c Update to v084r04 release.
byuu says:

Fixed the Ys 5 input bug in the auto joypad polling code. Can't
guarantee it's hardware-accurate (I have no way to extensively test it),
but I can guarantee it is closer to being correct now.
Also uses updated version of phoenix.

The justifier input is indeed all fucked up now. Seems like it stops
updating input after firing for a few frames.
I really don't want to debug that code anymore ... anyone want to make
$10 by fixing it? :P
2011-12-12 21:59:53 +11:00
Tim Allen
ad0805b168 Update to v084r03 release.
(r02 was not posted to the WIP thread)

byuu says:

Internally, all color is processed with 30-bit precision. The filters
also operate at 30-bit depth.
There's a new config file setting, video.depth, which defaults to 24.
This causes the final output to downsample to 24-bit, as most will
require.
If you set it to 30-bit, the downsampling will not occur, and bsnes will
ask ruby for a 30-bit surface. If you don't have one available, you're
going to get bad colors. Or maybe even a crash with OpenGL.
I don't yet have detection code to make sure you have an appropriate
visual in place.

30-bit mode will really only work if you are running Linux, running Xorg
at Depth 30, use the OpenGL or XShm driver, have an nVidia Quadro or AMD
FireGL card with the official drivers, and have a 30-bit capable
monitor.
Lots of planning and work for very little gain here, but it's nice that
it's finally finished.

Oh, I had to change the contrast/brightness formulas a tiny bit, but
they still work and look nice.
2011-12-03 14:22:54 +11:00
Tim Allen
2cc077e12b Update to v084r01 release.
I rewrote the S-SMP processor core (implementation of the 256 opcodes),
utilizing my new 6502-like syntax. It matches what bass v05r01 uses.
Took 10 hours.
Due to being able to group the "mov reg,mem" opcodes together with
"adc/sbc/ora/and/eor/cmp" sets, the total code size was reduced from
55.7KB to 42.5KB for identical accuracy and speed.
I also dropped the trick I was using to pass register variables as
template arguments, and instead just use a switch table to pass them as
function arguments. Makes the table a lot easier to read.

Passes all of my S-SMP tests, and all of blargg's
arithmetic/cycle-timing S-SMP tests. Runs Zelda 3 great as well. Didn't
test further.
This does have the potential to cause some regressions if I've messed
anything up, and none of the above tests caught it, so as always,
testing would be appreciated.

Anyway, yeah. By writing the actual processor with this new mnemonic
set, it confirms the parallels I've made.
My guess is that Sony really did clone the 6502, but was worried about
legal implications or something and changed the mnemonics last-minute.

(Note to self: need to re-enable snes.random before v085 official.)

EDIT: oh yeah, I also commented out the ALSA snd_pcm_drain() inside
term(). Without it, there is a tiny pop when the driver is
re-initialized. But with it, the entire emulator would lock up for five
whole seconds waiting on that call to complete. I'll take the pop any
day over that.
2011-11-17 23:05:35 +11:00
291 changed files with 121575 additions and 82892 deletions

View File

@@ -12,7 +12,7 @@ ui := ui
# compiler
c := $(compiler) -std=gnu99
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
flags := -O3 -fomit-frame-pointer -I.
flags := -I. -O3 -fomit-frame-pointer
link :=
objects := libco
@@ -29,8 +29,6 @@ endif
# platform
ifeq ($(platform),x)
# tree vectorization causes code generation errors with Linux/GCC 4.6.1
flags += -fno-tree-vectorize
link += -s -ldl -lX11 -lXext
else ifeq ($(platform),osx)
else ifeq ($(platform),win)
@@ -76,7 +74,23 @@ clean:
-@$(call delete,*.pdb)
-@$(call delete,*.manifest)
sync:
if [ -d ./libco ]; then rm -r ./libco; fi
if [ -d ./nall ]; then rm -r ./nall; fi
if [ -d ./ruby ]; then rm -r ./ruby; fi
if [ -d ./phoenix ]; then rm -r ./phoenix; fi
cp -r ../libco ./libco
cp -r ../nall ./nall
cp -r ../ruby ./ruby
cp -r ../phoenix ./phoenix
rm -r libco/doc
rm -r libco/test
rm -r nall/test
rm -r ruby/_test
rm -r phoenix/nall
rm -r phoenix/test
archive-all:
tar -cjf bsnes.tar.bz2 data gameboy libco nall nes obj out phoenix ruby snes ui ui-libsnes Makefile cc.bat clean.bat sync.sh
tar -cjf bsnes.tar.bz2 data gameboy libco nall nes obj out phoenix ruby snes ui ui-libsnes Makefile cc.bat clean.bat
help:;

File diff suppressed because it is too large Load Diff

112549
bsnes/data/cheats.xml Executable file

File diff suppressed because it is too large Load Diff

View File

@@ -30,9 +30,9 @@ void Cartridge::load(System::Revision revision, const string &markup, const uint
info.romsize = 0;
info.ramsize = 0;
BML::Document document(markup);
XML::Document document(markup);
auto &mapperid = document["cartridge"]["mapper"].value;
auto &mapperid = document["cartridge"]["mapper"].data;
if(mapperid == "none" ) info.mapper = Mapper::MBC0;
if(mapperid == "MBC1" ) info.mapper = Mapper::MBC1;
if(mapperid == "MBC2" ) info.mapper = Mapper::MBC2;
@@ -42,12 +42,12 @@ void Cartridge::load(System::Revision revision, const string &markup, const uint
if(mapperid == "HuC1" ) info.mapper = Mapper::HuC1;
if(mapperid == "HuC3" ) info.mapper = Mapper::HuC3;
info.rtc = document["cartridge"]["rtc"].exists();
info.rumble = document["cartridge"]["rumble"].exists();
info.rtc = document["cartridge"]["rtc"].data == "true";
info.rumble = document["cartridge"]["rumble"].data == "true";
info.romsize = hex(document["cartridge"]["rom"]["size"].value);
info.ramsize = hex(document["cartridge"]["ram"]["size"].value);
info.battery = document["cartridge"]["ram"]["non-volatile"].exists();
info.romsize = hex(document["cartridge"]["rom"]["size"].data);
info.ramsize = hex(document["cartridge"]["ram"]["size"].data);
info.battery = document["cartridge"]["ram"]["battery"].data == "true";
switch(info.mapper) { default:
case Mapper::MBC0: mapper = &mbc0; break;

View File

@@ -1,53 +1,54 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::HuC1::mmio_read(uint16 addr) {
if(within<0x0000, 0x3fff>(addr)) {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
}
if(within<0x4000, 0x7fff>(addr)) {
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return 0x00;
if((addr & 0xe000) == 0xa000) { //$a000-bfff
return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
}
return 0x00;
}
void Cartridge::HuC1::mmio_write(uint16 addr, uint8 data) {
if(within<0x0000, 0x1fff>(addr)) {
ram_enable = (data & 0x0f) == 0x0a;
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_writable = (data & 0x0f) == 0x0a;
return;
}
if(within<0x2000, 0x3fff>(addr)) {
if((addr & 0xe000) == 0x2000) { //$2000-3fff
rom_select = data;
if(rom_select == 0) rom_select = 1;
return;
}
if(within<0x4000, 0x5fff>(addr)) {
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data;
return;
}
if(within<0x6000, 0x7fff>(addr)) {
//unknown purpose
if((addr & 0xe000) == 0x6000) { //$6000-7fff
model = data & 0x01;
return;
}
if(within<0xa000, 0xbfff>(addr)) {
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
return;
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_writable == false) return;
return cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
}
}
void Cartridge::HuC1::power() {
ram_enable = false;
ram_writable = false;
rom_select = 0x01;
ram_select = 0x00;
model = 0;
}
#endif

View File

@@ -1,7 +1,8 @@
struct HuC1 : MMIO {
bool ram_enable; //0000-1fff
uint8 rom_select; //2000-3fff
uint8 ram_select; //4000-5fff
bool ram_writable; //$0000-1fff
uint8 rom_select; //$2000-3fff
uint8 ram_select; //$4000-5fff
bool model; //$6000-7fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);

View File

@@ -1,15 +1,15 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::HuC3::mmio_read(uint16 addr) {
if(within<0x0000, 0x3fff>(addr)) {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
}
if(within<0x4000, 0x7fff>(addr)) {
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if(within<0xa000, 0xbfff>(addr)) {
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return 0x00;
}
@@ -18,27 +18,27 @@ uint8 Cartridge::HuC3::mmio_read(uint16 addr) {
}
void Cartridge::HuC3::mmio_write(uint16 addr, uint8 data) {
if(within<0x0000, 0x1fff>(addr)) {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if(within<0x2000, 0x3fff>(addr)) {
if((addr & 0xe000) == 0x2000) { //$2000-3fff
rom_select = data;
return;
}
if(within<0x4000, 0x5fff>(addr)) {
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data;
return;
}
if(within<0x6000, 0x7fff>(addr)) {
if((addr & 0xe000) == 0x6000) { //$6000-7fff
//unknown purpose
return;
}
if(within<0xa000, 0xbfff>(addr)) {
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
return;
}

View File

@@ -1,7 +1,7 @@
struct HuC3 : MMIO {
bool ram_enable; //0000-1fff
uint8 rom_select; //2000-3fff
uint8 ram_select; //4000-5fff
bool ram_enable; //$0000-1fff
uint8 rom_select; //$2000-3fff
uint8 ram_select; //$4000-5fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);

View File

@@ -1,11 +1,11 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC0::mmio_read(uint16 addr) {
if(within<0x0000, 0x7fff>(addr)) {
if((addr & 0x8000) == 0x0000) { //$0000-7fff
return cartridge.rom_read(addr);
}
if(within<0xa000, 0xbfff>(addr)) {
if((addr & 0xe000) == 0xa000) { //$a000-bfff
return cartridge.ram_read(addr & 0x1fff);
}
@@ -13,7 +13,7 @@ uint8 Cartridge::MBC0::mmio_read(uint16 addr) {
}
void Cartridge::MBC0::mmio_write(uint16 addr, uint8 data) {
if(within<0xa000, 0xbfff>(addr)) {
if((addr & 0xe000) == 0xa000) { //$a000-bfff
cartridge.ram_write(addr & 0x1fff, data);
return;
}

View File

@@ -1,11 +1,11 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
if(within<0x0000, 0x3fff>(addr)) {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
}
if(within<0x4000, 0x7fff>(addr)) {
if((addr & 0xc000) == 0x4000) { //$4000-7fff
if(mode_select == 0) {
return cartridge.rom_read((ram_select << 19) | (rom_select << 14) | (addr & 0x3fff));
} else {
@@ -13,7 +13,7 @@ uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
}
}
if(within<0xa000, 0xbfff>(addr)) {
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) {
if(mode_select == 0) {
return cartridge.ram_read(addr & 0x1fff);
@@ -28,27 +28,27 @@ uint8 Cartridge::MBC1::mmio_read(uint16 addr) {
}
void Cartridge::MBC1::mmio_write(uint16 addr, uint8 data) {
if(within<0x0000, 0x1fff>(addr)) {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if(within<0x2000, 0x3fff>(addr)) {
if((addr & 0xe000) == 0x2000) { //$2000-3fff
rom_select = (data & 0x1f) + ((data & 0x1f) == 0);
return;
}
if(within<0x4000, 0x5fff>(addr)) {
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data & 0x03;
return;
}
if(within<0x6000, 0x7fff>(addr)) {
if((addr & 0xe000) == 0x6000) { //$6000-7fff
mode_select = data & 0x01;
return;
}
if(within<0xa000, 0xbfff>(addr)) {
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) {
if(mode_select == 0) {
cartridge.ram_write(addr & 0x1fff, data);

View File

@@ -1,8 +1,8 @@
struct MBC1 : MMIO {
bool ram_enable; //0000-1fff
uint8 rom_select; //2000-3fff
uint8 ram_select; //4000-5fff
bool mode_select; //6000-7fff
bool ram_enable; //$0000-1fff
uint8 rom_select; //$2000-3fff
uint8 ram_select; //$4000-5fff
bool mode_select; //$6000-7fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);

View File

@@ -1,15 +1,15 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
if(within<0x0000, 0x3fff>(addr)) {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
}
if(within<0x4000, 0x7fff>(addr)) {
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if(within<0xa000, 0xa1ff>(addr)) {
if((addr & 0xee00) == 0xa000) { //$a000-a1ff
if(ram_enable) return cartridge.ram_read(addr & 0x1ff);
return 0x00;
}
@@ -18,17 +18,17 @@ uint8 Cartridge::MBC2::mmio_read(uint16 addr) {
}
void Cartridge::MBC2::mmio_write(uint16 addr, uint8 data) {
if(within<0x0000, 0x1fff>(addr)) {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
if(!(addr & 0x0100)) ram_enable = (data & 0x0f) == 0x0a;
return;
}
if(within<0x2000, 0x3fff>(addr)) {
if((addr & 0xe000) == 0x2000) { //$2000-3fff
if( (addr & 0x0100)) rom_select = (data & 0x0f) + ((data & 0x0f) == 0);
return;
}
if(within<0xa000, 0xa1ff>(addr)) {
if((addr & 0xee00) == 0xa000) { //$a000-a1ff
if(ram_enable) cartridge.ram_write(addr & 0x1ff, data & 0x0f);
return;
}

View File

@@ -1,6 +1,6 @@
struct MBC2 : MMIO {
bool ram_enable; //0000-1fff
uint8 rom_select; //2000-3fff
bool ram_enable; //$0000-1fff
uint8 rom_select; //$2000-3fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);

View File

@@ -19,15 +19,15 @@ void Cartridge::MBC3::second() {
}
uint8 Cartridge::MBC3::mmio_read(uint16 addr) {
if(within<0x0000, 0x3fff>(addr)) {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
}
if(within<0x4000, 0x7fff>(addr)) {
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if(within<0xa000, 0xbfff>(addr)) {
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) {
if(ram_select >= 0x00 && ram_select <= 0x03) {
return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
@@ -45,22 +45,22 @@ uint8 Cartridge::MBC3::mmio_read(uint16 addr) {
}
void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) {
if(within<0x0000, 0x1fff>(addr)) {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if(within<0x2000, 0x3fff>(addr)) {
if((addr & 0xe000) == 0x2000) { //$2000-3fff
rom_select = (data & 0x7f) + ((data & 0x7f) == 0);
return;
}
if(within<0x4000, 0x5fff>(addr)) {
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data;
return;
}
if(within<0x6000, 0x7fff>(addr)) {
if((addr & 0xe000) == 0x6000) { //$6000-7fff
if(rtc_latch == 0 && data == 1) {
rtc_latch_second = rtc_second;
rtc_latch_minute = rtc_minute;
@@ -72,7 +72,7 @@ void Cartridge::MBC3::mmio_write(uint16 addr, uint8 data) {
return;
}
if(within<0xa000, 0xbfff>(addr)) {
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) {
if(ram_select >= 0x00 && ram_select <= 0x03) {
cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);

View File

@@ -1,8 +1,8 @@
struct MBC3 : MMIO {
bool ram_enable; //0000-1fff
uint8 rom_select; //2000-3fff
uint8 ram_select; //4000-5fff
bool rtc_latch; //6000-7fff
bool ram_enable; //$0000-1fff
uint8 rom_select; //$2000-3fff
uint8 ram_select; //$4000-5fff
bool rtc_latch; //$6000-7fff
bool rtc_halt;
unsigned rtc_second;

View File

@@ -1,15 +1,15 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
if(within<0x0000, 0x3fff>(addr)) {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(addr);
}
if(within<0x4000, 0x7fff>(addr)) {
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read((rom_select << 14) | (addr & 0x3fff));
}
if(within<0xa000, 0xbfff>(addr)) {
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) return cartridge.ram_read((ram_select << 13) | (addr & 0x1fff));
return 0x00;
}
@@ -18,27 +18,27 @@ uint8 Cartridge::MBC5::mmio_read(uint16 addr) {
}
void Cartridge::MBC5::mmio_write(uint16 addr, uint8 data) {
if(within<0x0000, 0x1fff>(addr)) {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
ram_enable = (data & 0x0f) == 0x0a;
return;
}
if(within<0x2000, 0x2fff>(addr)) {
if((addr & 0xf000) == 0x2000) { //$2000-2fff
rom_select = (rom_select & 0x0100) | data;
return;
}
if(within<0x3000, 0x3fff>(addr)) {
if((addr & 0xf000) == 0x3000) { //$3000-3fff
rom_select = ((data & 1) << 8) | (rom_select & 0x00ff);
return;
}
if(within<0x4000, 0x5fff>(addr)) {
if((addr & 0xe000) == 0x4000) { //$4000-5fff
ram_select = data & 0x0f;
return;
}
if(within<0xa000, 0xbfff>(addr)) {
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) cartridge.ram_write((ram_select << 13) | (addr & 0x1fff), data);
return;
}

View File

@@ -1,7 +1,7 @@
struct MBC5 : MMIO {
bool ram_enable; //0000-1fff
uint16 rom_select; //2000-2fff + 3000-3fff
uint8 ram_select; //4000-5fff
bool ram_enable; //$0000-1fff
uint16 rom_select; //$2000-2fff + $3000-3fff
uint8 ram_select; //$4000-5fff
uint8 mmio_read(uint16 addr);
void mmio_write(uint16 addr, uint8 data);

View File

@@ -1,19 +1,19 @@
#ifdef CARTRIDGE_CPP
uint8 Cartridge::MMM01::mmio_read(uint16 addr) {
if(within<0x0000, 0x7fff>(addr)) {
if((addr & 0x8000) == 0x0000) { //$0000-7fff
if(rom_mode == 0) return cartridge.rom_read(addr);
}
if(within<0x0000, 0x3fff>(addr)) {
if((addr & 0xc000) == 0x0000) { //$0000-3fff
return cartridge.rom_read(0x8000 + (rom_base << 14) + (addr & 0x3fff));
}
if(within<0x4000, 0x7fff>(addr)) {
if((addr & 0xc000) == 0x4000) { //$4000-7fff
return cartridge.rom_read(0x8000 + (rom_base << 14) + (rom_select << 14) + (addr & 0x3fff));
}
if(within<0xa000, 0xbfff>(addr)) {
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) return cartridge.ram_read((ram_select << 13) + (addr & 0x1fff));
return 0x00;
}
@@ -22,7 +22,7 @@ uint8 Cartridge::MMM01::mmio_read(uint16 addr) {
}
void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
if(within<0x0000, 0x1fff>(addr)) {
if((addr & 0xe000) == 0x0000) { //$0000-1fff
if(rom_mode == 0) {
rom_mode = 1;
} else {
@@ -30,7 +30,7 @@ void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
}
}
if(within<0x2000, 0x3fff>(addr)) {
if((addr & 0xe000) == 0x2000) { //$2000-3fff
if(rom_mode == 0) {
rom_base = data & 0x3f;
} else {
@@ -38,17 +38,17 @@ void Cartridge::MMM01::mmio_write(uint16 addr, uint8 data) {
}
}
if(within<0x4000, 0x5fff>(addr)) {
if((addr & 0xe000) == 0x4000) { //$4000-5fff
if(rom_mode == 1) {
ram_select = data;
}
}
if(within<0x6000, 0x7fff>(addr)) {
if((addr & 0xe000) == 0x6000) { //$6000-7fff
//unknown purpose
}
if(within<0xa000, 0xbfff>(addr)) {
if((addr & 0xe000) == 0xa000) { //$a000-bfff
if(ram_enable) cartridge.ram_write((ram_select << 13) + (addr & 0x1fff), data);
}
}

View File

@@ -41,9 +41,10 @@ void Cartridge::serialize(serializer &s) {
s.integer(mmm01.rom_select);
s.integer(mmm01.ram_select);
s.integer(huc1.ram_enable);
s.integer(huc1.ram_writable);
s.integer(huc1.rom_select);
s.integer(huc1.ram_select);
s.integer(huc1.model);
s.integer(huc3.ram_enable);
s.integer(huc3.rom_select);

View File

@@ -69,12 +69,6 @@ namespace GameBoy {
typedef uint_t<30> uint30;
typedef uint_t<31> uint31;
template<uint16 lo, uint16 hi>
alwaysinline bool within(uint16 addr) {
static const uint16 mask = ~(hi ^ lo);
return (addr & mask) == lo;
}
struct Processor {
cothread_t thread;
unsigned frequency;

View File

@@ -140,7 +140,7 @@ void LCD::cgb_render_ob() {
unsigned n = sprite[s] << 2;
unsigned sy = oam[n + 0] - 16;
unsigned sx = oam[n + 1] - 8;
unsigned tile = oam[n + 2];
unsigned tile = oam[n + 2] & ~status.ob_size;
unsigned attr = oam[n + 3];
sy = status.ly - sy;

View File

@@ -109,7 +109,7 @@ void LCD::dmg_render_ob() {
unsigned n = sprite[s] << 2;
unsigned sy = oam[n + 0] - 16;
unsigned sx = oam[n + 1] - 8;
unsigned tile = oam[n + 2];
unsigned tile = oam[n + 2] & ~status.ob_size;
unsigned attr = oam[n + 3];
sy = status.ly - sy;

View File

@@ -41,6 +41,9 @@ ifeq ($(compiler),)
endif
endif
c := $(compiler) -std=gnu99
cpp := $(subst cc,++,$(compiler)) -std=gnu++0x
ifeq ($(prefix),)
prefix := /usr/local
endif

View File

@@ -118,16 +118,21 @@ namespace nall {
operator=(std::move(source));
}
//index
inline T& operator[](unsigned index) {
if(index >= buffersize) resize(index + 1);
if(index >= buffersize) throw "array[] out of bounds";
return pool[index];
//access
inline T& operator[](unsigned position) {
if(position >= buffersize) resize(position + 1);
if(position >= buffersize) throw "array[] out of bounds";
return pool[position];
}
inline const T& operator[](unsigned index) const {
if(index >= buffersize) throw "array[] out of bounds";
return pool[index];
inline const T& operator[](unsigned position) const {
if(position >= buffersize) throw "array[] out of bounds";
return pool[position];
}
inline const T& operator()(unsigned position, const T& data) {
if(position >= buffersize) return data;
return pool[position];
}
//iteration

View File

@@ -8,11 +8,49 @@ namespace nall {
struct compositor {
inline static bool enabled();
inline static bool enable(bool status);
#if defined(PLATFORM_X)
enum class Compositor : unsigned { Unknown, Metacity, Xfwm4 };
inline static Compositor detect();
inline static bool enabled_metacity();
inline static bool enable_metacity(bool status);
inline static bool enabled_xfwm4();
inline static bool enable_xfwm4(bool status);
#endif
};
#if defined(PLATFORM_X)
bool compositor::enabled() {
//Metacity
bool compositor::enabled_metacity() {
FILE *fp = popen("gconftool-2 --get /apps/metacity/general/compositing_manager", "r");
if(fp == 0) return false;
char buffer[512];
if(fgets(buffer, sizeof buffer, fp) == 0) return false;
if(!memcmp(buffer, "true", 4)) return true;
return false;
}
bool compositor::enable_metacity(bool status) {
FILE *fp;
if(status) {
fp = popen("gconftool-2 --set --type bool /apps/metacity/general/compositing_manager true", "r");
} else {
fp = popen("gconftool-2 --set --type bool /apps/metacity/general/compositing_manager false", "r");
}
if(fp == 0) return false;
pclose(fp);
return true;
}
//Xfwm4
bool compositor::enabled_xfwm4() {
FILE *fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing'", "r");
if(fp == 0) return false;
@@ -23,7 +61,7 @@ bool compositor::enabled() {
return false;
}
bool compositor::enable(bool status) {
bool compositor::enable_xfwm4(bool status) {
FILE *fp;
if(status) {
fp = popen("xfconf-query -c xfwm4 -p '/general/use_compositing' -t 'bool' -s 'true'", "r");
@@ -35,6 +73,41 @@ bool compositor::enable(bool status) {
return true;
}
//General
compositor::Compositor compositor::detect() {
Compositor result = Compositor::Unknown;
FILE *fp;
char buffer[512];
fp = popen("pidof metacity", "r");
if(fp && fgets(buffer, sizeof buffer, fp)) result = Compositor::Metacity;
pclose(fp);
fp = popen("pidof xfwm4", "r");
if(fp && fgets(buffer, sizeof buffer, fp)) result = Compositor::Xfwm4;
pclose(fp);
return result;
}
bool compositor::enabled() {
switch(detect()) {
case Compositor::Metacity: return enabled_metacity();
case Compositor::Xfwm4: return enabled_xfwm4();
default: return false;
}
}
bool compositor::enable(bool status) {
switch(detect()) {
case Compositor::Metacity: return enable_metacity(status);
case Compositor::Xfwm4: return enable_xfwm4(status);
default: return false;
}
}
#elif defined(PLATFORM_WINDOWS)
bool compositor::enabled() {

View File

@@ -1,6 +1,7 @@
#ifndef NALL_FILEMAP_HPP
#define NALL_FILEMAP_HPP
#include <nall/file.hpp>
#include <nall/stdint.hpp>
#include <nall/windows/utf8.hpp>

View File

@@ -100,6 +100,16 @@ GameBoyCartridge::GameBoyCartridge(uint8_t *romdata, unsigned romsize) {
if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit
markup.append(
"<?xml version='1.0' encoding='UTF-8'?>\n",
"<cartridge mapper='", info.mapper, "' rtc='", info.rtc, "' rumble='", info.rumble, "'>\n",
" <rom size='0x", hex(romsize), "'/>\n");
if(info.ramsize > 0) markup.append(
" <ram size='0x", hex(info.ramsize), "' battery='", info.battery, "'/>\n");
markup.append(
"</cartridge>\n");
/*
markup.append("cartridge mapper=", info.mapper);
if(info.rtc) markup.append(" rtc");
if(info.rumble) markup.append(" rumble");
@@ -109,6 +119,7 @@ GameBoyCartridge::GameBoyCartridge(uint8_t *romdata, unsigned romsize) {
if(info.ramsize > 0)
markup.append("\t" "ram size=", hex(info.ramsize), info.battery ? " non-volatile\n" : "\n");
*/
}
}

55
bsnes/nall/hid.hpp Executable file
View File

@@ -0,0 +1,55 @@
#ifndef NALL_HID_HPP
#define NALL_HID_HPP
#include <nall/xorg/xorg.hpp>
#include <nall/input.hpp>
namespace nall {
namespace HID {
struct Keyboard {
XlibDisplay *display;
inline void poll() {
XQueryKeymap(display, state);
}
inline bool operator[](unsigned id) {
return state[scancode[id] >> 3] & (1 << (scancode[id] & 7));
}
inline Keyboard() {
display = XOpenDisplay(0);
memset(&scancode, 0, sizeof scancode);
#define map(key, sym) scancode[key] = XKeysymToKeycode(display, sym)
using nall::Keyboard;
map(Keyboard::Insert, XK_Insert);
map(Keyboard::Delete, XK_Delete);
map(Keyboard::Home, XK_Home);
map(Keyboard::End, XK_End);
map(Keyboard::PageUp, XK_Prior);
map(Keyboard::PageDown, XK_Next);
map(Keyboard::Up, XK_Up);
map(Keyboard::Down, XK_Down);
map(Keyboard::Left, XK_Left);
map(Keyboard::Right, XK_Right);
#undef map
}
inline ~Keyboard() {
XCloseDisplay(display);
}
private:
char state[32];
uint8_t scancode[256];
};
}
}
#endif

443
bsnes/nall/image.hpp Executable file
View File

@@ -0,0 +1,443 @@
#ifndef NALL_IMAGE_HPP
#define NALL_IMAGE_HPP
#include <nall/bmp.hpp>
#include <nall/interpolation.hpp>
#include <nall/png.hpp>
#include <nall/stdint.hpp>
#include <algorithm>
namespace nall {
struct image {
uint8_t *data;
unsigned width;
unsigned height;
unsigned pitch;
bool endian; //0 = little, 1 = big
unsigned depth;
unsigned stride;
struct Channel {
uint64_t mask;
unsigned depth;
unsigned shift;
} alpha, red, green, blue;
typedef double (*interpolation)(double, double, double, double, double);
static inline unsigned bitDepth(uint64_t color);
static inline unsigned bitShift(uint64_t color);
static inline uint64_t normalize(uint64_t color, unsigned sourceDepth, unsigned targetDepth);
inline image& operator=(const image &source);
inline image& operator=(image &&source);
inline image(const image &source);
inline image(image &&source);
inline image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask);
inline ~image();
inline uint64_t read(const uint8_t *data) const;
inline void write(uint8_t *data, uint64_t value) const;
inline void free();
inline void allocate(unsigned width, unsigned height);
inline void clear(uint64_t color);
inline bool load(const string &filename);
inline void scale(unsigned width, unsigned height, interpolation op);
inline void transform(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask);
inline void alphaBlend(uint64_t alphaColor);
protected:
inline uint64_t interpolate(double mu, const uint64_t *s, interpolation op);
inline void scaleX(unsigned width, interpolation op);
inline void scaleY(unsigned height, interpolation op);
inline bool loadBMP(const string &filename);
inline bool loadPNG(const string &filename);
};
//static
unsigned image::bitDepth(uint64_t color) {
unsigned depth = 0;
if(color) while((color & 1) == 0) color >>= 1;
while((color & 1) == 1) { color >>= 1; depth++; }
return depth;
}
unsigned image::bitShift(uint64_t color) {
unsigned shift = 0;
if(color) while((color & 1) == 0) { color >>= 1; shift++; }
return shift;
}
uint64_t image::normalize(uint64_t color, unsigned sourceDepth, unsigned targetDepth) {
while(sourceDepth < targetDepth) {
color = (color << sourceDepth) | color;
sourceDepth += sourceDepth;
}
if(targetDepth < sourceDepth) color >>= (sourceDepth - targetDepth);
return color;
}
//public
image& image::operator=(const image &source) {
free();
width = source.width;
height = source.height;
pitch = source.pitch;
endian = source.endian;
stride = source.stride;
alpha = source.alpha;
red = source.red;
green = source.green;
blue = source.blue;
data = new uint8_t[width * height * stride];
memcpy(data, source.data, width * height * stride);
return *this;
}
image& image::operator=(image &&source) {
width = source.width;
height = source.height;
pitch = source.pitch;
endian = source.endian;
stride = source.stride;
alpha = source.alpha;
red = source.red;
green = source.green;
blue = source.blue;
data = source.data;
source.data = nullptr;
return *this;
}
image::image(const image &source) : data(nullptr) {
operator=(source);
}
image::image(image &&source) : data(nullptr) {
operator=(std::forward<image>(source));
}
image::image(bool endian, unsigned depth, uint64_t alphaMask, uint64_t redMask, uint64_t greenMask, uint64_t blueMask) : data(nullptr) {
width = 0, height = 0, pitch = 0;
this->endian = endian;
this->depth = depth;
this->stride = (depth / 8) + ((depth & 7) > 0);
alpha.mask = alphaMask, red.mask = redMask, green.mask = greenMask, blue.mask = blueMask;
alpha.depth = bitDepth(alpha.mask), alpha.shift = bitShift(alpha.mask);
red.depth = bitDepth(red.mask), red.shift = bitShift(red.mask);
green.depth = bitDepth(green.mask), green.shift = bitShift(green.mask);
blue.depth = bitDepth(blue.mask), blue.shift = bitShift(blue.mask);
}
image::~image() {
free();
}
uint64_t image::read(const uint8_t *data) const {
uint64_t result = 0;
if(endian == 0) {
for(signed n = stride - 1; n >= 0; n--) result = (result << 8) | data[n];
} else {
for(signed n = 0; n < stride; n++) result = (result << 8) | data[n];
}
return result;
}
void image::write(uint8_t *data, uint64_t value) const {
if(endian == 0) {
for(signed n = 0; n < stride; n++) { data[n] = value; value >>= 8; }
} else {
for(signed n = stride - 1; n >= 0; n--) { data[n] = value; value >>= 8; }
}
}
void image::free() {
if(data) delete[] data;
data = nullptr;
}
void image::allocate(unsigned width, unsigned height) {
if(data != nullptr && this->width == width && this->height == height) return;
free();
data = new uint8_t[width * height * stride]();
pitch = width * stride;
this->width = width;
this->height = height;
}
void image::clear(uint64_t color) {
uint8_t *dp = data;
for(unsigned n = 0; n < width * height; n++) {
write(dp, color);
dp += stride;
}
}
bool image::load(const string &filename) {
if(loadBMP(filename) == true) return true;
if(loadPNG(filename) == true) return true;
return false;
}
void image::scale(unsigned outputWidth, unsigned outputHeight, interpolation op) {
scaleX(outputWidth, op);
scaleY(outputHeight, op);
}
void image::transform(bool outputEndian, unsigned outputDepth, uint64_t outputAlphaMask, uint64_t outputRedMask, uint64_t outputGreenMask, uint64_t outputBlueMask) {
image output(outputEndian, outputDepth, outputAlphaMask, outputRedMask, outputGreenMask, outputBlueMask);
output.allocate(width, height);
#pragma omp parallel for
for(unsigned y = 0; y < height; y++) {
uint8_t *dp = output.data + output.pitch * y;
uint8_t *sp = data + pitch * y;
for(unsigned x = 0; x < width; x++) {
uint64_t color = read(sp);
sp += stride;
uint64_t a = (color & alpha.mask) >> alpha.shift;
uint64_t r = (color & red.mask) >> red.shift;
uint64_t g = (color & green.mask) >> green.shift;
uint64_t b = (color & blue.mask) >> blue.shift;
a = normalize(a, alpha.depth, output.alpha.depth);
r = normalize(r, red.depth, output.red.depth);
g = normalize(g, green.depth, output.green.depth);
b = normalize(b, blue.depth, output.blue.depth);
output.write(dp, (a << output.alpha.shift) | (r << output.red.shift) | (g << output.green.shift) | (b << output.blue.shift));
dp += output.stride;
}
}
operator=(std::move(output));
}
void image::alphaBlend(uint64_t alphaColor) {
uint64_t alphaR = (alphaColor & red.mask) >> red.shift;
uint64_t alphaG = (alphaColor & green.mask) >> green.shift;
uint64_t alphaB = (alphaColor & blue.mask) >> blue.shift;
#pragma omp parallel for
for(unsigned y = 0; y < height; y++) {
uint8_t *dp = data + pitch * y;
for(unsigned x = 0; x < width; x++) {
uint64_t color = read(dp);
uint64_t colorA = (color & alpha.mask) >> alpha.shift;
uint64_t colorR = (color & red.mask) >> red.shift;
uint64_t colorG = (color & green.mask) >> green.shift;
uint64_t colorB = (color & blue.mask) >> blue.shift;
double alphaScale = (double)colorA / (double)((1 << alpha.depth) - 1);
colorA = (1 << alpha.depth) - 1;
colorR = (colorR * alphaScale) + (alphaR * (1.0 - alphaScale));
colorG = (colorG * alphaScale) + (alphaG * (1.0 - alphaScale));
colorB = (colorB * alphaScale) + (alphaB * (1.0 - alphaScale));
write(dp, (colorA << alpha.shift) | (colorR << red.shift) | (colorG << green.shift) | (colorB << blue.shift));
dp += stride;
}
}
}
//protected
uint64_t image::interpolate(double mu, const uint64_t *s, double (*op)(double, double, double, double, double)) {
uint64_t aa = (s[0] & alpha.mask) >> alpha.shift, ar = (s[0] & red.mask) >> red.shift,
ag = (s[0] & green.mask) >> green.shift, ab = (s[0] & blue.mask) >> blue.shift;
uint64_t ba = (s[1] & alpha.mask) >> alpha.shift, br = (s[1] & red.mask) >> red.shift,
bg = (s[1] & green.mask) >> green.shift, bb = (s[1] & blue.mask) >> blue.shift;
uint64_t ca = (s[2] & alpha.mask) >> alpha.shift, cr = (s[2] & red.mask) >> red.shift,
cg = (s[2] & green.mask) >> green.shift, cb = (s[2] & blue.mask) >> blue.shift;
uint64_t da = (s[3] & alpha.mask) >> alpha.shift, dr = (s[3] & red.mask) >> red.shift,
dg = (s[3] & green.mask) >> green.shift, db = (s[3] & blue.mask) >> blue.shift;
int64_t A = op(mu, aa, ba, ca, da);
int64_t R = op(mu, ar, br, cr, dr);
int64_t G = op(mu, ag, bg, cg, dg);
int64_t B = op(mu, ab, bb, cb, db);
A = max(0, min(A, (1 << alpha.depth) - 1));
R = max(0, min(R, (1 << red.depth) - 1));
G = max(0, min(G, (1 << green.depth) - 1));
B = max(0, min(B, (1 << blue.depth) - 1));
return (A << alpha.shift) | (R << red.shift) | (G << green.shift) | (B << blue.shift);
}
void image::scaleX(unsigned outputWidth, interpolation op) {
uint8_t *outputData = new uint8_t[outputWidth * height * stride];
unsigned outputPitch = outputWidth * stride;
double step = (double)width / (double)outputWidth;
#pragma omp parallel for
for(unsigned y = 0; y < height; y++) {
uint8_t *dp = outputData + outputPitch * y;
uint8_t *sp = data + pitch * y;
double fraction = 0.0;
uint64_t s[4] = { read(sp), read(sp), read(sp), read(sp) };
for(unsigned x = 0; x < width; x++) {
if(sp >= data + pitch * height) break;
s[0] = s[1];
s[1] = s[2];
s[2] = s[3];
s[3] = read(sp);
while(fraction <= 1.0) {
if(dp >= outputData + outputPitch * height) break;
write(dp, interpolate(fraction, (const uint64_t*)&s, op));
dp += stride;
fraction += step;
}
sp += stride;
fraction -= 1.0;
}
}
free();
data = outputData;
width = outputWidth;
pitch = width * stride;
}
void image::scaleY(unsigned outputHeight, interpolation op) {
uint8_t *outputData = new uint8_t[width * outputHeight * stride];
double step = (double)height / (double)outputHeight;
#pragma omp parallel for
for(unsigned x = 0; x < width; x++) {
uint8_t *dp = outputData + stride * x;
uint8_t *sp = data + stride * x;
double fraction = 0.0;
uint64_t s[4] = { read(sp), read(sp), read(sp), read(sp) };
for(unsigned y = 0; y < height; y++) {
if(sp >= data + pitch * height) break;
s[0] = s[1];
s[1] = s[2];
s[2] = s[3];
s[3] = read(sp);
while(fraction <= 1.0) {
if(dp >= outputData + pitch * outputHeight) break;
write(dp, interpolate(fraction, (const uint64_t*)&s, op));
dp += pitch;
fraction += step;
}
sp += pitch;
fraction -= 1.0;
}
}
free();
data = outputData;
height = outputHeight;
}
bool image::loadBMP(const string &filename) {
uint32_t *outputData;
unsigned outputWidth, outputHeight;
if(bmp::read(filename, outputData, outputWidth, outputHeight) == false) return false;
allocate(outputWidth, outputHeight);
const uint32_t *sp = outputData;
uint8_t *dp = data;
for(unsigned y = 0; y < outputHeight; y++) {
for(unsigned x = 0; x < outputWidth; x++) {
uint32_t color = *sp++;
uint64_t a = normalize((uint8_t)(color >> 24), 8, alpha.depth);
uint64_t r = normalize((uint8_t)(color >> 16), 8, red.depth);
uint64_t g = normalize((uint8_t)(color >> 8), 8, green.depth);
uint64_t b = normalize((uint8_t)(color >> 0), 8, blue.depth);
write(dp, (a << alpha.shift) | (r << red.shift) | (g << green.shift) | (b << blue.shift));
dp += stride;
}
}
delete[] outputData;
return true;
}
bool image::loadPNG(const string &filename) {
png source;
if(source.decode(filename) == false) return false;
allocate(source.info.width, source.info.height);
const uint8_t *sp = source.data;
uint8_t *dp = data;
auto decode = [&]() -> uint64_t {
uint64_t p, r, g, b, a;
switch(source.info.colorType) {
case 0: //L
r = g = b = source.readbits(sp);
a = (1 << source.info.bitDepth) - 1;
break;
case 2: //R,G,B
r = source.readbits(sp);
g = source.readbits(sp);
b = source.readbits(sp);
a = (1 << source.info.bitDepth) - 1;
break;
case 3: //P
p = source.readbits(sp);
r = source.info.palette[p][0];
g = source.info.palette[p][1];
b = source.info.palette[p][2];
a = (1 << source.info.bitDepth) - 1;
break;
case 4: //L,A
r = g = b = source.readbits(sp);
a = source.readbits(sp);
break;
case 6: //R,G,B,A
r = source.readbits(sp);
g = source.readbits(sp);
b = source.readbits(sp);
a = source.readbits(sp);
break;
}
a = normalize(a, source.info.bitDepth, alpha.depth);
r = normalize(r, source.info.bitDepth, red.depth);
g = normalize(g, source.info.bitDepth, green.depth);
b = normalize(b, source.info.bitDepth, blue.depth);
return (a << alpha.shift) | (r << red.shift) | (g << green.shift) | (b << blue.shift);
};
for(unsigned y = 0; y < height; y++) {
for(unsigned x = 0; x < width; x++) {
write(dp, decode());
dp += stride;
}
}
return true;
}
}
#endif

59
bsnes/nall/interpolation.hpp Executable file
View File

@@ -0,0 +1,59 @@
#ifndef NALL_INTERPOLATION_HPP
#define NALL_INTERPOLATION_HPP
namespace nall {
struct Interpolation {
static inline double Nearest(double mu, double a, double b, double c, double d) {
return (mu < 0.5 ? c : d);
}
static inline double Sublinear(double mu, double a, double b, double c, double d) {
mu = ((mu - 0.5) * 2.0) + 0.5;
if(mu < 0) mu = 0;
if(mu > 1) mu = 1;
return c * (1.0 - mu) + d * mu;
}
static inline double Linear(double mu, double a, double b, double c, double d) {
return c * (1.0 - mu) + d * mu;
}
static inline double Cosine(double mu, double a, double b, double c, double d) {
mu = (1.0 - cos(mu * 3.14159265)) / 2.0;
return c * (1.0 - mu) + d * mu;
}
static inline double Cubic(double mu, double a, double b, double c, double d) {
double A = d - c - a + b;
double B = a - b - A;
double C = c - a;
double D = b;
return A * (mu * mu * mu) + B * (mu * mu) + C * mu + D;
}
static inline double Hermite(double mu1, double a, double b, double c, double d) {
const double tension = 0.0; //-1 = low, 0 = normal, +1 = high
const double bias = 0.0; //-1 = left, 0 = even, +1 = right
double mu2, mu3, m0, m1, a0, a1, a2, a3;
mu2 = mu1 * mu1;
mu3 = mu2 * mu1;
m0 = (b - a) * (1.0 + bias) * (1.0 - tension) / 2.0;
m0 += (c - b) * (1.0 - bias) * (1.0 - tension) / 2.0;
m1 = (c - b) * (1.0 + bias) * (1.0 - tension) / 2.0;
m1 += (d - c) * (1.0 - bias) * (1.0 - tension) / 2.0;
a0 = +2 * mu3 - 3 * mu2 + 1;
a1 = mu3 - 2 * mu2 + mu1;
a2 = mu3 - mu2;
a3 = -2 * mu3 + 3 * mu2;
return (a0 * b) + (a1 * m0) + (a2 * m1) + (a3 * c);
}
};
}
#endif

10
bsnes/nall/mosaic.hpp Executable file
View File

@@ -0,0 +1,10 @@
#ifndef NALL_MOSAIC_HPP
#define NALL_MOSAIC_HPP
#define NALL_MOSAIC_INTERNAL_HPP
#include <nall/mosaic/bitstream.hpp>
#include <nall/mosaic/context.hpp>
#include <nall/mosaic/parser.hpp>
#undef NALL_MOSAIC_INTERNAL_HPP
#endif

55
bsnes/nall/mosaic/bitstream.hpp Executable file
View File

@@ -0,0 +1,55 @@
#ifdef NALL_MOSAIC_INTERNAL_HPP
namespace nall {
namespace mosaic {
struct bitstream {
filemap fp;
uint8_t *data;
unsigned size;
bool readonly;
bool endian;
inline bool read(uint64_t addr) const {
if(data == nullptr || (addr >> 3) >= size) return 0;
unsigned mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7));
return data[addr >> 3] & mask;
}
inline void write(uint64_t addr, bool value) {
if(data == nullptr || readonly == true || (addr >> 3) >= size) return;
unsigned mask = endian == 0 ? (0x01 << (addr & 7)) : (0x80 >> (addr & 7));
if(value == 0) data[addr >> 3] &= ~mask;
if(value == 1) data[addr >> 3] |= mask;
}
inline bool open(const string &filename) {
readonly = false;
if(fp.open(filename, filemap::mode::readwrite) == false) {
readonly = true;
if(fp.open(filename, filemap::mode::read) == false) {
return false;
}
}
data = fp.data();
size = fp.size();
return true;
}
inline void close() {
fp.close();
data = nullptr;
}
inline bitstream() : data(nullptr), endian(1) {
}
inline ~bitstream() {
close();
}
};
}
}
#endif

224
bsnes/nall/mosaic/context.hpp Executable file
View File

@@ -0,0 +1,224 @@
#ifdef NALL_MOSAIC_INTERNAL_HPP
namespace nall {
namespace mosaic {
struct context {
unsigned offset;
unsigned width;
unsigned height;
unsigned count;
bool endian; //0 = lsb, 1 = msb
bool order; //0 = linear, 1 = planar
unsigned depth; //1 - 24bpp
unsigned blockWidth;
unsigned blockHeight;
unsigned blockStride;
unsigned blockOffset;
array<unsigned> block;
unsigned tileWidth;
unsigned tileHeight;
unsigned tileStride;
unsigned tileOffset;
array<unsigned> tile;
unsigned mosaicWidth;
unsigned mosaicHeight;
unsigned mosaicStride;
unsigned mosaicOffset;
array<unsigned> mosaic;
unsigned paddingWidth;
unsigned paddingHeight;
unsigned paddingColor;
array<unsigned> palette;
inline unsigned objectWidth() const { return blockWidth * tileWidth * mosaicWidth + paddingWidth; }
inline unsigned objectHeight() const { return blockHeight * tileHeight * mosaicHeight + paddingHeight; }
inline unsigned objectSize() const {
unsigned size = blockStride * tileWidth * tileHeight * mosaicWidth * mosaicHeight
+ blockOffset * tileHeight * mosaicWidth * mosaicHeight
+ tileStride * mosaicWidth * mosaicHeight
+ tileOffset * mosaicHeight;
return max(1u, size);
}
inline unsigned eval(const string &expression) {
intmax_t result;
if(fixedpoint::eval(expression, result) == false) return 0u;
return result;
}
inline void eval(array<unsigned> &buffer, const string &expression_) {
string expression = expression_;
bool function = false;
for(auto &c : expression) {
if(c == '(') function = true;
if(c == ')') function = false;
if(c == ',' && function == true) c = ';';
}
lstring list = expression.split(",");
for(auto &item : list) {
item.trim();
if(item.wildcard("f(?*) ?*")) {
item.ltrim<1>("f(");
lstring part = item.split<1>(") ");
lstring args = part[0].split<3>(";");
for(auto &item : args) item.trim();
unsigned length = eval(args(0, "0"));
unsigned offset = eval(args(1, "0"));
unsigned stride = eval(args(2, "0"));
if(args.size() < 2) offset = buffer.size();
if(args.size() < 3) stride = 1;
for(unsigned n = 0; n < length; n++) {
string fn = part[1];
fn.replace("n", decimal(n));
fn.replace("o", decimal(offset));
fn.replace("p", decimal(buffer.size()));
buffer.resize(offset + 1);
buffer[offset] = eval(fn);
offset += stride;
}
} else if(item.wildcard("base64*")) {
unsigned offset = 0;
item.ltrim<1>("base64");
if(item.wildcard("(?*) *")) {
item.ltrim<1>("(");
lstring part = item.split<1>(") ");
offset = eval(part[0]);
item = part(1, "");
}
item.trim();
for(auto &c : item) {
if(c >= 'A' && c <= 'Z') buffer.append(offset + c - 'A' + 0);
if(c >= 'a' && c <= 'z') buffer.append(offset + c - 'a' + 26);
if(c >= '0' && c <= '9') buffer.append(offset + c - '0' + 52);
if(c == '-') buffer.append(offset + 62);
if(c == '_') buffer.append(offset + 63);
}
} else if(item.wildcard("file *")) {
item.ltrim<1>("file ");
item.trim();
//...
} else if(item.empty() == false) {
buffer.append(eval(item));
}
}
}
inline void parse(const string &data) {
reset();
lstring lines = data.split("\n");
for(auto &line : lines) {
lstring part = line.split<1>(":");
if(part.size() != 2) continue;
part[0].trim();
part[1].trim();
if(part[0] == "offset") offset = eval(part[1]);
if(part[0] == "width") width = eval(part[1]);
if(part[0] == "height") height = eval(part[1]);
if(part[0] == "count") count = eval(part[1]);
if(part[0] == "endian") endian = eval(part[1]);
if(part[0] == "order") order = eval(part[1]);
if(part[0] == "depth") depth = eval(part[1]);
if(part[0] == "blockWidth") blockWidth = eval(part[1]);
if(part[0] == "blockHeight") blockHeight = eval(part[1]);
if(part[0] == "blockStride") blockStride = eval(part[1]);
if(part[0] == "blockOffset") blockOffset = eval(part[1]);
if(part[0] == "block") eval(block, part[1]);
if(part[0] == "tileWidth") tileWidth = eval(part[1]);
if(part[0] == "tileHeight") tileHeight = eval(part[1]);
if(part[0] == "tileStride") tileStride = eval(part[1]);
if(part[0] == "tileOffset") tileOffset = eval(part[1]);
if(part[0] == "tile") eval(tile, part[1]);
if(part[0] == "mosaicWidth") mosaicWidth = eval(part[1]);
if(part[0] == "mosaicHeight") mosaicHeight = eval(part[1]);
if(part[0] == "mosaicStride") mosaicStride = eval(part[1]);
if(part[0] == "mosaicOffset") mosaicOffset = eval(part[1]);
if(part[0] == "mosaic") eval(mosaic, part[1]);
if(part[0] == "paddingWidth") paddingWidth = eval(part[1]);
if(part[0] == "paddingHeight") paddingHeight = eval(part[1]);
if(part[0] == "paddingColor") paddingColor = eval(part[1]);
if(part[0] == "palette") eval(palette, part[1]);
}
sanitize();
}
inline bool load(const string &filename) {
string filedata;
if(filedata.readfile(filename) == false) return false;
parse(filedata);
return true;
}
inline void sanitize() {
if(depth < 1) depth = 1;
if(depth > 24) depth = 24;
if(blockWidth < 1) blockWidth = 1;
if(blockHeight < 1) blockHeight = 1;
if(tileWidth < 1) tileWidth = 1;
if(tileHeight < 1) tileHeight = 1;
if(mosaicWidth < 1) mosaicWidth = 1;
if(mosaicHeight < 1) mosaicHeight = 1;
}
inline void reset() {
offset = 0;
width = 0;
height = 0;
count = 0;
endian = 1;
order = 0;
depth = 1;
blockWidth = 1;
blockHeight = 1;
blockStride = 0;
blockOffset = 0;
block.reset();
tileWidth = 1;
tileHeight = 1;
tileStride = 0;
tileOffset = 0;
tile.reset();
mosaicWidth = 1;
mosaicHeight = 1;
mosaicStride = 0;
mosaicOffset = 0;
mosaic.reset();
paddingWidth = 0;
paddingHeight = 0;
paddingColor = 0x000000;
palette.reset();
}
inline context() {
reset();
}
};
}
}
#endif

126
bsnes/nall/mosaic/parser.hpp Executable file
View File

@@ -0,0 +1,126 @@
#ifdef NALL_MOSAIC_INTERNAL_HPP
namespace nall {
namespace mosaic {
struct parser {
image canvas;
//export from bitstream to canvas
inline void load(bitstream &stream, uint64_t offset, context &ctx, unsigned width, unsigned height) {
canvas.allocate(width, height);
canvas.clear(ctx.paddingColor);
parse(1, stream, offset, ctx, width, height);
}
//import from canvas to bitstream
inline bool save(bitstream &stream, uint64_t offset, context &ctx) {
if(stream.readonly) return false;
parse(0, stream, offset, ctx, canvas.width, canvas.height);
return true;
}
inline parser() : canvas(0, 32, 0u, 255u << 16, 255u << 8, 255u << 0) {
}
private:
inline uint32_t read(unsigned x, unsigned y) const {
unsigned addr = y * canvas.width + x;
if(addr >= canvas.width * canvas.height) return 0u;
uint32_t *buffer = (uint32_t*)canvas.data;
return buffer[addr];
}
inline void write(unsigned x, unsigned y, uint32_t data) {
unsigned addr = y * canvas.width + x;
if(addr >= canvas.width * canvas.height) return;
uint32_t *buffer = (uint32_t*)canvas.data;
buffer[addr] = data;
}
inline void parse(bool load, bitstream &stream, uint64_t offset, context &ctx, unsigned width, unsigned height) {
stream.endian = ctx.endian;
unsigned canvasWidth = width / (ctx.mosaicWidth * ctx.tileWidth * ctx.blockWidth + ctx.paddingWidth);
unsigned canvasHeight = height / (ctx.mosaicHeight * ctx.tileHeight * ctx.blockHeight + ctx.paddingHeight);
unsigned bitsPerBlock = ctx.depth * ctx.blockWidth * ctx.blockHeight;
unsigned objectOffset = 0;
for(unsigned objectY = 0; objectY < canvasHeight; objectY++) {
for(unsigned objectX = 0; objectX < canvasWidth; objectX++) {
if(objectOffset >= ctx.count && ctx.count > 0) break;
unsigned objectIX = objectX * ctx.objectWidth();
unsigned objectIY = objectY * ctx.objectHeight();
objectOffset++;
unsigned mosaicOffset = 0;
for(unsigned mosaicY = 0; mosaicY < ctx.mosaicHeight; mosaicY++) {
for(unsigned mosaicX = 0; mosaicX < ctx.mosaicWidth; mosaicX++) {
unsigned mosaicData = ctx.mosaic(mosaicOffset, mosaicOffset);
unsigned mosaicIX = (mosaicData % ctx.mosaicWidth) * (ctx.tileWidth * ctx.blockWidth);
unsigned mosaicIY = (mosaicData / ctx.mosaicWidth) * (ctx.tileHeight * ctx.blockHeight);
mosaicOffset++;
unsigned tileOffset = 0;
for(unsigned tileY = 0; tileY < ctx.tileHeight; tileY++) {
for(unsigned tileX = 0; tileX < ctx.tileWidth; tileX++) {
unsigned tileData = ctx.tile(tileOffset, tileOffset);
unsigned tileIX = (tileData % ctx.tileWidth) * ctx.blockWidth;
unsigned tileIY = (tileData / ctx.tileWidth) * ctx.blockHeight;
tileOffset++;
unsigned blockOffset = 0;
for(unsigned blockY = 0; blockY < ctx.blockHeight; blockY++) {
for(unsigned blockX = 0; blockX < ctx.blockWidth; blockX++) {
if(load) {
unsigned palette = 0;
for(unsigned n = 0; n < ctx.depth; n++) {
unsigned index = blockOffset++;
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
palette |= stream.read(offset + ctx.block(index, index)) << n;
}
write(
objectIX + mosaicIX + tileIX + blockX,
objectIY + mosaicIY + tileIY + blockY,
ctx.palette(palette, palette)
);
} else /* save */ {
uint32_t palette = read(
objectIX + mosaicIX + tileIX + blockX,
objectIY + mosaicIY + tileIY + blockY
);
for(unsigned n = 0; n < ctx.depth; n++) {
unsigned index = blockOffset++;
if(ctx.order == 1) index = (index % ctx.depth) * ctx.blockWidth * ctx.blockHeight + (index / ctx.depth);
stream.write(offset + ctx.block(index, index), palette & 1);
palette >>= 1;
}
}
} //blockX
} //blockY
offset += ctx.blockStride;
} //tileX
offset += ctx.blockOffset;
} //tileY
offset += ctx.tileStride;
} //mosaicX
offset += ctx.tileOffset;
} //mosaicY
offset += ctx.mosaicStride;
} //objectX
offset += ctx.mosaicOffset;
} //objectY
}
};
}
}
#endif

View File

@@ -10,9 +10,12 @@
namespace nall {
struct png {
uint32_t *data;
unsigned size;
//colorType:
//0 = L
//2 = R,G,B
//3 = P
//4 = L,A
//6 = R,G,B,A
struct Info {
unsigned width;
unsigned height;
@@ -28,13 +31,14 @@ struct png {
uint8_t palette[256][3];
} info;
uint8_t *rawData;
unsigned rawSize;
uint8_t *data;
unsigned size;
inline bool decode(const string &filename);
inline bool decode(const uint8_t *sourceData, unsigned sourceSize);
inline void transform();
inline void alphaTransform(uint32_t rgb = 0xffffff);
inline unsigned readbits(const uint8_t *&data);
unsigned bitpos;
inline png();
inline ~png();
@@ -46,16 +50,11 @@ protected:
IEND = 0x49454e44,
};
unsigned bitpos;
inline unsigned interlace(unsigned pass, unsigned index);
inline unsigned inflateSize();
inline bool deinterlace(const uint8_t *&inputData, unsigned pass);
inline bool filter(uint8_t *outputData, const uint8_t *inputData, unsigned width, unsigned height);
inline unsigned read(const uint8_t *data, unsigned length);
inline unsigned decode(const uint8_t *&data);
inline unsigned readbits(const uint8_t *&data);
inline unsigned scale(unsigned n);
};
bool png::decode(const string &filename) {
@@ -146,14 +145,14 @@ bool png::decode(const uint8_t *sourceData, unsigned sourceSize) {
return false;
}
rawSize = info.width * info.height * info.bytesPerPixel;
rawData = new uint8_t[rawSize];
size = info.width * info.height * info.bytesPerPixel;
data = new uint8_t[size];
if(info.interlaceMethod == 0) {
if(filter(rawData, interlacedData, info.width, info.height) == false) {
if(filter(data, interlacedData, info.width, info.height) == false) {
delete[] interlacedData;
delete[] rawData;
rawData = 0;
delete[] data;
data = 0;
return false;
}
} else {
@@ -161,8 +160,8 @@ bool png::decode(const uint8_t *sourceData, unsigned sourceSize) {
for(unsigned pass = 0; pass < 7; pass++) {
if(deinterlace(passData, pass) == false) {
delete[] interlacedData;
delete[] rawData;
rawData = 0;
delete[] data;
data = 0;
return false;
}
}
@@ -216,7 +215,7 @@ bool png::deinterlace(const uint8_t *&inputData, unsigned pass) {
const uint8_t *rd = outputData;
for(unsigned y = yo; y < info.height; y += yd) {
uint8_t *wr = rawData + y * info.pitch;
uint8_t *wr = data + y * info.pitch;
for(unsigned x = xo; x < info.width; x += xd) {
for(unsigned b = 0; b < info.bytesPerPixel; b++) {
wr[x * info.bytesPerPixel + b] = *rd++;
@@ -298,42 +297,6 @@ unsigned png::read(const uint8_t *data, unsigned length) {
return result;
}
unsigned png::decode(const uint8_t *&data) {
unsigned p, r, g, b, a;
switch(info.colorType) {
case 0: //L
r = g = b = scale(readbits(data));
a = 0xff;
break;
case 2: //R,G,B
r = scale(readbits(data));
g = scale(readbits(data));
b = scale(readbits(data));
a = 0xff;
break;
case 3: //P
p = readbits(data);
r = info.palette[p][0];
g = info.palette[p][1];
b = info.palette[p][2];
a = 0xff;
break;
case 4: //L,A
r = g = b = scale(readbits(data));
a = scale(readbits(data));
break;
case 6: //R,G,B,A
r = scale(readbits(data));
g = scale(readbits(data));
b = scale(readbits(data));
a = scale(readbits(data));
break;
}
return (a << 24) | (r << 16) | (g << 8) | (b << 0);
}
unsigned png::readbits(const uint8_t *&data) {
unsigned result = 0;
switch(info.bitDepth) {
@@ -363,62 +326,12 @@ unsigned png::readbits(const uint8_t *&data) {
return result;
}
unsigned png::scale(unsigned n) {
switch(info.bitDepth) {
case 1: return n ? 0xff : 0x00;
case 2: return n * 0x55;
case 4: return n * 0x11;
case 8: return n;
case 16: return n >> 8;
}
return 0;
}
void png::transform() {
if(data) delete[] data;
data = new uint32_t[info.width * info.height];
png::png() : data(nullptr) {
bitpos = 0;
const uint8_t *rd = rawData;
for(unsigned y = 0; y < info.height; y++) {
uint32_t *wr = data + y * info.width;
for(unsigned x = 0; x < info.width; x++) {
wr[x] = decode(rd);
}
}
}
void png::alphaTransform(uint32_t rgb) {
transform();
uint8_t ir = rgb >> 16;
uint8_t ig = rgb >> 8;
uint8_t ib = rgb >> 0;
uint32_t *p = data;
for(unsigned y = 0; y < info.height; y++) {
for(unsigned x = 0; x < info.width; x++) {
uint32_t pixel = *p;
uint8_t a = pixel >> 24;
uint8_t r = pixel >> 16;
uint8_t g = pixel >> 8;
uint8_t b = pixel >> 0;
r = (r * a) + (ir * (255 - a)) >> 8;
g = (g * a) + (ig * (255 - a)) >> 8;
b = (b * a) + (ib * (255 - a)) >> 8;
*p++ = (255 << 24) | (r << 16) | (g << 8) | (b << 0);
}
}
}
png::png() : data(nullptr), rawData(nullptr) {
}
png::~png() {
if(data) delete[] data;
if(rawData) delete[] rawData;
}
}

View File

@@ -105,345 +105,438 @@ public:
bool has_st018;
};
#define T "\t"
SnesCartridge::SnesCartridge(const uint8_t *data, unsigned size) {
read_header(data, size);
string xml;
markup = "";
markup = "<?xml version='1.0' encoding='UTF-8'?>\n";
if(type == TypeBsx) {
markup.append("cartridge");
markup.append("<cartridge/>\n");
return;
}
if(type == TypeSufamiTurbo) {
markup.append("cartridge");
markup.append("<cartridge/>\n");
return;
}
if(type == TypeGameBoy) {
markup.append("cartridge rtc=", gameboy_has_rtc(data, size), "\n");
markup.append("<cartridge rtc='", gameboy_has_rtc(data, size), "'\n");
if(gameboy_ram_size(data, size) > 0) {
markup.append(T "ram size=0x", hex(gameboy_ram_size(data, size)), "\n");
markup.append(" <ram size='0x", hex(gameboy_ram_size(data, size)), "'>\n");
}
markup.append("</cartridge>\n");
return;
}
markup.append("cartridge region=", region == NTSC ? "NTSC\n" : "PAL\n");
const char *range = (rom_size > 0x200000) || (ram_size > 32 * 1024) ? "0000-7fff" : "0000-ffff";
markup.append("<cartridge region='", region == NTSC ? "NTSC" : "PAL", "'>\n");
if(type == TypeSuperGameBoy1Bios) {
markup.append(T "rom\n");
markup.append(T T "map mode=linear address=00-7f:8000-ffff\n");
markup.append(T T "map mode=linear address=80-ff:8000-ffff\n");
markup.append(T "icd2 revision=1\n");
markup.append(T T "map address=00-3f:6000-7fff\n");
markup.append(T T "map address=80-bf:6000-7fff\n");
} else if(type == TypeSuperGameBoy2Bios) {
markup.append(T "rom\n");
markup.append(T T "map mode=linear address=00-7f:8000-ffff\n");
markup.append(T T "map mode=linear address=80-ff:8000-ffff\n");
markup.append(T "icd2 revision=1\n");
markup.append(T T "map address=00-3f:6000-7fff\n");
markup.append(T T "map address=80-bf:6000-7fff\n");
} else if(has_cx4) {
markup.append(T "hitachidsp model=HG51B169 frequency=20000000 firmware=cx4.bin sha256=ae8d4d1961b93421ff00b3caa1d0f0ce7783e749772a3369c36b3dbf0d37ef18\n");
markup.append(T T "rom\n");
markup.append(T T T "map mode=linear address=00-7f:8000-ffff\n");
markup.append(T T T "map mode=linear address=80-ff:8000-ffff\n");
markup.append(T T "mmio\n");
markup.append(T T T "map address=00-3f:6000-7fff\n");
markup.append(T T T "map address=80-bf:6000-7fff\n");
} else if(has_spc7110) {
markup.append(T "rom\n");
markup.append(T T "map mode=shadow address=00-0f:8000-ffff\n");
markup.append(T T "map mode=shadow address=80-bf:8000-ffff\n");
markup.append(T T "map mode=linear address=c0-cf:0000-ffff\n");
if(type == TypeSuperGameBoy1Bios || type == TypeSuperGameBoy2Bios) markup.append(
" <rom>\n"
" <map mode='linear' address='00-7f:8000-ffff'/>\n"
" <map mode='linear' address='80-ff:8000-ffff'/>\n"
" </rom>\n"
" <icd2 revision='1'>\n"
" <map address='00-3f:6000-7fff'/>\n"
" <map address='80-bf:6000-7fff'/>\n"
" </icd2>\n"
);
markup.append(T "spc7110\n");
markup.append(T T "mcu\n");
markup.append(T T T "map address=d0-ff:0000-ffff offset=0x100000 size=0x", hex(size - 0x100000), "\n");
markup.append(T T "ram size=0x", hex(ram_size), "\n");
markup.append(T T T "map mode=linear address=00:6000-7fff\n");
markup.append(T T T "map mode=linear address=30:6000-7fff\n");
markup.append(T T "mmio\n");
markup.append(T T T "map address=00-3f:4800-483f\n");
markup.append(T T T "map address=80-bf:4800-483f\n");
if(has_spc7110rtc) {
markup.append(T T "rtc\n");
markup.append(T T T "map address=00-3f:4840-4842\n");
markup.append(T T T "map address=80-bf:4840-4842\n");
}
markup.append(T T "dcu\n");
markup.append(T T T "map address=50:0000-ffff\n");
} else if(mapper == LoROM) {
markup.append(T "rom\n");
markup.append(T T "map mode=linear address=00-7f:8000-ffff\n");
markup.append(T T "map mode=linear address=80-ff:8000-ffff\n");
else if(has_cx4) markup.append(
" <hitachidsp model='HG51B169' frequency='20000000' firmware='cx4.bin' sha256='ae8d4d1961b93421ff00b3caa1d0f0ce7783e749772a3369c36b3dbf0d37ef18'>\n"
" <rom>\n"
" <map mode='linear' address='00-7f:8000-ffff'/>\n"
" <map mode='linear' address='80-ff:8000-ffff'/>\n"
" </rom>\n"
" <mmio>\n"
" <map address='00-3f:6000-7fff'/>\n"
" <map address='80-bf:6000-7fff'/>\n"
" </mmio>\n"
" </hitachidsp>\n"
);
if(ram_size > 0) {
markup.append(T "ram size=0x", hex(ram_size), "\n");
markup.append(T T "map mode=linear address=20-3f:6000-7fff\n");
markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n");
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
markup.append(T T "map mode=linear address=70-7f:0000-7fff\n");
markup.append(T T "map mode=linear address=f0-ff:0000-7fff\n");
} else {
markup.append(T T "map mode=linear address=70-7f:0000-ffff\n");
markup.append(T T "map mode=linear address=f0-ff:0000-ffff\n");
}
}
} else if(mapper == HiROM) {
markup.append(T "rom\n");
markup.append(T T "map mode=shadow address=00-3f:8000-ffff\n");
markup.append(T T "map mode=linear address=40-7f:0000-ffff\n");
markup.append(T T "map mode=shadow address=80-bf:8000-ffff\n");
markup.append(T T "map mode=linear address=c0-ff:0000-ffff\n");
if(ram_size > 0) {
markup.append(T "ram size=0x", hex(ram_size), "\n");
markup.append(T T "map mode=linear address=20-3f:6000-7fff\n");
markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n");
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
markup.append(T T "map mode=linear address=70-7f:0000-7fff\n");
} else {
markup.append(T T "map mode=linear address=70-7f:0000-ffff\n");
}
}
} else if(mapper == ExLoROM) {
markup.append(T "rom\n");
markup.append(T T "map mode=linear address=00-3f:8000-ffff\n");
markup.append(T T "map mode=linear address=40-7f:0000-ffff\n");
markup.append(T T "map mode=linear address=80-bf:8000-ffff\n");
if(ram_size > 0) {
markup.append(T "ram size=0x", hex(ram_size), "\n");
markup.append(T T "map mode=linear address=20-3f:6000-7fff\n");
markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n");
markup.append(T T "map mode=linear address=70-7f:0000-7fff\n");
}
} else if(mapper == ExHiROM) {
markup.append(T "rom\n");
markup.append(T T "map mode=shadow address=00-3f:8000-ffff offset=0x400000\n");
markup.append(T T "map mode=linear address=40-7f:0000-ffff offset=0x400000\n");
markup.append(T T "map mode=shadow address=80-bf:8000-ffff offset=0x000000\n");
markup.append(T T "map mode=linear address=c0-ff:0000-ffff offset=0x000000\n");
if(ram_size > 0) {
markup.append(T "ram size=0x", hex(ram_size), "\n");
markup.append(T T "map mode=linear address=20-3f:6000-7fff\n");
markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n");
if((rom_size > 0x200000) || (ram_size > 32 * 1024)) {
markup.append(T T "map mode=linear address=70-7f:0000-7fff\n");
} else {
markup.append(T T "map mode=linear address=70-7f:0000-ffff\n");
}
}
} else if(mapper == SuperFXROM) {
markup.append(T "superfx revision=2\n");
markup.append(T T "rom\n");
markup.append(T T T "map mode=linear address=00-3f:8000-ffff\n");
markup.append(T T T "map mode=linear address=40-5f:0000-ffff\n");
markup.append(T T T "map mode=linear address=80-bf:8000-ffff\n");
markup.append(T T T "map mode=linear address=c0-df:0000-ffff\n");
markup.append(T T "ram size=0x", hex(ram_size), "\n");
markup.append(T T T "map mode=linear address=00-3f:6000-7fff size=0x2000\n");
markup.append(T T T "map mode=linear address=60-7f:0000-ffff\n");
markup.append(T T T "map mode=linear address=80-bf:6000-7fff size=0x2000\n");
markup.append(T T T "map mode=linear address=e0-ff:0000-ffff\n");
markup.append(T T "mmio\n");
markup.append(T T T "map address=00-3f:3000-32ff\n");
markup.append(T T T "map address=80-bf:3000-32ff\n");
} else if(mapper == SA1ROM) {
markup.append(T "sa1\n");
markup.append(T T "mcu\n");
markup.append(T T T "rom\n");
markup.append(T T T T "map mode=direct address=00-3f:8000-ffff\n");
markup.append(T T T T "map mode=direct address=80-bf:8000-ffff\n");
markup.append(T T T T "map mode=direct address=c0-ff:0000-ffff\n");
markup.append(T T T "ram\n");
markup.append(T T T T "map mode=direct address=00-3f:6000-7fff\n");
markup.append(T T T T "map mode=direct address=80-bf:6000-7fff\n");
markup.append(T T "iram size=0x800\n");
markup.append(T T T "map mode=linear address=00-3f:3000-37ff\n");
markup.append(T T T "map mode=linear address=80-bf:3000-37ff\n");
markup.append(T T "bwram size=0x", hex(ram_size), "\n");
markup.append(T T T "map mode=linear address=40-4f:0000-ffff\n");
markup.append(T T "mmio\n");
markup.append(T T T "map address=00-3f:2200-23ff\n");
markup.append(T T T "map address=80-bf:2200-23ff\n");
} else if(mapper == BSCLoROM) {
markup.append(T "rom\n");
markup.append(T T "map mode=linear address=00-1f:8000-ffff offset=0x000000\n");
markup.append(T T "map mode=linear address=20-3f:8000-ffff offset=0x100000\n");
markup.append(T T "map mode=linear address=80-9f:8000-ffff offset=0x200000\n");
markup.append(T T "map mode=linear address=a0-bf:8000-ffff offset=0x100000\n");
markup.append(T "ram size=0x", hex(ram_size), "\n");
markup.append(T T "map mode=linear address=70-7f:0000-7fff\n");
markup.append(T T "map mode=linear address=f0-ff:0000-7fff\n");
markup.append(T "bsx\n");
markup.append(T T "slot\n");
markup.append(T T T "map mode=linear address=c0-ef:0000-ffff\n");
} else if(mapper == BSCHiROM) {
markup.append(T "rom\n");
markup.append(T T "map mode=shadow address=00-1f:8000-ffff\n");
markup.append(T T "map mode=linear address=40-5f:0000-ffff\n");
markup.append(T T "map mode=shadow address=80-9f:8000-ffff\n");
markup.append(T T "map mode=linear address=c0-df:0000-ffff\n");
markup.append(T "ram size=0x", hex(ram_size), "\n");
markup.append(T T "map mode=linear address=20-3f:6000-7fff\n");
markup.append(T T "map mode=linear address=a0-bf:6000-7fff\n");
markup.append(T "bsx\n");
markup.append(T T "slot\n");
markup.append(T T T "map mode=shadow address=20-3f:8000-ffff\n");
markup.append(T T T "map mode=linear address=60-7f:0000-ffff\n");
markup.append(T T T "map mode=shadow address=a0-bf:8000-ffff\n");
markup.append(T T T "map mode=linear address=e0-ff:0000-ffff\n");
} else if(mapper == BSXROM) {
markup.append(T "bsx\n");
markup.append(T T "mcu\n");
markup.append(T T T "map address=00-3f:8000-ffff\n");
markup.append(T T T "map address=80-bf:8000-ffff\n");
markup.append(T T T "map address=40-7f:0000-ffff\n");
markup.append(T T T "map address=c0-ff:0000-ffff\n");
markup.append(T T T "map address=20-3f:6000-7fff\n");
markup.append(T T "mmio\n");
markup.append(T T T "map address=00-3f:5000-5fff\n");
markup.append(T T T "map address=80-bf:5000-5fff\n");
} else if(mapper == STROM) {
markup.append(T "rom\n");
markup.append(T T "map mode=linear address=00-1f:8000-ffff\n");
markup.append(T T "map mode=linear address=80-9f:8000-ffff\n");
markup.append(T "sufamiturbo\n");
markup.append(T T "slot id=A\n");
markup.append(T T T "rom\n");
markup.append(T T T T "map mode=linear address=20-3f:8000-ffff\n");
markup.append(T T T T "map mode=linear address=a0-bf:8000-ffff\n");
markup.append(T T T "ram size=0x20000\n");
markup.append(T T T T "map mode=linear address=60-63:8000-ffff\n");
markup.append(T T T T "map mode=linear address=e0-e3:8000-ffff\n");
markup.append(T T "slot id=B\n");
markup.append(T T T "rom\n");
markup.append(T T T T "map mode=linear address=40-5f:8000-ffff\n");
markup.append(T T T T "map mode=linear address=c0-df:8000-ffff\n");
markup.append(T T T "ram size=0x20000\n");
markup.append(T T T T "map mode=linear address=70-73:8000-ffff\n");
markup.append(T T T T "map mode=linear address=f0-f3:8000-ffff\n");
else if(has_spc7110) {
markup.append(
" <rom>\n"
" <map mode='shadow' address='00-0f:8000-ffff'/>\n"
" <map mode='shadow' address='80-bf:8000-ffff'/>\n"
" <map mode='linear' address='c0-cf:0000-ffff'/>\n"
" </rom>\n"
" <spc7110>\n"
" <ram size='0x", hex(ram_size), "'>\n"
" <map mode='linear' address='00:6000-7fff'/>\n"
" <map mode='linear' address='30:6000-7fff'/>\n"
" </ram>\n"
" <mmio>\n"
" <map address='00-3f:4800-483f'/>\n"
" <map address='80-bf:4800-483f'/>\n"
" </mmio>\n"
" <mcu>\n"
" <map address='d0-ff:0000-ffff' offset='0x100000' size='0x", hex(size - 0x100000), "'/>\n"
" </mcu>\n"
" <dcu>\n"
" <map address='50:0000-ffff'/>\n"
" </dcu>\n"
);
if(has_spc7110rtc) markup.append(
" <rtc>\n"
" <map address='00-3f:4840-4842'/>\n"
" <map address='80-bf:4840-4842'/>\n"
" </rtc>\n"
);
markup.append(
" </spc7110>\n"
);
}
if(has_srtc) {
markup.append(T "srtc\n");
markup.append(T T "map address=00-3f:2800-2801\n");
markup.append(T T "map address=80-bf:2800-2801\n");
else if(mapper == LoROM) {
markup.append(
" <rom>\n"
" <map mode='linear' address='00-7f:8000-ffff'/>\n"
" <map mode='linear' address='80-ff:8000-ffff'/>\n"
" </rom>\n"
);
if(ram_size > 0) markup.append(
" <ram size='0x", hex(ram_size), "'>\n"
" <map mode='linear' address='20-3f:6000-7fff'/>\n"
" <map mode='linear' address='a0-bf:6000-7fff'/>\n"
" <map mode='linear' address='70-7f:", range, "'/>\n"
" <map mode='linear' address='f0-ff:", range, "'/>\n"
" </ram>\n"
);
}
if(has_sdd1) {
markup.append(T "sdd1\n");
markup.append(T T "mcu\n");
markup.append(T T T "map address=c0-ff:0000-ffff\n");
markup.append(T T "mmio\n");
markup.append(T T T "map address=00-3f:4800-4807\n");
markup.append(T T T "map address=80-bf:4800-4807\n");
else if(mapper == HiROM) {
markup.append(
" <rom>\n"
" <map mode='shadow' address='00-3f:8000-ffff'/>\n"
" <map mode='linear' address='40-7f:0000-ffff'/>\n"
" <map mode='shadow' address='80-bf:8000-ffff'/>\n"
" <map mode='linear' address='c0-ff:0000-ffff'/>\n"
" </rom>\n"
);
if(ram_size > 0) markup.append(
" <ram size='0x", hex(ram_size), "'>\n"
" <map mode='linear' address='20-3f:6000-7fff'/>\n"
" <map mode='linear' address='a0-bf:6000-7fff'/>\n"
" <map mode='linear' address='70-7f:", range, "'/>\n"
" </ram>\n"
);
}
else if(mapper == ExLoROM) {
markup.append(
" <rom>\n"
" <map mode='linear' address='00-3f:8000-ffff'/>\n"
" <map mode='linear' address='40-7f:0000-ffff'/>\n"
" <map mode='linear' address='80-bf:8000-ffff'/>\n"
" </rom>\n"
);
if(ram_size > 0) markup.append(
" <ram size='0x", hex(ram_size), "'>\n"
" <map mode='linear' address='20-3f:6000-7fff'/>\n"
" <map mode='linear' address='a0-bf:6000-7fff'/>\n"
" <map mode='linear' address='70-7f:0000-7fff'/>\n"
" </ram>\n"
);
}
else if(mapper == ExHiROM) {
markup.append(
" <rom>\n"
" <map mode='shadow' address='00-3f:8000-ffff' offset='0x400000'/>\n"
" <map mode='linear' address='40-7f:0000-ffff' offset='0x400000'/>\n"
" <map mode='shadow' address='80-bf:8000-ffff' offset='0x000000'/>\n"
" <map mode='linear' address='c0-ff:0000-ffff' offset='0x000000'/>\n"
" </rom>\n"
);
if(ram_size > 0) markup.append(
" <ram size='0x", hex(ram_size), "'>\n"
" <map mode='linear' address='20-3f:6000-7fff'/>\n"
" <map mode='linear' address='a0-bf:6000-7fff'/>\n"
" <map mode='linear' address='70-7f:", range, "'/>\n"
" </ram>\n"
);
}
else if(mapper == SuperFXROM) markup.append(
" <superfx revision='2'>\n"
" <rom>\n"
" <map mode='linear' address='00-3f:8000-ffff'/>\n"
" <map mode='linear' address='40-5f:0000-ffff'/>\n"
" <map mode='linear' address='80-bf:8000-ffff'/>\n"
" <map mode='linear' address='c0-df:0000-ffff'/>\n"
" </rom>\n"
" <ram size='0x", hex(ram_size), "'>\n"
" <map mode='linear' address='00-3f:6000-7fff' size='0x2000'/>\n"
" <map mode='linear' address='60-7f:0000-ffff'/>\n"
" <map mode='linear' address='80-bf:6000-7fff' size='0x2000'/>\n"
" <map mode='linear' address='e0-ff:0000-ffff'/>\n"
" </ram>\n"
" <mmio>\n"
" <map address='00-3f:3000-32ff'/>\n"
" <map address='80-bf:3000-32ff'/>\n"
" </mmio>\n"
" </superfx>\n"
);
else if(mapper == SA1ROM) markup.append(
" <sa1>\n"
" <mcu>\n"
" <rom>\n"
" <map mode='direct' address='00-3f:8000-ffff'/>\n"
" <map mode='direct' address='80-bf:8000-ffff'/>\n"
" <map mode='direct' address='c0-ff:0000-ffff'/>\n"
" </rom>\n"
" <ram>\n"
" <map mode='direct' address='00-3f:6000-7fff'/>\n"
" <map mode='direct' address='80-bf:6000-7fff'/>\n"
" </ram>\n"
" </mcu>\n"
" <iram size='0x800'>\n"
" <map mode='linear' address='00-3f:3000-37ff'/>\n"
" <map mode='linear' address='80-bf:3000-37ff'/>\n"
" </iram>\n"
" <bwram size='0x", hex(ram_size), "'>\n"
" <map mode='linear' address='40-4f:0000-ffff'/>\n"
" </bwram>\n"
" <mmio>\n"
" <map address='00-3f:2200-23ff'/>\n"
" <map address='80-bf:2200-23ff'/>\n"
" </mmio>\n"
" </sa1>\n"
);
else if(mapper == BSCLoROM) markup.append(
" <rom>\n"
" <map mode='linear' address='00-1f:8000-ffff' offset='0x000000'/>\n"
" <map mode='linear' address='20-3f:8000-ffff' offset='0x100000'/>\n"
" <map mode='linear' address='80-9f:8000-ffff' offset='0x200000'/>\n"
" <map mode='linear' address='a0-bf:8000-ffff' offset='0x100000'/>\n"
" </rom>\n"
" <ram size='0x", hex(ram_size), "'>\n"
" <map mode='linear' address='70-7f:0000-7fff'/>\n"
" <map mode='linear' address='f0-ff:0000-7fff'/>\n"
" </ram>\n"
" <bsx>\n"
" <slot>\n"
" <map mode='linear' address='c0-ef:0000-ffff'/>\n"
" </slot>\n"
" </bsx>\n"
);
else if(mapper == BSCHiROM) markup.append(
" <rom>\n"
" <map mode='shadow' address='00-1f:8000-ffff'/>\n"
" <map mode='linear' address='40-5f:0000-ffff'/>\n"
" <map mode='shadow' address='80-9f:8000-ffff'/>\n"
" <map mode='linear' address='c0-df:0000-ffff'/>\n"
" </rom>\n"
" <ram size='0x", hex(ram_size), "'>\n"
" <map mode='linear' address='20-3f:6000-7fff'/>\n"
" <map mode='linear' address='a0-bf:6000-7fff'/>\n"
" </ram>\n"
" <bsx>\n"
" <slot>\n"
" <map mode='shadow' address='20-3f:8000-ffff'/>\n"
" <map mode='linear' address='60-7f:0000-ffff'/>\n"
" <map mode='shadow' address='a0-bf:8000-ffff'/>\n"
" <map mode='linear' address='e0-ff:0000-ffff'/>\n"
" </slot>\n"
" </bsx>\n"
);
else if(mapper == BSXROM) markup.append(
" <bsx>\n"
" <mcu>\n"
" <map address='00-3f:8000-ffff'/>\n"
" <map address='80-bf:8000-ffff'/>\n"
" <map address='40-7f:0000-ffff'/>\n"
" <map address='c0-ff:0000-ffff'/>\n"
" <map address='20-3f:6000-7fff'/>\n"
" </mcu>\n"
" <mmio>\n"
" <map address='00-3f:5000-5fff'/>\n"
" <map address='80-bf:5000-5fff'/>\n"
" </mmio>\n"
" </bsx>\n"
);
else if(mapper == STROM) markup.append(
" <rom>\n"
" <map mode='linear' address='00-1f:8000-ffff'/>\n"
" <map mode='linear' address='80-9f:8000-ffff'/>\n"
" </rom>\n"
" <sufamiturbo>\n"
" <slot id='A'>\n"
" <rom>\n"
" <map mode='linear' address='20-3f:8000-ffff'/>\n"
" <map mode='linear' address='a0-bf:8000-ffff'/>\n"
" </rom>\n"
" <ram size='0x20000'>\n"
" <map mode='linear' address='60-63:8000-ffff'/>\n"
" <map mode='linear' address='e0-e3:8000-ffff'/>\n"
" </ram>\n"
" </slot>\n"
" <slot id='B'>\n"
" <rom>\n"
" <map mode='linear' address='40-5f:8000-ffff'/>\n"
" <map mode='linear' address='c0-df:8000-ffff'/>\n"
" </rom>\n"
" <ram size='0x20000'>\n"
" <map mode='linear' address='70-73:8000-ffff'/>\n"
" <map mode='linear' address='f0-f3:8000-ffff'/>\n"
" </ram>\n"
" </slot>\n"
" </sufamiturbo>\n"
);
if(has_srtc) markup.append(
" <srtc>\n"
" <map address='00-3f:2800-2801'/>\n"
" <map address='80-bf:2800-2801'/>\n"
" </srtc>\n"
);
if(has_sdd1) markup.append(
" <sdd1>\n"
" <mcu>\n"
" <map address='c0-ff:0000-ffff'/>\n"
" </mcu>\n"
" <mmio>\n"
" <map address='00-3f:4800-4807'/>\n"
" <map address='80-bf:4800-4807'/>\n"
" </mmio>\n"
" </sdd1>\n"
);
if(has_obc1) markup.append(
" <obc1>\n"
" <map address='00-3f:6000-7fff'/>\n"
" <map address='80-bf:6000-7fff'/>\n"
" </obc1>\n"
);
if(has_dsp1) {
markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp1b.bin sha256=4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c\n");
if(dsp1_mapper == DSP1LoROM1MB) {
markup.append(T T "dr\n");
markup.append(T T T "map address=20-3f:8000-bfff\n");
markup.append(T T T "map address=a0-bf:8000-bfff\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=20-3f:c000-ffff\n");
markup.append(T T T "map address=a0-bf:c000-ffff\n");
} else if(dsp1_mapper == DSP1LoROM2MB) {
markup.append(T T "dr\n");
markup.append(T T T "map address=60-6f:0000-3fff\n");
markup.append(T T T "map address=e0-ef:0000-3fff\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=60-6f:4000-7fff\n");
markup.append(T T T "map address=e0-ef:4000-7fff\n");
} else if(dsp1_mapper == DSP1HiROM) {
markup.append(T T "dr\n");
markup.append(T T T "map address=00-1f:6000-6fff\n");
markup.append(T T T "map address=80-9f:6000-6fff\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=00-1f:7000-7fff\n");
markup.append(T T T "map address=80-9f:7000-7fff\n");
}
markup.append(" <necdsp model='uPD7725' frequency='8000000' firmware='dsp1b.bin' sha256='4d42db0f36faef263d6b93f508e8c1c4ae8fc2605fd35e3390ecc02905cd420c'>\n");
if(dsp1_mapper == DSP1LoROM1MB) markup.append(
" <dr>\n"
" <map address='20-3f:8000-bfff'/>\n"
" <map address='a0-bf:8000-bfff'/>\n"
" </dr>\n"
" <sr>\n"
" <map address='20-3f:c000-ffff'/>\n"
" <map address='a0-bf:c000-ffff'/>\n"
" </sr>\n"
);
if(dsp1_mapper == DSP1LoROM2MB) markup.append(
" <dr>\n"
" <map address='60-6f:0000-3fff'/>\n"
" <map address='e0-ef:0000-3fff'/>\n"
" </dr>\n"
" <sr>\n"
" <map address='60-6f:4000-7fff'/>\n"
" <map address='e0-ef:4000-7fff'/>\n"
" </sr>\n"
);
if(dsp1_mapper == DSP1HiROM) markup.append(
" <dr>\n"
" <map address='00-1f:6000-6fff'/>\n"
" <map address='80-9f:6000-6fff'/>\n"
" </dr>\n"
" <sr>\n"
" <map address='00-1f:7000-7fff'/>\n"
" <map address='80-9f:7000-7fff'/>\n"
" </sr>\n"
);
markup.append(" </necdsp>\n");
}
if(has_dsp2) {
markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp2.bin sha256=5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1\n");
markup.append(T T "dr\n");
markup.append(T T T "map address=20-3f:8000-bfff\n");
markup.append(T T T "map address=a0-bf:8000-bfff\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=20-3f:c000-ffff\n");
markup.append(T T T "map address=a0-bf:c000-ffff\n");
}
if(has_dsp2) markup.append(
" <necdsp model='uPD7725' frequency='8000000' firmware='dsp2.bin' sha256='5efbdf96ed0652790855225964f3e90e6a4d466cfa64df25b110933c6cf94ea1'>\n"
" <dr>\n"
" <map address='20-3f:8000-bfff'/>\n"
" <map address='a0-bf:8000-bfff'/>\n"
" </dr>\n"
" <sr>\n"
" <map address='20-3f:c000-ffff'/>\n"
" <map address='a0-bf:c000-ffff'/>\n"
" </sr>\n"
" </necdsp>\n"
);
if(has_dsp3) {
markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp3.bin sha256=2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90\n");
markup.append(T T "dr\n");
markup.append(T T T "map address=20-3f:8000-bfff\n");
markup.append(T T T "map address=a0-bf:8000-bfff\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=20-3f:c000-ffff\n");
markup.append(T T T "map address=a0-bf:c000-ffff\n");
}
if(has_dsp3) markup.append(
" <necdsp model='uPD7725' frequency='8000000' firmware='dsp3.bin' sha256='2e635f72e4d4681148bc35429421c9b946e4f407590e74e31b93b8987b63ba90'>\n"
" <dr>\n"
" <map address='20-3f:8000-bfff'/>\n"
" <map address='a0-bf:8000-bfff'/>\n"
" </dr>\n"
" <sr>\n"
" <map address='20-3f:c000-ffff'/>\n"
" <map address='a0-bf:c000-ffff'/>\n"
" </sr>\n"
" </necdsp>\n"
);
if(has_dsp4) {
markup.append(T "necdsp model=uPD7725 frequency=8000000 firmware=dsp4.bin sha256=63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a\n");
markup.append(T T "dr\n");
markup.append(T T T "map address=30-3f:8000-bfff\n");
markup.append(T T T "map address=b0-bf:8000-bfff\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=30-3f:c000-ffff\n");
markup.append(T T T "map address=b0-bf:c000-ffff\n");
}
if(has_dsp4) markup.append(
" <necdsp model='uPD7725' frequency='8000000' firmware='dsp4.bin' sha256='63ede17322541c191ed1fdf683872554a0a57306496afc43c59de7c01a6e764a'>\n"
" <dr>\n"
" <map address='30-3f:8000-bfff'/>\n"
" <map address='b0-bf:8000-bfff'/>\n"
" </dr>\n"
" <sr>\n"
" <map address='30-3f:c000-ffff'/>\n"
" <map address='b0-bf:c000-ffff'/>\n"
" </sr>\n"
" </necdsp>\n"
);
if(has_obc1) {
markup.append(T "obc1\n");
markup.append(T T "map address=00-3f:6000-7fff\n");
markup.append(T T "map address=80-bf:6000-7fff\n");
}
if(has_st010) markup.append(
" <necdsp model='uPD96050' frequency='10000000' firmware='st0010.bin' sha256='55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e'>\n"
" <dr>\n"
" <map address='60:0000'/>\n"
" <map address='e0:0000'/>\n"
" </dr>\n"
" <sr>\n"
" <map address='60:0001'/>\n"
" <map address='e0:0001'/>\n"
" </sr>\n"
" <dp>\n"
" <map address='68-6f:0000-0fff'/>\n"
" <map address='e8-ef:0000-0fff'/>\n"
" </dp>\n"
" </necdsp>\n"
);
if(has_st010) {
markup.append(T "necdsp model=uPD96050 frequency=10000000 firmware=st0010.bin sha256=55c697e864562445621cdf8a7bf6e84ae91361e393d382a3704e9aa55559041e\n");
markup.append(T T "dr\n");
markup.append(T T T "map address=60:0000\n");
markup.append(T T T "map address=e0:0000\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=60:0001\n");
markup.append(T T T "map address=e0:0001\n");
markup.append(T T "dp\n");
markup.append(T T T "map address=68-6f:0000-0fff\n");
markup.append(T T T "map address=e8-ef:0000-0fff\n");
}
if(has_st011) markup.append(
" <necdsp model='uPD96050' frequency='15000000' firmware='st0011.bin' sha256='651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e'>\n"
" <dr>\n"
" <map address='60:0000'/>\n"
" <map address='e0:0000'/>\n"
" </dr>\n"
" <sr>\n"
" <map address='60:0001'/>\n"
" <map address='e0:0001'/>\n"
" </sr>\n"
" <dp>\n"
" <map address='68-6f:0000-0fff'/>\n"
" <map address='e8-ef:0000-0fff'/>\n"
" </dp>\n"
" </necdsp>\n"
);
if(has_st011) {
markup.append(T "necdsp model=uPD96050 frequency=15000000 firmware=st0011.bin sha256=651b82a1e26c4fa8dd549e91e7f923012ed2ca54c1d9fd858655ab30679c2f0e\n");
markup.append(T T "dr\n");
markup.append(T T T "map address=60:0000\n");
markup.append(T T T "map address=e0:0000\n");
markup.append(T T "sr\n");
markup.append(T T T "map address=60:0001\n");
markup.append(T T T "map address=e0:0001\n");
markup.append(T T "dp\n");
markup.append(T T T "map address=68-6f:0000-0fff\n");
markup.append(T T T "map address=e8-ef:0000-0fff\n");
}
if(has_st018) markup.append(
" <setarisc firmware='ST-0018'>\n"
" <map address='00-3f:3800-38ff'/>\n"
" <map address='80-bf:3800-38ff'/>\n"
" </setarisc>\n"
);
if(has_st018) {
markup.append(T "setarisc firmware=ST-0018\n");
markup.append(T T "map address=00-3f:3800-38ff\n");
markup.append(T T "map address=80-bf:3800-38ff\n");
}
markup.append("</cartridge>\n");
}
#undef T
void SnesCartridge::read_header(const uint8_t *data, unsigned size) {
type = TypeUnknown;
mapper = LoROM;

View File

@@ -16,6 +16,7 @@
#include <nall/sha256.hpp>
#include <nall/stdint.hpp>
#include <nall/utility.hpp>
#include <nall/varint.hpp>
#include <nall/vector.hpp>
#include <nall/windows/utf8.hpp>
@@ -31,6 +32,8 @@
#include <nall/string/cstring.hpp>
#include <nall/string/filename.hpp>
#include <nall/string/math.hpp>
#include <nall/string/math-fixed-point.hpp>
#include <nall/string/math-floating-point.hpp>
#include <nall/string/platform.hpp>
#include <nall/string/strl.hpp>
#include <nall/string/strpos.hpp>
@@ -39,8 +42,10 @@
#include <nall/string/split.hpp>
#include <nall/string/utility.hpp>
#include <nall/string/variadic.hpp>
#include <nall/string/wildcard.hpp>
#include <nall/string/wrapper.hpp>
#include <nall/string/xml.hpp>
#include <nall/string/xml-legacy.hpp>
#undef NALL_STRING_INTERNAL_HPP
#endif

View File

@@ -23,6 +23,7 @@ namespace nall {
struct string {
inline void reserve(unsigned);
inline bool empty() const;
template<typename... Args> inline string& assign(Args&&... args);
template<typename... Args> inline string& append(Args&&... args);
@@ -35,6 +36,7 @@ namespace nall {
template<unsigned Limit = 0> inline string& iqreplace(const char*, const char*);
inline unsigned length() const;
inline unsigned capacity() const;
template<unsigned Limit = 0> inline lstring split(const char*) const;
template<unsigned Limit = 0> inline lstring isplit(const char*) const;
@@ -128,8 +130,6 @@ namespace nall {
inline char chrlower(char c);
inline char chrupper(char c);
inline int istrcmp(const char *str1, const char *str2);
inline bool wildcard(const char *str, const char *pattern);
inline bool iwildcard(const char *str, const char *pattern);
inline bool strbegin(const char *str, const char *key);
inline bool istrbegin(const char *str, const char *key);
inline bool strend(const char *str, const char *key);
@@ -185,11 +185,15 @@ namespace nall {
template<unsigned length = 0, char padding = ' '> inline string ldecimal(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string hex(uintmax_t value);
template<unsigned length = 0, char padding = '0'> inline string binary(uintmax_t value);
inline unsigned fp(char *str, double value);
inline string fp(double value);
inline unsigned fp(char *str, long double value);
inline string fp(long double value);
//variadic.hpp
template<typename... Args> inline void print(Args&&... args);
//wildcard.hpp
inline bool wildcard(const char *str, const char *pattern);
inline bool iwildcard(const char *str, const char *pattern);
};
#endif

View File

@@ -2,39 +2,184 @@
namespace nall {
//this is needed, as C++0x does not support explicit template specialization inside classes
template<> inline const char* to_string<bool>(bool v) { return v ? "true" : "false"; }
template<> inline const char* to_string<char>(char v) { static char temp[256]; return integer(temp, v); }
//convert any (supported) type to a const char* without constructing a new nall::string
//this is used inside istring(...) to build nall::string values
template<typename T> struct stringify;
template<> inline const char* to_string<signed char> (signed char v) { static char temp[256]; return integer(temp, v); }
template<> inline const char* to_string<signed short> (signed short v) { static char temp[256]; return integer(temp, v); }
template<> inline const char* to_string<signed int> (signed int v) { static char temp[256]; return integer(temp, v); }
template<> inline const char* to_string<signed long> (signed long v) { static char temp[256]; return integer(temp, v); }
template<> inline const char* to_string<signed long long>(signed long long v) { static char temp[256]; return integer(temp, v); }
// base types
template<> inline const char* to_string<unsigned char> (unsigned char v) { static char temp[256]; return decimal(temp, v); }
template<> inline const char* to_string<unsigned short> (unsigned short v) { static char temp[256]; return decimal(temp, v); }
template<> inline const char* to_string<unsigned int> (unsigned int v) { static char temp[256]; return decimal(temp, v); }
template<> inline const char* to_string<unsigned long> (unsigned long v) { static char temp[256]; return decimal(temp, v); }
template<> inline const char* to_string<unsigned long long>(unsigned long long v) { static char temp[256]; return decimal(temp, v); }
template<> struct stringify<bool> {
bool value;
operator const char*() const { return value ? "true" : "false"; }
stringify(bool value) : value(value) {}
};
template<> inline const char* to_string<float> (float v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; }
template<> inline const char* to_string<double> (double v) { static char temp[256]; snprintf(temp, 255, "%f", v); return temp; }
template<> inline const char* to_string<long double>(long double v) { static char temp[256]; snprintf(temp, 255, "%Lf", v); return temp; }
template<> struct stringify<char> {
char data[256];
operator const char*() const { return data; }
stringify(char value) { integer(data, value); }
};
template<> inline const char* to_string<char*> (char *v) { return v; }
template<> inline const char* to_string<const char*> (const char *v) { return v; }
template<> inline const char* to_string<string> (string v) { return v; }
template<> inline const char* to_string<const string&> (const string &v) { return v; }
template<> inline const char* to_string<cstring> (cstring v) { return v; }
template<> inline const char* to_string<const cstring&>(const cstring &v) { return v; }
// signed integers
template<> struct stringify<signed char> {
char data[256];
operator const char*() const { return data; }
stringify(signed char value) { integer(data, value); }
};
template<> struct stringify<signed short> {
char data[256];
operator const char*() const { return data; }
stringify(signed short value) { integer(data, value); }
};
template<> struct stringify<signed int> {
char data[256];
operator const char*() const { return data; }
stringify(signed int value) { integer(data, value); }
};
template<> struct stringify<signed long> {
char data[256];
operator const char*() const { return data; }
stringify(signed long value) { integer(data, value); }
};
template<> struct stringify<signed long long> {
char data[256];
operator const char*() const { return data; }
stringify(signed long long value) { integer(data, value); }
};
template<unsigned bits> struct stringify<int_t<bits>> {
char data[256];
operator const char*() const { return data; }
stringify(int_t<bits> value) { integer(data, value); }
};
// unsigned integers
template<> struct stringify<unsigned char> {
char data[256];
operator const char*() const { return data; }
stringify(unsigned char value) { decimal(data, value); }
};
template<> struct stringify<unsigned short> {
char data[256];
operator const char*() const { return data; }
stringify(unsigned short value) { decimal(data, value); }
};
template<> struct stringify<unsigned int> {
char data[256];
operator const char*() const { return data; }
stringify(unsigned int value) { decimal(data, value); }
};
template<> struct stringify<unsigned long> {
char data[256];
operator const char*() const { return data; }
stringify(unsigned long value) { decimal(data, value); }
};
template<> struct stringify<unsigned long long> {
char data[256];
operator const char*() const { return data; }
stringify(unsigned long long value) { decimal(data, value); }
};
template<unsigned bits> struct stringify<uint_t<bits>> {
char data[256];
operator const char*() const { return data; }
stringify(uint_t<bits> value) { decimal(data, value); }
};
// floating-point
template<> struct stringify<float> {
char data[256];
operator const char*() const { return data; }
stringify(float value) { fp(data, value); }
};
template<> struct stringify<double> {
char data[256];
operator const char*() const { return data; }
stringify(double value) { fp(data, value); }
};
template<> struct stringify<long double> {
char data[256];
operator const char*() const { return data; }
stringify(long double value) { fp(data, value); }
};
// strings
template<> struct stringify<char*> {
const char *value;
operator const char*() const { return value; }
stringify(char *value) : value(value) {}
};
template<> struct stringify<const char*> {
const char *value;
operator const char*() const { return value; }
stringify(const char *value) : value(value) {}
};
template<> struct stringify<string> {
const string &value;
operator const char*() const { return value; }
stringify(const string &value) : value(value) {}
};
template<> struct stringify<const string&> {
const string &value;
operator const char*() const { return value; }
stringify(const string &value) : value(value) {}
};
template<> struct stringify<cstring> {
const char *value;
operator const char*() const { return value; }
stringify(const cstring &value) : value(value) {}
};
template<> struct stringify<const cstring&> {
const char *value;
operator const char*() const { return value; }
stringify(const cstring &value) : value(value) {}
};
#if defined(QSTRING_H)
template<> inline const char* to_string<QString>(QString v) { return v.toUtf8().constData(); }
template<> inline const char* to_string<const QString&>(const QString &v) { return v.toUtf8().constData(); }
string::operator QString() const { return QString::fromUtf8(*this); }
template<> struct stringify<QString> {
const QString &value;
operator const char*() const { return value.toUtf8().constData(); }
stringify(const QString &value) : value(value) {}
};
template<> struct stringify<const QString&> {
const QString &value;
operator const char*() const { return value.toUtf8().constData(); }
stringify(const QString &value) : value(value) {}
};
string::operator QString() const {
return QString::fromUtf8(*this);
}
#endif
//
template<typename T> stringify<T> make_string(T value) {
return stringify<T>(std::forward<T>(value));
}
}
#endif

View File

@@ -18,46 +18,6 @@ int istrcmp(const char *str1, const char *str2) {
return (int)chrlower(*str1) - (int)chrlower(*str2);
}
bool wildcard(const char *s, const char *p) {
const char *cp = 0, *mp = 0;
while(*s && *p != '*') {
if(*p != '?' && *s != *p) return false;
p++, s++;
}
while(*s) {
if(*p == '*') {
if(!*++p) return true;
mp = p, cp = s + 1;
} else if(*p == '?' || *p == *s) {
p++, s++;
} else {
p = mp, s = cp++;
}
}
while(*p == '*') p++;
return !*p;
}
bool iwildcard(const char *s, const char *p) {
const char *cp = 0, *mp = 0;
while(*s && *p != '*') {
if(*p != '?' && chrlower(*s) != chrlower(*p)) return false;
p++, s++;
}
while(*s) {
if(*p == '*') {
if(!*++p) return true;
mp = p, cp = s + 1;
} else if(*p == '?' || chrlower(*p) == chrlower(*s)) {
p++, s++;
} else {
p = mp, s = cp++;
}
}
while(*p == '*') p++;
return !*p;
}
bool strbegin(const char *str, const char *key) {
int i, ssl = strlen(str), ksl = strlen(key);

View File

@@ -7,7 +7,7 @@ static void istring(string &output) {
template<typename T, typename... Args>
static void istring(string &output, const T &value, Args&&... args) {
output.append_(to_string(value));
output.append_(make_string(value));
istring(output, std::forward<Args>(args)...);
}
@@ -19,6 +19,10 @@ void string::reserve(unsigned size_) {
}
}
bool string::empty() const {
return !*data;
}
template<typename... Args> string& string::assign(Args&&... args) {
*data = 0;
istring(*this, std::forward<Args>(args)...);

View File

@@ -0,0 +1,166 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace fixedpoint {
static nall::function<intmax_t (const char *&)> eval_fallback;
static intmax_t eval_integer(const char *& s) {
if(!*s) throw "unrecognized integer";
intmax_t value = 0, x = *s, y = *(s + 1);
//hexadecimal
if(x == '0' && (y == 'X' || y == 'x')) {
s += 2;
while(true) {
if(*s >= '0' && *s <= '9') { value = value * 16 + (*s++ - '0'); continue; }
if(*s >= 'A' && *s <= 'F') { value = value * 16 + (*s++ - 'A' + 10); continue; }
if(*s >= 'a' && *s <= 'f') { value = value * 16 + (*s++ - 'a' + 10); continue; }
return value;
}
}
//binary
if(x == '0' && (y == 'B' || y == 'b')) {
s += 2;
while(true) {
if(*s == '0' || *s == '1') { value = value * 2 + (*s++ - '0'); continue; }
return value;
}
}
//octal (or decimal '0')
if(x == '0') {
s += 1;
while(true) {
if(*s >= '0' && *s <= '7') { value = value * 8 + (*s++ - '0'); continue; }
return value;
}
}
//decimal
if(x >= '0' && x <= '9') {
while(true) {
if(*s >= '0' && *s <= '9') { value = value * 10 + (*s++ - '0'); continue; }
return value;
}
}
//char
if(x == '\'' && y != '\'') {
s += 1;
while(true) {
value = value * 256 + *s++;
if(*s == '\'') { s += 1; return value; }
if(!*s) throw "mismatched char";
}
}
throw "unrecognized integer";
}
static intmax_t eval(const char *&s, int depth = 0) {
while(*s == ' ' || *s == '\t') s++; //trim whitespace
if(!*s) throw "unrecognized token";
intmax_t value = 0, x = *s, y = *(s + 1);
if(*s == '(') {
value = eval(++s, 1);
if(*s++ != ')') throw "mismatched group";
}
else if(x == '!') value = !eval(++s, 13);
else if(x == '~') value = ~eval(++s, 13);
else if(x == '+') value = +eval(++s, 13);
else if(x == '-') value = -eval(++s, 13);
else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s);
else if(eval_fallback) value = eval_fallback(s); //optional user-defined syntax parsing
else throw "unrecognized token";
while(true) {
while(*s == ' ' || *s == '\t') s++; //trim whitespace
if(!*s) break;
x = *s, y = *(s + 1);
if(depth >= 13) break;
if(x == '*') { value *= eval(++s, 13); continue; }
if(x == '/') { intmax_t result = eval(++s, 13); if(result == 0) throw "division by zero"; value /= result; continue; }
if(x == '%') { intmax_t result = eval(++s, 13); if(result == 0) throw "division by zero"; value %= result; continue; }
if(depth >= 12) break;
if(x == '+') { value += eval(++s, 12); continue; }
if(x == '-') { value -= eval(++s, 12); continue; }
if(depth >= 11) break;
if(x == '<' && y == '<') { value <<= eval(++++s, 11); continue; }
if(x == '>' && y == '>') { value >>= eval(++++s, 11); continue; }
if(depth >= 10) break;
if(x == '<' && y == '=') { value = value <= eval(++++s, 10); continue; }
if(x == '>' && y == '=') { value = value >= eval(++++s, 10); continue; }
if(x == '<') { value = value < eval(++s, 10); continue; }
if(x == '>') { value = value > eval(++s, 10); continue; }
if(depth >= 9) break;
if(x == '=' && y == '=') { value = value == eval(++++s, 9); continue; }
if(x == '!' && y == '=') { value = value != eval(++++s, 9); continue; }
if(depth >= 8) break;
if(x == '&' && y != '&') { value = value & eval(++s, 8); continue; }
if(depth >= 7) break;
if(x == '^' && y != '^') { value = value ^ eval(++s, 7); continue; }
if(depth >= 6) break;
if(x == '|' && y != '|') { value = value | eval(++s, 6); continue; }
if(depth >= 5) break;
if(x == '&' && y == '&') { value = eval(++++s, 5) && value; continue; }
if(depth >= 4) break;
if(x == '^' && y == '^') { value = (!eval(++++s, 4) != !value); continue; }
if(depth >= 3) break;
if(x == '|' && y == '|') { value = eval(++++s, 3) || value; continue; }
if(x == '?') {
intmax_t lhs = eval(++s, 2);
if(*s != ':') throw "mismatched ternary";
intmax_t rhs = eval(++s, 2);
value = value ? lhs : rhs;
continue;
}
if(depth >= 2) break;
if(depth > 0 && x == ')') break;
throw "unrecognized token";
}
return value;
}
static bool eval(const char *s, intmax_t &result) {
try {
result = eval(s);
return true;
} catch(const char*) {
result = 0;
return false;
}
}
static intmax_t parse(const char *s) {
try {
intmax_t result = eval(s);
return result;
} catch(const char *) {
return 0;
}
}
}
#endif

View File

@@ -0,0 +1,157 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace floatingpoint {
static nall::function<double (const char *&)> eval_fallback;
static double eval_integer(const char *&s) {
if(!*s) throw "unrecognized integer";
intmax_t value = 0, radix = 0, x = *s, y = *(s + 1);
//hexadecimal
if(x == '0' && (y == 'X' || y == 'x')) {
s += 2;
while(true) {
if(*s >= '0' && *s <= '9') { value = value * 16 + (*s++ - '0'); continue; }
if(*s >= 'A' && *s <= 'F') { value = value * 16 + (*s++ - 'A' + 10); continue; }
if(*s >= 'a' && *s <= 'f') { value = value * 16 + (*s++ - 'a' + 10); continue; }
return value;
}
}
//binary
if(x == '0' && (y == 'B' || y == 'b')) {
s += 2;
while(true) {
if(*s == '0' || *s == '1') { value = value * 2 + (*s++ - '0'); continue; }
return value;
}
}
//octal (or decimal '0')
if(x == '0' && y != '.') {
s += 1;
while(true) {
if(*s >= '0' && *s <= '7') { value = value * 8 + (*s++ - '0'); continue; }
return value;
}
}
//decimal
if(x >= '0' && x <= '9') {
while(true) {
if(*s >= '0' && *s <= '9') { value = value * 10 + (*s++ - '0'); continue; }
if(*s == '.') { s++; break; }
return value;
}
//floating-point
while(true) {
if(*s >= '0' && *s <= '9') { radix = radix * 10 + (*s++ - '0'); continue; }
return atof(nall::string{ nall::decimal(value), ".", nall::decimal(radix) });
}
}
//char
if(x == '\'' && y != '\'') {
s += 1;
while(true) {
value = value * 256 + *s++;
if(*s == '\'') { s += 1; return value; }
if(!*s) throw "mismatched char";
}
}
throw "unrecognized integer";
}
static double eval(const char *&s, int depth = 0) {
while(*s == ' ' || *s == '\t') s++; //trim whitespace
if(!*s) throw "unrecognized token";
double value = 0, x = *s, y = *(s + 1);
if(*s == '(') {
value = eval(++s, 1);
if(*s++ != ')') throw "mismatched group";
}
else if(x == '!') value = !eval(++s, 9);
else if(x == '+') value = +eval(++s, 9);
else if(x == '-') value = -eval(++s, 9);
else if((x >= '0' && x <= '9') || x == '\'') value = eval_integer(s);
else if(eval_fallback) value = eval_fallback(s); //optional user-defined syntax parsing
else throw "unrecognized token";
while(true) {
while(*s == ' ' || *s == '\t') s++; //trim whitespace
if(!*s) break;
x = *s, y = *(s + 1);
if(depth >= 9) break;
if(x == '*') { value *= eval(++s, 9); continue; }
if(x == '/') { double result = eval(++s, 9); if(result == 0.0) throw "division by zero"; value /= result; continue; }
if(depth >= 8) break;
if(x == '+') { value += eval(++s, 8); continue; }
if(x == '-') { value -= eval(++s, 8); continue; }
if(depth >= 7) break;
if(x == '<' && y == '=') { value = value <= eval(++++s, 7); continue; }
if(x == '>' && y == '=') { value = value >= eval(++++s, 7); continue; }
if(x == '<') { value = value < eval(++s, 7); continue; }
if(x == '>') { value = value > eval(++s, 7); continue; }
if(depth >= 6) break;
if(x == '=' && y == '=') { value = value == eval(++++s, 6); continue; }
if(x == '!' && y == '=') { value = value != eval(++++s, 6); continue; }
if(depth >= 5) break;
if(x == '&' && y == '&') { value = eval(++++s, 5) && value; continue; }
if(depth >= 4) break;
if(x == '^' && y == '^') { value = (!eval(++++s, 4) != !value); continue; }
if(depth >= 3) break;
if(x == '|' && y == '|') { value = eval(++++s, 3) || value; continue; }
if(x == '?') {
double lhs = eval(++s, 2);
if(*s != ':') throw "mismatched ternary";
double rhs = eval(++s, 2);
value = value ? lhs : rhs;
continue;
}
if(depth >= 2) break;
if(depth > 0 && x == ')') break;
throw "unrecognized token";
}
return value;
}
static bool eval(const char *s, double &result) {
try {
result = eval(s);
return true;
} catch(const char*e) {
result = 0;
return false;
}
}
static double parse(const char *s) {
try {
double result = eval(s);
return result;
} catch(const char *) {
return 0;
}
}
}
#endif

View File

@@ -86,8 +86,8 @@ static int eval(const char *&s, int depth = 0) {
if(depth >= 13) break;
if(x == '*') { value *= eval(++s, 13); continue; }
if(x == '/') { value /= eval(++s, 13); continue; }
if(x == '%') { value %= eval(++s, 13); continue; }
if(x == '/') { int result = eval(++s, 13); if(result == 0) throw "division_by_zero"; value /= result; continue; }
if(x == '%') { int result = eval(++s, 13); if(result == 0) throw "division_by_zero"; value %= result; continue; }
if(depth >= 12) break;
if(x == '+') { value += eval(++s, 12); continue; }

View File

@@ -253,9 +253,14 @@ template<unsigned length_, char padding> string binary(uintmax_t value) {
//using sprintf is certainly not the most ideal method to convert
//a double to a string ... but attempting to parse a double by
//hand, digit-by-digit, results in subtle rounding errors.
unsigned fp(char *str, double value) {
unsigned fp(char *str, long double value) {
char buffer[256];
sprintf(buffer, "%f", value);
#ifdef _WIN32
//Windows C-runtime does not support long double via sprintf()
sprintf(buffer, "%f", (double)value);
#else
sprintf(buffer, "%Lf", value);
#endif
//remove excess 0's in fraction (2.500000 -> 2.5)
for(char *p = buffer; *p; p++) {
@@ -274,7 +279,7 @@ unsigned fp(char *str, double value) {
return length + 1;
}
string fp(double value) {
string fp(long double value) {
string temp;
temp.reserve(fp(0, value));
fp(temp(), value);

78
bsnes/nall/string/wildcard.hpp Executable file
View File

@@ -0,0 +1,78 @@
#ifdef NALL_STRING_INTERNAL_HPP
namespace nall {
bool wildcard(const char *s, const char *p) {
const char *cp = 0, *mp = 0;
while(*s && *p != '*') {
if(*p != '?' && *s != *p) return false;
p++, s++;
}
while(*s) {
if(*p == '*') {
if(!*++p) return true;
mp = p, cp = s + 1;
} else if(*p == '?' || *p == *s) {
p++, s++;
} else {
p = mp, s = cp++;
}
}
while(*p == '*') p++;
return !*p;
}
bool iwildcard(const char *s, const char *p) {
const char *cp = 0, *mp = 0;
while(*s && *p != '*') {
if(*p != '?' && chrlower(*s) != chrlower(*p)) return false;
p++, s++;
}
while(*s) {
if(*p == '*') {
if(!*++p) return true;
mp = p, cp = s + 1;
} else if(*p == '?' || chrlower(*p) == chrlower(*s)) {
p++, s++;
} else {
p = mp, s = cp++;
}
}
while(*p == '*') p++;
return !*p;
}
inline bool tokenize(const char *s, const char *p) {
while(*s) {
if(*p == '*') {
while(*s) if(tokenize(s++, p + 1)) return true;
return !*++p;
}
if(*s++ != *p++) return false;
}
while(*p == '*') p++;
return !*p;
}
inline bool tokenize(lstring &list, const char *s, const char *p) {
while(*s) {
if(*p == '*') {
const char *b = s;
while(*s) {
if(tokenize(list, s++, p + 1)) {
list.prepend(substr(b, 0, --s - b));
return true;
}
}
list.prepend(b);
return !*++p;
}
if(*s++ != *p++) return false;
}
while(*p == '*') { list.prepend(s); p++; }
return !*p;
}
}
#endif

View File

@@ -3,6 +3,7 @@
namespace nall {
unsigned string::length() const { return strlen(data); }
unsigned string::capacity() const { return size; }
template<unsigned limit> lstring string::split(const char *key) const { lstring result; result.split<limit>(key, data); return result; }
template<unsigned limit> lstring string::isplit(const char *key) const { lstring result; result.isplit<limit>(key, data); return result; }

265
bsnes/nall/string/xml-legacy.hpp Executable file
View File

@@ -0,0 +1,265 @@
#ifdef NALL_STRING_INTERNAL_HPP
//XML v1.0 subset parser
//revision 0.05
namespace nall {
struct xml_attribute {
string name;
string content;
virtual string parse() const;
};
struct xml_element : xml_attribute {
string parse() const;
linear_vector<xml_attribute> attribute;
linear_vector<xml_element> element;
protected:
void parse_doctype(const char *&data);
bool parse_head(string data);
bool parse_body(const char *&data);
friend xml_element xml_parse(const char *data);
};
inline string xml_attribute::parse() const {
string data;
unsigned offset = 0;
const char *source = content;
while(*source) {
if(*source == '&') {
if(strbegin(source, "&lt;")) { data[offset++] = '<'; source += 4; continue; }
if(strbegin(source, "&gt;")) { data[offset++] = '>'; source += 4; continue; }
if(strbegin(source, "&amp;")) { data[offset++] = '&'; source += 5; continue; }
if(strbegin(source, "&apos;")) { data[offset++] = '\''; source += 6; continue; }
if(strbegin(source, "&quot;")) { data[offset++] = '"'; source += 6; continue; }
}
//reject illegal characters
if(*source == '&') return "";
if(*source == '<') return "";
if(*source == '>') return "";
data[offset++] = *source++;
}
data[offset] = 0;
return data;
}
inline string xml_element::parse() const {
string data;
unsigned offset = 0;
const char *source = content;
while(*source) {
if(*source == '&') {
if(strbegin(source, "&lt;")) { data[offset++] = '<'; source += 4; continue; }
if(strbegin(source, "&gt;")) { data[offset++] = '>'; source += 4; continue; }
if(strbegin(source, "&amp;")) { data[offset++] = '&'; source += 5; continue; }
if(strbegin(source, "&apos;")) { data[offset++] = '\''; source += 6; continue; }
if(strbegin(source, "&quot;")) { data[offset++] = '"'; source += 6; continue; }
}
if(strbegin(source, "<!--")) {
if(auto pos = strpos(source, "-->")) {
source += pos() + 3;
continue;
} else {
return "";
}
}
if(strbegin(source, "<![CDATA[")) {
if(auto pos = strpos(source, "]]>")) {
if(pos() - 9 > 0) {
string cdata = substr(source, 9, pos() - 9);
data.append(cdata);
offset += strlen(cdata);
}
source += 9 + offset + 3;
continue;
} else {
return "";
}
}
//reject illegal characters
if(*source == '&') return "";
if(*source == '<') return "";
if(*source == '>') return "";
data[offset++] = *source++;
}
data[offset] = 0;
return data;
}
inline void xml_element::parse_doctype(const char *&data) {
name = "!DOCTYPE";
const char *content_begin = data;
signed counter = 0;
while(*data) {
char value = *data++;
if(value == '<') counter++;
if(value == '>') counter--;
if(counter < 0) {
content = substr(content_begin, 0, data - content_begin - 1);
return;
}
}
throw "...";
}
inline bool xml_element::parse_head(string data) {
data.qreplace("\t", " ");
data.qreplace("\r", " ");
data.qreplace("\n", " ");
while(qstrpos(data, " ")) data.qreplace(" ", " ");
data.qreplace(" =", "=");
data.qreplace("= ", "=");
data.rtrim();
lstring part;
part.qsplit(" ", data);
name = part[0];
if(name == "") throw "...";
for(unsigned i = 1; i < part.size(); i++) {
lstring side;
side.qsplit("=", part[i]);
if(side.size() != 2) throw "...";
xml_attribute attr;
attr.name = side[0];
attr.content = side[1];
if(strbegin(attr.content, "\"") && strend(attr.content, "\"")) attr.content.trim<1>("\"");
else if(strbegin(attr.content, "'") && strend(attr.content, "'")) attr.content.trim<1>("'");
else throw "...";
attribute.append(attr);
}
}
inline bool xml_element::parse_body(const char *&data) {
while(true) {
if(!*data) return false;
if(*data++ != '<') continue;
if(*data == '/') return false;
if(strbegin(data, "!DOCTYPE") == true) {
parse_doctype(data);
return true;
}
if(strbegin(data, "!--")) {
if(auto offset = strpos(data, "-->")) {
data += offset() + 3;
continue;
} else {
throw "...";
}
}
if(strbegin(data, "![CDATA[")) {
if(auto offset = strpos(data, "]]>")) {
data += offset() + 3;
continue;
} else {
throw "...";
}
}
auto offset = strpos(data, ">");
if(!offset) throw "...";
string tag = substr(data, 0, offset());
data += offset() + 1;
const char *content_begin = data;
bool self_terminating = false;
if(strend(tag, "?") == true) {
self_terminating = true;
tag.rtrim<1>("?");
} else if(strend(tag, "/") == true) {
self_terminating = true;
tag.rtrim<1>("/");
}
parse_head(tag);
if(self_terminating) return true;
while(*data) {
unsigned index = element.size();
xml_element node;
if(node.parse_body(data) == false) {
if(*data == '/') {
signed length = data - content_begin - 1;
if(length > 0) content = substr(content_begin, 0, length);
data++;
auto offset = strpos(data, ">");
if(!offset) throw "...";
tag = substr(data, 0, offset());
data += offset() + 1;
tag.replace("\t", " ");
tag.replace("\r", " ");
tag.replace("\n", " ");
while(strpos(tag, " ")) tag.replace(" ", " ");
tag.rtrim();
if(name != tag) throw "...";
return true;
}
} else {
element.append(node);
}
}
}
}
//ensure there is only one root element
inline bool xml_validate(xml_element &document) {
unsigned root_counter = 0;
for(unsigned i = 0; i < document.element.size(); i++) {
string &name = document.element[i].name;
if(strbegin(name, "?")) continue;
if(strbegin(name, "!")) continue;
if(++root_counter > 1) return false;
}
return true;
}
inline xml_element xml_parse(const char *data) {
xml_element self;
try {
while(*data) {
xml_element node;
if(node.parse_body(data) == false) {
break;
} else {
self.element.append(node);
}
}
if(xml_validate(self) == false) throw "...";
return self;
} catch(const char*) {
xml_element empty;
return empty;
}
}
}
#endif

View File

@@ -1,265 +1,250 @@
#ifdef NALL_STRING_INTERNAL_HPP
//XML v1.0 subset parser
//revision 0.05
//revision 0.01
namespace nall {
namespace XML {
struct xml_attribute {
struct Node {
string name;
string content;
virtual string parse() const;
};
struct xml_element : xml_attribute {
string parse() const;
linear_vector<xml_attribute> attribute;
linear_vector<xml_element> element;
protected:
void parse_doctype(const char *&data);
bool parse_head(string data);
bool parse_body(const char *&data);
friend xml_element xml_parse(const char *data);
};
inline string xml_attribute::parse() const {
string data;
unsigned offset = 0;
bool attribute;
array<Node*> children;
const char *source = content;
while(*source) {
if(*source == '&') {
if(strbegin(source, "&lt;")) { data[offset++] = '<'; source += 4; continue; }
if(strbegin(source, "&gt;")) { data[offset++] = '>'; source += 4; continue; }
if(strbegin(source, "&amp;")) { data[offset++] = '&'; source += 5; continue; }
if(strbegin(source, "&apos;")) { data[offset++] = '\''; source += 6; continue; }
if(strbegin(source, "&quot;")) { data[offset++] = '"'; source += 6; continue; }
}
//reject illegal characters
if(*source == '&') return "";
if(*source == '<') return "";
if(*source == '>') return "";
data[offset++] = *source++;
inline bool exists() const {
return !name.empty();
}
data[offset] = 0;
return data;
}
inline bool isName(char c) const {
if(c >= 'A' && c <= 'Z') return true;
if(c >= 'a' && c <= 'z') return true;
if(c >= '0' && c <= '9') return true;
if(c == '.' || c == '_') return true;
if(c == '?') return true;
return false;
}
inline string xml_element::parse() const {
string data;
unsigned offset = 0;
inline bool isWhitespace(char c) const {
if(c == ' ' || c == '\t') return true;
if(c == '\r' || c == '\n') return true;
return false;
}
const char *source = content;
while(*source) {
if(*source == '&') {
if(strbegin(source, "&lt;")) { data[offset++] = '<'; source += 4; continue; }
if(strbegin(source, "&gt;")) { data[offset++] = '>'; source += 4; continue; }
if(strbegin(source, "&amp;")) { data[offset++] = '&'; source += 5; continue; }
if(strbegin(source, "&apos;")) { data[offset++] = '\''; source += 6; continue; }
if(strbegin(source, "&quot;")) { data[offset++] = '"'; source += 6; continue; }
}
//copy part of string from source document into target string; decode markup while copying
inline void copy(string &target, const char *source, unsigned length) {
target.reserve(length + 1);
if(strbegin(source, "<!--")) {
if(auto pos = strpos(source, "-->")) {
source += pos() + 3;
continue;
} else {
return "";
#if defined(NALL_XML_LITERAL)
memcpy(target(), source, length);
target[length] = 0;
return;
#endif
char *output = target();
while(length) {
if(*source == '&') {
if(!memcmp(source, "&lt;", 4)) { *output++ = '<'; source += 4; length -= 4; continue; }
if(!memcmp(source, "&gt;", 4)) { *output++ = '>'; source += 4; length -= 4; continue; }
if(!memcmp(source, "&amp;", 5)) { *output++ = '&'; source += 5; length -= 5; continue; }
if(!memcmp(source, "&apos;", 6)) { *output++ = '\''; source += 6; length -= 6; continue; }
if(!memcmp(source, "&quot;", 6)) { *output++ = '\"'; source += 6; length -= 6; continue; }
}
}
if(strbegin(source, "<![CDATA[")) {
if(auto pos = strpos(source, "]]>")) {
if(pos() - 9 > 0) {
string cdata = substr(source, 9, pos() - 9);
data.append(cdata);
offset += strlen(cdata);
if(attribute == false && source[0] == '<' && source[1] == '!') {
//comment
if(!memcmp(source, "<!--", 4)) {
source += 4, length -= 4;
while(memcmp(source, "-->", 3)) source++, length--;
source += 3, length -= 3;
continue;
}
//CDATA
if(!memcmp(source, "<![CDATA[", 9)) {
source += 9, length -= 9;
while(memcmp(source, "]]>", 3)) *output++ = *source++, length--;
source += 3, length -= 3;
continue;
}
source += 9 + offset + 3;
continue;
} else {
return "";
}
*output++ = *source++, length--;
}
//reject illegal characters
if(*source == '&') return "";
if(*source == '<') return "";
if(*source == '>') return "";
data[offset++] = *source++;
*output = 0;
}
data[offset] = 0;
return data;
}
inline bool parseExpression(const char *&p) {
if(*(p + 1) != '!') return false;
inline void xml_element::parse_doctype(const char *&data) {
name = "!DOCTYPE";
const char *content_begin = data;
signed counter = 0;
while(*data) {
char value = *data++;
if(value == '<') counter++;
if(value == '>') counter--;
if(counter < 0) {
content = substr(content_begin, 0, data - content_begin - 1);
return;
}
}
throw "...";
}
inline bool xml_element::parse_head(string data) {
data.qreplace("\t", " ");
data.qreplace("\r", " ");
data.qreplace("\n", " ");
while(qstrpos(data, " ")) data.qreplace(" ", " ");
data.qreplace(" =", "=");
data.qreplace("= ", "=");
data.rtrim();
lstring part;
part.qsplit(" ", data);
name = part[0];
if(name == "") throw "...";
for(unsigned i = 1; i < part.size(); i++) {
lstring side;
side.qsplit("=", part[i]);
if(side.size() != 2) throw "...";
xml_attribute attr;
attr.name = side[0];
attr.content = side[1];
if(strbegin(attr.content, "\"") && strend(attr.content, "\"")) attr.content.trim<1>("\"");
else if(strbegin(attr.content, "'") && strend(attr.content, "'")) attr.content.trim<1>("'");
else throw "...";
attribute.append(attr);
}
}
inline bool xml_element::parse_body(const char *&data) {
while(true) {
if(!*data) return false;
if(*data++ != '<') continue;
if(*data == '/') return false;
if(strbegin(data, "!DOCTYPE") == true) {
parse_doctype(data);
//comment
if(!memcmp(p, "<!--", 4)) {
while(*p && memcmp(p, "-->", 3)) p++;
if(!*p) throw "unclosed comment";
p += 3;
return true;
}
if(strbegin(data, "!--")) {
if(auto offset = strpos(data, "-->")) {
data += offset() + 3;
continue;
} else {
throw "...";
}
//CDATA
if(!memcmp(p, "<![CDATA[", 9)) {
while(*p && memcmp(p, "]]>", 3)) p++;
if(!*p) throw "unclosed CDATA";
p += 3;
return true;
}
if(strbegin(data, "![CDATA[")) {
if(auto offset = strpos(data, "]]>")) {
data += offset() + 3;
continue;
} else {
throw "...";
}
//DOCTYPE
if(!memcmp(p, "<!DOCTYPE", 9)) {
unsigned counter = 0;
do {
char n = *p++;
if(!n) throw "unclosed DOCTYPE";
if(n == '<') counter++;
if(n == '>') counter--;
} while(counter);
return true;
}
auto offset = strpos(data, ">");
if(!offset) throw "...";
string tag = substr(data, 0, offset());
data += offset() + 1;
const char *content_begin = data;
bool self_terminating = false;
if(strend(tag, "?") == true) {
self_terminating = true;
tag.rtrim<1>("?");
} else if(strend(tag, "/") == true) {
self_terminating = true;
tag.rtrim<1>("/");
}
parse_head(tag);
if(self_terminating) return true;
while(*data) {
unsigned index = element.size();
xml_element node;
if(node.parse_body(data) == false) {
if(*data == '/') {
signed length = data - content_begin - 1;
if(length > 0) content = substr(content_begin, 0, length);
data++;
auto offset = strpos(data, ">");
if(!offset) throw "...";
tag = substr(data, 0, offset());
data += offset() + 1;
tag.replace("\t", " ");
tag.replace("\r", " ");
tag.replace("\n", " ");
while(strpos(tag, " ")) tag.replace(" ", " ");
tag.rtrim();
if(name != tag) throw "...";
return true;
}
} else {
element.append(node);
}
}
}
}
//ensure there is only one root element
inline bool xml_validate(xml_element &document) {
unsigned root_counter = 0;
for(unsigned i = 0; i < document.element.size(); i++) {
string &name = document.element[i].name;
if(strbegin(name, "?")) continue;
if(strbegin(name, "!")) continue;
if(++root_counter > 1) return false;
return false;
}
return true;
}
//returns true if tag closes itself (<tag/>); false if not (<tag>)
inline bool parseHead(const char *&p) {
//parse name
const char *nameStart = ++p; //skip '<'
while(isName(*p)) p++;
const char *nameEnd = p;
copy(name, nameStart, nameEnd - nameStart);
if(name.empty()) throw "missing element name";
inline xml_element xml_parse(const char *data) {
xml_element self;
//parse attributes
while(*p) {
while(isWhitespace(*p)) p++;
if(!*p) throw "unclosed attribute";
if(*p == '?' || *p == '/' || *p == '>') break;
try {
while(*data) {
xml_element node;
if(node.parse_body(data) == false) {
break;
} else {
self.element.append(node);
}
//parse attribute name
Node *attribute = new Node;
children.append(attribute);
attribute->attribute = true;
const char *nameStart = p;
while(isName(*p)) p++;
const char *nameEnd = p;
copy(attribute->name, nameStart, nameEnd - nameStart);
if(attribute->name.empty()) throw "missing attribute name";
//parse attribute data
if(*p++ != '=') throw "missing attribute value";
char terminal = *p++;
if(terminal != '\'' && terminal != '\"') throw "attribute value not quoted";
const char *dataStart = p;
while(*p && *p != terminal) p++;
if(!*p) throw "missing attribute data terminal";
const char *dataEnd = p++; //skip closing terminal
copy(attribute->data, dataStart, dataEnd - dataStart);
}
if(xml_validate(self) == false) throw "...";
return self;
} catch(const char*) {
xml_element empty;
return empty;
//parse closure
if(*p == '?' && *(p + 1) == '>') { p += 2; return true; }
if(*p == '/' && *(p + 1) == '>') { p += 2; return true; }
if(*p == '>') { p += 1; return false; }
throw "invalid element tag";
}
}
//parse element and all of its child elements
inline void parseElement(const char *&p) {
Node *node = new Node;
children.append(node);
if(node->parseHead(p) == true) return;
node->parse(p);
}
//return true if </tag> matches this node's name
inline bool parseClosureElement(const char *&p) {
if(p[0] != '<' || p[1] != '/') return false;
p += 2;
const char *nameStart = p;
while(*p && *p != '>') p++;
if(*p != '>') throw "unclosed closure element";
const char *nameEnd = p++;
if(memcmp(name, nameStart, nameEnd - nameStart)) throw "closure element name mismatch";
return true;
}
//parse contents of an element
inline void parse(const char *&p) {
const char *dataStart = p, *dataEnd = p;
while(*p) {
while(*p && *p != '<') p++;
if(!*p) break;
dataEnd = p;
if(parseClosureElement(p) == true) break;
if(parseExpression(p) == true) continue;
parseElement(p);
}
copy(data, dataStart, dataEnd - dataStart);
}
inline void reset() {
for(auto &child : children) delete child;
children.reset();
}
struct iterator {
inline bool operator!=(const iterator &source) const { return index != source.index; }
inline Node& operator*() { return *node.children[index]; }
inline iterator& operator++() { index++; return *this; }
inline iterator(const Node &node, unsigned index) : node(node), index(index) {}
private:
const Node &node;
unsigned index;
};
inline iterator begin() { return iterator(*this, 0); }
inline iterator end() { return iterator(*this, children.size()); }
inline const iterator begin() const { return iterator(*this, 0); }
inline const iterator end() const { return iterator(*this, children.size()); }
inline Node& operator[](const char *name) {
for(auto &node : *this) {
if(node.name == name) return node;
}
static Node node;
return node;
}
inline Node() : attribute(false) {}
inline ~Node() { reset(); }
Node(const Node&) = delete;
Node& operator=(const Node&) = delete;
};
struct Document : Node {
string error;
inline bool load(const char *document) {
if(document == nullptr) return false;
reset();
try {
parse(document);
} catch(const char *error) {
reset();
this->error = error;
return false;
}
return true;
}
inline Document() {}
inline Document(const char *document) { load(document); }
};
}
}
#endif

View File

@@ -55,6 +55,11 @@ namespace nall {
new(pool + objectsize++) T(data);
}
void prepend(const T& data) {
append(data);
for(unsigned n = objectsize - 1; n; n--) swap(pool[n], pool[n - 1]);
}
void remove(unsigned index, unsigned count = 1) {
for(unsigned n = index; count + n < objectsize; n++) {
pool[n] = pool[count + n];

29
bsnes/nall/xorg/guard.hpp Executable file
View File

@@ -0,0 +1,29 @@
#ifndef NALL_XORG_GUARD_HPP
#define NALL_XORG_GUARD_HPP
#define None
#undef XlibNone
#define XlibNone 0L
#define Button1 XlibButton1
#define Button2 XlibButton2
#define Button3 XlibButton3
#define Button4 XlibButton4
#define Button5 XlibButton5
#define Display XlibDisplay
#define Screen XlibScreen
#define Window XlibWindow
#else
#undef NALL_XORG_GUARD_HPP
#undef None
#undef Button1
#undef Button2
#undef Button3
#undef Button4
#undef Button5
#undef Display
#undef Screen
#undef Window
#endif

12
bsnes/nall/xorg/xorg.hpp Executable file
View File

@@ -0,0 +1,12 @@
#ifndef NALL_XORG_XORG_HPP
#define NALL_XORG_XORG_HPP
#include <nall/xorg/guard.hpp>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <nall/xorg/guard.hpp>
#endif

View File

@@ -111,7 +111,7 @@ void serialize(serializer &s) {
s.integer(irq_latch);
}
BandaiFCG(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
BandaiFCG(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
}
};

View File

@@ -86,14 +86,14 @@ void Board::serialize(serializer &s) {
if(chrram.size) s.array(chrram.data, chrram.size);
}
Board::Board(BML::Node &board, const uint8_t *data, unsigned size) {
information.type = board["type"].value;
information.battery = board["prg"]["battery"].value;
Board::Board(XML::Node &board, const uint8_t *data, unsigned size) {
information.type = board["type"].data;
information.battery = board["prg"]["battery"].data == "true";
prgrom.size = decimal(board["prg"]["rom"].value);
prgram.size = decimal(board["prg"]["ram"].value);
chrrom.size = decimal(board["chr"]["rom"].value);
chrram.size = decimal(board["chr"]["ram"].value);
prgrom.size = hex(board["prg"]["rom"].data);
prgram.size = hex(board["prg"]["ram"].data);
chrrom.size = hex(board["chr"]["rom"].data);
chrram.size = hex(board["chr"]["ram"].data);
if(prgrom.size) prgrom.data = new uint8[prgrom.size]();
if(prgram.size) prgram.data = new uint8[prgram.size]();
@@ -111,9 +111,9 @@ Board::~Board() {
}
Board* Board::load(const string &markup, const uint8_t *data, unsigned size) {
BML::Document document(markup);
XML::Document document(markup);
auto &board = document["cartridge"]["board"];
string type = board["type"].value;
string type = board["type"].data;
if(type == "BANDAI-FCG") return new BandaiFCG(board, data, size);

View File

@@ -31,7 +31,7 @@ struct Board {
virtual void reset();
virtual void serialize(serializer&);
Board(BML::Node &board, const uint8_t *data, unsigned size);
Board(XML::Node &board, const uint8_t *data, unsigned size);
virtual ~Board();
static Board* load(const string &markup, const uint8_t *data, unsigned size);

View File

@@ -34,7 +34,7 @@ void serialize(serializer &s) {
vrc1.serialize(s);
}
KonamiVRC1(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc1(*this) {
KonamiVRC1(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc1(*this) {
}
};

View File

@@ -49,9 +49,9 @@ void serialize(serializer &s) {
vrc2.serialize(s);
}
KonamiVRC2(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc2(*this) {
settings.pinout.a0 = 1 << decimal(board["chip"]["pinout"]["a0"].value);
settings.pinout.a1 = 1 << decimal(board["chip"]["pinout"]["a1"].value);
KonamiVRC2(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc2(*this) {
settings.pinout.a0 = 1 << decimal(board["chip"]["pinout"]["a0"].data);
settings.pinout.a1 = 1 << decimal(board["chip"]["pinout"]["a1"].data);
}
};

View File

@@ -50,8 +50,8 @@ void serialize(serializer &s) {
vrc3.serialize(s);
}
KonamiVRC3(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc3(*this) {
settings.mirror = board["mirror"].value == "vertical" ? 1 : 0;
KonamiVRC3(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc3(*this) {
settings.mirror = board["mirror"]["mode"].data == "vertical" ? 1 : 0;
}
};

View File

@@ -53,9 +53,9 @@ void serialize(serializer &s) {
vrc4.serialize(s);
}
KonamiVRC4(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc4(*this) {
settings.pinout.a0 = 1 << decimal(board["chip"]["pinout"]["a0"].value);
settings.pinout.a1 = 1 << decimal(board["chip"]["pinout"]["a1"].value);
KonamiVRC4(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc4(*this) {
settings.pinout.a0 = 1 << decimal(board["chip"]["pinout"]["a0"].data);
settings.pinout.a1 = 1 << decimal(board["chip"]["pinout"]["a1"].data);
}
};

View File

@@ -36,7 +36,7 @@ void main() { vrc6.main(); }
void power() { vrc6.power(); }
void reset() { vrc6.reset(); }
KonamiVRC6(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc6(*this) {
KonamiVRC6(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc6(*this) {
}
};

View File

@@ -41,7 +41,7 @@ void serialize(serializer &s) {
vrc7.serialize(s);
}
KonamiVRC7(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc7(*this) {
KonamiVRC7(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc7(*this) {
}
};

View File

@@ -45,7 +45,7 @@ void serialize(serializer &s) {
s.integer(mirror_select);
}
NES_AxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
NES_AxROM(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
}
};

View File

@@ -45,8 +45,8 @@ void serialize(serializer &s) {
s.integer(prg_bank);
}
NES_BNROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
settings.mirror = board["mirror"].value == "vertical" ? 1 : 0;
NES_BNROM(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
settings.mirror = board["mirror"]["mode"].data == "vertical" ? 1 : 0;
}
};

View File

@@ -47,8 +47,8 @@ void serialize(serializer &s) {
s.integer(chr_bank);
}
NES_CNROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
settings.mirror = board["mirror"].value == "vertical" ? 1 : 0;
NES_CNROM(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
settings.mirror = board["mirror"]["mode"].data == "vertical" ? 1 : 0;
}
};

View File

@@ -46,7 +46,7 @@ void serialize(serializer &s) {
mmc5.serialize(s);
}
NES_ExROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc5(*this) {
NES_ExROM(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc5(*this) {
revision = Revision::ELROM;
}

View File

@@ -84,7 +84,7 @@ void serialize(serializer &s) {
s.array(latch);
}
NES_FxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
NES_FxROM(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
revision = Revision::FKROM;
}

View File

@@ -54,8 +54,8 @@ void serialize(serializer &s) {
s.integer(chr_bank);
}
NES_GxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
settings.mirror = board["mirror"].value == "vertical" ? 1 : 0;
NES_GxROM(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
settings.mirror = board["mirror"]["mode"].data == "vertical" ? 1 : 0;
}
};

View File

@@ -42,7 +42,7 @@ void serialize(serializer &s) {
mmc6.serialize(s);
}
NES_HKROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc6(*this) {
NES_HKROM(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc6(*this) {
}
};

View File

@@ -36,8 +36,8 @@ void serialize(serializer &s) {
Board::serialize(s);
}
NES_NROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
settings.mirror = board["mirror"].value == "vertical" ? 1 : 0;
NES_NROM(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
settings.mirror = board["mirror"]["mode"].data == "vertical" ? 1 : 0;
}
};

View File

@@ -90,7 +90,7 @@ void serialize(serializer &s) {
s.array(latch);
}
NES_PxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
NES_PxROM(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
revision = Revision::PNROM;
}

View File

@@ -94,7 +94,7 @@ void serialize(serializer &s) {
mmc1.serialize(s);
}
NES_SxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc1(*this) {
NES_SxROM(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc1(*this) {
revision = Revision::SXROM;
}

View File

@@ -60,7 +60,7 @@ void serialize(serializer &s) {
mmc3.serialize(s);
}
NES_TxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc3(*this) {
NES_TxROM(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc3(*this) {
revision = Revision::TLROM;
}

View File

@@ -48,8 +48,8 @@ void serialize(serializer &s) {
s.integer(prg_bank);
}
NES_UxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
settings.mirror = board["mirror"].value == "vertical" ? 1 : 0;
NES_UxROM(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
settings.mirror = board["mirror"]["mode"].data == "vertical" ? 1 : 0;
}
};

View File

@@ -220,7 +220,7 @@ void serialize(serializer &s) {
pulse[2].serialize(s);
}
Sunsoft5B(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
Sunsoft5B(XML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) {
}
};

View File

@@ -16,135 +16,142 @@ static string iNES(const uint8_t *data, unsigned size) {
//print("iNES mapper: ", mapper, "\n");
output.append("cartridge\n");
output.append("<?xml version='1.0' encoding='UTF-8'?>\n");
output.append("<cartridge>\n");
switch(mapper) {
default:
output.append("\tboard type:NES-NROM-256\n");
output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n");
output.append(" <board type='NES-NROM-256'>\n");
output.append(" <mirror mode='", mirror == 0 ? "horizontal" : "vertical", "'/>\n");
break;
case 1:
output.append("\tboard type:NES-SXROM\n");
output.append("\t\tchip type:MMC1B2\n");
output.append(" <board type='NES-SXROM'>\n");
output.append(" <chip type='MMC1B2'/>\n");
prgram = 8192;
break;
case 2:
output.append("\tboard type:NES-UOROM\n");
output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n");
output.append(" <board type='NES-UOROM'>\n");
output.append(" <mirror mode='", mirror == 0 ? "horizontal" : "vertical", "'/>\n");
break;
case 3:
output.append("\tboard type:NES-CNROM\n");
output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n");
output.append(" <board type='NES-CNROM'>\n");
output.append(" <mirror mode='", mirror == 0 ? "horizontal" : "vertical", "'/>\n");
break;
case 4:
//MMC3
output.append("\tboard type:NES-TLROM\n");
output.append("\t\tchip type:MMC3B\n");
output.append(" <board type='NES-TLROM'>\n");
output.append(" <chip type='MMC3B'/>\n");
prgram = 8192;
//MMC6
//output.append("\tboard type:NES-HKROM\n");
//output.append("\t\tchip type:MMC6\n");
//output.append(" <board type='NES-HKROM'>\n");
//output.append(" <chip type='MMC6'/>\n");
//prgram = 1024;
break;
case 5:
output.append("\tboard type:NES-ELROM\n");
output.append("\t\tchip type:MMC5\n");
output.append(" <board type='NES-ELROM'>\n");
output.append(" <chip type='MMC5'/>\n");
prgram = 65536;
break;
case 7:
output.append("\tboard type:NES-AOROM\n");
output.append(" <board type='NES-AOROM'>\n");
break;
case 9:
output.append("\tboard type:NES-PNROM\n");
output.append("\t\tchip type:MMC2\n");
output.append(" <board type='NES-PNROM'>\n");
output.append(" <chip type='MMC2'/>\n");
prgram = 8192;
break;
case 10:
output.append("\tboard type:NES-FKROM\n");
output.append("\t\tchip type:MMC4\n");
output.append(" <board type='NES-FKROM'>\n");
output.append(" <chip type='MMC4'/>\n");
prgram = 8192;
break;
case 16:
output.append("\tboard type:BANDAI-FCG\n");
output.append("\t\tchip type:LZ93D50\n");
output.append(" <board type='BANDAI-FCG'>\n");
output.append(" <chip type='LZ93D50'/>\n");
break;
case 21:
case 23:
case 25:
//VRC4
output.append("\tboard type:KONAMI-VRC-4\n");
output.append("\t\tchip type:VRC4\n");
output.append("\t\t\tpinout a0=1 a1=0\n");
output.append(" <board type='KONAMI-VRC-4'>\n");
output.append(" <chip type='VRC4'>\n");
output.append(" <pinout a0='1' a1='0'/>\n");
output.append(" </chip>\n");
prgram = 8192;
break;
case 22:
//VRC2
output.append("\tboard type:KONAMI-VRC-2\n");
output.append("\t\tchip type:VRC2\n");
output.append("\t\t\tpinout a0=0 a1=1\n");
output.append(" <board type='KONAMI-VRC-2'>\n");
output.append(" <chip type='VRC2'>\n");
output.append(" <pinout a0='0' a1='1'/>\n");
output.append(" </chip>\n");
break;
case 24:
output.append("\tboard type:KONAMI-VRC-6\n");
output.append("\t\tchip type:VRC6\n");
output.append(" <board type='KONAMI-VRC-6'>\n");
output.append(" <chip type='VRC6'/>\n");
break;
case 26:
output.append("\tboard type:KONAMI-VRC-6\n");
output.append("\t\tchip type:VRC6\n");
output.append(" <board type='KONAMI-VRC-6'>\n");
output.append(" <chip type='VRC6'/>\n");
prgram = 8192;
break;
case 34:
output.append("\tboard type:NES-BNROM\n");
output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n");
output.append(" <board type='NES-BNROM'>\n");
output.append(" <mirror type='", mirror == 0 ? "horizontal" : "vertical", "'/>\n");
break;
case 66:
output.append("\tboard type:NES-GNROM\n");
output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n");
output.append(" <board type='NES-GNROM'>\n");
output.append(" <mirror type='", mirror == 0 ? "horizontal" : "vertical", "'/>\n");
break;
case 69:
output.append("\tboard type:SUNSOFT-5B\n");
output.append("\t\tchip type:5B\n");
output.append(" <board type='SUNSOFT-5B'>\n");
output.append(" <chip type='5B'/>\n");
prgram = 8192;
break;
case 73:
output.append("\tboard type:KONAMI-VRC-3\n");
output.append("\t\tchip type:VRC3\n");
output.append("\t\tmirror:", mirror == 0 ? "horizontal" : "vertical", "\n");
output.append(" <board type='KONAMI-VRC-3'>\n");
output.append(" <chip type='VRC3'/>\n");
output.append(" <mirror type='", mirror == 0 ? "horizontal" : "vertical", "'/>\n");
prgram = 8192;
break;
case 75:
output.append("\tboard type:KONAMI-VRC-1\n");
output.append("\t\tchip type:VRC1\n");
output.append(" <board type='KONAMI-VRC-1'>\n");
output.append(" <chip type='VRC1'/>\n");
break;
case 85:
output.append("\tboard type:KONAMI-VRC-7\n");
output.append("\t\tchip type:VRC7\n");
output.append(" <board type='KONAMI-VRC-7'>\n");
output.append(" <chip type='VRC7'/>\n");
prgram = 8192;
break;
}
output.append("\t\tprg rom=", prgrom, " ram=", prgram, "\n");
output.append("\t\tchr rom=", chrrom, " ram=", chrram, "\n");
output.append(
" <prg rom='0x", hex(prgrom), "' ram='0x", hex(prgram), "'/>\n"
" <chr rom='0x", hex(chrrom), "' ram='0x", hex(chrram), "'/>\n"
" </board>\n"
"</cartridge>\n"
);
//print(output, "\n");
print(output, "\n");
return output;
}

View File

@@ -42,7 +42,6 @@ void Input::connect(bool port, Device device) {
}
void Input::power() {
reset();
}
void Input::reset() {

View File

@@ -16,7 +16,6 @@ void Scheduler::exit(ExitReason reason) {
}
void Scheduler::power() {
reset();
}
void Scheduler::reset() {

21
bsnes/phoenix/Makefile Executable file
View File

@@ -0,0 +1,21 @@
ifeq ($(platform),x)
ifeq ($(phoenix),)
phoenix := gtk
endif
ifeq ($(phoenix),gtk)
phoenixflags := -DPHOENIX_GTK `pkg-config --cflags gtk+-2.0`
phoenixlink := `pkg-config --libs gtk+-2.0`
endif
ifeq ($(phoenix),qt)
phoenixflags := -DPHOENIX_QT `pkg-config --cflags QtCore QtGui`
phoenixlink := `pkg-config --libs QtCore QtGui`
endif
else ifeq ($(platform),win)
phoenixflags := -DPHOENIX_WINDOWS
phoenixlink := -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32
else
phoenixflags := -DPHOENIX_REFERENCE
phoenixlink :=
endif

View File

@@ -16,6 +16,29 @@
static bool OS_quit = false;
Window Window::None;
//Geometry
//========
Position Geometry::position() const {
return { x, y };
}
Size Geometry::size() const {
return { width, height };
}
string Geometry::text() const {
return { x, ",", y, ",", width, ",", height };
}
Geometry::Geometry(const string &text) {
lstring part = text.split(",");
x = integer(part(0, "256"));
y = integer(part(1, "256"));
width = decimal(part(2, "256"));
height = decimal(part(3, "256"));
}
//Font
//====
@@ -27,85 +50,6 @@ Font::Font(const string &description):
description(description) {
}
//Image
//=====
bool Image::load(const string &filename, const Color &alpha) {
if(data) { delete[] data; data = nullptr; }
file fp;
if(fp.open(filename, file::mode::read) == false) return false;
uint8_t d0 = fp.read();
uint8_t d1 = fp.read();
uint8_t d2 = fp.read();
uint8_t d3 = fp.read();
fp.close();
if(d0 == 'B' && d1 == 'M') {
bmp::read(filename, data, width, height);
}
if(d0 == 0x89 && d1 == 'P' && d2 == 'N' && d3 == 'G') {
png image;
if(image.decode(filename)) {
image.alphaTransform((alpha.red << 16) + (alpha.green << 8) + (alpha.blue << 0));
width = image.info.width, height = image.info.height;
data = new uint32_t[width * height];
memcpy(data, image.data, width * height * sizeof(uint32_t));
}
}
return data;
}
void Image::load(const uint32_t *data, const Size &size) {
if(data) { delete[] data; data = nullptr; }
width = size.width, height = size.height;
this->data = new uint32_t[width * height];
memcpy(this->data, data, width * height * sizeof(uint32_t));
}
Image& Image::operator=(const Image &source) {
if(this == &source) return *this;
if(data) { delete[] data; data = nullptr; }
if(source.data == nullptr) return *this;
width = source.width, height = source.height;
data = new uint32_t[width * height];
memcpy(data, source.data, width * height * sizeof(uint32_t));
return *this;
}
Image& Image::operator=(Image &&source) {
if(this == &source) return *this;
if(data) { delete[] data; data = nullptr; }
data = source.data, width = source.width, height = source.height;
source.data = nullptr;
return *this;
}
Image::Image() : data(nullptr) {
}
Image::Image(const string &filename, const Color &alpha) : data(nullptr) {
load(filename, alpha);
}
Image::Image(const uint32_t *data, const Size &size) {
load(data, size);
}
Image::Image(const Image &source) : data(nullptr) {
operator=(source);
}
Image::Image(Image &&source) : data(nullptr) {
operator=(std::forward<Image>(source));
}
Image::~Image() {
if(data) delete[] data;
}
//Object
//======
@@ -739,7 +683,7 @@ uint32_t* Canvas::data() {
return state.data;
}
bool Canvas::setImage(const Image &image) {
bool Canvas::setImage(const nall::image &image) {
if(image.data == nullptr || image.width == 0 || image.height == 0) return false;
state.width = image.width;
state.height = image.height;

View File

@@ -47,13 +47,6 @@ struct Color {
inline Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = 255) : red(red), green(green), blue(blue), alpha(alpha) {}
};
struct Geometry {
signed x, y;
unsigned width, height;
inline Geometry() : x(0), y(0), width(0), height(0) {}
inline Geometry(signed x, signed y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
};
struct Position {
signed x, y;
inline Position() : x(0), y(0) {}
@@ -66,27 +59,23 @@ struct Size {
inline Size(unsigned width, unsigned height) : width(width), height(height) {}
};
struct Geometry {
signed x, y;
unsigned width, height;
Position position() const;
Size size() const;
nall::string text() const;
inline Geometry() : x(0), y(0), width(0), height(0) {}
inline Geometry(signed x, signed y, unsigned width, unsigned height) : x(x), y(y), width(width), height(height) {}
Geometry(const nall::string &text);
};
struct Font {
nall::string description;
Geometry geometry(const nall::string &text);
Font(const nall::string &description = "");
};
struct Image {
uint32_t *data;
unsigned width, height;
bool load(const nall::string &filename, const Color &alpha = Color{255, 255, 255});
void load(const uint32_t *data, const Size &size);
Image& operator=(const Image &source);
Image& operator=(Image &&source);
Image();
Image(const nall::string &filename, const Color &alpha = Color{255, 255, 255});
Image(const uint32_t *data, const Size &size);
Image(const Image &source);
Image(Image &&source);
~Image();
};
struct Object {
Object(pObject &p);
Object& operator=(const Object&) = delete;
@@ -223,7 +212,7 @@ struct Separator : private nall::base_from_member<pSeparator&>, Action {
};
struct Item : private nall::base_from_member<pItem&>, Action {
nall::function<void ()> onTick;
nall::function<void ()> onActivate;
void setText(const nall::string &text);
@@ -235,7 +224,7 @@ struct Item : private nall::base_from_member<pItem&>, Action {
};
struct CheckItem : private nall::base_from_member<pCheckItem&>, Action {
nall::function<void ()> onTick;
nall::function<void ()> onToggle;
bool checked();
void setChecked(bool checked = true);
@@ -252,7 +241,7 @@ struct RadioItem : private nall::base_from_member<pRadioItem&>, Action {
template<typename... Args> static void group(Args&... args) { group({ args... }); }
static void group(const nall::reference_array<RadioItem&> &list);
nall::function<void ()> onTick;
nall::function<void ()> onActivate;
bool checked();
void setChecked();
@@ -317,7 +306,7 @@ struct Widget : private nall::base_from_member<pWidget&>, Sizable {
};
struct Button : private nall::base_from_member<pButton&>, Widget {
nall::function<void ()> onTick;
nall::function<void ()> onActivate;
void setText(const nall::string &text);
@@ -330,7 +319,7 @@ struct Button : private nall::base_from_member<pButton&>, Widget {
struct Canvas : private nall::base_from_member<pCanvas&>, Widget {
uint32_t* data();
bool setImage(const Image &image);
bool setImage(const nall::image &image);
void setSize(const Size &size);
Size size();
void update();
@@ -343,7 +332,7 @@ struct Canvas : private nall::base_from_member<pCanvas&>, Widget {
};
struct CheckBox : private nall::base_from_member<pCheckBox&>, Widget {
nall::function<void ()> onTick;
nall::function<void ()> onToggle;
bool checked();
void setChecked(bool checked = true);
@@ -446,7 +435,7 @@ struct LineEdit : private nall::base_from_member<pLineEdit&>, Widget {
struct ListView : private nall::base_from_member<pListView&>, Widget {
nall::function<void ()> onActivate;
nall::function<void ()> onChange;
nall::function<void (unsigned)> onTick;
nall::function<void (unsigned)> onToggle;
template<typename... Args> void append(const Args&... args) { append_({ args... }); }
void autoSizeColumns();
@@ -488,7 +477,7 @@ struct RadioBox : private nall::base_from_member<pRadioBox&>, Widget {
template<typename... Args> static void group(Args&... args) { group({ args... }); }
static void group(const nall::reference_array<RadioBox&> &list);
nall::function<void ()> onTick;
nall::function<void ()> onActivate;
bool checked();
void setChecked();

View File

@@ -1,5 +1,5 @@
static void CheckItem_tick(CheckItem *self) {
if(self->p.locked == false && self->onTick) self->onTick();
static void CheckItem_toggle(CheckItem *self) {
if(self->p.locked == false && self->onToggle) self->onToggle();
}
bool pCheckItem::checked() {
@@ -19,7 +19,7 @@ void pCheckItem::setText(const string &text) {
void pCheckItem::constructor() {
widget = gtk_check_menu_item_new_with_label(checkItem.state.text);
setChecked(checkItem.state.checked);
g_signal_connect_swapped(G_OBJECT(widget), "toggled", G_CALLBACK(CheckItem_tick), (gpointer)&checkItem);
g_signal_connect_swapped(G_OBJECT(widget), "toggled", G_CALLBACK(CheckItem_toggle), (gpointer)&checkItem);
}
void pCheckItem::destructor() {

View File

@@ -1,5 +1,5 @@
static void Item_tick(Item *self) {
if(self->onTick) self->onTick();
static void Item_activate(Item *self) {
if(self->onActivate) self->onActivate();
}
void pItem::setText(const string &text) {
@@ -8,7 +8,7 @@ void pItem::setText(const string &text) {
void pItem::constructor() {
widget = gtk_menu_item_new_with_label(item.state.text);
g_signal_connect_swapped(G_OBJECT(widget), "activate", G_CALLBACK(Item_tick), (gpointer)&item);
g_signal_connect_swapped(G_OBJECT(widget), "activate", G_CALLBACK(Item_activate), (gpointer)&item);
}
void pItem::destructor() {

View File

@@ -1,6 +1,6 @@
static void RadioItem_tick(RadioItem *self) {
static void RadioItem_activate(RadioItem *self) {
for(auto &item : self->state.group) item.state.checked = (&item == self);
if(self->p.locked == false && self->checked() && self->onTick) self->onTick();
if(self->p.locked == false && self->checked() && self->onActivate) self->onActivate();
}
bool pRadioItem::checked() {
@@ -34,7 +34,7 @@ void pRadioItem::constructor() {
for(auto &item : radioItem.state.group) {
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item.p.widget), item.state.checked);
}
g_signal_connect_swapped(G_OBJECT(widget), "toggled", G_CALLBACK(RadioItem_tick), (gpointer)&radioItem);
g_signal_connect_swapped(G_OBJECT(widget), "toggled", G_CALLBACK(RadioItem_activate), (gpointer)&radioItem);
}
void pRadioItem::destructor() {

View File

@@ -34,11 +34,11 @@
Font pOS::defaultFont;
Geometry pOS::availableGeometry() {
Display *display = XOpenDisplay(0);
XlibDisplay *display = XOpenDisplay(0);
int screen = DefaultScreen(display);
static Atom atom = X11None;
if(atom == X11None) atom = XInternAtom(display, "_NET_WORKAREA", True);
static Atom atom = XlibNone;
if(atom == XlibNone) atom = XInternAtom(display, "_NET_WORKAREA", True);
int format;
unsigned char *data = 0;
@@ -150,8 +150,6 @@ void pOS::processEvents() {
}
void pOS::quit() {
settings->save();
gtk_main_quit();
}
@@ -167,13 +165,16 @@ void pOS::initialize() {
char **argvp = argv;
gtk_init(&argc, &argvp);
gtk_rc_parse_string(
"style \"phoenix-gtk\"\n"
"{\n"
" GtkComboBox::appears-as-list = 1\n"
" GtkTreeView::vertical-separator = 0\n"
"}\n"
//"class \"GtkComboBox\" style \"phoenix-gtk\"\n"
"class \"GtkTreeView\" style \"phoenix-gtk\"\n"
);
gtk_rc_parse_string(R"(
style "phoenix-gtk"
{
GtkWindow::resize-grip-width = 0
GtkWindow::resize-grip-height = 0
GtkTreeView::vertical-separator = 0
GtkComboBox::appears-as-list = 1
}
class "GtkWindow" style "phoenix-gtk"
class "GtkTreeView" style "phoenix-gtk"
# class "GtkComboBox" style "phoenix-gtk"
)");
}

View File

@@ -1,5 +1,5 @@
static void Button_tick(Button *self) {
if(self->onTick) self->onTick();
static void Button_activate(Button *self) {
if(self->onActivate) self->onActivate();
}
Geometry pButton::minimumGeometry() {
@@ -9,11 +9,12 @@ Geometry pButton::minimumGeometry() {
void pButton::setText(const string &text) {
gtk_button_set_label(GTK_BUTTON(gtkWidget), text);
setFont(widget.state.font);
}
void pButton::constructor() {
gtkWidget = gtk_button_new();
g_signal_connect_swapped(G_OBJECT(gtkWidget), "clicked", G_CALLBACK(Button_tick), (gpointer)&button);
g_signal_connect_swapped(G_OBJECT(gtkWidget), "clicked", G_CALLBACK(Button_activate), (gpointer)&button);
setText(button.state.text);
}

View File

@@ -1,6 +1,6 @@
static void CheckBox_tick(CheckBox *self) {
static void CheckBox_toggle(CheckBox *self) {
self->state.checked = self->checked();
if(self->p.locked == false && self->onTick) self->onTick();
if(self->p.locked == false && self->onToggle) self->onToggle();
}
bool pCheckBox::checked() {
@@ -24,7 +24,7 @@ void pCheckBox::setText(const string &text) {
void pCheckBox::constructor() {
gtkWidget = gtk_check_button_new_with_label("");
g_signal_connect_swapped(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(CheckBox_tick), (gpointer)&checkBox);
g_signal_connect_swapped(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(CheckBox_toggle), (gpointer)&checkBox);
setChecked(checkBox.state.checked);
setText(checkBox.state.text);

View File

@@ -130,17 +130,17 @@ bool pHexEdit::keyPress(unsigned scancode) {
unsigned cursorY = position / lineWidth;
unsigned cursorX = position % lineWidth;
if(scancode == GDK_KEY_Home) {
if(scancode == GDK_Home) {
setCursorPosition(cursorY * lineWidth + 10);
return true;
}
if(scancode == GDK_KEY_End) {
if(scancode == GDK_End) {
setCursorPosition(cursorY * lineWidth + 10 + (hexEdit.state.columns * 3 - 1));
return true;
}
if(scancode == GDK_KEY_Up) {
if(scancode == GDK_Up) {
if(cursorY != 0) return false;
signed newOffset = hexEdit.state.offset - hexEdit.state.columns;
@@ -151,7 +151,7 @@ bool pHexEdit::keyPress(unsigned scancode) {
return true;
}
if(scancode == GDK_KEY_Down) {
if(scancode == GDK_Down) {
if(cursorY != hexEdit.state.rows - 1) return false;
signed newOffset = hexEdit.state.offset + hexEdit.state.columns;
@@ -162,7 +162,7 @@ bool pHexEdit::keyPress(unsigned scancode) {
return true;
}
if(scancode == GDK_KEY_Page_Up) {
if(scancode == GDK_Page_Up) {
signed newOffset = hexEdit.state.offset - hexEdit.state.columns * hexEdit.state.rows;
if(newOffset >= 0) {
hexEdit.setOffset(newOffset);
@@ -173,7 +173,7 @@ bool pHexEdit::keyPress(unsigned scancode) {
return true;
}
if(scancode == GDK_KEY_Page_Down) {
if(scancode == GDK_Page_Down) {
signed newOffset = hexEdit.state.offset + hexEdit.state.columns * hexEdit.state.rows;
for(unsigned n = 0; n < hexEdit.state.rows; n++) {
if(newOffset + hexEdit.state.columns * hexEdit.state.rows - (hexEdit.state.columns - 1) <= hexEdit.state.length) {

View File

@@ -1,7 +1,7 @@
static void HorizontalScrollBar_change(HorizontalScrollBar *self) {
if(self->state.position == self->position()) return;
self->state.position = self->position();
if(self->onChange) self->onChange();
if(self->p.locked == false && self->onChange) self->onChange();
}
Geometry pHorizontalScrollBar::minimumGeometry() {
@@ -13,9 +13,11 @@ unsigned pHorizontalScrollBar::position() {
}
void pHorizontalScrollBar::setLength(unsigned length) {
locked = true;
length += length == 0;
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1);
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1));
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
locked = false;
}
void pHorizontalScrollBar::setPosition(unsigned position) {

View File

@@ -14,7 +14,7 @@ unsigned pHorizontalSlider::position() {
void pHorizontalSlider::setLength(unsigned length) {
length += length == 0;
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1);
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1));
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
}

View File

@@ -10,10 +10,10 @@ static void ListView_change(ListView *self) {
}
}
static void ListView_tick(GtkCellRendererToggle *cell, gchar *path_string, ListView *self) {
static void ListView_toggle(GtkCellRendererToggle *cell, gchar *path_string, ListView *self) {
unsigned row = decimal(path_string);
self->setChecked(row, !self->checked(row));
if(self->onTick) self->onTick(row);
if(self->onToggle) self->onToggle(row);
}
void pListView::append(const lstring &text) {
@@ -28,22 +28,17 @@ void pListView::autoSizeColumns() {
bool pListView::checked(unsigned row) {
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget));
GtkTreePath *path = gtk_tree_path_new_from_string(string(row));
GtkTreeIter iter;
bool state;
gtk_tree_model_get_iter(model, &iter, path);
if(gtk_tree_model_get_iter_from_string(model, &iter, string(row)) == false) return false;
gtk_tree_model_get(model, &iter, 0, &state, -1);
gtk_tree_path_free(path);
return state;
}
void pListView::modify(unsigned row, const lstring &text) {
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget));
GtkTreeIter iter;
for(unsigned i = 0; i <= row; i++) {
if(i == 0) gtk_tree_model_get_iter_first(model, &iter);
else gtk_tree_model_iter_next(model, &iter);
}
gtk_tree_model_get_iter_from_string(model, &iter, string(row));
for(unsigned n = 0; n < text.size(); n++) gtk_list_store_set(store, &iter, 1 + n, (const char*)text[n], -1);
}
@@ -59,30 +54,18 @@ void pListView::reset() {
bool pListView::selected() {
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget));
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget));
GtkTreeIter iter;
if(gtk_tree_model_get_iter_first(model, &iter) == false) return false;
if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) return true;
for(unsigned n = 1;; n++) {
if(gtk_tree_model_iter_next(model, &iter) == false) return false;
if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) return true;
}
return false;
return gtk_tree_selection_get_selected(selection, 0, 0);
}
unsigned pListView::selection() {
if(selected() == false) return listView.state.selection;
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget));
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget));
GtkTreeIter iter;
if(gtk_tree_model_get_iter_first(model, &iter) == false) return 0;
if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) return 0;
for(unsigned n = 1;; n++) {
if(gtk_tree_model_iter_next(model, &iter) == false) return 0;
if(gtk_tree_selection_iter_is_selected(selection, &iter) == true) return n;
}
return 0;
if(gtk_tree_selection_get_selected(selection, 0, &iter) == false) return listView.state.selection;
char *path = gtk_tree_model_get_string_from_iter(model, &iter);
unsigned row = decimal(path);
g_free(path);
return row;
}
void pListView::setCheckable(bool checkable) {
@@ -91,11 +74,9 @@ void pListView::setCheckable(bool checkable) {
void pListView::setChecked(unsigned row, bool checked) {
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget));
GtkTreePath *path = gtk_tree_path_new_from_string(string(row));
GtkTreeIter iter;
gtk_tree_model_get_iter(model, &iter, path);
gtk_tree_model_get_iter_from_string(model, &iter, string(row));
gtk_list_store_set(GTK_LIST_STORE(model), &iter, 0, checked, -1);
gtk_tree_path_free(path);
}
void pListView::setHeaderText(const lstring &text) {
@@ -117,25 +98,12 @@ void pListView::setSelected(bool selected) {
}
void pListView::setSelection(unsigned row) {
signed current = -1;
if(selected()) current = selection();
GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(subWidget));
GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(subWidget));
gtk_tree_selection_unselect_all(selection);
GtkTreeIter iter;
if(gtk_tree_model_get_iter_first(model, &iter) == false) return;
if(row == 0) {
gtk_tree_selection_select_iter(selection, &iter);
return;
}
for(unsigned n = 1;; n++) {
if(gtk_tree_model_iter_next(model, &iter) == false) return;
if(row == n) {
gtk_tree_selection_select_iter(selection, &iter);
return;
}
}
if(gtk_tree_model_get_iter_from_string(model, &iter, string(row)) == false) return;
gtk_tree_selection_select_iter(selection, &iter);
}
void pListView::constructor() {
@@ -166,7 +134,7 @@ void pListView::constructor() {
column[n].column = gtk_tree_view_column_new_with_attributes("", column[n].renderer, "active", n, (void*)0);
gtk_tree_view_column_set_resizable(column[n].column, false);
gtk_tree_view_column_set_visible(column[n].column, false);
g_signal_connect(column[n].renderer, "toggled", G_CALLBACK(ListView_tick), (gpointer)&listView);
g_signal_connect(column[n].renderer, "toggled", G_CALLBACK(ListView_toggle), (gpointer)&listView);
} else {
column[n].renderer = gtk_cell_renderer_text_new();
column[n].column = gtk_tree_view_column_new_with_attributes("", column[n].renderer, "text", n, (void*)0);

View File

@@ -1,5 +1,5 @@
static void RadioBox_tick(RadioBox *self) {
if(self->p.locked == false && self->checked() && self->onTick) self->onTick();
static void RadioBox_activate(RadioBox *self) {
if(self->p.locked == false && self->checked() && self->onActivate) self->onActivate();
}
bool pRadioBox::checked() {
@@ -35,7 +35,7 @@ void pRadioBox::setText(const string &text) {
void pRadioBox::constructor() {
gtkWidget = gtk_radio_button_new_with_label(0, "");
g_signal_connect_swapped(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(RadioBox_tick), (gpointer)&radioBox);
g_signal_connect_swapped(G_OBJECT(gtkWidget), "toggled", G_CALLBACK(RadioBox_activate), (gpointer)&radioBox);
setText(radioBox.state.text);
}

View File

@@ -1,7 +1,7 @@
static void VerticalScrollBar_change(VerticalScrollBar *self) {
if(self->state.position == self->position()) return;
self->state.position = self->position();
if(self->onChange) self->onChange();
if(self->p.locked == false && self->onChange) self->onChange();
}
Geometry pVerticalScrollBar::minimumGeometry() {
@@ -13,9 +13,11 @@ unsigned pVerticalScrollBar::position() {
}
void pVerticalScrollBar::setLength(unsigned length) {
locked = true;
length += length == 0;
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1);
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1));
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
locked = false;
}
void pVerticalScrollBar::setPosition(unsigned position) {

View File

@@ -14,7 +14,7 @@ unsigned pVerticalSlider::position() {
void pVerticalSlider::setLength(unsigned length) {
length += length == 0;
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, length - 1);
gtk_range_set_range(GTK_RANGE(gtkWidget), 0, max(1u, length - 1));
gtk_range_set_increments(GTK_RANGE(gtkWidget), 1, length >> 3);
}

View File

@@ -6,6 +6,7 @@ static gint Window_close(GtkWidget *widget, GdkEvent *event, Window *window) {
}
static gboolean Window_expose(GtkWidget *widget, GdkEvent *event, Window *window) {
if(window->state.backgroundColorOverride == false) return false;
cairo_t *context = gdk_cairo_create(widget->window);
Color color = window->backgroundColor();
@@ -42,6 +43,7 @@ static gboolean Window_configure(GtkWidget *widget, GdkEvent *event, Window *win
settings->frameGeometryY = client.y - border.y;
settings->frameGeometryWidth = border.width - client.width;
settings->frameGeometryHeight = border.height - client.height;
settings->save();
}
//move
@@ -240,6 +242,10 @@ void pWindow::constructor() {
}
gtk_window_set_resizable(GTK_WINDOW(widget), true);
#if GTK_MAJOR_VERSION >= 3
gtk_window_set_has_resize_grip(GTK_WINDOW(widget), false);
#endif
gtk_widget_set_app_paintable(widget, true);
gtk_widget_add_events(widget, GDK_CONFIGURE);

View File

@@ -18,19 +18,14 @@
#include <QApplication>
#include <QtGui>
#elif defined(PHOENIX_GTK)
#define None
#define Window X11Window
#define X11None 0L
#include <nall/xorg/guard.hpp>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <gdk/gdkx.h>
#include <cairo.h>
#include <gdk/gdkkeysyms.h>
#include <X11/Xatom.h>
#undef None
#undef Window
#include <nall/xorg/guard.hpp>
#elif defined(PHOENIX_REFERENCE)
#else
#error "phoenix: unrecognized target"

View File

@@ -1,11 +1,11 @@
#ifndef PHOENIX_HPP
#define PHOENIX_HPP
#include <nall/platform.hpp>
#include <nall/array.hpp>
#include <nall/bmp.hpp>
#include <nall/config.hpp>
#include <nall/function.hpp>
#include <nall/png.hpp>
#include <nall/image.hpp>
#include <nall/reference_array.hpp>
#include <nall/stdint.hpp>
#include <nall/string.hpp>

View File

@@ -13,7 +13,7 @@ void pCheckItem::setText(const string &text) {
void pCheckItem::constructor() {
qtAction = new QAction(0);
qtAction->setCheckable(true);
connect(qtAction, SIGNAL(triggered()), SLOT(onTick()));
connect(qtAction, SIGNAL(triggered()), SLOT(onToggle()));
}
void pCheckItem::destructor() {
@@ -21,7 +21,7 @@ void pCheckItem::destructor() {
delete qtAction;
}
void pCheckItem::onTick() {
void pCheckItem::onToggle() {
checkItem.state.checked = checked();
if(checkItem.onTick) checkItem.onTick();
if(checkItem.onToggle) checkItem.onToggle();
}

View File

@@ -4,7 +4,7 @@ void pItem::setText(const string &text) {
void pItem::constructor() {
qtAction = new QAction(0);
connect(qtAction, SIGNAL(triggered()), SLOT(onTick()));
connect(qtAction, SIGNAL(triggered()), SLOT(onActivate()));
}
void pItem::destructor() {
@@ -12,6 +12,6 @@ void pItem::destructor() {
delete qtAction;
}
void pItem::onTick() {
if(item.onTick) item.onTick();
void pItem::onActivate() {
if(item.onActivate) item.onActivate();
}

View File

@@ -25,7 +25,7 @@ void pRadioItem::constructor() {
qtAction->setCheckable(true);
qtAction->setActionGroup(qtGroup);
qtAction->setChecked(true);
connect(qtAction, SIGNAL(triggered()), SLOT(onTick()));
connect(qtAction, SIGNAL(triggered()), SLOT(onActivate()));
}
void pRadioItem::destructor() {
@@ -33,9 +33,9 @@ void pRadioItem::destructor() {
delete qtAction;
}
void pRadioItem::onTick() {
void pRadioItem::onActivate() {
if(radioItem.state.checked == false) {
setChecked();
if(locked == false && radioItem.onTick) radioItem.onTick();
if(locked == false && radioItem.onActivate) radioItem.onActivate();
}
}

View File

@@ -113,8 +113,6 @@ void pOS::processEvents() {
}
void pOS::quit() {
settings->save();
QApplication::quit();
//note: QApplication cannot be deleted; or libQtGui will crash
qtApplication = 0;

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