diff options
Diffstat (limited to 'lib/nes/sys/mapper.cc')
| -rw-r--r-- | lib/nes/sys/mapper.cc | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/lib/nes/sys/mapper.cc b/lib/nes/sys/mapper.cc new file mode 100644 index 0000000..4951966 --- /dev/null +++ b/lib/nes/sys/mapper.cc @@ -0,0 +1,172 @@ +#include "nes/sys/mapper.hh" +#include "nes/sys/cartridge.hh" + +namespace nes +{ + namespace + { + // ------------------------------------------------------------------------------------------------------------- + // NROM + // ------------------------------------------------------------------------------------------------------------- + + class mapper_nrom final : public mapper + { + public: + explicit mapper_nrom() = default; + + auto validate(cartridge& cartridge) -> status override + { + if (cartridge.get_ram_length() != 0x2000) + { + return status::error_invalid_ines_data; + } + + if (cartridge.get_prg_rom_length() != 0x4000 && cartridge.get_prg_rom_length() != 0x8000) + { + return status::error_invalid_ines_data; + } + + if (cartridge.get_chr_rom_length() != 0x2000) + { + return status::error_invalid_ines_data; + } + + return status::success; + } + + auto read_cpu(address const addr, cartridge& cartridge) -> std::uint8_t override + { + if (addr <= address{ 0x5FFF }) + { + return 0x0; + } + if (addr <= address{ 0x7FFF }) + { + return cartridge.get_ram()[addr.get_absolute() - 0x6000]; + } + if (addr <= address{ 0xBFFF }) + { + auto const rel = addr.get_absolute() - 0x8000u; + return cartridge.get_prg_rom()[rel]; + } + if (addr <= address{ 0xFFFF }) + { + auto rel = addr.get_absolute() - 0xC000u; + if (cartridge.get_prg_rom_length() > 0x4000) { rel += 0x4000; } + return cartridge.get_prg_rom()[rel]; + } + + return 0x0; + } + + auto write_cpu(address const addr, std::uint8_t const value, cartridge& cartridge) -> void override + { + if (addr <= address{ 0x5FFF }) + { + return; + } + if (addr <= address{ 0x7FFF }) + { + cartridge.get_ram_mut()[addr.get_absolute() - 0x6000] = value; + return; + } + } + + auto read_ppu(address const addr, cartridge& cartridge, std::uint8_t const* vram) -> std::uint8_t override + { + if (addr <= address{ 0x1FFF }) + { + auto const rel = addr.get_absolute(); + return cartridge.get_chr_rom()[rel]; + } + if (addr <= address{ 0x3EFF }) + { + return vram[mirrored_vram_address(addr, cartridge)]; + } + + return 0x0; + } + + auto write_ppu(address const addr, std::uint8_t const value, cartridge& cartridge, std::uint8_t* vram) -> void override + { + if (addr <= address{ 0x1FFF }) + { + return; + } + if (addr <= address{ 0x3EFF }) + { + vram[mirrored_vram_address(addr, cartridge)] = value; + return; + } + } + + private: + static auto mirrored_vram_address(address const addr, cartridge const& cartridge) -> unsigned + { + auto const rel = addr.get_absolute() % 0x1000u; + + switch (cartridge.get_name_table_arrangement()) + { + case name_table_arrangement::horizontal: + // $2000 = $2400, $2800 = $2c00 + if (rel <= 0x3FF) { return 0x000u + (rel % 0x400u); } + if (rel <= 0x7FF) { return 0x000u + (rel % 0x400u); } + if (rel <= 0xBFF) { return 0x400u + (rel % 0x400u); } + if (rel <= 0xFFF) { return 0x400u + (rel % 0x400u); } + break; + case name_table_arrangement::vertical: + // $2000 = $2800, $2400 = $2c00 + if (rel <= 0x3FF) { return 0x000u + (rel % 0x400u); } + if (rel <= 0x7FF) { return 0x400u + (rel % 0x400u); } + if (rel <= 0xBFF) { return 0x000u + (rel % 0x400u); } + if (rel <= 0xFFF) { return 0x400u + (rel % 0x400u); } + break; + } + + return 0; + } + }; + + // ------------------------------------------------------------------------------------------------------------- + // Invalid + // ------------------------------------------------------------------------------------------------------------- + + class mapper_invalid final : public mapper + { + public: + explicit mapper_invalid() = default; + + auto validate(cartridge&) -> status override { return status::error_unsupported_mapper; } + auto read_cpu(address, cartridge&) -> std::uint8_t override { return 0; } + auto write_cpu(address, std::uint8_t, cartridge&) -> void override {} + auto read_ppu(address, cartridge&, std::uint8_t const*) -> std::uint8_t override { return 0; } + auto write_ppu(address, std::uint8_t, cartridge&, std::uint8_t*) -> void override {} + }; + } // namespace + + // ----------------------------------------------------------------------------------------------------------------- + // Instances + // ----------------------------------------------------------------------------------------------------------------- + + auto mapper::invalid() -> mapper& + { + static auto instance = mapper_invalid{}; + return instance; + } + + auto mapper::get(std::uint8_t const number) -> mapper& + { + switch (number) + { + case 0x00: + { + static auto instance = mapper_nrom{}; + return instance; + } + default: + { + return invalid(); + } + } + } +} // namespace nes
\ No newline at end of file |
