I have this function
uint8_t ROM::read(uint16_t addr)
{
uint16_t mapped_addr = 0;
mapper->CPUread(addr, mapped_addr);
return prg_rom[mapped_addr];
}
inside my ROM class. When this function is called and accesses the CPUread function of the mapper. The mapper's values change. However, when call the mapper CPUread from outside the ROM class, it works as expected.
ROM rom("nestest.nes");
uint16_t mapped_addr = 0;
rom.mapper->CPUread(0xC010, mapped_addr);
Calling it like this(below) does not work, (EDIT: it assigns random values to prg_banks and chr_banks
ROM rom("nestest.nes");
rom.read(0xC010);
ROM.cpp
#include "ROM.h"
ROM::ROM(std::string filename)
{
std::ifstream file;
file.open(filename, std::ifstream::binary);
if (file.is_open())
{
//Read and store nes file header
file.read((char*)&header, sizeof(HEADER));
//Determine mapper ID
mapper_id = (header.flag_7 & 0xF0) | ((header.flag_6 & 0xF0) >> 4);
//Determine if rom contains trainer
if (header.flag_6 & 0x40)
{
file.seekg(512, std::ios_base::cur);
}
//Read and store prg rom data
prg_rom = (uint8_t*)malloc(header.prg_blocks * 16384);
file.read((char*)prg_rom, header.prg_blocks * 16384);
//Read and store chr rom data
chr_rom = (uint8_t*)malloc(header.chr_blocks * 8192);
file.read((char*)chr_rom, header.chr_blocks * 8192);
switch (mapper_id)
{
case 0x00:
mapper = &Mapper_000(header.prg_blocks, header.chr_blocks);
break;
default:
break;
}
}
else
{
std::cout << "Could not open file: " << filename << std::endl;
}
file.close();
}
uint8_t ROM::read(uint16_t addr)
{
uint16_t mapped_addr = 0;
mapper->CPUread(addr, mapped_addr);
return prg_rom[mapped_addr];
}
ROM.h
#pragma once
#include <cstdint>
#include <array>
#include <fstream>
#include <iostream>
#include <string>
#include "Mapper.h"
#include "Mapper_000.h"
class ROM
{
public:
uint8_t* prg_rom = nullptr;
uint8_t* chr_rom = nullptr;
uint8_t mapper_id = 0;
Mapper* mapper = nullptr;
struct HEADER
{
char constant[4]; //0-3: Constant $4E $45 $53 $1A ("NES" followed by MS-DOS end-of-file)
uint8_t prg_blocks; //Size of PRG ROM in 16 KB units
uint8_t chr_blocks; //Size of CHR ROM in 8 KB units (Value 0 means the board uses CHR RAM)
uint8_t flag_6; //Mapper, mirroring, battery, trainer
uint8_t flag_7; //Mapper, VS/Playchoice, NES 2.0
uint8_t flag_8; //PRG-RAM size (rarely used extension)
uint8_t flag_9; //TV system (rarely used extension)
uint8_t flag_10; //TV system, PRG-RAM presence (unofficial, rarely used extension)
uint8_t unused[5]; //Unused padding (should be filled with zero, but some rippers put their name across bytes 7-15)
} header;
public:
ROM(std::string filename);
uint8_t read(uint16_t addr);
};
Mapper.h
#pragma once
#include <cstdint>
class Mapper
{
protected:
uint8_t prg_banks = 0;
uint8_t chr_banks = 0;
public:
Mapper(uint8_t prgBanks, uint8_t chrBanks)
{
prg_banks = prgBanks;
chr_banks = chrBanks;
}
virtual void CPUread(uint16_t addr, uint16_t &mapped_addr) = 0;
virtual void CPUwrite(uint16_t addr, uint16_t &mapped_addr) = 0;
};
Mapper_000.h
#pragma once
#include <cstdint>
#include "Mapper.h"
class Mapper_000 : public Mapper
{
public:
//Constructor
Mapper_000(uint8_t prgBanks, uint8_t chrBanks) : Mapper(prgBanks, chrBanks)
{
}
//Read & write
void CPUread(uint16_t addr, uint16_t& mapped_addr);
void CPUwrite(uint16_t addr, uint16_t& mapped_addr);
};
Mapper_000.cpp
#include <cstdint>
#include "Mapper_000.h"
//Read & Write
void Mapper_000::CPUread(uint16_t addr, uint16_t& mapped_addr)
{
if (addr >= 0x8000 && addr <= 0xFFFF)
{
if (prg_banks > 1)
{
mapped_addr = addr & 0x7FFF;
}
else
{
mapped_addr = addr & 0x3FFF;
}
}
}
void Mapper_000::CPUwrite(uint16_t addr, uint16_t& mapped_addr)
{
if (addr >= 0x8000 && addr <= 0xFFFF)
{
if (prg_banks > 1)
{
mapped_addr = addr & 0x7FFF;
}
else
{
mapped_addr = addr & 0x3FFF;
}
}
}