mirror of
https://github.com/amhndu/SimpleNES.git
synced 2024-05-31 18:47:21 -04:00
Created an interface for mappers
Also implemented NROM or "no mapper"
This commit is contained in:
parent
c1af387390
commit
cdf9a4b44c
|
@ -23,7 +23,7 @@ namespace sn
|
|||
std::vector<Byte> m_PRG_ROM;
|
||||
std::vector<Byte> m_CHR_ROM;
|
||||
Byte m_nameTableMirroring;
|
||||
Byte m_mapper;
|
||||
Byte m_mapperNumber;
|
||||
bool m_extendedRAM;
|
||||
bool m_chrRAM;
|
||||
};
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace sn
|
|||
CPU m_cpu;
|
||||
PPU m_ppu;
|
||||
Cartridge m_cartridge;
|
||||
std::unique_ptr<Mapper> m_mapper;
|
||||
|
||||
Controller m_controller1;
|
||||
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
#include <vector>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include "Cartridge.h"
|
||||
#include "Mapper.h"
|
||||
|
||||
namespace sn
|
||||
{
|
||||
|
@ -28,20 +30,17 @@ namespace sn
|
|||
MainBus();
|
||||
Byte read(Address addr);
|
||||
void write(Address addr, Byte value);
|
||||
bool loadCartridge(Cartridge *cart);
|
||||
bool setMapper(Mapper* mapper);
|
||||
bool setWriteCallback(IORegisters reg, std::function<void(Byte)> callback);
|
||||
bool setReadCallback(IORegisters reg, std::function<Byte(void)> callback);
|
||||
const Byte* getPagePtr(Byte page);
|
||||
private:
|
||||
std::vector<Byte> m_RAM;
|
||||
std::vector<Byte> m_extRAM;
|
||||
Cartridge* m_cartride;
|
||||
Byte m_mapper;
|
||||
Mapper* m_mapper;
|
||||
|
||||
std::map<IORegisters, std::function<void(Byte)>> m_writeCallbacks;
|
||||
std::map<IORegisters, std::function<Byte(void)>> m_readCallbacks;
|
||||
//temporary only
|
||||
bool one_bank;
|
||||
std::map<IORegisters, std::function<Byte(void)>> m_readCallbacks;;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
52
include/Mapper.h
Normal file
52
include/Mapper.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
#ifndef MAPPER_H
|
||||
#define MAPPER_H
|
||||
#include "Cartridge.h"
|
||||
#include <memory>
|
||||
|
||||
namespace sn
|
||||
{
|
||||
enum NameTableMirroring
|
||||
{
|
||||
Horizontal = 0,
|
||||
Vertical = 1,
|
||||
FourScreen = 8,
|
||||
};
|
||||
|
||||
|
||||
class Mapper
|
||||
{
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
NROM = 0,
|
||||
MMC1 = 1,
|
||||
UxROM = 2,
|
||||
};
|
||||
|
||||
Mapper(Cartridge& cart, Type t) : m_cartridge(cart), m_type(t) {};
|
||||
virtual void writePRG (Address addr, Byte value) = 0;
|
||||
virtual Byte readPRG (Address addr) = 0;
|
||||
virtual const Byte* getPagePtr (Address addr) = 0; //for DMAs
|
||||
|
||||
virtual Byte readCHR (Address addr) = 0;
|
||||
virtual void writeCHR (Address addr, Byte value) = 0;
|
||||
|
||||
bool inline hasExtendedRAM()
|
||||
{
|
||||
return m_cartridge.hasExtendedRAM();
|
||||
}
|
||||
|
||||
NameTableMirroring inline getNameTableMirroring()
|
||||
{
|
||||
return static_cast<NameTableMirroring>(m_cartridge.getNameTableMirroring());
|
||||
}
|
||||
|
||||
static std::unique_ptr<Mapper> createMapper (Type mapper_t, Cartridge& cart);
|
||||
|
||||
protected:
|
||||
Cartridge& m_cartridge;
|
||||
Type m_type;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //MAPPER_H
|
25
include/MapperNROM.h
Normal file
25
include/MapperNROM.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef MAPPERNROM_H
|
||||
#define MAPPERNROM_H
|
||||
#include "Mapper.h"
|
||||
|
||||
namespace sn
|
||||
{
|
||||
class MapperNROM : public Mapper
|
||||
{
|
||||
public:
|
||||
MapperNROM(Cartridge& cart);
|
||||
void writePRG (Address addr, Byte value);
|
||||
Byte readPRG (Address addr);
|
||||
const Byte* getPagePtr(Address addr);
|
||||
|
||||
Byte readCHR (Address addr);
|
||||
void writeCHR (Address addr, Byte value);
|
||||
private:
|
||||
bool m_oneBank;
|
||||
bool m_usesCharacterRAM;
|
||||
|
||||
std::vector<Byte> m_characterRAM;
|
||||
|
||||
};
|
||||
}
|
||||
#endif // MAPPERNROM_H
|
|
@ -2,16 +2,10 @@
|
|||
#define PICTUREBUS_H
|
||||
#include <vector>
|
||||
#include "Cartridge.h"
|
||||
#include "Mapper.h"
|
||||
|
||||
namespace sn
|
||||
{
|
||||
enum NameTableMirroring
|
||||
{
|
||||
Horizontal = 0,
|
||||
Vertical = 1,
|
||||
FourScreen = 8,
|
||||
};
|
||||
|
||||
class PictureBus
|
||||
{
|
||||
public:
|
||||
|
@ -19,18 +13,15 @@ namespace sn
|
|||
Byte read(Address addr);
|
||||
void write(Address addr, Byte value);
|
||||
|
||||
bool loadCartridge(Cartridge *cart);
|
||||
bool setMapper(Mapper *mapper);
|
||||
Byte readPalette(Byte paletteAddr);
|
||||
private:
|
||||
std::vector<Byte> m_RAM;
|
||||
NameTableMirroring m_mirroring;
|
||||
std::size_t NameTable0, NameTable1, NameTable2, NameTable3; //indices where they start in RAM vector
|
||||
|
||||
bool m_usesCharacterRAM;
|
||||
std::vector<Byte> m_characterRAM;
|
||||
std::vector<Byte> m_palette;
|
||||
|
||||
Cartridge* m_cartride;
|
||||
Mapper* m_mapper;
|
||||
};
|
||||
}
|
||||
#endif // PICTUREBUS_H
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace sn
|
|||
{
|
||||
Cartridge::Cartridge() :
|
||||
m_nameTableMirroring(0),
|
||||
m_mapper(0),
|
||||
m_mapperNumber(0),
|
||||
m_extendedRAM(false)
|
||||
{
|
||||
|
||||
|
@ -24,7 +24,7 @@ namespace sn
|
|||
|
||||
Byte Cartridge::getMapper()
|
||||
{
|
||||
return m_mapper;
|
||||
return m_mapperNumber;
|
||||
}
|
||||
|
||||
Byte Cartridge::getNameTableMirroring()
|
||||
|
@ -42,7 +42,7 @@ namespace sn
|
|||
std::ifstream romFile (path, std::ios_base::binary | std::ios_base::in);
|
||||
if (!romFile)
|
||||
{
|
||||
LOG(Error) << "Could not open ROM file" << std::endl;
|
||||
LOG(Error) << "Could not open ROM file from path: " << path << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -81,8 +81,8 @@ namespace sn
|
|||
m_nameTableMirroring = header[6] & 0xB;
|
||||
LOG(Info) << "Name Table Mirroring: " << +m_nameTableMirroring << std::endl;
|
||||
|
||||
m_mapper = ((header[6] >> 4) & 0xf) | (header[7] & 0xf0);
|
||||
LOG(Info) << "Mapper #: " << +m_mapper << std::endl;
|
||||
m_mapperNumber = ((header[6] >> 4) & 0xf) | (header[7] & 0xf0);
|
||||
LOG(Info) << "Mapper #: " << +m_mapperNumber << std::endl;
|
||||
|
||||
m_extendedRAM = header[6] & 0x2;
|
||||
LOG(Info) << "Extended (CPU) RAM: " << std::boolalpha << m_extendedRAM << std::endl;
|
||||
|
|
|
@ -43,8 +43,15 @@ namespace sn
|
|||
if (!m_cartridge.loadFromFile(rom_path))
|
||||
return;
|
||||
|
||||
if (!m_bus.loadCartridge(&m_cartridge) ||
|
||||
!m_pictureBus.loadCartridge(&m_cartridge))
|
||||
m_mapper = Mapper::createMapper(static_cast<Mapper::Type>(m_cartridge.getMapper()), m_cartridge);
|
||||
if (!m_mapper)
|
||||
{
|
||||
LOG(Error) << "Creating Mapper failed. Probably unsupported." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_bus.setMapper(m_mapper.get()) ||
|
||||
!m_pictureBus.setMapper(m_mapper.get()))
|
||||
return;
|
||||
|
||||
m_cpu.reset();
|
||||
|
@ -92,10 +99,11 @@ namespace sn
|
|||
|
||||
while (m_elapsedTime > m_cpuCycleDuration)
|
||||
{
|
||||
//PPU
|
||||
m_ppu.step();
|
||||
m_ppu.step();
|
||||
m_ppu.step();
|
||||
|
||||
//CPU
|
||||
m_cpu.step();
|
||||
|
||||
m_elapsedTime -= m_cpuCycleDuration;
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace sn
|
|||
{
|
||||
MainBus::MainBus() :
|
||||
m_RAM(0x800, 0),
|
||||
m_cartride(nullptr)
|
||||
m_mapper(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -45,17 +45,14 @@ namespace sn
|
|||
}
|
||||
else if (addr < 0x8000)
|
||||
{
|
||||
if (m_cartride->hasExtendedRAM())
|
||||
if (m_mapper->hasExtendedRAM())
|
||||
{
|
||||
return m_extRAM[addr - 0x6000];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!one_bank)
|
||||
return m_cartride->getROM()[addr - 0x8000];
|
||||
else //mirrored
|
||||
return m_cartride->getROM()[(addr - 0x8000) & 0x3fff];
|
||||
return m_mapper->readPRG(addr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -95,14 +92,14 @@ namespace sn
|
|||
}
|
||||
else if (addr < 0x8000)
|
||||
{
|
||||
if (m_cartride->hasExtendedRAM())
|
||||
if (m_mapper->hasExtendedRAM())
|
||||
{
|
||||
m_extRAM[addr - 0x8000] = value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(InfoVerbose) << "ROM memory write attempt\n" << std::endl;
|
||||
m_mapper->writePRG(addr, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,44 +118,30 @@ namespace sn
|
|||
}
|
||||
else if (addr < 0x8000)
|
||||
{
|
||||
if (m_cartride->hasExtendedRAM())
|
||||
if (m_mapper->hasExtendedRAM())
|
||||
{
|
||||
return &m_extRAM[addr - 0x8000];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!one_bank)
|
||||
return &m_cartride->getROM()[addr - 0x8000];
|
||||
else //mirrored
|
||||
return &m_cartride->getROM()[(addr - 0x8000) & 0x3fff];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool MainBus::loadCartridge(Cartridge* cart)
|
||||
bool MainBus::setMapper(Mapper* mapper)
|
||||
{
|
||||
m_cartride = cart;
|
||||
m_mapper = cart->getMapper();
|
||||
auto rom = cart->getROM();
|
||||
m_mapper = mapper;
|
||||
|
||||
if (m_mapper != 0)
|
||||
if (!mapper)
|
||||
{
|
||||
LOG(Error) << "Mapper not supported" << std::endl;
|
||||
LOG(Error) << "Mapper pointer is nullptr" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cart->hasExtendedRAM())
|
||||
if (mapper->hasExtendedRAM())
|
||||
m_extRAM.resize(0x2000);
|
||||
|
||||
if (rom.size() == 0x4000) //1 bank
|
||||
{
|
||||
one_bank = true;
|
||||
}
|
||||
else //2 banks
|
||||
{
|
||||
one_bank = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
19
src/Mapper.cpp
Normal file
19
src/Mapper.cpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#include "Mapper.h"
|
||||
#include "MapperNROM.h"
|
||||
|
||||
namespace sn
|
||||
{
|
||||
std::unique_ptr<Mapper> Mapper::createMapper(Mapper::Type mapper_t, sn::Cartridge& cart)
|
||||
{
|
||||
std::unique_ptr<Mapper> ret;
|
||||
switch (mapper_t)
|
||||
{
|
||||
case NROM:
|
||||
ret.reset(new MapperNROM(cart));
|
||||
break;
|
||||
default:
|
||||
ret.reset(nullptr);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
64
src/MapperNROM.cpp
Normal file
64
src/MapperNROM.cpp
Normal file
|
@ -0,0 +1,64 @@
|
|||
#include "MapperNROM.h"
|
||||
#include "Log.h"
|
||||
|
||||
namespace sn
|
||||
{
|
||||
MapperNROM::MapperNROM(Cartridge &cart) :
|
||||
Mapper(cart, Mapper::NROM)
|
||||
{
|
||||
if (cart.getROM().size() == 0x4000) //1 bank
|
||||
{
|
||||
m_oneBank = true;
|
||||
}
|
||||
else //2 banks
|
||||
{
|
||||
m_oneBank = false;
|
||||
}
|
||||
|
||||
if (cart.getVROM().size() == 0)
|
||||
{
|
||||
m_usesCharacterRAM = true;
|
||||
m_characterRAM.resize(0x2000);
|
||||
LOG(Info) << "Uses character RAM" << std::endl;
|
||||
}
|
||||
else
|
||||
m_usesCharacterRAM = false;
|
||||
}
|
||||
|
||||
Byte MapperNROM::readPRG(Address addr)
|
||||
{
|
||||
if (!m_oneBank)
|
||||
return m_cartridge.getROM()[addr - 0x8000];
|
||||
else //mirrored
|
||||
return m_cartridge.getROM()[(addr - 0x8000) & 0x3fff];
|
||||
}
|
||||
|
||||
void MapperNROM::writePRG(Address addr, Byte value)
|
||||
{
|
||||
LOG(InfoVerbose) << "ROM memory write attempt at " << +addr << " to set " << +value << std::endl;
|
||||
}
|
||||
|
||||
const Byte* MapperNROM::getPagePtr(Address addr)
|
||||
{
|
||||
if (!m_oneBank)
|
||||
return &m_cartridge.getROM()[addr - 0x8000];
|
||||
else //mirrored
|
||||
return &m_cartridge.getROM()[(addr - 0x8000) & 0x3fff];
|
||||
}
|
||||
|
||||
Byte MapperNROM::readCHR(Address addr)
|
||||
{
|
||||
if (m_usesCharacterRAM)
|
||||
return m_characterRAM[addr];
|
||||
else
|
||||
return m_cartridge.getVROM()[addr];
|
||||
}
|
||||
|
||||
void MapperNROM::writeCHR(Address addr, Byte value)
|
||||
{
|
||||
if (m_usesCharacterRAM)
|
||||
m_characterRAM[addr] = value;
|
||||
else
|
||||
LOG(Info) << "Read-only CHR memory write attempt at " << std::hex << addr << std::endl;
|
||||
}
|
||||
}
|
|
@ -7,17 +7,14 @@ namespace sn
|
|||
PictureBus::PictureBus() :
|
||||
m_RAM(0x800),
|
||||
m_palette(0x20),
|
||||
m_cartride(nullptr)
|
||||
m_mapper(nullptr)
|
||||
{}
|
||||
|
||||
Byte PictureBus::read(Address addr)
|
||||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
if (m_usesCharacterRAM)
|
||||
return m_characterRAM[addr];
|
||||
else
|
||||
return m_cartride->getVROM()[addr];
|
||||
return m_mapper->readCHR(addr);
|
||||
}
|
||||
else if (addr < 0x3eff) //Name tables upto 0x3000, then mirrored upto 3eff
|
||||
{
|
||||
|
@ -47,10 +44,7 @@ namespace sn
|
|||
{
|
||||
if (addr < 0x2000)
|
||||
{
|
||||
if (m_usesCharacterRAM)
|
||||
m_characterRAM[addr] = value;
|
||||
else
|
||||
LOG(Info) << "Read-only memory write attempt at " << std::hex << addr << std::endl;
|
||||
m_mapper->writeCHR(addr, value);
|
||||
}
|
||||
else if (addr < 0x3eff) //Name tables upto 0x3000, then mirrored upto 3eff
|
||||
{
|
||||
|
@ -73,20 +67,17 @@ namespace sn
|
|||
}
|
||||
}
|
||||
|
||||
bool PictureBus::loadCartridge(Cartridge* cart)
|
||||
bool PictureBus::setMapper(Mapper *mapper)
|
||||
{
|
||||
if (!cart)
|
||||
if (!mapper)
|
||||
{
|
||||
LOG(Error) << "Mapper argument is nullptr" << std::endl;
|
||||
return false;
|
||||
LOG(Error) << "Cartride argument is nullptr" << std::endl;
|
||||
}
|
||||
|
||||
m_cartride = cart;
|
||||
m_mapper = mapper;
|
||||
|
||||
auto mirroring = cart->getNameTableMirroring();
|
||||
// mirroring = (mirroring & FourScreen) ? FourScreen : mirroring;
|
||||
m_mirroring = static_cast<NameTableMirroring>(mirroring);
|
||||
switch (m_mirroring)
|
||||
switch (m_mapper->getNameTableMirroring())
|
||||
{
|
||||
case Horizontal:
|
||||
NameTable0 = NameTable1 = 0;
|
||||
|
@ -103,15 +94,6 @@ namespace sn
|
|||
return false;
|
||||
}
|
||||
|
||||
if (cart->getVROM().size() == 0)
|
||||
{
|
||||
m_usesCharacterRAM = true;
|
||||
m_characterRAM.resize(0x2000);
|
||||
LOG(Info) << "Uses character RAM" << std::endl;
|
||||
}
|
||||
else
|
||||
m_usesCharacterRAM = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue