diff --git a/src/nes/cartridge/mapper.cc b/src/nes/cartridge/mapper.cc index 52a1bec..0f83196 100644 --- a/src/nes/cartridge/mapper.cc +++ b/src/nes/cartridge/mapper.cc @@ -98,6 +98,7 @@ Mapper::Mapper( #include "mappers/mapper_004.h" #include "mappers/mapper_007.h" #include "mappers/mapper_009.h" +#include "mappers/mapper_474.h" Mapper* Mapper::Factory(const ROM_File* rom_file) { if (rom_file == nullptr) @@ -111,6 +112,7 @@ Mapper* Mapper::Factory(const ROM_File* rom_file) { case 4: return new Mapper_004(*rom_file); case 7: return new Mapper_007(*rom_file); case 9: return new Mapper_009(*rom_file); + case 474: return new Mapper_474(*rom_file); } return nullptr; diff --git a/src/nes/cartridge/mappers/mapper_474.cc b/src/nes/cartridge/mappers/mapper_474.cc new file mode 100644 index 0000000..57e55a9 --- /dev/null +++ b/src/nes/cartridge/mappers/mapper_474.cc @@ -0,0 +1,52 @@ +#include "mapper_474.h" + +#include +#include + +Mapper_474::Mapper_474(const ROM_File& rom_file) + : Mapper(474, "NROM-383", rom_file, 0x4000, 0x2000) + , prg_ram(0x2000) +{ + this->mirror_mode = rom_file.meta.mirror_mode; + this->has_battery = rom_file.meta.has_battery; +} + +// reading has no side-effects +u8 Mapper_474::read(u16 addr) { return this->peek(addr); } +u8 Mapper_474::peek(u16 addr) const { + // Wired to the PPU MMU + if (in_range(addr, 0x0000, 0x1FFF)) return this->chr_mem->peek(addr); + + // Wired to the CPU MMU + + // submapper 3 has_battery must be true + if (in_range(addr, 0x4020, 0x5FFF)) return this->has_battery ? + this->prg_ram.peek(addr - 0x4000) : + this->prg_extra->peek(addr - 0x4000); + if (in_range(addr, 0x6000, 0x7FFF)) return this->prg_extra->peek(addr - 0x4000); + if (in_range(addr, 0x8000, 0xBFFF)) return this->prg_lo->peek(addr - 0x8000); + if (in_range(addr, 0xC000, 0xFFFF)) return this->prg_hi->peek(addr - 0xC000); + + assert(false); + return 0; +} + +void Mapper_474::write(u16 addr, u8 val) { + // Since there is potentially CHR RAM, try to write to it (if in range) + if (in_range(addr, 0x0000, 0x1FFF)) { + this->chr_mem->write(addr, val); + } + else if (in_range(addr, 0x4020, 0x5FFF)) { + if (this->has_battery) { + this->prg_ram.write(addr - 0x4000, val); + } + } +} + +void Mapper_474::update_banks() { + this->prg_extra = &this->get_prg_bank(0); + this->prg_lo = &this->get_prg_bank(1); + this->prg_hi = &this->get_prg_bank(2); + + this->chr_mem = &this->get_chr_bank(0); +} diff --git a/src/nes/cartridge/mappers/mapper_474.h b/src/nes/cartridge/mappers/mapper_474.h new file mode 100644 index 0000000..04e6076 --- /dev/null +++ b/src/nes/cartridge/mappers/mapper_474.h @@ -0,0 +1,45 @@ +#pragma once + +#include "nes/generic/ram/ram.h" +#include "nes/generic/rom/rom.h" +#include "common/util.h" +#include "../mapper.h" + +#include "common/serializable.h" + +// https://www.nesdev.org/wiki/NES_2.0_Mapper_474 +class Mapper_474 final : public Mapper { +private: + // CPU Memory Space + RAM prg_ram; // 0x4020 ... 0x5FFF - Fixed RAM (only submapper 3) + ROM* prg_extra; // 0x4020 ... 0x7FFF - Fixed + ROM* prg_lo; // 0x8000 ... 0xBFFF - Fixed + ROM* prg_hi; // 0xC000 ... 0xFFFF - Fixed + + // PPU Memory Space + Memory* chr_mem; // 0x0000 ... 0x1FFF - Fixed + + Mirroring::Type mirror_mode; + bool has_battery; + + SERIALIZE_PARENT(Mapper) + SERIALIZE_START(1, "Mapper_474") + SERIALIZE_POD(mirror_mode) + SERIALIZE_END(1) + + void update_banks() override; + + // Nothing to reset... + void reset() override {} + +public: + Mapper_474(const ROM_File& rom_file); + + // + u8 read(u16 addr) override; + u8 peek(u16 addr) const override; + void write(u16 addr, u8 val) override; + // + + Mirroring::Type mirroring() const override { return this->mirror_mode; }; +}; diff --git a/src/nes/cartridge/parse_rom.cc b/src/nes/cartridge/parse_rom.cc index e84fd53..d4b2b09 100644 --- a/src/nes/cartridge/parse_rom.cc +++ b/src/nes/cartridge/parse_rom.cc @@ -79,7 +79,14 @@ static ROM_File* parseROM_iNES(const u8* data, uint data_len) { if (rf->meta.is_VS) fprintf(stderr, "[File Parsing][iNES] This is a VS ROM\n"); - rf->meta.mapper = data[6] >> 4 | (data[7] & 0xFF00); + if (is_NES2) + { + rf->meta.mapper = data[6] >> 4 | (data[7] & 0xF0) | ((data[8] & 0xF) << 8); + } + else + { + rf->meta.mapper = data[6] >> 4 | (data[7] & 0xF0); + } fprintf(stderr, "[File Parsing][iNES] Mapper: %d\n", rf->meta.mapper); diff --git a/src/nes/cartridge/rom_file.h b/src/nes/cartridge/rom_file.h index 27cc89b..66f4380 100644 --- a/src/nes/cartridge/rom_file.h +++ b/src/nes/cartridge/rom_file.h @@ -14,7 +14,7 @@ struct ROM_File { struct { // ROM metadata Mirroring::Type mirror_mode; - u8 mapper; + u16 mapper; bool has_battery; // Has battery backed SRAM at 0x6000 - 0x7FFF bool has_trainer; // Has 512 byte trainer at 0x7000 - 0x71FF