diff options
| author | Hannes Schulze <haschu0103@outlook.de> | 2025-01-23 22:10:55 +0100 |
|---|---|---|
| committer | Hannes Schulze <haschu0103@outlook.de> | 2025-01-23 22:10:55 +0100 |
| commit | 0f24863561b7c609395b59ab73e634509d3111d8 (patch) | |
| tree | b89c6a8db88f0c1c8c55d41d733b6cfa566a08f4 /lib/nes/ref/mapper.cc | |
| parent | b1d1573702f21e3104606d6ade5f5d39ec86a33a (diff) | |
copy reference implementation
Diffstat (limited to 'lib/nes/ref/mapper.cc')
| -rw-r--r-- | lib/nes/ref/mapper.cc | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/lib/nes/ref/mapper.cc b/lib/nes/ref/mapper.cc new file mode 100644 index 0000000..7e4cffe --- /dev/null +++ b/lib/nes/ref/mapper.cc @@ -0,0 +1,134 @@ +#include "nes/ref/mapper.hh" +#include "nes/ref/cartridge.hh" +#include <iostream> + +namespace nes::ref +{ + 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 } + { + } + + auto mapper::select(cartridge& cartridge) -> mapper + { + switch (cartridge.get_mapper_number()) + { + 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(); + } + } + + // ----------------------------------------------------------------------------------------------------------------- + // NROM + // ----------------------------------------------------------------------------------------------------------------- + + 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() - 0x8000; + if (rel >= cartridge_.get_prg_rom_length()) { return 0x0; } + + return cartridge_.get_prg_rom()[rel]; + } + if (addr <= address{ 0xFFFF }) + { + auto rel = addr.get_absolute() - 0xC000; + if (cartridge_.get_prg_rom_length() > 0x4000) { rel += 0x4000; } + if (rel >= cartridge_.get_prg_rom_length()) { return 0x0; } + + return cartridge_.get_prg_rom()[rel]; + } + + return 0x0; + } + + 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; + } + } + + 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; } + + return cartridge_.get_chr_rom()[rel]; + } + if (addr <= address{ 0x3EFF }) + { + return vram[nrom_mirrored_vram_address(addr)]; + } + + return 0x0; + } + + auto mapper::nrom_write_ppu(address const addr, std::uint8_t* vram, std::uint8_t const value) -> void + { + if (addr <= address{ 0x1FFF }) + { + return; + } + if (addr <= address{ 0x3EFF }) + { + vram[nrom_mirrored_vram_address(addr)] = value; + return; + } + } + + auto mapper::nrom_mirrored_vram_address(address const addr) const -> unsigned + { + auto const rel = addr.get_absolute() % 0x1000; + + switch (cartridge_.get_name_table_arrangement()) + { + case name_table_arrangement::horizontal: + // $2000 = $2400, $2800 = $2c00 + if (rel <= 0x3FF) { return 0x000 + (rel % 0x400); } + if (rel <= 0x7FF) { return 0x000 + (rel % 0x400); } + if (rel <= 0xBFF) { return 0x400 + (rel % 0x400); } + if (rel <= 0xFFF) { return 0x400 + (rel % 0x400); } + break; + case name_table_arrangement::vertical: + // $2000 = $2800, $2400 = $2c00 + if (rel <= 0x3FF) { return 0x000 + (rel % 0x400); } + if (rel <= 0x7FF) { return 0x400 + (rel % 0x400); } + if (rel <= 0xBFF) { return 0x000 + (rel % 0x400); } + if (rel <= 0xFFF) { return 0x400 + (rel % 0x400); } + break; + } + + return 0; + } +} // namespace nes::ref
\ No newline at end of file |
