diff options
Diffstat (limited to 'lib/nes/mapper.cc')
| -rw-r--r-- | lib/nes/mapper.cc | 252 |
1 files changed, 145 insertions, 107 deletions
diff --git a/lib/nes/mapper.cc b/lib/nes/mapper.cc index ad9ec40..40d11f8 100644 --- a/lib/nes/mapper.cc +++ b/lib/nes/mapper.cc @@ -1,134 +1,172 @@ #include "nes/mapper.hh" #include "nes/cartridge.hh" -#include <iostream> namespace nes { - mapper::mapper( - cartridge& cartridge, - read_cpu_func const read_cpu, write_cpu_func const write_cpu, - read_ppu_func const read_ppu, write_ppu_func const write_ppu) - : cartridge_{ cartridge } - , read_cpu_{ read_cpu } - , write_cpu_{ write_cpu } - , read_ppu_{ read_ppu } - , write_ppu_{ write_ppu } + namespace { - } + // ------------------------------------------------------------------------------------------------------------- + // NROM + // ------------------------------------------------------------------------------------------------------------- - auto mapper::select(cartridge& cartridge) -> mapper - { - switch (cartridge.get_mapper_number()) + class mapper_nrom final : public mapper { - case 0x00: - return mapper{ - cartridge, - &mapper::nrom_read_cpu, &mapper::nrom_write_cpu, - &mapper::nrom_read_ppu, &mapper::nrom_write_ppu }; - default: - std::cerr << "Mapper not implemented: " << std::hex << cartridge.get_mapper_number() << std::endl; - std::abort(); - } - } + public: + explicit mapper_nrom() = default; - // ----------------------------------------------------------------------------------------------------------------- - // NROM - // ----------------------------------------------------------------------------------------------------------------- + auto validate(cartridge& cartridge) -> status override + { + if (cartridge.get_ram_length() != 0x2000) + { + return status::error_invalid_ines_data; + } - auto mapper::nrom_read_cpu(address const addr) -> std::uint8_t - { - 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; - if (rel >= cartridge_.get_prg_rom_length()) { return 0x0; } + if (cartridge.get_prg_rom_length() != 0x4000 && cartridge.get_prg_rom_length() != 0x8000) + { + return status::error_invalid_ines_data; + } - 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; } - if (rel >= cartridge_.get_prg_rom_length()) { return 0x0; } + if (cartridge.get_chr_rom_length() != 0x2000) + { + return status::error_invalid_ines_data; + } - return cartridge_.get_prg_rom()[rel]; - } + return status::success; + } - return 0x0; - } + 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]; + } - auto mapper::nrom_write_cpu(address const addr, std::uint8_t const value) -> void - { - if (addr <= address{ 0x5FFF }) - { - return; - } - if (addr <= address{ 0x7FFF }) - { - cartridge_.get_ram_mut()[addr.get_absolute() - 0x6000] = value; - return; - } - } + return 0x0; + } - auto mapper::nrom_read_ppu(address const addr, std::uint8_t const* vram) -> std::uint8_t - { - if (addr <= address{ 0x1FFF }) - { - auto const rel = addr.get_absolute(); - if (rel >= cartridge_.get_chr_rom_length()) { 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; + } + } - return cartridge_.get_chr_rom()[rel]; - } - if (addr <= address{ 0x3EFF }) + 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 { - return vram[nrom_mirrored_vram_address(addr)]; - } + public: + explicit mapper_invalid() = default; - return 0x0; - } + 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 - auto mapper::nrom_write_ppu(address const addr, std::uint8_t* vram, std::uint8_t const value) -> void + // ----------------------------------------------------------------------------------------------------------------- + // Selection + // ----------------------------------------------------------------------------------------------------------------- + + auto mapper::invalid() -> mapper& { - if (addr <= address{ 0x1FFF }) - { - return; - } - if (addr <= address{ 0x3EFF }) - { - vram[nrom_mirrored_vram_address(addr)] = value; - return; - } + static auto instance = mapper_invalid{}; + return instance; } - auto mapper::nrom_mirrored_vram_address(address const addr) const -> unsigned + auto mapper::get(std::uint8_t const number) -> mapper& { - auto const rel = addr.get_absolute() % 0x1000u; - - switch (cartridge_.get_name_table_arrangement()) + switch (number) { - 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; + case 0x00: + { + static auto instance = mapper_nrom{}; + return instance; + } + default: + { + return invalid(); + } } - - return 0; } } // namespace nes
\ No newline at end of file |
