diff --git a/bsnes/nes/cartridge/board/axrom.cpp b/bsnes/nes/cartridge/board/axrom.cpp index d44f8c1c..2140551b 100755 --- a/bsnes/nes/cartridge/board/axrom.cpp +++ b/bsnes/nes/cartridge/board/axrom.cpp @@ -40,6 +40,8 @@ void reset() { } void serialize(serializer &s) { + Board::serialize(s); + s.integer(prg_bank); s.integer(mirror_select); } diff --git a/bsnes/nes/cartridge/board/bandai-fcg.cpp b/bsnes/nes/cartridge/board/bandai-fcg.cpp new file mode 100755 index 00000000..39399586 --- /dev/null +++ b/bsnes/nes/cartridge/board/bandai-fcg.cpp @@ -0,0 +1,117 @@ +//BANDAI-FCG + +struct BandaiFCG : Board { + +uint8 chr_bank[8]; +uint8 prg_bank; +uint2 mirror; +bool irq_counter_enable; +uint16 irq_counter; +uint16 irq_latch; + +void main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(irq_counter_enable) { + if(--irq_counter == 0xffff) { + cpu.set_irq_line(1); + irq_counter_enable = false; + } + } + + tick(); + } +} + +unsigned ciram_addr(unsigned addr) const { + switch(mirror) { + case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); + case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); + case 2: return 0x0000 | (addr & 0x03ff); + case 3: return 0x0400 | (addr & 0x03ff); + } +} + +uint8 prg_read(unsigned addr) { + if(addr & 0x8000) { + bool region = addr & 0x4000; + unsigned bank = (region == 0 ? prg_bank : 0x0f); + return Board::prg_read((bank << 14) | (addr & 0x3fff)); + } + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if(addr >= 0x6000) { + switch(addr & 15) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + chr_bank[addr & 7] = data; + break; + case 0x08: + prg_bank = data & 0x0f; + break; + case 0x09: + mirror = data & 0x03; + break; + case 0x0a: + cpu.set_irq_line(0); + irq_counter_enable = data & 0x01; + irq_counter = irq_latch; + break; + case 0x0b: + irq_latch = (irq_latch & 0xff00) | (data << 0); + break; + case 0x0c: + irq_latch = (irq_latch & 0x00ff) | (data << 8); + break; + case 0x0d: + //TODO: serial EEPROM support + break; + } + } +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) return ppu.ciram_read(ciram_addr(addr)); + addr = (chr_bank[addr >> 10] << 10) | (addr & 0x03ff); + return Board::chr_read(addr); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) return ppu.ciram_write(ciram_addr(addr), data); + addr = (chr_bank[addr >> 10] << 10) | (addr & 0x03ff); + return Board::chr_write(addr, data); +} + +void power() { + reset(); +} + +void reset() { + for(auto &n : chr_bank) n = 0; + prg_bank = 0; + mirror = 0; + irq_counter_enable = 0; + irq_counter = 0; + irq_latch = 0; +} + +void serialize(serializer &s) { + Board::serialize(s); + + s.array(chr_bank); + s.integer(prg_bank); + s.integer(mirror); + s.integer(irq_counter_enable); + s.integer(irq_counter); + s.integer(irq_latch); +} + +BandaiFCG(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) { +} + +}; diff --git a/bsnes/nes/cartridge/board/board.cpp b/bsnes/nes/cartridge/board/board.cpp index a58a04f7..5b53ba9c 100755 --- a/bsnes/nes/cartridge/board/board.cpp +++ b/bsnes/nes/cartridge/board/board.cpp @@ -2,7 +2,10 @@ #include "cnrom.cpp" #include "nrom.cpp" #include "sxrom.cpp" +#include "txrom.cpp" #include "uxrom.cpp" +#include "bandai-fcg.cpp" +#include "konami-vrc6.cpp" unsigned Board::mirror(unsigned addr, unsigned size) const { unsigned base = 0; @@ -106,10 +109,16 @@ Board* Board::load(const string &markup, const uint8_t *data, unsigned size) { if(type == "NES-AN1ROM" ) return new AxROM(board, data, size); if(type == "NES-AOROM" ) return new AxROM(board, data, size); if(type == "NES-CNROM" ) return new CNROM(board, data, size); - if(type == "NES-NROM-256") return new NROM(board, data, size); + if(type == "NES-NROM-256") return new NROM (board, data, size); if(type == "NES-UNROM" ) return new UxROM(board, data, size); + if(type == "NES-SNROM" ) return new SxROM(board, data, size); if(type == "NES-SXROM" ) return new SxROM(board, data, size); + if(type == "NES-TLROM" ) return new TxROM(board, data, size); if(type == "NES-UOROM" ) return new UxROM(board, data, size); + if(type == "BANDAI-FCG") return new BandaiFCG(board, data, size); + + if(type == "KONAMI-VRC-6") return new KonamiVRC6(board, data, size); + return nullptr; } diff --git a/bsnes/nes/cartridge/board/board.hpp b/bsnes/nes/cartridge/board/board.hpp index 1ce83be7..d55a8756 100755 --- a/bsnes/nes/cartridge/board/board.hpp +++ b/bsnes/nes/cartridge/board/board.hpp @@ -2,6 +2,7 @@ struct Board { struct Memory { uint8_t *data; unsigned size; + inline Memory(uint8_t *data, unsigned size) : data(data), size(size) {} inline Memory() : data(nullptr), size(0u) {} }; @@ -32,7 +33,6 @@ struct Board { bool battery; } information; -protected: Memory prgrom; Memory prgram; Memory chrrom; diff --git a/bsnes/nes/cartridge/board/cnrom.cpp b/bsnes/nes/cartridge/board/cnrom.cpp index fccf5db6..be77de0b 100755 --- a/bsnes/nes/cartridge/board/cnrom.cpp +++ b/bsnes/nes/cartridge/board/cnrom.cpp @@ -44,6 +44,8 @@ void reset() { } void serialize(serializer &s) { + Board::serialize(s); + s.integer(chr_bank); } diff --git a/bsnes/nes/cartridge/board/konami-vrc6.cpp b/bsnes/nes/cartridge/board/konami-vrc6.cpp new file mode 100755 index 00000000..cec08700 --- /dev/null +++ b/bsnes/nes/cartridge/board/konami-vrc6.cpp @@ -0,0 +1,43 @@ +struct KonamiVRC6 : Board { + +VRC6 vrc6; + +uint8 prg_read(unsigned addr) { + if((addr & 0xe000) == 0x6000) return vrc6.ram_read(addr); + if(addr & 0x8000) return Board::prg_read(vrc6.prg_addr(addr)); + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if((addr & 0xe000) == 0x6000) return vrc6.ram_write(addr, data); + if(addr & 0x8000) { + addr = (addr & 0xf003); + if(prgram.size) addr = (addr & ~3) | ((addr & 2) >> 1) | ((addr & 1) << 1); + return vrc6.reg_write(addr, data); + } +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) return ppu.ciram_read(vrc6.ciram_addr(addr)); + return Board::chr_read(vrc6.chr_addr(addr)); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) return ppu.ciram_write(vrc6.ciram_addr(addr), data); + return Board::chr_write(vrc6.chr_addr(addr), data); +} + +void serialize(serializer &s) { + Board::serialize(s); + vrc6.serialize(s); +} + +void main() { vrc6.main(); } +void power() { vrc6.power(); } +void reset() { vrc6.reset(); } +Memory memory() { return prgram; } + +KonamiVRC6(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), vrc6(*this) { +} + +}; diff --git a/bsnes/nes/cartridge/board/nrom.cpp b/bsnes/nes/cartridge/board/nrom.cpp index 3a4b6617..eaee9007 100755 --- a/bsnes/nes/cartridge/board/nrom.cpp +++ b/bsnes/nes/cartridge/board/nrom.cpp @@ -31,6 +31,10 @@ void chr_write(unsigned addr, uint8 data) { return Board::chr_write(addr, data); } +void serialize(serializer &s) { + Board::serialize(s); +} + NROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) { settings.mirror = board["mirror"].value() == "vertical" ? 1 : 0; } diff --git a/bsnes/nes/cartridge/board/sxrom.cpp b/bsnes/nes/cartridge/board/sxrom.cpp index 3b3bf6fd..0541a9e7 100755 --- a/bsnes/nes/cartridge/board/sxrom.cpp +++ b/bsnes/nes/cartridge/board/sxrom.cpp @@ -1,29 +1,148 @@ -//NES-SAROM -//NES-SBROM -//NES-SCROM -//NES-SC1ROM -//NES-SEROM -//NES-SFROM -//NES-SGROM -//NES-SHROM -//NES-SH1ROM -//NES-SIROM -//NES-SJROM -//NES-SKROM -//NES-SLROM -//NES-SL1ROM -//NES-SL2ROM -//NES-SL3ROM -//NES-SLRROM -//NES-SMROM -//NES-SNROM -//NES-SOROM -//NES-SUROM -//NES-SXROM - struct SxROM : Board { -SxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size) { +enum class Revision : unsigned { + SAROM, + SBROM, + SCROM, + SC1ROM, + SEROM, + SFROM, + SGROM, + SHROM, + SH1ROM, + SIROM, + SJROM, + SKROM, + SLROM, + SL1ROM, + SL2ROM, + SL3ROM, + SLRROM, + SMROM, + SNROM, + SOROM, + SUROM, + SXROM, +} revision; + +MMC1 mmc1; + +unsigned shiftaddr; +unsigned shiftdata; + +uint8 prg_read(unsigned addr) { + if((addr & 0xe000) == 0x6000) return mmc1.ram_read(addr); + if(addr & 0x8000) return Board::prg_read(mmc1.prg_addr(addr)); + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if((addr & 0xe000) == 0x6000) return mmc1.ram_write(addr, data); + + if(addr & 0x8000) { + if(data & 0x80) { + shiftaddr = 0; + mmc1.prg_size = 1; + mmc1.prg_mode = 1; + } else { + shiftdata = ((data & 1) << 4) | (shiftdata >> 1); + if(++shiftaddr == 5) { + shiftaddr = 0; + reg_write((addr >> 13) & 3, shiftdata); + } + } + } +} + +uint8 chr_read(unsigned addr) { + if(addr & 0x2000) return ppu.ciram_read(mmc1.ciram_addr(addr)); + return Board::chr_read(mmc1.chr_addr(addr)); +} + +void chr_write(unsigned addr, uint8 data) { + if(addr & 0x2000) return ppu.ciram_write(mmc1.ciram_addr(addr), data); + return Board::chr_write(mmc1.chr_addr(addr), data); +} + +void reg_write(unsigned addr, uint8 data) { + switch(addr) { + case 0: + mmc1.chr_mode = (data & 0x10); + mmc1.prg_size = (data & 0x08); + mmc1.prg_mode = (data & 0x04); + mmc1.mirror = (data & 0x03); + break; + + case 1: + mmc1.chr_bank[0] = (data & 0x1f); + switch(revision) { + case Revision::SNROM: + mmc1.ram_disable[1] = (data & 0x10); + break; + case Revision::SOROM: + mmc1.ram_bank = (data & 0x08) >> 3; + break; + case Revision::SUROM: + mmc1.prg_page = (data & 0x10); + break; + case Revision::SXROM: + mmc1.prg_page = (data & 0x10); + mmc1.ram_bank = (data & 0x0c) >> 2; + break; + } + break; + + case 2: + mmc1.chr_bank[1] = (data & 0x1f); + switch(revision) { + case Revision::SNROM: + mmc1.ram_disable[1] = (data & 0x10); + break; + case Revision::SOROM: + mmc1.ram_bank = (data & 0x08) >> 3; + break; + case Revision::SUROM: + mmc1.prg_page = (data & 0x10); + break; + case Revision::SXROM: + mmc1.prg_page = (data & 0x10); + mmc1.ram_bank = (data & 0x0c) >> 2; + break; + } + break; + + case 3: + mmc1.ram_disable[0] = (data & 0x10); + mmc1.prg_bank = (data & 0x0f); + break; + } +} + +Memory memory() { + return prgram; +} + +void power() { + mmc1.power(); +} + +void reset() { + mmc1.reset(); +} + +void serialize(serializer &s) { + Board::serialize(s); + mmc1.serialize(s); + + s.integer(shiftaddr); + s.integer(shiftdata); +} + +SxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc1(*this) { + revision = Revision::SXROM; + + shiftaddr = 0; + shiftdata = 0; } }; diff --git a/bsnes/nes/cartridge/board/txrom.cpp b/bsnes/nes/cartridge/board/txrom.cpp new file mode 100755 index 00000000..c73ddc0a --- /dev/null +++ b/bsnes/nes/cartridge/board/txrom.cpp @@ -0,0 +1,117 @@ +struct TxROM : Board { + +enum class Revision : unsigned { + TBROM, + TEROM, + TFROM, + TGROM, + TKROM, + TKSROM, + TLROM, + TL1ROM, + TL2ROM, + TLSROM, + TNROM, + TQROM, + TR1ROM, + TSROM, + TVROM, +} revision; + +MMC3 mmc3; + +void main() { + mmc3.main(); +} + +uint8 prg_read(unsigned addr) { + if((addr & 0xe000) == 0x6000) return mmc3.ram_read(addr); + if(addr & 0x8000) return Board::prg_read(mmc3.prg_addr(addr)); + return cpu.mdr(); +} + +void prg_write(unsigned addr, uint8 data) { + if((addr & 0xe000) == 0x6000) return mmc3.ram_write(addr, data); + + switch(addr & 0xe001) { + case 0x8000: + mmc3.chr_mode = data & 0x80; + mmc3.prg_mode = data & 0x40; + mmc3.bank_select = data & 0x07; + break; + + case 0x8001: + switch(mmc3.bank_select) { + case 0: mmc3.chr_bank[0] = data & ~1; break; + case 1: mmc3.chr_bank[1] = data & ~1; break; + case 2: mmc3.chr_bank[2] = data; break; + case 3: mmc3.chr_bank[3] = data; break; + case 4: mmc3.chr_bank[4] = data; break; + case 5: mmc3.chr_bank[5] = data; break; + case 6: mmc3.prg_bank[0] = data & 0x3f; break; + case 7: mmc3.prg_bank[1] = data & 0x3f; break; + } + break; + + case 0xa000: + mmc3.mirror = data & 0x01; + break; + + case 0xa001: + mmc3.ram_enable = data & 0x80; + mmc3.ram_write_protect = data & 0x40; + break; + + case 0xc000: + mmc3.irq_latch = data; + break; + + case 0xc001: + mmc3.irq_counter = 0; + break; + + case 0xe000: + mmc3.irq_enable = false; + mmc3.irq_line = 0; + break; + + case 0xe001: + mmc3.irq_enable = true; + break; + } +} + +uint8 chr_read(unsigned addr) { + mmc3.irq_test(addr); + if(addr & 0x2000) return ppu.ciram_read(mmc3.ciram_addr(addr)); + return Board::chr_read(mmc3.chr_addr(addr)); +} + +void chr_write(unsigned addr, uint8 data) { + mmc3.irq_test(addr); + if(addr & 0x2000) return ppu.ciram_write(mmc3.ciram_addr(addr), data); + return Board::chr_write(mmc3.chr_addr(addr), data); +} + +Memory memory() { + return prgram; +} + +void power() { + mmc3.power(); +} + +void reset() { + mmc3.reset(); +} + +void serialize(serializer &s) { + Board::serialize(s); + mmc3.serialize(s); +} + +TxROM(BML::Node &board, const uint8_t *data, unsigned size) : Board(board, data, size), mmc3(*this) { + revision = Revision::TLROM; +} + +}; diff --git a/bsnes/nes/cartridge/board/uxrom.cpp b/bsnes/nes/cartridge/board/uxrom.cpp index c7aea46e..b801ba26 100755 --- a/bsnes/nes/cartridge/board/uxrom.cpp +++ b/bsnes/nes/cartridge/board/uxrom.cpp @@ -44,6 +44,8 @@ void reset() { } void serialize(serializer &s) { + Board::serialize(s); + s.integer(prg_bank); } diff --git a/bsnes/nes/cartridge/cartridge.cpp b/bsnes/nes/cartridge/cartridge.cpp index c5a0bfe7..331b750d 100755 --- a/bsnes/nes/cartridge/cartridge.cpp +++ b/bsnes/nes/cartridge/cartridge.cpp @@ -20,6 +20,7 @@ void Cartridge::load(const string &markup, const uint8_t *data, unsigned size) { sha256 = nall::sha256(data, size); board = Board::load(markup, data, size); } else { + sha256 = nall::sha256(data + 16, size - 16); board = Board::load(markup != "" ? markup : iNES(data, size), data + 16, size - 16); } diff --git a/bsnes/nes/cartridge/cartridge.hpp b/bsnes/nes/cartridge/cartridge.hpp index 44198cc6..f6db4b15 100755 --- a/bsnes/nes/cartridge/cartridge.hpp +++ b/bsnes/nes/cartridge/cartridge.hpp @@ -9,7 +9,7 @@ struct Cartridge : Processor, property { void unload(); unsigned ram_size(); - uint8 *ram_data(); + uint8* ram_data(); void power(); void reset(); diff --git a/bsnes/nes/cartridge/chip/chip.cpp b/bsnes/nes/cartridge/chip/chip.cpp index e69de29b..51dc1b7e 100755 --- a/bsnes/nes/cartridge/chip/chip.cpp +++ b/bsnes/nes/cartridge/chip/chip.cpp @@ -0,0 +1,10 @@ +#include "mmc1.cpp" +#include "mmc3.cpp" +#include "vrc6.cpp" + +void Chip::tick() { + board.tick(); +} + +Chip::Chip(Board &board) : board(board) { +} diff --git a/bsnes/nes/cartridge/chip/chip.hpp b/bsnes/nes/cartridge/chip/chip.hpp index b30e88b4..8753c66b 100755 --- a/bsnes/nes/cartridge/chip/chip.hpp +++ b/bsnes/nes/cartridge/chip/chip.hpp @@ -1,2 +1,7 @@ +struct Board; + struct Chip { + Board &board; + void tick(); + Chip(Board &board); }; diff --git a/bsnes/nes/cartridge/chip/mmc1.cpp b/bsnes/nes/cartridge/chip/mmc1.cpp new file mode 100755 index 00000000..1c6bfe61 --- /dev/null +++ b/bsnes/nes/cartridge/chip/mmc1.cpp @@ -0,0 +1,95 @@ +struct MMC1 : Chip { + +enum class Revision : unsigned { + MMC1, + MMC1A, + MMC1B1, + MMC1B2, + MMC1B3, + MMC1C, +} revision; + +bool chr_mode; +bool prg_size; //0 = 32K, 1 = 16K +bool prg_mode; +uint2 mirror; //0 = first, 1 = second, 2 = vertical, 3 = horizontal +uint5 chr_bank[2]; +uint4 prg_bank; +bool prg_page; +uint2 ram_bank; +bool ram_disable[2]; + +unsigned prg_addr(unsigned addr) const { + bool region = addr & 0x4000; + unsigned bank = (prg_bank & ~1) + region; + + if(prg_size) { + bank = (region == 0 ? 0x0 : 0xf); + if(region != prg_mode) bank = prg_bank; + } + + return (prg_page << 18) | (bank << 14) | (addr & 0x3fff); +} + +unsigned chr_addr(unsigned addr) const { + bool region = addr & 0x1000; + unsigned bank = chr_bank[region]; + if(chr_mode == 0) bank = (chr_bank[0] & ~1) | region; + return (bank << 12) | (addr & 0x0fff); +} + +unsigned ciram_addr(unsigned addr) const { + switch(mirror) { + case 0: return 0x0000 | (addr & 0x03ff); + case 1: return 0x0400 | (addr & 0x03ff); + case 2: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); + case 3: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); + } +} + +uint8 ram_read(unsigned addr) { + addr = (ram_bank * 0x2000) | (addr & 0x1fff); + if(ram_disable[0] == false && ram_disable[1] == false) return board.prgram.data[addr]; + return 0x00; +} + +void ram_write(unsigned addr, uint8 data) { + addr = (ram_bank * 0x2000) | (addr & 0x1fff); + if(ram_disable[0] == false && ram_disable[1] == false) board.prgram.data[addr] = data; +} + +void power() { + reset(); +} + +void reset() { + chr_mode = 0; + prg_size = 1; + prg_mode = 1; + mirror = 0; + chr_bank[0] = 0; + chr_bank[1] = 1; + prg_bank = 0; + prg_page = 0; + ram_bank = 0; + ram_disable[0] = 0; + ram_disable[1] = 0; +} + +void serialize(serializer &s) { + s.integer(chr_mode); + s.integer(prg_size); + s.integer(prg_mode); + s.integer(mirror); + s.array(chr_bank); + s.integer(prg_bank); + s.integer(prg_page); + s.integer(ram_bank); + s.array(ram_disable); +} + +MMC1(Board &board) : Chip(board) { + revision = Revision::MMC1B2; +} + +}; diff --git a/bsnes/nes/cartridge/chip/mmc3.cpp b/bsnes/nes/cartridge/chip/mmc3.cpp new file mode 100755 index 00000000..525f296b --- /dev/null +++ b/bsnes/nes/cartridge/chip/mmc3.cpp @@ -0,0 +1,141 @@ +struct MMC3 : Chip { + +bool chr_mode; +bool prg_mode; +uint3 bank_select; +uint8 prg_bank[2]; +uint8 chr_bank[6]; +bool mirror; +bool ram_enable; +bool ram_write_protect; +uint8 irq_latch; +uint8 irq_counter; +bool irq_enable; +unsigned irq_delay; +bool irq_line; + +uint16 chr_abus; + +void main() { + while(true) { + if(scheduler.sync == Scheduler::SynchronizeMode::All) { + scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); + } + + if(irq_delay) irq_delay--; + cpu.set_irq_line(irq_line); + tick(); + } +} + +void irq_test(unsigned addr) { + if(!(chr_abus & 0x1000) && (addr & 0x1000)) { + if(irq_delay == 0) { + if(irq_counter == 0) { + irq_counter = irq_latch; + } else if(--irq_counter == 0) { + if(irq_enable) irq_line = 1; + } + } + irq_delay = 6; + } + chr_abus = addr; +} + +unsigned prg_addr(unsigned addr) const { + switch((addr >> 13) & 3) { + case 0: + if(prg_mode == 1) return (0x3e << 13) | (addr & 0x1fff); + return (prg_bank[0] << 13) | (addr & 0x1fff); + case 1: + return (prg_bank[1] << 13) | (addr & 0x1fff); + case 2: + if(prg_mode == 0) return (0x3e << 13) | (addr & 0x1fff); + return (prg_bank[0] << 13) | (addr & 0x1fff); + case 3: + return (0x3f << 13) | (addr & 0x1fff); + } +} + +unsigned chr_addr(unsigned addr) const { + if(chr_mode == 0) { + if(addr <= 0x07ff) return (chr_bank[0] << 10) | (addr & 0x07ff); + if(addr <= 0x0fff) return (chr_bank[1] << 10) | (addr & 0x07ff); + if(addr <= 0x13ff) return (chr_bank[2] << 10) | (addr & 0x03ff); + if(addr <= 0x17ff) return (chr_bank[3] << 10) | (addr & 0x03ff); + if(addr <= 0x1bff) return (chr_bank[4] << 10) | (addr & 0x03ff); + if(addr <= 0x1fff) return (chr_bank[5] << 10) | (addr & 0x03ff); + } else { + if(addr <= 0x03ff) return (chr_bank[2] << 10) | (addr & 0x03ff); + if(addr <= 0x07ff) return (chr_bank[3] << 10) | (addr & 0x03ff); + if(addr <= 0x0bff) return (chr_bank[4] << 10) | (addr & 0x03ff); + if(addr <= 0x0fff) return (chr_bank[5] << 10) | (addr & 0x03ff); + if(addr <= 0x17ff) return (chr_bank[0] << 10) | (addr & 0x07ff); + if(addr <= 0x1fff) return (chr_bank[1] << 10) | (addr & 0x07ff); + } +} + +unsigned ciram_addr(unsigned addr) const { + if(mirror == 0) return ((addr & 0x0400) >> 0) | (addr & 0x03ff); + if(mirror == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff); +} + +uint8 ram_read(unsigned addr) { + if(ram_enable) return board.prgram.data[addr & 0x1fff]; + return 0x00; +} + +void ram_write(unsigned addr, uint8 data) { + if(ram_enable && !ram_write_protect) board.prgram.data[addr & 0x1fff] = data; +} + +void power() { + reset(); +} + +void reset() { + chr_mode = 0; + prg_mode = 0; + bank_select = 0; + prg_bank[0] = 0; + prg_bank[1] = 0; + chr_bank[0] = 0; + chr_bank[1] = 0; + chr_bank[2] = 0; + chr_bank[3] = 0; + chr_bank[4] = 0; + chr_bank[5] = 0; + mirror = 0; + ram_enable = 1; + ram_write_protect = 0; + irq_latch = 0; + irq_counter = 0; + irq_enable = false; + irq_delay = 0; + irq_line = 0; + + chr_abus = 0; +} + +void serialize(serializer &s) { + s.integer(chr_mode); + s.integer(prg_mode); + s.integer(bank_select); + s.array(prg_bank); + s.array(chr_bank); + s.integer(mirror); + s.integer(ram_enable); + s.integer(ram_write_protect); + s.integer(irq_latch); + s.integer(irq_counter); + s.integer(irq_enable); + s.integer(irq_delay); + s.integer(irq_line); + + s.integer(chr_abus); +} + +MMC3(Board &board) : Chip(board) { +} + +}; diff --git a/bsnes/nes/mapper/vrc6/vrc6.cpp b/bsnes/nes/cartridge/chip/vrc6.cpp similarity index 64% rename from bsnes/nes/mapper/vrc6/vrc6.cpp rename to bsnes/nes/cartridge/chip/vrc6.cpp index 19f707a1..f872cf23 100755 --- a/bsnes/nes/mapper/vrc6/vrc6.cpp +++ b/bsnes/nes/cartridge/chip/vrc6.cpp @@ -1,32 +1,92 @@ -VRC6 vrc6; +struct VRC6 : Chip { -void VRC6::Pulse::clock() { - if(--divider == 0) { - divider = frequency + 1; - cycle++; - output = (mode == 1 || cycle > duty) ? volume : (uint4)0; +uint8 prg_bank[2]; +uint8 chr_bank[8]; +uint2 mirror; +uint8 irq_latch; +bool irq_mode; +bool irq_enable; +bool irq_acknowledge; + +uint8 irq_counter; +signed irq_scalar; +bool irq_line; + +struct Pulse { + bool mode; + uint3 duty; + uint4 volume; + bool enable; + uint12 frequency; + + uint12 divider; + uint4 cycle; + uint4 output; + + void clock() { + if(--divider == 0) { + divider = frequency + 1; + cycle++; + output = (mode == 1 || cycle > duty) ? volume : (uint4)0; + } + + if(enable == false) output = 0; } - if(enable == false) output = 0; -} + void serialize(serializer &s) { + s.integer(mode); + s.integer(duty); + s.integer(volume); + s.integer(enable); + s.integer(frequency); -void VRC6::Sawtooth::clock() { - if(--divider == 0) { - divider = frequency + 1; - if(++phase == 0) { - accumulator += rate; - if(++stage == 7) { - stage = 0; - accumulator = 0; + s.integer(divider); + s.integer(cycle); + s.integer(output); + } +} pulse1, pulse2; + +struct Sawtooth { + uint6 rate; + bool enable; + uint12 frequency; + + uint12 divider; + uint1 phase; + uint3 stage; + uint8 accumulator; + uint5 output; + + void clock() { + if(--divider == 0) { + divider = frequency + 1; + if(++phase == 0) { + accumulator += rate; + if(++stage == 7) { + stage = 0; + accumulator = 0; + } } } + + output = accumulator >> 3; + if(enable == false) output = 0; } - output = accumulator >> 3; - if(enable == false) output = 0; -} + void serialize(serializer &s) { + s.integer(rate); + s.integer(enable); + s.integer(frequency); -void VRC6::main() { + s.integer(divider); + s.integer(phase); + s.integer(stage); + s.integer(accumulator); + s.integer(output); + } +} sawtooth; + +void main() { while(true) { if(scheduler.sync == Scheduler::SynchronizeMode::All) { scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); @@ -67,35 +127,35 @@ void VRC6::main() { } } -uint8 VRC6::prg_read(unsigned addr) { - if((addr & 0xe000) == 0x6000) { - return prg_ram[addr & 0x1fff]; - } - - if((addr & 0xc000) == 0x8000) { - return Mapper::prg_read((prg_bank[0] << 14) | (addr & 0x3fff)); - } - - if((addr & 0xe000) == 0xc000) { - return Mapper::prg_read((prg_bank[1] << 13) | (addr & 0x1fff)); - } - - if((addr & 0xe000) == 0xe000) { - return Mapper::prg_read((0xff << 13) | (addr & 0x1fff)); - } - - return cpu.mdr(); +unsigned prg_addr(unsigned addr) const { + if((addr & 0xc000) == 0x8000) return (prg_bank[0] << 14) | (addr & 0x3fff); + if((addr & 0xe000) == 0xc000) return (prg_bank[1] << 13) | (addr & 0x1fff); + if((addr & 0xe000) == 0xe000) return ( 0xff << 13) | (addr & 0x1fff); } -void VRC6::prg_write(unsigned addr, uint8 data) { - if((addr & 0xe000) == 0x6000) { - prg_ram[addr & 0x1fff] = data; - return; +unsigned chr_addr(unsigned addr) const { + unsigned bank = chr_bank[(addr >> 10) & 7]; + return (bank << 10) | (addr & 0x03ff); +} + +unsigned ciram_addr(unsigned addr) const { + switch(mirror) { + case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring + case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring + case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) + case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) } +} - addr = (addr & 0xf003); - if(abus_swap) addr = (addr & ~3) | ((addr & 2) >> 1) | ((addr & 1) << 1); +uint8 ram_read(unsigned addr) { + return board.prgram.data[addr & 0x1fff]; +} +void ram_write(unsigned addr, uint8 data) { + board.prgram.data[addr & 0x1fff] = data; +} + +void reg_write(unsigned addr, uint8 data) { switch(addr) { case 0x8000: case 0x8001: case 0x8002: case 0x8003: prg_bank[0] = data; @@ -145,7 +205,7 @@ void VRC6::prg_write(unsigned addr, uint8 data) { break; case 0xb003: - mirror_select = (data >> 2) & 3; + mirror = (data >> 2) & 3; break; case 0xc000: case 0xc001: case 0xc002: case 0xc003: @@ -182,44 +242,11 @@ void VRC6::prg_write(unsigned addr, uint8 data) { } } -uint8 VRC6::chr_read(unsigned addr) { - if(addr & 0x2000) return ppu.ciram_read(ciram_addr(addr)); - - unsigned bank = chr_bank[(addr >> 10) & 7]; - return Mapper::chr_read((bank << 10) | (addr & 0x03ff)); -} - -void VRC6::chr_write(unsigned addr, uint8 data) { - if(addr & 0x2000) return ppu.ciram_write(ciram_addr(addr), data); - - unsigned bank = chr_bank[(addr >> 10) & 7]; - Mapper::chr_write((bank << 10) | (addr & 0x03ff), data); -} - -unsigned VRC6::ciram_addr(unsigned addr) const { - switch(mirror_select) { - case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring - case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring - case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) - case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) - } -} - -unsigned VRC6::ram_size() { - return 8192u; -} - -uint8* VRC6::ram_data() { - return prg_ram; -} - -void VRC6::power() { +void power() { reset(); } -void VRC6::reset() { - for(auto &n : prg_ram) n = 0xff; - +void reset() { prg_bank[0] = 0; prg_bank[1] = 0; chr_bank[0] = 0; @@ -230,7 +257,7 @@ void VRC6::reset() { chr_bank[5] = 0; chr_bank[6] = 0; chr_bank[7] = 0; - mirror_select = 0; + mirror = 0; irq_latch = 0; irq_mode = 0; irq_enable = 0; @@ -271,12 +298,14 @@ void VRC6::reset() { sawtooth.output = 0; } -void VRC6::serialize(serializer &s) { - s.array(prg_ram); +void serialize(serializer &s) { + pulse1.serialize(s); + pulse2.serialize(s); + sawtooth.serialize(s); s.array(prg_bank); s.array(chr_bank); - s.integer(mirror_select); + s.integer(mirror); s.integer(irq_latch); s.integer(irq_mode); s.integer(irq_enable); @@ -285,32 +314,9 @@ void VRC6::serialize(serializer &s) { s.integer(irq_counter); s.integer(irq_scalar); s.integer(irq_line); - - pulse1.serialize(s); - pulse2.serialize(s); - sawtooth.serialize(s); } -void VRC6::Pulse::serialize(serializer &s) { - s.integer(mode); - s.integer(duty); - s.integer(volume); - s.integer(enable); - s.integer(frequency); - - s.integer(divider); - s.integer(cycle); - s.integer(output); +VRC6(Board &board) : Chip(board) { } -void VRC6::Sawtooth::serialize(serializer &s) { - s.integer(rate); - s.integer(enable); - s.integer(frequency); - - s.integer(divider); - s.integer(phase); - s.integer(stage); - s.integer(accumulator); - s.integer(output); -} +}; diff --git a/bsnes/nes/cartridge/ines.cpp b/bsnes/nes/cartridge/ines.cpp index 42a9d10e..207c2495 100755 --- a/bsnes/nes/cartridge/ines.cpp +++ b/bsnes/nes/cartridge/ines.cpp @@ -24,23 +24,47 @@ static string iNES(const uint8_t *data, unsigned size) { output.append(" mirror=", mirror == 0 ? "horizontal" : "vertical", "\n"); break; - case 1: + case 1: output.append(" board type=NES-SXROM\n"); + output.append(" chip type=MMC1B2\n"); + prgram = 8192; break; - case 2: + case 2: output.append(" board type=NES-UOROM\n"); output.append(" mirror=", mirror == 0 ? "horizontal" : "vertical", "\n"); break; - case 3: + case 3: output.append(" board type=NES-CNROM\n"); output.append(" mirror=", mirror == 0 ? "horizontal" : "vertical", "\n"); break; - case 7: + case 4: + output.append(" board type=NES-TLROM\n"); + output.append(" chip type=MMC3B\n"); + prgram = 8192; + break; + + case 7: output.append(" board type=NES-AOROM\n"); break; + + case 16: + output.append(" board type=BANDAI-FCG\n"); + output.append(" chip type=LZ93D50 manufacturer=Sharp\n"); + break; + + case 24: + output.append(" board type=KONAMI-VRC-6\n"); + output.append(" chip type=VRC6\n"); + break; + + case 26: + output.append(" board type=KONAMI-VRC-6\n"); + output.append(" chip type=VRC6\n"); + prgram = 8192; + break; } output.append(" prg rom=", prgrom, " ram=", prgram, "\n"); @@ -50,17 +74,3 @@ static string iNES(const uint8_t *data, unsigned size) { return output; } - -/* - switch(mapperNumber) { -//default : mapper = &Mapper::none; break; -//case 1: mapper = &Mapper::mmc1; break; -//case 2: mapper = &Mapper::uorom; break; -//case 3: mapper = &Mapper::cnrom; break; - case 4: mapper = &Mapper::mmc3; break; -//case 7: mapper = &Mapper::aorom; break; - case 16: mapper = &Mapper::bandaiFCG; break; - case 24: mapper = &Mapper::vrc6; Mapper::vrc6.abus_swap = 0; break; - case 26: mapper = &Mapper::vrc6; Mapper::vrc6.abus_swap = 1; break; - } -*/ diff --git a/bsnes/nes/mapper/aorom/aorom.cpp b/bsnes/nes/mapper/aorom/aorom.cpp deleted file mode 100755 index 646572f7..00000000 --- a/bsnes/nes/mapper/aorom/aorom.cpp +++ /dev/null @@ -1,40 +0,0 @@ -AOROM aorom; - -uint8 AOROM::prg_read(unsigned addr) { - if(addr & 0x8000) { - addr = (prg_bank << 15) | (addr & 0x7fff); - return Mapper::prg_read(addr); - } - return cpu.mdr(); -} - -void AOROM::prg_write(unsigned addr, uint8 data) { - if(addr & 0x8000) { - prg_bank = data & 0x0f; - mirror_select = data & 0x10; - } -} - -uint8 AOROM::chr_read(unsigned addr) { - if(addr & 0x2000) return ppu.ciram_read((mirror_select << 10) | (addr & 0x03ff)); - return Mapper::chr_read(addr); -} - -void AOROM::chr_write(unsigned addr, uint8 data) { - if(addr & 0x2000) return ppu.ciram_write((mirror_select << 10) | (addr & 0x03ff), data); - return Mapper::chr_write(addr, data); -} - -void AOROM::power() { - reset(); -} - -void AOROM::reset() { - prg_bank = 0x0f; - mirror_select = 0; -} - -void AOROM::serialize(serializer &s) { - s.integer(prg_bank); - s.integer(mirror_select); -} diff --git a/bsnes/nes/mapper/aorom/aorom.hpp b/bsnes/nes/mapper/aorom/aorom.hpp deleted file mode 100755 index 32fd0c60..00000000 --- a/bsnes/nes/mapper/aorom/aorom.hpp +++ /dev/null @@ -1,18 +0,0 @@ -struct AOROM : Mapper { - uint8 prg_read(unsigned addr); - void prg_write(unsigned addr, uint8 data); - - uint8 chr_read(unsigned addr); - void chr_write(unsigned addr, uint8 data); - - void power(); - void reset(); - - void serialize(serializer&); - -private: - uint4 prg_bank; - bool mirror_select; -}; - -extern AOROM aorom; diff --git a/bsnes/nes/mapper/bandai-fcg/bandai-fcg.cpp b/bsnes/nes/mapper/bandai-fcg/bandai-fcg.cpp deleted file mode 100755 index f00bea12..00000000 --- a/bsnes/nes/mapper/bandai-fcg/bandai-fcg.cpp +++ /dev/null @@ -1,109 +0,0 @@ -BandaiFCG bandaiFCG; - -void BandaiFCG::main() { - while(true) { - if(scheduler.sync == Scheduler::SynchronizeMode::All) { - scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); - } - - if(irq_counter_enable) { - if(--irq_counter == 0xffff) { - cpu.set_irq_line(1); - irq_counter_enable = false; - } - } - - tick(); - } -} - -uint8 BandaiFCG::prg_read(unsigned addr) { - if((addr & 0xc000) == 0x8000) { - addr = (prg_bank << 14) | (addr & 0x3fff); - return Mapper::prg_read(addr); - } - - if((addr & 0xc000) == 0xc000) { - addr = (0x0f << 14) | (addr & 0x3fff); - return Mapper::prg_read(addr); - } - - return cpu.mdr(); -} - -void BandaiFCG::prg_write(unsigned addr, uint8 data) { - if(addr >= 0x6000) { - addr &= 0x0f; - switch(addr) { - case 0x0: case 0x1: case 0x2: case 0x3: case 0x4: case 0x5: case 0x6: case 0x7: - chr_bank[addr] = data; - break; - case 0x8: - prg_bank = data & 0x0f; - break; - case 0x9: - mirror_select = data & 0x03; - break; - case 0xa: - cpu.set_irq_line(0); - irq_counter_enable = data & 0x01; - irq_counter = irq_latch; - break; - case 0xb: - irq_latch = (irq_latch & 0xff00) | (data << 0); - break; - case 0xc: - irq_latch = (irq_latch & 0x00ff) | (data << 8); - break; - case 0xd: - //TODO: serial EEPROM support - break; - } - } -} - -uint8 BandaiFCG::chr_read(unsigned addr) { - if(addr & 0x2000) return ppu.ciram_read(ciram_addr(addr)); - - addr = (chr_bank[addr >> 10] << 10) | (addr & 0x03ff); - return Mapper::chr_read(addr); -} - -void BandaiFCG::chr_write(unsigned addr, uint8 data) { - if(addr & 0x2000) return ppu.ciram_write(ciram_addr(addr), data); - - addr = (chr_bank[addr >> 10] << 10) | (addr & 0x03ff); - Mapper::chr_write(addr, data); -} - -void BandaiFCG::power() { - reset(); -} - -void BandaiFCG::reset() { - for(unsigned n = 0; n < 8; n++) chr_bank[n] = 0x00; - prg_bank = 0x00; - mirror_select = 0; - irq_counter_enable = false; - irq_counter = 0; - irq_latch = 0; -} - -unsigned BandaiFCG::ciram_addr(unsigned addr) const { - switch(mirror_select & 0x03) { - case 0: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring - case 1: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring - case 2: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) - case 3: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) - } - throw; -} - -void BandaiFCG::serialize(serializer &s) { - s.array(chr_bank); - s.integer(prg_bank); - s.integer(mirror_select); - s.integer(irq_counter_enable); - s.integer(irq_counter); - s.integer(irq_latch); -} diff --git a/bsnes/nes/mapper/bandai-fcg/bandai-fcg.hpp b/bsnes/nes/mapper/bandai-fcg/bandai-fcg.hpp deleted file mode 100755 index e1fd8b58..00000000 --- a/bsnes/nes/mapper/bandai-fcg/bandai-fcg.hpp +++ /dev/null @@ -1,26 +0,0 @@ -struct BandaiFCG : Mapper { - void main(); - - uint8 prg_read(unsigned addr); - void prg_write(unsigned addr, uint8 data); - - uint8 chr_read(unsigned addr); - void chr_write(unsigned addr, uint8 data); - - void power(); - void reset(); - - void serialize(serializer&); - -private: - unsigned ciram_addr(unsigned addr) const; - - uint8 chr_bank[8]; - uint8 prg_bank; - uint8 mirror_select; - bool irq_counter_enable; - uint16 irq_counter; - uint16 irq_latch; -}; - -extern BandaiFCG bandaiFCG; diff --git a/bsnes/nes/mapper/cnrom/cnrom.cpp b/bsnes/nes/mapper/cnrom/cnrom.cpp deleted file mode 100755 index df1c1e09..00000000 --- a/bsnes/nes/mapper/cnrom/cnrom.cpp +++ /dev/null @@ -1,42 +0,0 @@ -CNROM cnrom; - -uint8 CNROM::prg_read(unsigned addr) { - if(addr & 0x8000) return Mapper::prg_read(addr & 0x7fff); - return cpu.mdr(); -} - -void CNROM::prg_write(unsigned addr, uint8 data) { - if(addr & 0x8000) chr_bank = data & 0x03; -} - -uint8 CNROM::chr_read(unsigned addr) { - if(addr & 0x2000) { - if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.ciram_read(addr & 0x07ff); - } - - addr = (chr_bank * 0x2000) + (addr & 0x1fff); - return Mapper::chr_read(addr); -} - -void CNROM::chr_write(unsigned addr, uint8 data) { - if(addr & 0x2000) { - if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.ciram_write(addr & 0x07ff, data); - } - - addr = (chr_bank * 0x2000) + (addr & 0x1fff); - Mapper::chr_write(addr, data); -} - -void CNROM::power() { - reset(); -} - -void CNROM::reset() { - chr_bank = 0; -} - -void CNROM::serialize(serializer &s) { - s.integer(chr_bank); -} diff --git a/bsnes/nes/mapper/cnrom/cnrom.hpp b/bsnes/nes/mapper/cnrom/cnrom.hpp deleted file mode 100755 index af32d78f..00000000 --- a/bsnes/nes/mapper/cnrom/cnrom.hpp +++ /dev/null @@ -1,17 +0,0 @@ -struct CNROM : Mapper { - uint8 prg_read(unsigned addr); - void prg_write(unsigned addr, uint8 data); - - uint8 chr_read(unsigned addr); - void chr_write(unsigned addr, uint8 data); - - void power(); - void reset(); - - void serialize(serializer&); - -private: - uint2 chr_bank; -}; - -extern CNROM cnrom; diff --git a/bsnes/nes/mapper/mapper.cpp b/bsnes/nes/mapper/mapper.cpp deleted file mode 100755 index db6ba850..00000000 --- a/bsnes/nes/mapper/mapper.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include - -namespace NES { -namespace Mapper { - -void Mapper::main() { - while(true) { - if(scheduler.sync == Scheduler::SynchronizeMode::All) { - scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); - } - - cartridge.clock += 12 * 4095; - tick(); - } -} - -void Mapper::tick() { - cartridge.clock += 12; - if(cartridge.clock >= 0 && scheduler.sync != Scheduler::SynchronizeMode::All) co_switch(cpu.thread); -} - -unsigned Mapper::mirror(unsigned addr, unsigned size) const { - unsigned base = 0; - if(size) { - unsigned mask = 1 << 23; - while(addr >= size) { - while(!(addr & mask)) mask >>= 1; - addr -= mask; - if(size > mask) { - size -= mask; - base += mask; - } - mask >>= 1; - } - base += addr; - } - return base; -} - -uint8 Mapper::prg_read(unsigned addr) { - return cartridge.prg_data[mirror(addr, cartridge.prg_size)]; -} - -void Mapper::prg_write(unsigned addr, uint8 data) { - cartridge.prg_data[mirror(addr, cartridge.prg_size)] = data; -} - -uint8 Mapper::chr_read(unsigned addr) { - return cartridge.chr_data[mirror(addr, cartridge.chr_size)]; -} - -void Mapper::chr_write(unsigned addr, uint8 data) { - if(cartridge.chr_ram == false) return; - cartridge.chr_data[mirror(addr, cartridge.chr_size)] = data; -} - -unsigned Mapper::ram_size() { - return 0u; -} - -uint8* Mapper::ram_data() { - return 0; -} - -#include "none/none.cpp" -#include "aorom/aorom.cpp" -#include "bandai-fcg/bandai-fcg.cpp" -#include "cnrom/cnrom.cpp" -#include "mmc1/mmc1.cpp" -#include "mmc3/mmc3.cpp" -#include "uorom/uorom.cpp" -#include "vrc6/vrc6.cpp" - -} -} diff --git a/bsnes/nes/mapper/mapper.hpp b/bsnes/nes/mapper/mapper.hpp deleted file mode 100755 index 08e1ef69..00000000 --- a/bsnes/nes/mapper/mapper.hpp +++ /dev/null @@ -1,37 +0,0 @@ -namespace Mapper { - struct Mapper { - virtual void main(); - virtual void tick(); - - unsigned mirror(unsigned addr, unsigned size) const; - - //note: Mapper::{prg,chr}_read() functions take literal ROM addresses; mirroring appropriately - //subclasses of Mapper take 16-bit bus addresses; decode them; and call Mapper read functions - - virtual uint8 prg_read(unsigned addr); - virtual void prg_write(unsigned addr, uint8 data); - - virtual uint8 chr_read(unsigned addr); - virtual void chr_write(unsigned addr, uint8 data); - - virtual uint8 ciram_read(uint13 addr) {} - virtual void ciram_write(uint13 addr, uint8 data) {} - - virtual unsigned ram_size(); - virtual uint8* ram_data(); - - virtual void power() = 0; - virtual void reset() = 0; - - virtual void serialize(serializer&) = 0; - }; - - #include "none/none.hpp" - #include "aorom/aorom.hpp" - #include "bandai-fcg/bandai-fcg.hpp" - #include "cnrom/cnrom.hpp" - #include "mmc1/mmc1.hpp" - #include "mmc3/mmc3.hpp" - #include "uorom/uorom.hpp" - #include "vrc6/vrc6.hpp" -} diff --git a/bsnes/nes/mapper/mmc1/mmc1.cpp b/bsnes/nes/mapper/mmc1/mmc1.cpp deleted file mode 100755 index 11a53149..00000000 --- a/bsnes/nes/mapper/mmc1/mmc1.cpp +++ /dev/null @@ -1,176 +0,0 @@ -MMC1 mmc1; - -unsigned MMC1::ciram_addr(unsigned addr) const { - switch(r[0] & 0x03) { - case 0: return 0x0000 | (addr & 0x03ff); //one-screen mirroring (first) - case 1: return 0x0400 | (addr & 0x03ff); //one-screen mirroring (second) - case 2: return ((addr & 0x0400) >> 0) | (addr & 0x03ff); //vertical mirroring - case 3: return ((addr & 0x0800) >> 1) | (addr & 0x03ff); //horizontal mirroring - } -} - -//static block: 0 = 8000-ffff, 1 = c000-ffff -bool MMC1::prg_mode() const { - return r[0] & 0x04; -} - -//block size: 0 = 32K, 1 = 16K -bool MMC1::prg_size() const { - return r[0] & 0x08; -} - -unsigned MMC1::prg_addr(bool region) const { - unsigned addr, bank; - - //region(0) = $8000-bfff; region(1) = $c000-ffff - if(prg_size()) { //16K mode - bank = (region == 0 ? 0x0 : 0xf); //8000-bfff defaults to first bank; c000-ffff defaults to last bank - if(region != prg_mode()) { //if this is the active dynamic region ... - bank = prg_bank(); - } - } else { //32K mode - bank = (prg_bank() & ~1) + region; - } - addr = bank << 14; //<<14 = 16K - - //256K page selection (for 512K PRG ROMs) - if(prg_ex_select == 0) { - addr |= (chr_banklo() >> 4) << 18; //<<18 = 256K - } else { - addr |= (chr_bankhi() >> 4) << 18; - } - - return addr; -} - -//0 = 8K, 1 = 4K -bool MMC1::chr_mode() const { - return r[0] & 0x10; -} - -unsigned MMC1::chr_banklo() const { - if(chr_mode() == 0) return (r[1] & ~1) | 0; - return r[1]; -} - -unsigned MMC1::chr_bankhi() const { - if(chr_mode() == 0) return (r[1] & ~1) | 1; - return r[2]; -} - -unsigned MMC1::prg_bank() const { - return r[3] & 0x0f; -} - -bool MMC1::prg_ram_disable() const { - return r[3] & 0x10; -} - -uint8 MMC1::prg_read(unsigned addr) { - if((addr & 0xe000) == 0x6000) { - if(prg_ram_disable() == false) return prg_ram[addr & 0x1fff]; - return 0x00; - } - - if(addr & 0x8000) { - addr = prg_addr(addr & 0x4000) | (addr & 0x3fff); - return Mapper::prg_read(addr); - } - - return cpu.mdr(); -} - -void MMC1::prg_write(unsigned addr, uint8 data) { - if((addr & 0xe000) == 0x6000) { - if(prg_ram_disable() == false) prg_ram[addr & 0x1fff] = data; - return; - } - - if(addr & 0x8000) { - if(data & 0x80) { - shiftaddr = 0; - r[0] |= 0x0c; - } else { - shiftdata >>= 1; - shiftdata |= (data & 1) << 4; - if(++shiftaddr == 5) { - shiftaddr = 0; - r[(addr >> 13) & 3] = shiftdata; - } - } - return; - } -} - -uint8 MMC1::chr_read(unsigned addr) { - if(addr & 0x2000) { - return ppu.ciram_read(ciram_addr(addr)); - } - - prg_ex_select = addr & 0x1000; - - if(addr <= 0x0fff) { - addr = chr_banklo() * 0x1000 + (addr & 0x0fff); - return Mapper::chr_read(addr); - } - - if(addr <= 0x1fff) { - addr = chr_bankhi() * 0x1000 + (addr & 0x0fff); - return Mapper::chr_read(addr); - } - - throw; -} - -void MMC1::chr_write(unsigned addr, uint8 data) { - if(addr & 0x2000) { - return ppu.ciram_write(ciram_addr(addr), data); - } - - prg_ex_select = addr & 0x1000; - - if(addr <= 0x0fff) { - if(cartridge.chr_ram == false) return; - addr = chr_banklo() * 0x1000 + (addr & 0x0fff); - return Mapper::chr_write(addr, data); - } - - if(addr <= 0x1fff) { - if(cartridge.chr_ram == false) return; - addr = chr_bankhi() * 0x1000 + (addr & 0x0fff); - return Mapper::chr_write(addr, data); - } - - throw; -} - -unsigned MMC1::ram_size() { - return 8192u; -} - -uint8* MMC1::ram_data() { - return prg_ram; -} - -void MMC1::power() { - reset(); -} - -void MMC1::reset() { - prg_ex_select = 0; - shiftaddr = 0; - shiftdata = 0; - - r[0] = 0x0c; - r[1] = 0x00; - r[2] = 0x01; - r[3] = 0x00; -} - -void MMC1::serialize(serializer &s) { - s.array(prg_ram); - s.array(r); - s.integer(prg_ex_select); - s.integer(shiftaddr); - s.integer(shiftdata); -} diff --git a/bsnes/nes/mapper/mmc1/mmc1.hpp b/bsnes/nes/mapper/mmc1/mmc1.hpp deleted file mode 100755 index 446270bf..00000000 --- a/bsnes/nes/mapper/mmc1/mmc1.hpp +++ /dev/null @@ -1,34 +0,0 @@ -struct MMC1 : Mapper { - uint8 prg_read(unsigned addr); - void prg_write(unsigned addr, uint8 data); - - uint8 chr_read(unsigned addr); - void chr_write(unsigned addr, uint8 data); - - unsigned ram_size(); - uint8* ram_data(); - - void power(); - void reset(); - - void serialize(serializer&); - -private: - uint8 prg_ram[8192]; - uint8 r[4]; - bool prg_ex_select; - unsigned shiftaddr; - unsigned shiftdata; - - unsigned ciram_addr(unsigned addr) const; - bool prg_mode() const; - bool prg_size() const; - unsigned prg_addr(bool region) const; - bool chr_mode() const; - unsigned chr_banklo() const; - unsigned chr_bankhi() const; - unsigned prg_bank() const; - bool prg_ram_disable() const; -}; - -extern MMC1 mmc1; diff --git a/bsnes/nes/mapper/mmc3/mmc3.cpp b/bsnes/nes/mapper/mmc3/mmc3.cpp deleted file mode 100755 index d5a5c0f3..00000000 --- a/bsnes/nes/mapper/mmc3/mmc3.cpp +++ /dev/null @@ -1,213 +0,0 @@ -MMC3 mmc3; - -void MMC3::main() { - while(true) { - if(scheduler.sync == Scheduler::SynchronizeMode::All) { - scheduler.exit(Scheduler::ExitReason::SynchronizeEvent); - } - - if(irq_delay) irq_delay--; - cpu.set_irq_line(irq_line); - tick(); - } -} - -void MMC3::irq_test(uint16 addr) { - if(!(chr_abus & 0x1000) && (addr & 0x1000)) { - if(irq_delay == 0) { - if(irq_counter == 0) { - irq_counter = irq_latch; - } else if(--irq_counter == 0) { - if(irq_enable) irq_line = 1; - } - } - irq_delay = 6; - } - chr_abus = addr; -} - -unsigned MMC3::prg_addr(uint16 addr) { - if((addr & 0xe000) == 0x8000) { - if((bank_select & 0x40) != 0) return (0x3e << 13) | (addr & 0x1fff); - return (prg_bank[0] << 13) | (addr & 0x1fff); - } - - if((addr & 0xe000) == 0xa000) { - return (prg_bank[1] << 13) | (addr & 0x1fff); - } - - if((addr & 0xe000) == 0xc000) { - if((bank_select & 0x40) == 0) return (0x3e << 13) | (addr & 0x1fff); - return (prg_bank[0] << 13) | (addr & 0x1fff); - } - - if((addr & 0xe000) == 0xe000) { - return (0x3f << 13) | (addr & 0x1fff); - } - - throw; -} - -uint8 MMC3::prg_read(unsigned addr) { - if((addr & 0xe000) == 0x6000) { //$6000-7fff - if(prg_ram_enable) { - return prg_ram[addr & 0x1fff]; - } - } - - if(addr & 0x8000) { //$8000-ffff - return Mapper::prg_read(prg_addr(addr)); - } - - return cpu.mdr(); -} - -void MMC3::prg_write(unsigned addr, uint8 data) { - if((addr & 0xe000) == 0x6000) { //$6000-7fff - if(prg_ram_enable && prg_ram_write_protect == false) { - prg_ram[addr & 0x1fff] = data; - } - } - - switch(addr & 0xe001) { - case 0x8000: - bank_select = data & 0xc7; - break; - - case 0x8001: - switch(bank_select & 7) { - case 0: chr_bank[0] = data & ~1; break; - case 1: chr_bank[1] = data & ~1; break; - case 2: chr_bank[2] = data; break; - case 3: chr_bank[3] = data; break; - case 4: chr_bank[4] = data; break; - case 5: chr_bank[5] = data; break; - case 6: prg_bank[0] = data & 0x3f; break; - case 7: prg_bank[1] = data & 0x3f; break; - } - break; - - case 0xa000: - mirror_select = data & 0x01; - break; - - case 0xa001: - prg_ram_enable = data & 0x80; - prg_ram_write_protect = data & 0x40; - break; - - case 0xc000: - irq_latch = data; - break; - - case 0xc001: - irq_counter = 0; - break; - - case 0xe000: - irq_enable = false; - irq_line = 0; - cpu.set_irq_line(irq_line); - break; - - case 0xe001: - irq_enable = true; - break; - } -} - -unsigned MMC3::chr_addr(uint16 addr) { - if((bank_select & 0x80) == 0) { - if(addr <= 0x07ff) return (chr_bank[0] << 10) | (addr & 0x07ff); - if(addr <= 0x0fff) return (chr_bank[1] << 10) | (addr & 0x07ff); - if(addr <= 0x13ff) return (chr_bank[2] << 10) | (addr & 0x03ff); - if(addr <= 0x17ff) return (chr_bank[3] << 10) | (addr & 0x03ff); - if(addr <= 0x1bff) return (chr_bank[4] << 10) | (addr & 0x03ff); - if(addr <= 0x1fff) return (chr_bank[5] << 10) | (addr & 0x03ff); - } - - if((bank_select & 0x80) != 0) { - if(addr <= 0x03ff) return (chr_bank[2] << 10) | (addr & 0x03ff); - if(addr <= 0x07ff) return (chr_bank[3] << 10) | (addr & 0x03ff); - if(addr <= 0x0bff) return (chr_bank[4] << 10) | (addr & 0x03ff); - if(addr <= 0x0fff) return (chr_bank[5] << 10) | (addr & 0x03ff); - if(addr <= 0x17ff) return (chr_bank[0] << 10) | (addr & 0x07ff); - if(addr <= 0x1fff) return (chr_bank[1] << 10) | (addr & 0x07ff); - } - - throw; -} - -uint8 MMC3::chr_read(unsigned addr) { - irq_test(addr); - if(addr & 0x2000) return ppu.ciram_read(ciram_addr(addr)); - return Mapper::chr_read(chr_addr(addr)); -} - -void MMC3::chr_write(unsigned addr, uint8 data) { - irq_test(addr); - if(addr & 0x2000) return ppu.ciram_write(ciram_addr(addr), data); - return Mapper::chr_write(chr_addr(addr), data); -} - -unsigned MMC3::ciram_addr(uint13 addr) { - if(mirror_select == 0) return ((addr & 0x0400) >> 0) | (addr & 0x03ff); - if(mirror_select == 1) return ((addr & 0x0800) >> 1) | (addr & 0x03ff); - throw; -} - -unsigned MMC3::ram_size() { - return 8192u; -} - -uint8* MMC3::ram_data() { - return prg_ram; -} - -void MMC3::power() { - reset(); -} - -void MMC3::reset() { - bank_select = 0; - - prg_bank[0] = 0; - prg_bank[1] = 0; - - chr_bank[0] = 0; - chr_bank[1] = 0; - chr_bank[2] = 0; - chr_bank[3] = 0; - chr_bank[4] = 0; - chr_bank[5] = 0; - - mirror_select = 0; - prg_ram_enable = 1; - prg_ram_write_protect = 0; - - irq_latch = 0x00; - irq_counter = 0x00; - irq_enable = false; - irq_delay = 0; - irq_line = 0; - - chr_abus = 0; -} - -void MMC3::serialize(serializer &s) { - s.array(prg_ram); - - s.integer(bank_select); - s.array(prg_bank); - s.array(chr_bank); - s.integer(mirror_select); - s.integer(prg_ram_enable); - s.integer(prg_ram_write_protect); - s.integer(irq_latch); - s.integer(irq_counter); - s.integer(irq_enable); - s.integer(irq_delay); - s.integer(irq_line); - - s.integer(chr_abus); -} diff --git a/bsnes/nes/mapper/mmc3/mmc3.hpp b/bsnes/nes/mapper/mmc3/mmc3.hpp deleted file mode 100755 index d6394ff6..00000000 --- a/bsnes/nes/mapper/mmc3/mmc3.hpp +++ /dev/null @@ -1,41 +0,0 @@ -struct MMC3 : Mapper { - void main(); - - uint8 prg_read(unsigned addr); - void prg_write(unsigned addr, uint8 data); - - uint8 chr_read(unsigned addr); - void chr_write(unsigned addr, uint8 data); - - unsigned ram_size(); - uint8* ram_data(); - - void power(); - void reset(); - - void serialize(serializer&); - -private: - uint8 prg_ram[8192]; - - uint8 bank_select; - uint8 prg_bank[2]; - uint8 chr_bank[6]; - bool mirror_select; - bool prg_ram_enable; - bool prg_ram_write_protect; - uint8 irq_latch; - uint8 irq_counter; - bool irq_enable; - unsigned irq_delay; - bool irq_line; - - uint16 chr_abus; - - void irq_test(uint16 addr); - unsigned prg_addr(uint16 addr); - unsigned chr_addr(uint16 addr); - unsigned ciram_addr(uint13 addr); -}; - -extern MMC3 mmc3; diff --git a/bsnes/nes/mapper/none/none.cpp b/bsnes/nes/mapper/none/none.cpp deleted file mode 100755 index a675da33..00000000 --- a/bsnes/nes/mapper/none/none.cpp +++ /dev/null @@ -1,34 +0,0 @@ -None none; - -uint8 None::prg_read(unsigned addr) { - if(addr & 0x8000) return Mapper::prg_read(addr); - return cpu.mdr(); -} - -void None::prg_write(unsigned addr, uint8 data) { -} - -uint8 None::chr_read(unsigned addr) { - if(addr & 0x2000) { - if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.ciram_read(addr & 0x07ff); - } - return Mapper::chr_read(addr); -} - -void None::chr_write(unsigned addr, uint8 data) { - if(addr & 0x2000) { - if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.ciram_write(addr & 0x07ff, data); - } - return Mapper::chr_write(addr, data); -} - -void None::power() { -} - -void None::reset() { -} - -void None::serialize(serializer &s) { -} diff --git a/bsnes/nes/mapper/none/none.hpp b/bsnes/nes/mapper/none/none.hpp deleted file mode 100755 index 957e501c..00000000 --- a/bsnes/nes/mapper/none/none.hpp +++ /dev/null @@ -1,14 +0,0 @@ -struct None : Mapper { - uint8 prg_read(unsigned addr); - void prg_write(unsigned addr, uint8 data); - - uint8 chr_read(unsigned addr); - void chr_write(unsigned addr, uint8 data); - - void power(); - void reset(); - - void serialize(serializer&); -}; - -extern None none; diff --git a/bsnes/nes/mapper/uorom/uorom.cpp b/bsnes/nes/mapper/uorom/uorom.cpp deleted file mode 100755 index 65d9f5a0..00000000 --- a/bsnes/nes/mapper/uorom/uorom.cpp +++ /dev/null @@ -1,45 +0,0 @@ -UOROM uorom; - -uint8 UOROM::prg_read(unsigned addr) { - if((addr & 0xc000) == 0x8000) { - return Mapper::prg_read((prg_bank << 14) | (addr & 0x3fff)); - } - - if((addr & 0xc000) == 0xc000) { - return Mapper::prg_read((0x0f << 14) | (addr & 0x3fff)); - } -} - -void UOROM::prg_write(unsigned addr, uint8 data) { - if(addr & 0x8000) prg_bank = data & 0x0f; -} - -uint8 UOROM::chr_read(unsigned addr) { - if(addr & 0x2000) { - if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.ciram_read(addr); - } - - return Mapper::chr_read(addr); -} - -void UOROM::chr_write(unsigned addr, uint8 data) { - if(addr & 0x2000) { - if(cartridge.mirroring == 0) addr = ((addr & 0x0800) >> 1) | (addr & 0x03ff); - return ppu.ciram_write(addr, data); - } - - return Mapper::chr_write(addr, data); -} - -void UOROM::power() { - reset(); -} - -void UOROM::reset() { - prg_bank = 0; -} - -void UOROM::serialize(serializer &s) { - s.integer(prg_bank); -} diff --git a/bsnes/nes/mapper/uorom/uorom.hpp b/bsnes/nes/mapper/uorom/uorom.hpp deleted file mode 100755 index 1c36c039..00000000 --- a/bsnes/nes/mapper/uorom/uorom.hpp +++ /dev/null @@ -1,17 +0,0 @@ -struct UOROM : Mapper { - uint8 prg_read(unsigned addr); - void prg_write(unsigned addr, uint8 data); - - uint8 chr_read(unsigned addr); - void chr_write(unsigned addr, uint8 data); - - void power(); - void reset(); - - void serialize(serializer&); - -private: - uint4 prg_bank; -}; - -extern UOROM uorom; diff --git a/bsnes/nes/mapper/vrc6/vrc6.hpp b/bsnes/nes/mapper/vrc6/vrc6.hpp deleted file mode 100755 index 395b52f6..00000000 --- a/bsnes/nes/mapper/vrc6/vrc6.hpp +++ /dev/null @@ -1,69 +0,0 @@ -struct VRC6 : Mapper { - void main(); - - uint8 prg_read(unsigned addr); - void prg_write(unsigned addr, uint8 data); - - uint8 chr_read(unsigned addr); - void chr_write(unsigned addr, uint8 data); - - unsigned ram_size(); - uint8* ram_data(); - - void power(); - void reset(); - - void serialize(serializer&); - -//privileged: - bool abus_swap; - -private: - uint8 prg_ram[8192]; - - uint8 prg_bank[2]; - uint8 chr_bank[8]; - uint2 mirror_select; - uint8 irq_latch; - bool irq_mode; - bool irq_enable; - bool irq_acknowledge; - - uint8 irq_counter; - signed irq_scalar; - bool irq_line; - - struct Pulse { - bool mode; - uint3 duty; - uint4 volume; - bool enable; - uint12 frequency; - - uint12 divider; - uint4 cycle; - uint4 output; - - void clock(); - void serialize(serializer&); - } pulse1, pulse2; - - struct Sawtooth { - uint6 rate; - bool enable; - uint12 frequency; - - uint12 divider; - uint1 phase; - uint3 stage; - uint8 accumulator; - uint5 output; - - void clock(); - void serialize(serializer&); - } sawtooth; - - unsigned ciram_addr(unsigned addr) const; -}; - -extern VRC6 vrc6; diff --git a/bsnes/ui/general/main-window.cpp b/bsnes/ui/general/main-window.cpp index e4b8e31d..c9f5ec73 100755 --- a/bsnes/ui/general/main-window.cpp +++ b/bsnes/ui/general/main-window.cpp @@ -326,7 +326,7 @@ void MainWindow::synchronize() { void MainWindow::setupVideoFilters() { lstring files = directory::files({ application->basepath, "filters/" }, "*.filter"); - if(files.size() == 0) directory::files({ application->userpath, "filters/" }, "*.filter"); + if(files.size() == 0) files = directory::files({ application->userpath, "filters/" }, "*.filter"); reference_array group; settingsVideoFilterList = new RadioItem[files.size()]; diff --git a/bsnes/ui/interface/interface.cpp b/bsnes/ui/interface/interface.cpp index fde7d33f..a42ae023 100755 --- a/bsnes/ui/interface/interface.cpp +++ b/bsnes/ui/interface/interface.cpp @@ -44,7 +44,7 @@ void Interface::setController(unsigned port, unsigned device) { } void Interface::updateDSP() { - dspaudio.setVolume((double)config->audio.volume / 100.0); + dspaudio.setVolume(config->audio.mute == false ? (double)config->audio.volume / 100.0 : 0.0); switch(mode()) { case Mode::NES: return dspaudio.setFrequency(config->audio.frequencyNES); case Mode::SNES: return dspaudio.setFrequency(config->audio.frequencySNES); diff --git a/bsnes/ui/main.cpp b/bsnes/ui/main.cpp index b227de8d..b331f1f8 100755 --- a/bsnes/ui/main.cpp +++ b/bsnes/ui/main.cpp @@ -49,7 +49,7 @@ Application::Application(int argc, char **argv) { inputManager = new InputManager; utility = new Utility; - title = "bsnes v082.26"; + title = "bsnes v082.27"; string fontFamily = Intrinsics::platform() == Intrinsics::Platform::Windows ? "Tahoma, " : "Sans, "; normalFont = { fontFamily, "8" }; diff --git a/bsnes/ui/tools/cheat-editor.cpp b/bsnes/ui/tools/cheat-editor.cpp index 9a517659..a65d789d 100755 --- a/bsnes/ui/tools/cheat-editor.cpp +++ b/bsnes/ui/tools/cheat-editor.cpp @@ -161,11 +161,11 @@ bool CheatEditor::save(const string &filename) { file fp; if(fp.open(filename, file::mode::write) == false) return false; - fp.print("cartridge sha256=", interface->sha256(), "\n"); + fp.print("cartridge sha256=`", interface->sha256(), "`\n"); for(unsigned n = 0; n <= lastSave; n++) { fp.print(" cheat", cheatList.checked(n) ? " enable" : "", "\n"); - fp.print(" description=|", cheatText[n][Desc], "|\n"); - fp.print(" code=|", cheatText[n][Code], "|\n"); + fp.print(" description=`", string{cheatText[n][Desc]}.transform("`", "'"), "`\n"); + fp.print(" code=`", string{cheatText[n][Code]}.transform("`", "'"), "`\n"); } fp.close();