From 4b2944c39b8707a61457546660bd9e71d920f2d0 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sun, 22 Apr 2012 20:49:19 +1000 Subject: [PATCH] Update to v087r30 release. byuu says: Changelog: - DMA channel masks added (some are 27-bit source/target and some are 14-bit length -- hooray, varuint_t class.) - No more state.pending flags. Instead, we set dma.pending flag when we want a transfer (fixes GBA Video - Pokemon audio) [Cydrak] - fixed OBJ Vmosaic [Cydrak, krom] - OBJ cannot read <=0x13fff in BG modes 3-5 (fixes the garbled tile at the top-left of some games) - DMA timing should be much closer to hardware now, but probably not perfect - PPU frame blending uses blargg's bit-perfect, rounded method (slower, but what can you do?) - GBA carts really unload now - added nall/gba/cartridge.hpp: used when there is no manifest. Scans ROMs for library tags, and selects the first valid one found - added EEPROM auto-detection when EEPROM size=0. Forces disk/save state size to 8192 (otherwise states could crash between pre and post detect.) - detects first read after a set read address command when the size is zero, and sets all subsequent bit-lengths to that value, prints detected size to terminal - added nall/nes/cartridge.hpp: moves iNES detection out of emulation core. Important to note: long-term goal is to remove all nall/(system)/cartridge.hpp detections from the core and replace with databases. All in good time. Anyway, the GBA workarounds should work for ~98.5% of the library, if my pre-scanning was correct (~40 games with odd tags. I reject ones without numeric versions now, too.) I think we're basically at a point where we can release a new version now. Compatibility should be relatively high (at least for a first release), and fixes are only going to affect one or two games at a time. I'd like to start doing some major cleaning house internally (rename NES->Famicom, SNES->SuperFamicom and such.) Would be much wiser to do that on a .01 WIP to minimize regressions. The main problems with a release now: - speed is pretty bad, haven't really optimized much yet (not sure how much we can improve it yet, this usually isn't easy) - sound isn't -great-, but the GBA audio sucks anyway :P - couple of known bugs (Sonic X video, etc.) --- bsnes/base/base.hpp | 40 ++-- bsnes/gb/cartridge/cartridge.cpp | 47 +++-- bsnes/gb/cartridge/cartridge.hpp | 4 +- bsnes/gb/cartridge/serialization.cpp | 2 +- bsnes/gb/gb.hpp | 1 - bsnes/gba/cartridge/cartridge.cpp | 6 +- bsnes/gba/cartridge/cartridge.hpp | 4 + bsnes/gba/cartridge/eeprom.cpp | 14 +- bsnes/gba/cartridge/memory.hpp | 1 + bsnes/gba/cpu/cpu.cpp | 20 ++ bsnes/gba/cpu/cpu.hpp | 4 + bsnes/gba/cpu/dma.cpp | 57 +++--- bsnes/gba/cpu/mmio.cpp | 3 + bsnes/gba/cpu/registers.hpp | 13 +- bsnes/gba/cpu/timer.cpp | 17 +- bsnes/gba/ppu/object.cpp | 14 +- bsnes/gba/ppu/ppu.cpp | 6 +- bsnes/gba/ppu/ppu.hpp | 1 + bsnes/gba/ppu/screen.cpp | 4 +- bsnes/nall/{gameboy => gb}/cartridge.hpp | 33 +--- bsnes/nall/gba/cartridge.hpp | 65 +++++++ bsnes/nall/nes/cartridge.hpp | 171 ++++++++++++++++++ bsnes/nall/snes/cartridge.hpp | 17 +- bsnes/nall/string/base.hpp | 2 + bsnes/nall/string/core.hpp | 8 + bsnes/nall/varint.hpp | 116 +++++------- bsnes/nall/vector.hpp | 6 + bsnes/nes/cartridge/cartridge.cpp | 5 +- bsnes/nes/cartridge/cartridge.hpp | 4 + bsnes/nes/cartridge/ines.cpp | 162 ----------------- bsnes/snes/cartridge/cartridge.cpp | 4 +- bsnes/snes/cartridge/cartridge.hpp | 5 +- bsnes/target-ui/base.hpp | 5 +- bsnes/target-ui/general/general.cpp | 1 + bsnes/target-ui/general/general.hpp | 1 + .../target-ui/general/information-window.cpp | 43 +++++ .../target-ui/general/information-window.hpp | 11 ++ bsnes/target-ui/general/main-window.cpp | 7 +- bsnes/target-ui/general/main-window.hpp | 1 + bsnes/target-ui/interface/gb/gb.cpp | 8 +- bsnes/target-ui/interface/gb/gb.hpp | 2 + bsnes/target-ui/interface/gba/gba.cpp | 5 + bsnes/target-ui/interface/gba/gba.hpp | 2 + bsnes/target-ui/interface/interface.cpp | 10 +- bsnes/target-ui/interface/interface.hpp | 3 + bsnes/target-ui/interface/nes/nes.cpp | 5 + bsnes/target-ui/interface/nes/nes.hpp | 3 + bsnes/target-ui/interface/snes/snes.cpp | 14 +- bsnes/target-ui/interface/snes/snes.hpp | 2 + bsnes/target-ui/main.cpp | 4 + bsnes/target-ui/utility/utility.cpp | 1 + 51 files changed, 606 insertions(+), 378 deletions(-) rename bsnes/nall/{gameboy => gb}/cartridge.hpp (82%) create mode 100755 bsnes/nall/gba/cartridge.hpp create mode 100755 bsnes/nall/nes/cartridge.hpp delete mode 100755 bsnes/nes/cartridge/ines.cpp create mode 100755 bsnes/target-ui/general/information-window.cpp create mode 100755 bsnes/target-ui/general/information-window.hpp diff --git a/bsnes/base/base.hpp b/bsnes/base/base.hpp index 64df2b2f..5b863cb7 100755 --- a/bsnes/base/base.hpp +++ b/bsnes/base/base.hpp @@ -1,7 +1,7 @@ #ifndef BASE_HPP #define BASE_HPP -static const char Version[] = "087.29"; +static const char Version[] = "087.30"; #include #include @@ -56,15 +56,15 @@ template struct hook { #define privileged private #endif -typedef int1_t int1; -typedef int2_t int2; -typedef int3_t int3; -typedef int4_t int4; -typedef int5_t int5; -typedef int6_t int6; -typedef int7_t int7; -typedef int8_t int8; -typedef int9_t int9; +typedef int1_t int1; +typedef int2_t int2; +typedef int3_t int3; +typedef int4_t int4; +typedef int5_t int5; +typedef int6_t int6; +typedef int7_t int7; +typedef int8_t int8; +typedef int9_t int9; typedef int10_t int10; typedef int11_t int11; typedef int12_t int12; @@ -90,15 +90,15 @@ typedef int31_t int31; typedef int32_t int32; typedef int64_t int64; -typedef uint1_t uint1; -typedef uint2_t uint2; -typedef uint3_t uint3; -typedef uint4_t uint4; -typedef uint5_t uint5; -typedef uint6_t uint6; -typedef uint7_t uint7; -typedef uint8_t uint8; -typedef uint9_t uint9; +typedef uint1_t uint1; +typedef uint2_t uint2; +typedef uint3_t uint3; +typedef uint4_t uint4; +typedef uint5_t uint5; +typedef uint6_t uint6; +typedef uint7_t uint7; +typedef uint8_t uint8; +typedef uint9_t uint9; typedef uint10_t uint10; typedef uint11_t uint11; typedef uint12_t uint12; @@ -125,6 +125,6 @@ typedef uint32_t uint32; typedef uint_t<33> uint33; typedef uint64_t uint64; -typedef varuint_t varuint; +typedef varuint_t varuint; #endif diff --git a/bsnes/gb/cartridge/cartridge.cpp b/bsnes/gb/cartridge/cartridge.cpp index e132b68e..29c72452 100755 --- a/bsnes/gb/cartridge/cartridge.cpp +++ b/bsnes/gb/cartridge/cartridge.cpp @@ -1,7 +1,5 @@ #include -#include - #define CARTRIDGE_CPP namespace GB { @@ -21,35 +19,36 @@ void Cartridge::load(System::Revision revision, const string &markup, const uint romdata = allocate(romsize = size, 0xff); if(data) memcpy(romdata, data, size); - info.mapper = Mapper::Unknown; - info.ram = false; - info.battery = false; - info.rtc = false; - info.rumble = false; + information.markup = markup; + information.mapper = Mapper::Unknown; + information.ram = false; + information.battery = false; + information.rtc = false; + information.rumble = false; - info.romsize = 0; - info.ramsize = 0; + information.romsize = 0; + information.ramsize = 0; XML::Document document(markup); 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; - if(mapperid == "MBC3" ) info.mapper = Mapper::MBC3; - if(mapperid == "MBC5" ) info.mapper = Mapper::MBC5; - if(mapperid == "MMM01") info.mapper = Mapper::MMM01; - if(mapperid == "HuC1" ) info.mapper = Mapper::HuC1; - if(mapperid == "HuC3" ) info.mapper = Mapper::HuC3; + if(mapperid == "none" ) information.mapper = Mapper::MBC0; + if(mapperid == "MBC1" ) information.mapper = Mapper::MBC1; + if(mapperid == "MBC2" ) information.mapper = Mapper::MBC2; + if(mapperid == "MBC3" ) information.mapper = Mapper::MBC3; + if(mapperid == "MBC5" ) information.mapper = Mapper::MBC5; + if(mapperid == "MMM01") information.mapper = Mapper::MMM01; + if(mapperid == "HuC1" ) information.mapper = Mapper::HuC1; + if(mapperid == "HuC3" ) information.mapper = Mapper::HuC3; - info.rtc = document["cartridge"]["rtc"].data == "true"; - info.rumble = document["cartridge"]["rumble"].data == "true"; + information.rtc = document["cartridge"]["rtc"].data == "true"; + information.rumble = document["cartridge"]["rumble"].data == "true"; - info.romsize = numeral(document["cartridge"]["rom"]["size"].data); - info.ramsize = numeral(document["cartridge"]["ram"]["size"].data); - info.battery = document["cartridge"]["ram"]["battery"].data == "true"; + information.romsize = numeral(document["cartridge"]["rom"]["size"].data); + information.ramsize = numeral(document["cartridge"]["ram"]["size"].data); + information.battery = document["cartridge"]["ram"]["nonvolatile"].data == "true"; - switch(info.mapper) { default: + switch(information.mapper) { default: case Mapper::MBC0: mapper = &mbc0; break; case Mapper::MBC1: mapper = &mbc1; break; case Mapper::MBC2: mapper = &mbc2; break; @@ -60,7 +59,7 @@ void Cartridge::load(System::Revision revision, const string &markup, const uint case Mapper::HuC3: mapper = &huc3; break; } - ramdata = new uint8_t[ramsize = info.ramsize](); + ramdata = new uint8_t[ramsize = information.ramsize](); system.load(revision); loaded = true; diff --git a/bsnes/gb/cartridge/cartridge.hpp b/bsnes/gb/cartridge/cartridge.hpp index d7e4c2a5..b505fcf0 100755 --- a/bsnes/gb/cartridge/cartridge.hpp +++ b/bsnes/gb/cartridge/cartridge.hpp @@ -21,7 +21,7 @@ struct Cartridge : MMIO, property { }; struct Information { - string xml; + string markup; Mapper mapper; bool ram; @@ -31,7 +31,7 @@ struct Cartridge : MMIO, property { unsigned romsize; unsigned ramsize; - } info; + } information; readonly loaded; readonly sha256; diff --git a/bsnes/gb/cartridge/serialization.cpp b/bsnes/gb/cartridge/serialization.cpp index 2f54262a..c05e0892 100755 --- a/bsnes/gb/cartridge/serialization.cpp +++ b/bsnes/gb/cartridge/serialization.cpp @@ -1,7 +1,7 @@ #ifdef CARTRIDGE_CPP void Cartridge::serialize(serializer &s) { - if(info.battery) s.array(ramdata, ramsize); + if(information.battery) s.array(ramdata, ramsize); s.integer(bootrom_enable); s.integer(mbc1.ram_enable); diff --git a/bsnes/gb/gb.hpp b/bsnes/gb/gb.hpp index 6046a5ce..97de251b 100755 --- a/bsnes/gb/gb.hpp +++ b/bsnes/gb/gb.hpp @@ -18,7 +18,6 @@ namespace GB { */ #include -#include namespace GB { struct Thread { diff --git a/bsnes/gba/cartridge/cartridge.cpp b/bsnes/gba/cartridge/cartridge.cpp index bbc990f6..ea8da6c0 100755 --- a/bsnes/gba/cartridge/cartridge.cpp +++ b/bsnes/gba/cartridge/cartridge.cpp @@ -8,6 +8,7 @@ namespace GBA { Cartridge cartridge; bool Cartridge::load(const string &markup, const uint8_t *data, unsigned size) { + information.markup = markup; XML::Document document(markup); for(unsigned addr = 0; addr < rom.size; addr++) { @@ -31,6 +32,8 @@ bool Cartridge::load(const string &markup, const uint8_t *data, unsigned size) { if(info["type"].data == "EEPROM") { has_eeprom = true; eeprom.size = numeral(info["size"].data); + eeprom.bits = eeprom.size <= 512 ? 6 : 14; + if(eeprom.size == 0) eeprom.size = 8192, eeprom.bits = 0; //auto-detect size eeprom.mask = size > 16 * 1024 * 1024 ? 0x0fffff00 : 0x0f000000; eeprom.test = size > 16 * 1024 * 1024 ? 0x0dffff00 : 0x0d000000; for(unsigned n = 0; n < eeprom.size; n++) eeprom.data[n] = 0xff; @@ -51,7 +54,7 @@ bool Cartridge::load(const string &markup, const uint8_t *data, unsigned size) { } void Cartridge::unload() { - if(loaded) return; + if(loaded == false) return; loaded = false; } @@ -120,6 +123,7 @@ Cartridge::Cartridge() { Cartridge::~Cartridge() { delete[] rom.data; delete[] ram.data; + delete[] eeprom.data; delete[] flashrom.data; } diff --git a/bsnes/gba/cartridge/cartridge.hpp b/bsnes/gba/cartridge/cartridge.hpp index 8348f01d..9d69fa04 100755 --- a/bsnes/gba/cartridge/cartridge.hpp +++ b/bsnes/gba/cartridge/cartridge.hpp @@ -8,6 +8,10 @@ struct Cartridge : property { readonly has_eeprom; readonly has_flashrom; + struct Information { + string markup; + } information; + bool load(const string &markup, const uint8_t *data, unsigned size); void unload(); void power(); diff --git a/bsnes/gba/cartridge/eeprom.cpp b/bsnes/gba/cartridge/eeprom.cpp index 898029d8..33289ecd 100755 --- a/bsnes/gba/cartridge/eeprom.cpp +++ b/bsnes/gba/cartridge/eeprom.cpp @@ -10,6 +10,16 @@ void Cartridge::EEPROM::write(unsigned addr, bool bit) { bool Cartridge::EEPROM::read() { bool bit = 1; + //EEPROM size auto-detection + if(bits == 0 && mode == Mode::ReadAddress) { + print("EEPROM address bits: ", --addressbits, "\n"); + bits = addressbits == 6 ? 6 : 14; + size = 8192; + mode = Mode::ReadData; + offset = 0; + //fallthrough + } + if(mode == Mode::ReadData) { if(offset >= 4) bit = read(address * 64 + (offset - 4)); if(++offset == 68) mode = Mode::Wait; @@ -28,10 +38,12 @@ void Cartridge::EEPROM::write(bool bit) { if(bit == 1) mode = Mode::ReadAddress; offset = 0; address = 0; + addressbits = 0; } else if(mode == Mode::ReadAddress) { address = (address << 1) | bit; + addressbits++; if(++offset == bits) { mode = Mode::ReadValidate; offset = 0; @@ -65,8 +77,6 @@ void Cartridge::EEPROM::write(bool bit) { } void Cartridge::EEPROM::power() { - bits = (size <= 512 ? 6 : 14); - mode = Mode::Wait; offset = 0; address = 0; diff --git a/bsnes/gba/cartridge/memory.hpp b/bsnes/gba/cartridge/memory.hpp index 47ded28d..2eb0f0f7 100755 --- a/bsnes/gba/cartridge/memory.hpp +++ b/bsnes/gba/cartridge/memory.hpp @@ -14,6 +14,7 @@ struct EEPROM { enum class Mode : unsigned { Wait, Command, ReadAddress, ReadValidate, ReadData, WriteAddress, WriteData, WriteValidate } mode; unsigned offset; unsigned address; + unsigned addressbits; bool read(unsigned addr); void write(unsigned addr, bool bit); diff --git a/bsnes/gba/cpu/cpu.cpp b/bsnes/gba/cpu/cpu.cpp index 6f45fde3..f1d946ff 100755 --- a/bsnes/gba/cpu/cpu.cpp +++ b/bsnes/gba/cpu/cpu.cpp @@ -110,6 +110,10 @@ void CPU::power() { dma.target = 0; dma.length = 0; dma.control = 0; + dma.pending = 0; + dma.run.target = 0; + dma.run.source = 0; + dma.run.length = 0; } for(auto &timer : regs.timer) { timer.period = 0; @@ -143,6 +147,22 @@ void CPU::power() { CPU::CPU() { iwram = new uint8[ 32 * 1024]; ewram = new uint8[256 * 1024]; + + regs.dma[0].source.bits(27); regs.dma[0].run.source.bits(27); + regs.dma[0].target.bits(27); regs.dma[0].run.target.bits(27); + regs.dma[0].length.bits(14); regs.dma[0].run.length.bits(14); + + regs.dma[1].source.bits(28); regs.dma[1].run.source.bits(28); + regs.dma[1].target.bits(27); regs.dma[1].run.target.bits(27); + regs.dma[1].length.bits(14); regs.dma[1].run.length.bits(14); + + regs.dma[2].source.bits(28); regs.dma[2].run.source.bits(28); + regs.dma[2].target.bits(27); regs.dma[2].run.target.bits(27); + regs.dma[2].length.bits(14); regs.dma[2].run.length.bits(14); + + regs.dma[3].source.bits(28); regs.dma[3].run.source.bits(28); + regs.dma[3].target.bits(28); regs.dma[3].run.target.bits(28); + regs.dma[3].length.bits(16); regs.dma[3].run.length.bits(16); } CPU::~CPU() { diff --git a/bsnes/gba/cpu/cpu.hpp b/bsnes/gba/cpu/cpu.hpp index 5d0aed33..d3effba2 100755 --- a/bsnes/gba/cpu/cpu.hpp +++ b/bsnes/gba/cpu/cpu.hpp @@ -27,9 +27,13 @@ struct CPU : Processor::ARM, Thread, MMIO { void dma_run(); void dma_transfer(Registers::DMA &dma); + void dma_vblank(); + void dma_hblank(); + void dma_hdma(); void timer_step(unsigned clocks); void timer_increment(unsigned n); + void timer_fifo_run(unsigned n); void serialize(serializer&); CPU(); diff --git a/bsnes/gba/cpu/dma.cpp b/bsnes/gba/cpu/dma.cpp index 26e08e4a..d288e497 100755 --- a/bsnes/gba/cpu/dma.cpp +++ b/bsnes/gba/cpu/dma.cpp @@ -1,45 +1,28 @@ void CPU::dma_run() { for(unsigned n = 0; n < 4; n++) { auto &dma = regs.dma[n]; - - if(dma.control.enable == false) continue; - - switch(dma.control.timingmode) { - case 0: break; - case 1: if(pending.dma.vblank == false) continue; break; - case 2: if(pending.dma.hblank == false) continue; break; - case 3: - if(n == 0) { - continue; - } - if(n == 1 || n == 2) { - if(apu.fifo[n - 1].size > 16) continue; - dma.control.targetmode = 2; - dma.control.size = 1; - dma.run.length = 4; - } - if(n == 3) { - if(pending.dma.hdma == false) continue; - } + if(dma.pending) { + dma.pending = false; + dma_transfer(dma); + if(dma.control.irq) regs.irq.flag.dma[n] = 1; + if(dma.control.drq && n == 3) regs.irq.flag.cartridge = 1; } - - dma_transfer(dma); - if(dma.control.irq) regs.irq.flag.dma[n] = 1; } - - pending.dma.vblank = false; - pending.dma.hblank = false; - pending.dma.hdma = false; } void CPU::dma_transfer(Registers::DMA &dma) { unsigned size = dma.control.size ? Word : Half; unsigned seek = dma.control.size ? 4 : 2; + sequential() = false; do { + step(bus.speed(dma.run.source, size)); uint32 word = bus.read(dma.run.source, size); + + step(bus.speed(dma.run.target, size)); bus.write(dma.run.target, size, word); - step(2); + + sequential() = true; switch(dma.control.sourcemode) { case 0: dma.run.source += seek; break; @@ -52,8 +35,26 @@ void CPU::dma_transfer(Registers::DMA &dma) { case 3: dma.run.target += seek; break; } } while(--dma.run.length); + sequential() = false; if(dma.control.targetmode == 3) dma.run.target = dma.target; if(dma.control.repeat == 1) dma.run.length = dma.length; if(dma.control.repeat == 0) dma.control.enable = false; } + +void CPU::dma_vblank() { + for(auto &dma : regs.dma) { + if(dma.control.enable && dma.control.timingmode == 1) dma.pending = true; + } +} + +void CPU::dma_hblank() { + for(auto &dma : regs.dma) { + if(dma.control.enable && dma.control.timingmode == 2) dma.pending = true; + } +} + +void CPU::dma_hdma() { + auto &dma = regs.dma[3]; + if(dma.control.enable && dma.control.timingmode == 3) dma.pending = true; +} diff --git a/bsnes/gba/cpu/mmio.cpp b/bsnes/gba/cpu/mmio.cpp index 26888af0..dc226da1 100755 --- a/bsnes/gba/cpu/mmio.cpp +++ b/bsnes/gba/cpu/mmio.cpp @@ -192,9 +192,12 @@ void CPU::write(uint32 addr, uint8 byte) { bool enable = dma.control.enable; dma.control = (dma.control & ~(255 << shift)) | (byte << shift); if(enable == 0 && dma.control.enable) { + if(dma.control.timingmode == 0) dma.pending = true; //immediate transfer mode dma.run.target = dma.target; dma.run.source = dma.source; dma.run.length = dma.length; + } else if(dma.control.enable == 0) { + dma.pending = false; } return; } diff --git a/bsnes/gba/cpu/registers.hpp b/bsnes/gba/cpu/registers.hpp index 838ca1a0..341cadad 100755 --- a/bsnes/gba/cpu/registers.hpp +++ b/bsnes/gba/cpu/registers.hpp @@ -15,16 +15,17 @@ struct Registers { }; struct DMA { - uint32 source; - uint32 target; - uint16 length; + varuint source; + varuint target; + varuint length; DMAControl control; //internal + bool pending; struct Run { - uint32 target; - uint32 source; - uint16 length; + varuint target; + varuint source; + varuint length; } run; } dma[4]; diff --git a/bsnes/gba/cpu/timer.cpp b/bsnes/gba/cpu/timer.cpp index dbb78ed6..7f7004a3 100755 --- a/bsnes/gba/cpu/timer.cpp +++ b/bsnes/gba/cpu/timer.cpp @@ -21,11 +21,24 @@ void CPU::timer_increment(unsigned n) { if(timer.control.irq) regs.irq.flag.timer[n] = 1; - if(apu.fifo[0].timer == n) apu.fifo[0].read(); - if(apu.fifo[1].timer == n) apu.fifo[1].read(); + if(apu.fifo[0].timer == n) timer_fifo_run(0); + if(apu.fifo[1].timer == n) timer_fifo_run(1); if(n < 3 && regs.timer[n + 1].control.enable && regs.timer[n + 1].control.cascade) { timer_increment(n + 1); } } } + +void CPU::timer_fifo_run(unsigned n) { + apu.fifo[n].read(); + if(apu.fifo[n].size > 16) return; + + auto &dma = regs.dma[1 + n]; + if(dma.control.enable && dma.control.timingmode == 3) { + dma.pending = true; + dma.control.targetmode = 2; + dma.control.size = 1; + dma.run.length = 4; + } +} diff --git a/bsnes/gba/ppu/object.cpp b/bsnes/gba/ppu/object.cpp index d7d20df2..a9656518 100755 --- a/bsnes/gba/ppu/object.cpp +++ b/bsnes/gba/ppu/object.cpp @@ -14,14 +14,15 @@ void PPU::render_object(Object &obj) { auto &output = layer[OBJ]; unsigned rowsize = regs.control.objmapping == 0 ? 32 >> obj.colors : obj.width / 8; - unsigned baseaddr = 0x10000 + obj.character * 32; + unsigned baseaddr = obj.character * 32; if(obj.vflip && obj.affine == 0) { py ^= obj.height - 1; } if(obj.mosaic && regs.mosaic.objvsize) { - py = (py / (1 + regs.mosaic.objvsize)) * (1 + regs.mosaic.objvsize); + signed mosaicy = (regs.vcounter / (1 + regs.mosaic.objvsize)) * (1 + regs.mosaic.objvsize); + py = obj.y >= 160 || mosaicy - obj.y >= 0 ? mosaicy - obj.y : 0; } int16 pa = objectparam[obj.affineparam].pa; @@ -57,7 +58,7 @@ void PPU::render_object(Object &obj) { unsigned offset = (y / 8) * rowsize + (x / 8); offset = offset * 64 + (y & 7) * 8 + (x & 7); - uint8 color = vram[baseaddr + (offset >> !obj.colors)]; + uint8 color = object_vram_read(baseaddr + (offset >> !obj.colors)); if(obj.colors == 0) color = (x & 1) ? color >> 4 : color & 15; if(color) { if(obj.mode & 2) { @@ -73,3 +74,10 @@ void PPU::render_object(Object &obj) { fy += pc; } } + +uint8 PPU::object_vram_read(unsigned addr) const { + if(regs.control.bgmode == 3 || regs.control.bgmode == 4 || regs.control.bgmode == 5) { + if(addr <= 0x3fff) return 0u; + } + return vram[0x10000 + (addr & 0x7fff)]; +} diff --git a/bsnes/gba/ppu/ppu.cpp b/bsnes/gba/ppu/ppu.cpp index abfbb178..67a9684d 100755 --- a/bsnes/gba/ppu/ppu.cpp +++ b/bsnes/gba/ppu/ppu.cpp @@ -105,7 +105,7 @@ void PPU::scanline() { if(regs.vcounter == 160) { if(regs.status.irqvblank) cpu.regs.irq.flag.vblank = 1; - cpu.pending.dma.vblank = true; + cpu.dma_vblank(); } if(regs.status.irqvcoincidence) { @@ -138,11 +138,11 @@ void PPU::scanline() { step(960); regs.status.hblank = 1; if(regs.status.irqhblank) cpu.regs.irq.flag.hblank = 1; - if(regs.vcounter < 160) cpu.pending.dma.hblank = true; + if(regs.vcounter < 160) cpu.dma_hblank(); step(240); regs.status.hblank = 0; - if(regs.vcounter < 160) cpu.pending.dma.hdma = true; + if(regs.vcounter < 160) cpu.dma_hdma(); step(32); if(++regs.vcounter == 228) regs.vcounter = 0; diff --git a/bsnes/gba/ppu/ppu.hpp b/bsnes/gba/ppu/ppu.hpp index c1eaec14..c4573de8 100755 --- a/bsnes/gba/ppu/ppu.hpp +++ b/bsnes/gba/ppu/ppu.hpp @@ -33,6 +33,7 @@ struct PPU : Thread, MMIO { void render_objects(); void render_object(Object&); + uint8 object_vram_read(unsigned addr) const; void render_mosaic_background(unsigned id); void render_mosaic_object(); diff --git a/bsnes/gba/ppu/screen.cpp b/bsnes/gba/ppu/screen.cpp index 42d25602..09b2934e 100755 --- a/bsnes/gba/ppu/screen.cpp +++ b/bsnes/gba/ppu/screen.cpp @@ -2,7 +2,7 @@ void PPU::render_forceblank() { uint16 *line = output + regs.vcounter * 240; uint16 *last = blur + regs.vcounter * 240; for(unsigned x = 0; x < 240; x++) { - line[x] = ((last[x] >> 1) & 0x3def) + ((0x7fff >> 1) & 0x3def); + line[x] = (0x7fff + last[x] - ((0x7fff ^ last[x]) & 0x0421)) >> 1; last[x] = 0x7fff; } } @@ -59,7 +59,7 @@ void PPU::render_screen() { } //output pixel; blend with previous pixel to simulate GBA LCD blur - line[x] = ((last[x] >> 1) & 0x3def) + ((color >> 1) & 0x3def); + line[x] = (color + last[x] - ((color ^ last[x]) & 0x0421)) >> 1; last[x] = color; } } diff --git a/bsnes/nall/gameboy/cartridge.hpp b/bsnes/nall/gb/cartridge.hpp similarity index 82% rename from bsnes/nall/gameboy/cartridge.hpp rename to bsnes/nall/gb/cartridge.hpp index 29525028..326c8852 100755 --- a/bsnes/nall/gameboy/cartridge.hpp +++ b/bsnes/nall/gb/cartridge.hpp @@ -1,10 +1,9 @@ -#ifndef NALL_GAMEBOY_CARTRIDGE_HPP -#define NALL_GAMEBOY_CARTRIDGE_HPP +#ifndef NALL_GB_CARTRIDGE_HPP +#define NALL_GB_CARTRIDGE_HPP namespace nall { -class GameBoyCartridge { -public: +struct GameBoyCartridge { string markup; inline GameBoyCartridge(uint8_t *data, unsigned size); @@ -100,26 +99,12 @@ GameBoyCartridge::GameBoyCartridge(uint8_t *romdata, unsigned romsize) { if(info.mapper == "MBC2") info.ramsize = 512; //512 x 4-bit - markup.append( - "\n", - "\n", - " \n"); - if(info.ramsize > 0) markup.append( - " \n"); - markup.append( - "\n"); - -/* - markup.append("cartridge mapper=", info.mapper); - if(info.rtc) markup.append(" rtc"); - if(info.rumble) markup.append(" rumble"); - markup.append("\n"); - - markup.append("\t" "rom size=", hex(romsize), "\n"); //TODO: trust/check info.romsize? - - if(info.ramsize > 0) - markup.append("\t" "ram size=", hex(info.ramsize), info.battery ? " non-volatile\n" : "\n"); -*/ + markup = "\n"; + markup.append("\n"); + markup.append(" \n"); + if(info.ramsize > 0) markup.append(" \n"); + markup.append("\n"); + markup.transform("'", "\""); } } diff --git a/bsnes/nall/gba/cartridge.hpp b/bsnes/nall/gba/cartridge.hpp new file mode 100755 index 00000000..d6ed002f --- /dev/null +++ b/bsnes/nall/gba/cartridge.hpp @@ -0,0 +1,65 @@ +#ifndef NALL_GBA_CARTRIDGE_HPP +#define NALL_GBA_CARTRIDGE_HPP + +#include +#include + +namespace nall { + +struct GameBoyAdvanceCartridge { + string markup; + string identifiers; + inline GameBoyAdvanceCartridge(const uint8_t *data, unsigned size); +}; + +GameBoyAdvanceCartridge::GameBoyAdvanceCartridge(const uint8_t *data, unsigned size) { + struct Identifier { + string name; + unsigned size; + }; + vector idlist; + idlist.append({"SRAM_V", 6}); + idlist.append({"SRAM_F_V", 8}); + idlist.append({"EEPROM_V", 8}); + idlist.append({"FLASH_V", 7}); + idlist.append({"FLASH512_V", 10}); + idlist.append({"FLASH1M_V", 9}); + + lstring list; + for(auto &id : idlist) { + for(signed n = 0; n < size - 16; n++) { + if(!memcmp(data + n, (const char*)id.name, id.size)) { + const char *p = (const char*)data + n + id.size; + if(p[0] >= '0' && p[0] <= '9' + && p[1] >= '0' && p[1] <= '9' + && p[2] >= '0' && p[2] <= '9' + ) { + char text[16]; + memcpy(text, data + n, id.size + 3); + text[id.size + 3] = 0; + list.appendonce(text); + } + } + } + } + identifiers = list.concatenate(","); + + markup = "\n"; + markup.append("\n"); + markup.append(" \n"); + if(0); + else if(identifiers.beginswith("SRAM_V" )) markup.append(" \n"); + else if(identifiers.beginswith("SRAM_F_V" )) markup.append(" \n"); + else if(identifiers.beginswith("EEPROM_V" )) markup.append(" \n"); + else if(identifiers.beginswith("FLASH_V" )) markup.append(" \n"); + else if(identifiers.beginswith("FLASH512_V")) markup.append(" \n"); + else if(identifiers.beginswith("FLASH1M_V" )) markup.append(" \n"); + if(identifiers.empty() == false) markup.append(" \n"); + + markup.append("\n"); + markup.transform("'", "\""); +} + +} + +#endif diff --git a/bsnes/nall/nes/cartridge.hpp b/bsnes/nall/nes/cartridge.hpp new file mode 100755 index 00000000..49e78de1 --- /dev/null +++ b/bsnes/nall/nes/cartridge.hpp @@ -0,0 +1,171 @@ +#ifndef NALL_NES_CARTRIDGE_HPP +#define NALL_NES_CARTRIDGE_HPP + +#include + +namespace nall { + +struct FamicomCartridge { + string markup; + inline FamicomCartridge(const uint8_t *data, unsigned size); +}; + +FamicomCartridge::FamicomCartridge(const uint8_t *data, unsigned size) { + markup = "\n"; + if(size < 16) return; + if(data[0] != 'N') return; + if(data[1] != 'E') return; + if(data[2] != 'S') return; + if(data[3] != 26) return; + + unsigned mapper = ((data[7] >> 4) << 4) | (data[6] >> 4); + unsigned mirror = ((data[6] & 0x08) >> 2) | (data[6] & 0x01); + unsigned prgrom = data[4] * 0x4000; + unsigned chrrom = data[5] * 0x2000; + unsigned prgram = 0u; + unsigned chrram = chrrom == 0u ? 8192u : 0u; + + markup.append("\n"); + + switch(mapper) { + default: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 1: + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + + case 2: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 3: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 4: + //MMC3 + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + //MMC6 + //markup.append(" \n"); + //markup.append(" \n"); + //prgram = 1024; + break; + + case 5: + markup.append(" \n"); + markup.append(" \n"); + prgram = 65536; + break; + + case 7: + markup.append(" \n"); + break; + + case 9: + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + + case 10: + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + + case 16: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 21: + case 23: + case 25: + //VRC4 + markup.append(" \n"); + markup.append(" \n"); + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + + case 22: + //VRC2 + markup.append(" \n"); + markup.append(" \n"); + markup.append(" \n"); + markup.append(" \n"); + break; + + case 24: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 26: + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + + case 34: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 66: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 69: + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + + case 73: + markup.append(" \n"); + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + + case 75: + markup.append(" \n"); + markup.append(" \n"); + break; + + case 85: + markup.append(" \n"); + markup.append(" \n"); + prgram = 8192; + break; + } + + markup.append(" \n"); + if(prgrom) markup.append(" \n"); + if(prgram) markup.append(" \n"); + markup.append(" \n"); + + markup.append(" \n"); + if(chrrom) markup.append(" \n"); + if(chrram) markup.append(" \n"); + markup.append(" \n"); + + markup.append("\n"); + markup.transform("'", "\""); +} + +} + +#endif diff --git a/bsnes/nall/snes/cartridge.hpp b/bsnes/nall/snes/cartridge.hpp index 5596f69b..1c64c659 100755 --- a/bsnes/nall/snes/cartridge.hpp +++ b/bsnes/nall/snes/cartridge.hpp @@ -3,10 +3,9 @@ namespace nall { -class SnesCartridge { -public: +struct SuperFamicomCartridge { string markup; - inline SnesCartridge(const uint8_t *data, unsigned size); + inline SuperFamicomCartridge(const uint8_t *data, unsigned size); //private: inline void read_header(const uint8_t *data, unsigned size); @@ -105,7 +104,7 @@ public: bool has_st018; }; -SnesCartridge::SnesCartridge(const uint8_t *data, unsigned size) { +SuperFamicomCartridge::SuperFamicomCartridge(const uint8_t *data, unsigned size) { read_header(data, size); string xml; @@ -538,7 +537,7 @@ SnesCartridge::SnesCartridge(const uint8_t *data, unsigned size) { markup.append("\n"); } -void SnesCartridge::read_header(const uint8_t *data, unsigned size) { +void SuperFamicomCartridge::read_header(const uint8_t *data, unsigned size) { type = TypeUnknown; mapper = LoROM; dsp1_mapper = DSP1Unmapped; @@ -766,7 +765,7 @@ void SnesCartridge::read_header(const uint8_t *data, unsigned size) { } } -unsigned SnesCartridge::find_header(const uint8_t *data, unsigned size) { +unsigned SuperFamicomCartridge::find_header(const uint8_t *data, unsigned size) { unsigned score_lo = score_header(data, size, 0x007fc0); unsigned score_hi = score_header(data, size, 0x00ffc0); unsigned score_ex = score_header(data, size, 0x40ffc0); @@ -781,7 +780,7 @@ unsigned SnesCartridge::find_header(const uint8_t *data, unsigned size) { } } -unsigned SnesCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) { +unsigned SuperFamicomCartridge::score_header(const uint8_t *data, unsigned size, unsigned addr) { if(size < addr + 64) return 0; //image too small to contain header at this location? int score = 0; @@ -862,7 +861,7 @@ unsigned SnesCartridge::score_header(const uint8_t *data, unsigned size, unsigne return score; } -unsigned SnesCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) { +unsigned SuperFamicomCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) { if(size < 512) return 0; switch(data[0x0149]) { case 0x00: return 0 * 1024; @@ -875,7 +874,7 @@ unsigned SnesCartridge::gameboy_ram_size(const uint8_t *data, unsigned size) { } } -bool SnesCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) { +bool SuperFamicomCartridge::gameboy_has_rtc(const uint8_t *data, unsigned size) { if(size < 512) return false; if(data[0x0147] == 0x0f ||data[0x0147] == 0x10) return true; return false; diff --git a/bsnes/nall/string/base.hpp b/bsnes/nall/string/base.hpp index 2e0d4296..6bbc7ee4 100755 --- a/bsnes/nall/string/base.hpp +++ b/bsnes/nall/string/base.hpp @@ -111,6 +111,8 @@ namespace nall { struct lstring : vector { inline optional find(const char*) const; + inline string concatenate(const char*) const; + template inline lstring& split(const char*, const char*); template inline lstring& isplit(const char*, const char*); template inline lstring& qsplit(const char*, const char*); diff --git a/bsnes/nall/string/core.hpp b/bsnes/nall/string/core.hpp index e5281b82..c6245723 100755 --- a/bsnes/nall/string/core.hpp +++ b/bsnes/nall/string/core.hpp @@ -138,6 +138,14 @@ optional lstring::find(const char *key) const { return { false, 0 }; } +string lstring::concatenate(const char *separator) const { + string output; + for(unsigned i = 0; i < size(); i++) { + output.append(operator[](i), i < size() - 1 ? separator : ""); + } + return output; +} + bool lstring::operator==(const lstring &source) const { if(this == &source) return true; if(size() != source.size()) return false; diff --git a/bsnes/nall/varint.hpp b/bsnes/nall/varint.hpp index 439d3c6b..6bfd1c15 100755 --- a/bsnes/nall/varint.hpp +++ b/bsnes/nall/varint.hpp @@ -5,7 +5,7 @@ #include namespace nall { - template class uint_t { + template struct uint_t { private: typedef typename type_if::type type_t; type_t data; @@ -35,7 +35,7 @@ namespace nall { template inline uint_t(const uint_t &i) : data(uclip(i)) {} }; - template class int_t { + template struct int_t { private: typedef typename type_if::type type_t; type_t data; @@ -65,73 +65,46 @@ namespace nall { template inline int_t(const int_t &i) : data(sclip(i)) {} }; - class varuint_t { + template struct varuint_t { private: - unsigned data; - unsigned mask; + type_t data; + type_t mask; public: - inline operator unsigned() const { return data; } - inline unsigned operator ++(int) { unsigned r = data; data = (data + 1) & mask; return r; } - inline unsigned operator --(int) { unsigned r = data; data = (data - 1) & mask; return r; } - inline unsigned operator ++() { return data = (data + 1) & mask; } - inline unsigned operator --() { return data = (data - 1) & mask; } - inline unsigned operator =(const unsigned i) { return data = (i) & mask; } - inline unsigned operator |=(const unsigned i) { return data = (data | i) & mask; } - inline unsigned operator ^=(const unsigned i) { return data = (data ^ i) & mask; } - inline unsigned operator &=(const unsigned i) { return data = (data & i) & mask; } - inline unsigned operator<<=(const unsigned i) { return data = (data << i) & mask; } - inline unsigned operator>>=(const unsigned i) { return data = (data >> i) & mask; } - inline unsigned operator +=(const unsigned i) { return data = (data + i) & mask; } - inline unsigned operator -=(const unsigned i) { return data = (data - i) & mask; } - inline unsigned operator *=(const unsigned i) { return data = (data * i) & mask; } - inline unsigned operator /=(const unsigned i) { return data = (data / i) & mask; } - inline unsigned operator %=(const unsigned i) { return data = (data % i) & mask; } + inline operator type_t() const { return data; } + inline type_t operator ++(int) { type_t r = data; data = (data + 1) & mask; return r; } + inline type_t operator --(int) { type_t r = data; data = (data - 1) & mask; return r; } + inline type_t operator ++() { return data = (data + 1) & mask; } + inline type_t operator --() { return data = (data - 1) & mask; } + inline type_t operator =(const type_t i) { return data = (i) & mask; } + inline type_t operator |=(const type_t i) { return data = (data | i) & mask; } + inline type_t operator ^=(const type_t i) { return data = (data ^ i) & mask; } + inline type_t operator &=(const type_t i) { return data = (data & i) & mask; } + inline type_t operator<<=(const type_t i) { return data = (data << i) & mask; } + inline type_t operator>>=(const type_t i) { return data = (data >> i) & mask; } + inline type_t operator +=(const type_t i) { return data = (data + i) & mask; } + inline type_t operator -=(const type_t i) { return data = (data - i) & mask; } + inline type_t operator *=(const type_t i) { return data = (data * i) & mask; } + inline type_t operator /=(const type_t i) { return data = (data / i) & mask; } + inline type_t operator %=(const type_t i) { return data = (data % i) & mask; } - inline void bits(unsigned bits) { mask = (1U << (bits - 1)) + ((1U << (bits - 1)) - 1); data &= mask; } - inline varuint_t() : data(0), mask(~0U) {} - inline varuint_t(const unsigned i) : data(i), mask(~0U) {} - }; - - class varuintmax_t { - private: - uintmax_t data; - uintmax_t mask; - - public: - inline operator uintmax_t() const { return data; } - inline uintmax_t operator ++(int) { uintmax_t r = data; data = (data + 1) & mask; return r; } - inline uintmax_t operator --(int) { uintmax_t r = data; data = (data - 1) & mask; return r; } - inline uintmax_t operator ++() { return data = (data + 1) & mask; } - inline uintmax_t operator --() { return data = (data - 1) & mask; } - inline uintmax_t operator =(const uintmax_t i) { return data = (i) & mask; } - inline uintmax_t operator |=(const uintmax_t i) { return data = (data | i) & mask; } - inline uintmax_t operator ^=(const uintmax_t i) { return data = (data ^ i) & mask; } - inline uintmax_t operator &=(const uintmax_t i) { return data = (data & i) & mask; } - inline uintmax_t operator<<=(const uintmax_t i) { return data = (data << i) & mask; } - inline uintmax_t operator>>=(const uintmax_t i) { return data = (data >> i) & mask; } - inline uintmax_t operator +=(const uintmax_t i) { return data = (data + i) & mask; } - inline uintmax_t operator -=(const uintmax_t i) { return data = (data - i) & mask; } - inline uintmax_t operator *=(const uintmax_t i) { return data = (data * i) & mask; } - inline uintmax_t operator /=(const uintmax_t i) { return data = (data / i) & mask; } - inline uintmax_t operator %=(const uintmax_t i) { return data = (data % i) & mask; } - - inline void bits(unsigned bits) { mask = (1ULL << (bits - 1)) + ((1ULL << (bits - 1)) - 1); data &= mask; } - inline varuintmax_t() : data(0), mask(~0ULL) {} - inline varuintmax_t(const uintmax_t i) : data(i), mask(~0ULL) {} + inline void bits(type_t bits) { mask = (1ull << (bits - 1)) + ((1ull << (bits - 1)) - 1); data &= mask; } + inline varuint_t() : data(0ull), mask((type_t)~0ull) {} + inline varuint_t(const type_t i) : data(i), mask((type_t)~0ull) {} }; } //typedefs - typedef nall::uint_t< 1> uint1_t; - typedef nall::uint_t< 2> uint2_t; - typedef nall::uint_t< 3> uint3_t; - typedef nall::uint_t< 4> uint4_t; - typedef nall::uint_t< 5> uint5_t; - typedef nall::uint_t< 6> uint6_t; - typedef nall::uint_t< 7> uint7_t; -//typedef nall::uint_t< 8> uint8_t; - typedef nall::uint_t< 9> uint9_t; + typedef nall::uint_t< 1> uint1_t; + typedef nall::uint_t< 2> uint2_t; + typedef nall::uint_t< 3> uint3_t; + typedef nall::uint_t< 4> uint4_t; + typedef nall::uint_t< 5> uint5_t; + typedef nall::uint_t< 6> uint6_t; + typedef nall::uint_t< 7> uint7_t; +//typedef nall::uint_t< 8> uint8_t; + + typedef nall::uint_t< 9> uint9_t; typedef nall::uint_t<10> uint10_t; typedef nall::uint_t<11> uint11_t; typedef nall::uint_t<12> uint12_t; @@ -139,6 +112,7 @@ namespace nall { typedef nall::uint_t<14> uint14_t; typedef nall::uint_t<15> uint15_t; //typedef nall::uint_t<16> uint16_t; + typedef nall::uint_t<17> uint17_t; typedef nall::uint_t<18> uint18_t; typedef nall::uint_t<19> uint19_t; @@ -156,15 +130,16 @@ namespace nall { typedef nall::uint_t<31> uint31_t; //typedef nall::uint_t<32> uint32_t; - typedef nall::int_t< 1> int1_t; - typedef nall::int_t< 2> int2_t; - typedef nall::int_t< 3> int3_t; - typedef nall::int_t< 4> int4_t; - typedef nall::int_t< 5> int5_t; - typedef nall::int_t< 6> int6_t; - typedef nall::int_t< 7> int7_t; -//typedef nall::int_t< 8> int8_t; - typedef nall::int_t< 9> int9_t; + typedef nall::int_t< 1> int1_t; + typedef nall::int_t< 2> int2_t; + typedef nall::int_t< 3> int3_t; + typedef nall::int_t< 4> int4_t; + typedef nall::int_t< 5> int5_t; + typedef nall::int_t< 6> int6_t; + typedef nall::int_t< 7> int7_t; +//typedef nall::int_t< 8> int8_t; + + typedef nall::int_t< 9> int9_t; typedef nall::int_t<10> int10_t; typedef nall::int_t<11> int11_t; typedef nall::int_t<12> int12_t; @@ -172,6 +147,7 @@ namespace nall { typedef nall::int_t<14> int14_t; typedef nall::int_t<15> int15_t; //typedef nall::int_t<16> int16_t; + typedef nall::int_t<17> int17_t; typedef nall::int_t<18> int18_t; typedef nall::int_t<19> int19_t; diff --git a/bsnes/nall/vector.hpp b/bsnes/nall/vector.hpp index efa522a8..ddf84ca5 100755 --- a/bsnes/nall/vector.hpp +++ b/bsnes/nall/vector.hpp @@ -56,6 +56,12 @@ namespace nall { new(pool + objectsize++) T(data); } + bool appendonce(const T& data) { + if(find(data) == true) return false; + append(data); + return true; + } + void insert(unsigned position, const T& data) { append(data); for(signed n = size() - 1; n > position; n--) pool[n] = pool[n - 1]; diff --git a/bsnes/nes/cartridge/cartridge.cpp b/bsnes/nes/cartridge/cartridge.cpp index e12c1c13..1c52d367 100755 --- a/bsnes/nes/cartridge/cartridge.cpp +++ b/bsnes/nes/cartridge/cartridge.cpp @@ -2,7 +2,6 @@ namespace NES { -#include "ines.cpp" #include "chip/chip.cpp" #include "board/board.cpp" Cartridge cartridge; @@ -16,12 +15,14 @@ void Cartridge::main() { } void Cartridge::load(const string &markup, const uint8_t *data, unsigned size) { + information.markup = markup; + if((size & 0xff) == 0) { sha256 = nall::sha256(data, size); board = Board::load(markup, data, size); } else { sha256 = nall::sha256(data + 16, size - 16); - board = Board::load(!markup.empty() ? markup : iNES(data, size), data + 16, size - 16); + board = Board::load(markup, data + 16, size - 16); } if(board == nullptr) return; diff --git a/bsnes/nes/cartridge/cartridge.hpp b/bsnes/nes/cartridge/cartridge.hpp index a7da75bc..fb3014a5 100755 --- a/bsnes/nes/cartridge/cartridge.hpp +++ b/bsnes/nes/cartridge/cartridge.hpp @@ -17,6 +17,10 @@ struct Cartridge : Thread, property { readonly loaded; readonly sha256; + struct Information { + string markup; + } information; + void serialize(serializer&); Cartridge(); diff --git a/bsnes/nes/cartridge/ines.cpp b/bsnes/nes/cartridge/ines.cpp deleted file mode 100755 index 6699c813..00000000 --- a/bsnes/nes/cartridge/ines.cpp +++ /dev/null @@ -1,162 +0,0 @@ -static string iNES(const uint8_t *data, unsigned size) { - if(size < 16) return ""; - if(data[0] != 'N') return ""; - if(data[1] != 'E') return ""; - if(data[2] != 'S') return ""; - if(data[3] != 0x1a) return ""; - - string output; - - unsigned mapper = ((data[7] >> 4) << 4) | (data[6] >> 4); - unsigned mirror = ((data[6] & 0x08) >> 2) | (data[6] & 0x01); - unsigned prgrom = data[4] * 0x4000; - unsigned chrrom = data[5] * 0x2000; - unsigned prgram = 0; - unsigned chrram = chrrom == 0 ? 8192 : 0; - -//print("iNES mapper: ", mapper, "\n"); - - output.append("\n"); - output.append("\n"); - - switch(mapper) { - default: - output.append(" \n"); - output.append(" \n"); - break; - - case 1: - output.append(" \n"); - output.append(" \n"); - prgram = 8192; - break; - - case 2: - output.append(" \n"); - output.append(" \n"); - break; - - case 3: - output.append(" \n"); - output.append(" \n"); - break; - - case 4: - //MMC3 - output.append(" \n"); - output.append(" \n"); - prgram = 8192; - //MMC6 - //output.append(" \n"); - //output.append(" \n"); - //prgram = 1024; - break; - - case 5: - output.append(" \n"); - output.append(" \n"); - prgram = 65536; - break; - - case 7: - output.append(" \n"); - break; - - case 9: - output.append(" \n"); - output.append(" \n"); - prgram = 8192; - break; - - case 10: - output.append(" \n"); - output.append(" \n"); - prgram = 8192; - break; - - case 16: - output.append(" \n"); - output.append(" \n"); - break; - - case 21: - case 23: - case 25: - //VRC4 - output.append(" \n"); - output.append(" \n"); - output.append(" \n"); - output.append(" \n"); - prgram = 8192; - break; - - case 22: - //VRC2 - output.append(" \n"); - output.append(" \n"); - output.append(" \n"); - output.append(" \n"); - break; - - case 24: - output.append(" \n"); - output.append(" \n"); - break; - - case 26: - output.append(" \n"); - output.append(" \n"); - prgram = 8192; - break; - - case 34: - output.append(" \n"); - output.append(" \n"); - break; - - case 66: - output.append(" \n"); - output.append(" \n"); - break; - - case 69: - output.append(" \n"); - output.append(" \n"); - prgram = 8192; - break; - - case 73: - output.append(" \n"); - output.append(" \n"); - output.append(" \n"); - prgram = 8192; - break; - - case 75: - output.append(" \n"); - output.append(" \n"); - break; - - case 85: - output.append(" \n"); - output.append(" \n"); - prgram = 8192; - break; - } - - output.append( - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - " \n" - "\n" - ); - -//print(output, "\n"); - - return output; -} diff --git a/bsnes/snes/cartridge/cartridge.cpp b/bsnes/snes/cartridge/cartridge.cpp index 73456fe5..87182ee2 100755 --- a/bsnes/snes/cartridge/cartridge.cpp +++ b/bsnes/snes/cartridge/cartridge.cpp @@ -11,8 +11,10 @@ namespace SNES { Cartridge cartridge; -void Cartridge::load(Mode cartridge_mode, const char *markup) { +void Cartridge::load(Mode cartridge_mode, const string &markup) { mode = cartridge_mode; + information.markup = markup; + region = Region::NTSC; ram_size = 0; diff --git a/bsnes/snes/cartridge/cartridge.hpp b/bsnes/snes/cartridge/cartridge.hpp index a108d8ba..6fa795bc 100755 --- a/bsnes/snes/cartridge/cartridge.hpp +++ b/bsnes/snes/cartridge/cartridge.hpp @@ -52,7 +52,7 @@ struct Cartridge : property { uint8_t *data; unsigned size; Slot slot; - NonVolatileRAM() : id(""), data(0), size(0), slot(Slot::Base) {} + NonVolatileRAM() : id(""), data(nullptr), size(0), slot(Slot::Base) {} NonVolatileRAM(const string id, uint8_t *data, unsigned size, Slot slot = Slot::Base) : id(id), data(data), size(size), slot(slot) {} }; @@ -76,13 +76,14 @@ struct Cartridge : property { linear_vector mapping; struct Information { + string markup; struct NSS { lstring setting; lstring option[16]; } nss; } information; - void load(Mode, const char*); + void load(Mode, const string&); void unload(); void serialize(serializer&); diff --git a/bsnes/target-ui/base.hpp b/bsnes/target-ui/base.hpp index 1cb41bfd..8e7ccdd2 100755 --- a/bsnes/target-ui/base.hpp +++ b/bsnes/target-ui/base.hpp @@ -11,8 +11,10 @@ #include #include #include +#include #include -#include +#include +#include using namespace nall; #include @@ -45,6 +47,7 @@ struct Application { string normalFont; string boldFont; string titleFont; + string monospaceFont; void run(); Application(int argc, char **argv); diff --git a/bsnes/target-ui/general/general.cpp b/bsnes/target-ui/general/general.cpp index d4ebdf8c..1a39b2c1 100755 --- a/bsnes/target-ui/general/general.cpp +++ b/bsnes/target-ui/general/general.cpp @@ -2,3 +2,4 @@ #include "main-window.cpp" #include "file-browser.cpp" #include "dip-switches.cpp" +#include "information-window.cpp" diff --git a/bsnes/target-ui/general/general.hpp b/bsnes/target-ui/general/general.hpp index 54e5dba7..5f51a006 100755 --- a/bsnes/target-ui/general/general.hpp +++ b/bsnes/target-ui/general/general.hpp @@ -1,3 +1,4 @@ #include "main-window.hpp" #include "file-browser.hpp" #include "dip-switches.hpp" +#include "information-window.hpp" diff --git a/bsnes/target-ui/general/information-window.cpp b/bsnes/target-ui/general/information-window.cpp new file mode 100755 index 00000000..8f15ec06 --- /dev/null +++ b/bsnes/target-ui/general/information-window.cpp @@ -0,0 +1,43 @@ +InformationWindow *informationWindow = nullptr; + +InformationWindow::InformationWindow() { + setTitle("Information"); + + layout.setMargin(5); + markup.setFont(application->monospaceFont); + markupXML.setChecked(); + markupXML.setText("Show original XML markup"); + + append(layout); + layout.append(markup, {~0, ~0}, 5); + layout.append(markupXML, {~0, 0}); + + setGeometry({128, 128, 600, 360}); + windowManager->append(this, "InformationWindow"); + + markupXML.onToggle = { &InformationWindow::update, this }; +} + +void InformationWindow::update() { + string markupData = interface->markup(); + if(markupXML.checked()) { + markup.setText(markupData); + return; + } + + XML::Document document(markupData); + markupData = ""; + parse(document, markupData, 0); + markup.setText(markupData); +} + +void InformationWindow::parse(XML::Node &header, string &output, unsigned depth) { + for(auto &node : header) { + if(node.name.beginswith("?")) continue; + for(unsigned n = 0; n < depth; n++) output.append(" "); + output.append(node.name); + if(node.children.size() == 0 && !node.data.empty()) output.append(": ", node.data); + output.append("\n"); + parse(node, output, depth + 1); + } +} diff --git a/bsnes/target-ui/general/information-window.hpp b/bsnes/target-ui/general/information-window.hpp new file mode 100755 index 00000000..96b77e67 --- /dev/null +++ b/bsnes/target-ui/general/information-window.hpp @@ -0,0 +1,11 @@ +struct InformationWindow : Window { + VerticalLayout layout; + TextEdit markup; + CheckBox markupXML; + + void update(); + void parse(XML::Node &node, string &output, unsigned depth); + InformationWindow(); +}; + +extern InformationWindow *informationWindow; diff --git a/bsnes/target-ui/general/main-window.cpp b/bsnes/target-ui/general/main-window.cpp index ba0afd1d..a2b76b9e 100755 --- a/bsnes/target-ui/general/main-window.cpp +++ b/bsnes/target-ui/general/main-window.cpp @@ -16,7 +16,7 @@ MainWindow::MainWindow() { cartridgeLoadSatellaview.setText("BS-X Satellaview ..."); cartridgeLoadSufamiTurbo.setText("Sufami Turbo ..."); - nesMenu.setText("&NES"); + nesMenu.setText("&Famicom"); nesPower.setText("&Power Cycle"); nesReset.setText("&Reset"); nesPort1.setText("Controller Port &1"); @@ -31,7 +31,7 @@ MainWindow::MainWindow() { nesPort2Device[config->nes.controllerPort2Device].setChecked(); nesCartridgeUnload.setText("&Unload Cartridge"); - snesMenu.setText("&SNES"); + snesMenu.setText("&Super Famicom"); snesPower.setText("&Power Cycle"); snesReset.setText("&Reset"); snesPort1.setText("Controller Port &1"); @@ -98,6 +98,7 @@ MainWindow::MainWindow() { toolsStateLoad3.setText("Slot &3"); toolsStateLoad4.setText("Slot &4"); toolsStateLoad5.setText("Slot &5"); + toolsInformationWindow.setText("&Information ..."); toolsShrinkWindow.setText("Shrink &Window"); toolsCheatEditor.setText("&Cheat Editor ..."); toolsStateManager.setText("State &Manager ..."); @@ -185,6 +186,7 @@ MainWindow::MainWindow() { toolsStateLoad.append(toolsStateLoad4); toolsStateLoad.append(toolsStateLoad5); toolsMenu.append(toolsSeparator); + toolsMenu.append(toolsInformationWindow); toolsMenu.append(toolsShrinkWindow); toolsMenu.append(toolsCheatEditor); toolsMenu.append(toolsStateManager); @@ -364,6 +366,7 @@ MainWindow::MainWindow() { toolsStateLoad4.onActivate = [&] { interface->loadState(4); }; toolsStateLoad5.onActivate = [&] { interface->loadState(5); }; + toolsInformationWindow.onActivate = [&] { informationWindow->setVisible(); }; toolsShrinkWindow.onActivate = [&] { utility->resizeMainWindow(true); }; toolsCheatEditor.onActivate = [&] { cheatEditor->setVisible(); }; toolsStateManager.onActivate = [&] { stateManager->setVisible(); }; diff --git a/bsnes/target-ui/general/main-window.hpp b/bsnes/target-ui/general/main-window.hpp index 6de8927f..bed390a5 100755 --- a/bsnes/target-ui/general/main-window.hpp +++ b/bsnes/target-ui/general/main-window.hpp @@ -79,6 +79,7 @@ struct MainWindow : Window { Item toolsStateLoad4; Item toolsStateLoad5; Separator toolsSeparator; + Item toolsInformationWindow; Item toolsShrinkWindow; Item toolsCheatEditor; Item toolsStateManager; diff --git a/bsnes/target-ui/interface/gb/gb.cpp b/bsnes/target-ui/interface/gb/gb.cpp index 26a0d07b..ede6146d 100755 --- a/bsnes/target-ui/interface/gb/gb.cpp +++ b/bsnes/target-ui/interface/gb/gb.cpp @@ -7,6 +7,10 @@ void InterfaceGB::initialize() { GB::system.init(); } +string InterfaceGB::markup() { + return GB::cartridge.information.markup; +} + bool InterfaceGB::cartridgeLoaded() { return GB::cartridge.loaded(); } @@ -31,9 +35,7 @@ bool InterfaceGB::loadCartridge(GB::System::Revision revision, const string &fil string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); - - GameBoyCartridge info(data, size); - if(markup.empty()) markup = info.markup; + if(markup.empty()) markup = GameBoyCartridge(data, size).markup; GB::cartridge.load(revision, markup, data, size); GB::system.power(); diff --git a/bsnes/target-ui/interface/gb/gb.hpp b/bsnes/target-ui/interface/gb/gb.hpp index 6dca8a58..1f2727d1 100755 --- a/bsnes/target-ui/interface/gb/gb.hpp +++ b/bsnes/target-ui/interface/gb/gb.hpp @@ -1,6 +1,8 @@ struct InterfaceGB : InterfaceCore, GB::Interface { void initialize(); + string markup(); + bool cartridgeLoaded(); bool loadCartridge(GB::System::Revision revision, const string &filename); void unloadCartridge(); diff --git a/bsnes/target-ui/interface/gba/gba.cpp b/bsnes/target-ui/interface/gba/gba.cpp index 533184a6..94682686 100755 --- a/bsnes/target-ui/interface/gba/gba.cpp +++ b/bsnes/target-ui/interface/gba/gba.cpp @@ -5,6 +5,10 @@ void InterfaceGBA::initialize() { GBA::system.init(); } +string InterfaceGBA::markup() { + return GBA::cartridge.information.markup; +} + bool InterfaceGBA::cartridgeLoaded() { return GBA::cartridge.loaded(); } @@ -29,6 +33,7 @@ bool InterfaceGBA::loadCartridge(const string &filename) { string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); + if(markup.empty()) markup = GameBoyAdvanceCartridge(data, size).markup; GBA::cartridge.load(markup, data, size); GBA::system.power(); diff --git a/bsnes/target-ui/interface/gba/gba.hpp b/bsnes/target-ui/interface/gba/gba.hpp index dd313f2f..2f00f57b 100755 --- a/bsnes/target-ui/interface/gba/gba.hpp +++ b/bsnes/target-ui/interface/gba/gba.hpp @@ -1,6 +1,8 @@ struct InterfaceGBA : InterfaceCore, GBA::Interface { void initialize(); + string markup(); + bool cartridgeLoaded(); bool loadCartridge(const string &filename); void unloadCartridge(); diff --git a/bsnes/target-ui/interface/interface.cpp b/bsnes/target-ui/interface/interface.cpp index f0e99fd8..02db1917 100755 --- a/bsnes/target-ui/interface/interface.cpp +++ b/bsnes/target-ui/interface/interface.cpp @@ -38,7 +38,7 @@ string CartridgePath::title() const { title = notdir(nall::basename(title)); return title; } - return notdir(nall::basename(name)); + return notdir(name); } void Interface::bindControllers() { @@ -80,13 +80,17 @@ void Interface::updateDSP() { } } +string Interface::markup() { + if(core) return core->markup(); + return ""; +} + bool Interface::cartridgeLoaded() { if(core) return core->cartridgeLoaded(); return false; } void Interface::loadCartridge(Mode mode) { - utility->setMode(this->mode = mode); switch(mode) { case Mode::NES: core = &nes; break; case Mode::SNES: core = &snes; break; @@ -94,6 +98,7 @@ void Interface::loadCartridge(Mode mode) { case Mode::GBA: core = &gba; break; default: core = nullptr; break; } + utility->setMode(this->mode = mode); bindControllers(); cheatEditor->load(game.filename("cheats.xml", ".cht")); @@ -122,6 +127,7 @@ void Interface::unloadCartridge() { setCheatCodes(); if(core) core->unloadCartridge(); + core = nullptr; cartridgeTitle = ""; utility->setMode(mode = Mode::None); } diff --git a/bsnes/target-ui/interface/interface.hpp b/bsnes/target-ui/interface/interface.hpp index 9bf500ae..1e0153c2 100755 --- a/bsnes/target-ui/interface/interface.hpp +++ b/bsnes/target-ui/interface/interface.hpp @@ -3,6 +3,7 @@ struct InterfaceCore { bool loadFirmware(string filename, string keyname, uint8_t *targetdata, unsigned targetsize); + virtual string markup() = 0; virtual bool cartridgeLoaded() = 0; virtual void unloadCartridge() = 0; @@ -51,6 +52,8 @@ struct Interface : property { void setController(unsigned port, unsigned device); void updateDSP(); + string markup(); + bool cartridgeLoaded(); void loadCartridge(Mode mode); bool loadCartridge(string filename); //auto-detect system-type based on file extension diff --git a/bsnes/target-ui/interface/nes/nes.cpp b/bsnes/target-ui/interface/nes/nes.cpp index f8bb6ddc..bc4b040e 100755 --- a/bsnes/target-ui/interface/nes/nes.cpp +++ b/bsnes/target-ui/interface/nes/nes.cpp @@ -3,6 +3,10 @@ void InterfaceNES::initialize() { NES::system.init(); } +string InterfaceNES::markup() { + return NES::cartridge.information.markup; +} + void InterfaceNES::setController(bool port, unsigned device) { if(port == 0) config->nes.controllerPort1Device = device; if(port == 1) config->nes.controllerPort2Device = device; @@ -42,6 +46,7 @@ bool InterfaceNES::loadCartridge(const string &filename) { string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); + if(markup.empty()) markup = FamicomCartridge(data, size).markup; NES::cartridge.load(markup, data, size); NES::system.power(); diff --git a/bsnes/target-ui/interface/nes/nes.hpp b/bsnes/target-ui/interface/nes/nes.hpp index 1584bfbc..f502de49 100755 --- a/bsnes/target-ui/interface/nes/nes.hpp +++ b/bsnes/target-ui/interface/nes/nes.hpp @@ -1,5 +1,8 @@ struct InterfaceNES : InterfaceCore, NES::Interface { void initialize(); + + string markup(); + void setController(bool port, unsigned device); bool cartridgeLoaded(); diff --git a/bsnes/target-ui/interface/snes/snes.cpp b/bsnes/target-ui/interface/snes/snes.cpp index 5656974a..ebff8243 100755 --- a/bsnes/target-ui/interface/snes/snes.cpp +++ b/bsnes/target-ui/interface/snes/snes.cpp @@ -5,6 +5,10 @@ void InterfaceSNES::initialize() { SNES::system.init(); } +string InterfaceSNES::markup() { + return SNES::cartridge.information.markup; +} + void InterfaceSNES::setController(bool port, unsigned device) { if(port == 0) config->snes.controllerPort1Device = device; if(port == 1) config->snes.controllerPort2Device = device; @@ -63,7 +67,7 @@ bool InterfaceSNES::loadCartridge(string basename) { string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); - if(markup.empty()) markup = SnesCartridge(data, size).markup; + if(markup.empty()) markup = SuperFamicomCartridge(data, size).markup; SNES::cartridge.rom.copy(data, size); SNES::cartridge.load(SNES::Cartridge::Mode::Normal, markup); @@ -91,7 +95,7 @@ bool InterfaceSNES::loadSatellaviewSlottedCartridge(string basename, string slot string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); - if(markup.empty()) markup = SnesCartridge(data[0], size[0]).markup; + if(markup.empty()) markup = SuperFamicomCartridge(data[0], size[0]).markup; SNES::cartridge.rom.copy(data[0], size[0]); if(data[1]) SNES::bsxflash.memory.copy(data[1], size[1]); @@ -121,7 +125,7 @@ bool InterfaceSNES::loadSatellaviewCartridge(string basename, string slotname) { string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); - if(markup.empty()) markup = SnesCartridge(data[0], size[0]).markup; + if(markup.empty()) markup = SuperFamicomCartridge(data[0], size[0]).markup; SNES::cartridge.rom.copy(data[0], size[0]); if(data[1]) SNES::bsxflash.memory.copy(data[1], size[1]); @@ -156,7 +160,7 @@ bool InterfaceSNES::loadSufamiTurboCartridge(string basename, string slotAname, string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); - if(markup.empty()) markup = SnesCartridge(data[0], size[0]).markup; + if(markup.empty()) markup = SuperFamicomCartridge(data[0], size[0]).markup; SNES::cartridge.rom.copy(data[0], size[0]); if(data[1]) SNES::sufamiturbo.slotA.rom.copy(data[1], size[1]); @@ -188,7 +192,7 @@ bool InterfaceSNES::loadSuperGameBoyCartridge(string basename, string slotname) string markup; markup.readfile(interface->base.filename("manifest.xml", ".xml")); - if(markup.empty()) markup = SnesCartridge(data[0], size[0]).markup; + if(markup.empty()) markup = SuperFamicomCartridge(data[0], size[0]).markup; string gbMarkup; gbMarkup.readfile(interface->slot[0].filename("manifest.xml", ".xml")); diff --git a/bsnes/target-ui/interface/snes/snes.hpp b/bsnes/target-ui/interface/snes/snes.hpp index f6fc7cc2..047350a1 100755 --- a/bsnes/target-ui/interface/snes/snes.hpp +++ b/bsnes/target-ui/interface/snes/snes.hpp @@ -1,6 +1,8 @@ struct InterfaceSNES : InterfaceCore, SNES::Interface { void initialize(); + string markup(); + void setController(bool port, unsigned device); bool cartridgeLoaded(); diff --git a/bsnes/target-ui/main.cpp b/bsnes/target-ui/main.cpp index ecc7e7e7..65c74c31 100755 --- a/bsnes/target-ui/main.cpp +++ b/bsnes/target-ui/main.cpp @@ -54,9 +54,11 @@ Application::Application(int argc, char **argv) { utility = new Utility; string fontFamily = Intrinsics::platform() == Intrinsics::Platform::Windows ? "Tahoma, " : "Sans, "; + string monoFamily = Intrinsics::platform() == Intrinsics::Platform::Windows ? "Lucida Console, " : "Liberation Mono, "; normalFont = {fontFamily, "8"}; boldFont = {fontFamily, "8, Bold"}; titleFont = {fontFamily, "16, Bold"}; + monospaceFont = {monoFamily, "8"}; compositionEnable = compositor::enabled(); if(config->video.compositionMode == 2) compositor::enable(false); @@ -65,6 +67,7 @@ Application::Application(int argc, char **argv) { mainWindow = new MainWindow; fileBrowser = new FileBrowser; dipSwitches = new DipSwitches; + informationWindow = new InformationWindow; settingsWindow = new SettingsWindow; cheatDatabase = new CheatDatabase; cheatEditor = new CheatEditor; @@ -133,6 +136,7 @@ Application::~Application() { delete cheatEditor; delete cheatDatabase; delete settingsWindow; + delete informationWindow; delete dipSwitches; delete fileBrowser; delete mainWindow; diff --git a/bsnes/target-ui/utility/utility.cpp b/bsnes/target-ui/utility/utility.cpp index b8833968..cd3dcb2c 100755 --- a/bsnes/target-ui/utility/utility.cpp +++ b/bsnes/target-ui/utility/utility.cpp @@ -47,6 +47,7 @@ void Utility::setMode(Interface::Mode mode) { interface->updateDSP(); mainWindow->synchronize(); resizeMainWindow(); + informationWindow->update(); } void Utility::resizeMainWindow(bool shrink) {