nes/src/Cartridge.cpp
2025-08-06 13:23:17 +03:00

91 lines
2.7 KiB
C++

//
// Created by Selim Mustafaev on 09.08.2023.
//
#include "Cartridge.h"
#include "Mapper/Mapper0.h"
#include "Mapper/Mapper1.h"
#include <fstream>
#include <iostream>
#include <memory>
#include <cstddef>
namespace nes {
Cartridge::Cartridge(const fs::path &path) {
auto romSize = fs::file_size(path);
_romData = std::make_unique<uint8_t[]>(romSize);
std::ifstream rom(path, std::ios::binary);
rom.read(reinterpret_cast<char*>(_romData.get()), static_cast<std::streamsize>(romSize));
_header = reinterpret_cast<RomHeader*>(_romData.get());
if (memcmp(_header->magic, ROM_MAGIC, sizeof(ROM_MAGIC)) != 0) {
throw std::runtime_error("Wrong ROM magic");
}
const size_t prgSize = _header->prgChunks*PRG_CHUNK_SIZE;
const size_t chrSize = _header->chrChunks*CHR_CHUNK_SIZE;
_prgRom = std::span(_romData.get() + sizeof(RomHeader), prgSize);
if (chrSize == 0) {
_chrRam = std::make_unique<uint8_t[]>(CHR_CHUNK_SIZE);
_chrRom = std::span(_chrRam.get(), CHR_CHUNK_SIZE);
} else {
_chrRom = std::span(_romData.get() + sizeof(RomHeader) + prgSize, chrSize);
}
uint8_t mapper = _header->flags.mapper | (_header->flags2.upperMapper << 4);
switch (mapper) {
case 0:
_mapper = std::make_unique<Mapper0>(_header->prgChunks, _header->chrChunks);
break;
case 1:
_mapper = std::make_unique<Mapper1>(_header->prgChunks, _header->chrChunks);
break;
default:
throw std::runtime_error("unknown mapper");
}
if (const auto ramSize = _mapper->ramSize(); ramSize > 0) {
_ram = std::make_unique<uint8_t[]>(ramSize);
}
}
uint8_t Cartridge::readPrg(uint16_t address) {
uint32_t mappedAddress = _mapper->mapPrg(address);
return _prgRom[mappedAddress];
}
void Cartridge::writePrg(uint16_t address, uint8_t value) {
_mapper->write(address, value);
}
uint8_t Cartridge::readChr(uint16_t address) {
uint32_t mappedAddress = _mapper->mapChr(address);
return _chrRom[mappedAddress];
}
void Cartridge::writeChr(uint16_t address, uint8_t value) {
_chrRom[address] = value;
}
uint8_t Cartridge::readRam(uint16_t address) {
uint32_t mappedAddress = _mapper->mapRam(address);
return _ram[mappedAddress];
}
void Cartridge::writeRam(uint16_t address, uint8_t value) {
uint32_t mappedAddress = _mapper->mapRam(address);
_ram[mappedAddress] = value;
}
Cartridge::Mirroring Cartridge::mirroring() const {
return _header->flags.mirroring;
}
}