Skip to content

Commit

Permalink
Merge branch 'add-mappers'
Browse files Browse the repository at this point in the history
  • Loading branch information
amhndu committed Oct 16, 2016
2 parents 5e39d3f + 0bf9170 commit 5a12981
Show file tree
Hide file tree
Showing 9 changed files with 267 additions and 26 deletions.
15 changes: 7 additions & 8 deletions include/Mapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ namespace sn
Horizontal = 0,
Vertical = 1,
FourScreen = 8,
OneScreenLower,
OneScreenHigher,
};


Expand All @@ -18,8 +20,8 @@ namespace sn
public:
enum Type
{
NROM = 0,
MMC1 = 1,
NROM = 0,
SxROM = 1,
UxROM = 2,
CNROM = 3,
};
Expand All @@ -32,17 +34,14 @@ namespace sn
virtual Byte readCHR (Address addr) = 0;
virtual void writeCHR (Address addr, Byte value) = 0;

virtual NameTableMirroring getNameTableMirroring();

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);
static std::unique_ptr<Mapper> createMapper (Type mapper_t, Cartridge& cart, std::function<void(void)> mirroring_cb);

protected:
Cartridge& m_cartridge;
Expand Down
45 changes: 45 additions & 0 deletions include/MapperSxROM.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifndef MAPPERSXROM_H
#define MAPPERSXROM_H
#include "Mapper.h"

namespace sn
{
class MapperSxROM : public Mapper
{
public:
MapperSxROM(Cartridge& cart, std::function<void(void)> mirroring_cb);
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);

NameTableMirroring getNameTableMirroring();
private:
void calculatePRGPointers();

std::function<void(void)> m_mirroringCallback;
NameTableMirroring m_mirroing;

bool m_usesCharacterRAM;
int m_modeCHR;
int m_modePRG;

Byte m_tempRegister;
int m_writeCounter;

Byte m_regPRG;
Byte m_regCHR0;
Byte m_regCHR1;

const Byte* m_firstBankPRG;
const Byte* m_secondBankPRG;

const Byte* m_firstBankCHR;
const Byte* m_secondBankCHR;

std::vector<Byte> m_characterRAM;
};
}
#endif // MAPPERSXROM_H
2 changes: 2 additions & 0 deletions include/PictureBus.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ namespace sn

bool setMapper(Mapper *mapper);
Byte readPalette(Byte paletteAddr);

void updateMirroring();
private:
std::vector<Byte> m_RAM;
std::size_t NameTable0, NameTable1, NameTable2, NameTable3; //indices where they start in RAM vector
Expand Down
4 changes: 2 additions & 2 deletions src/Cartridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,15 @@ namespace sn
LOG(Info) << "Reading header, it dictates: \n";

Byte banks = header[4];
LOG(Info) << "PRG-ROM Banks: " << +banks << std::endl;
LOG(Info) << "16KB PRG-ROM Banks: " << +banks << std::endl;
if (!banks)
{
LOG(Error) << "ROM has no PRG-ROM banks. Loading ROM failed." << std::endl;
return false;
}

Byte vbanks = header[5];
LOG(Info) << "CHR-ROM Banks: " << +vbanks << std::endl;
LOG(Info) << "8KB CHR-ROM Banks: " << +vbanks << std::endl;

m_nameTableMirroring = header[6] & 0xB;
LOG(Info) << "Name Table Mirroring: " << +m_nameTableMirroring << std::endl;
Expand Down
4 changes: 3 additions & 1 deletion src/Emulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,9 @@ namespace sn
if (!m_cartridge.loadFromFile(rom_path))
return;

m_mapper = Mapper::createMapper(static_cast<Mapper::Type>(m_cartridge.getMapper()), m_cartridge);
m_mapper = Mapper::createMapper(static_cast<Mapper::Type>(m_cartridge.getMapper()),
m_cartridge,
[&](){ m_pictureBus.updateMirroring(); });
if (!m_mapper)
{
LOG(Error) << "Creating Mapper failed. Probably unsupported." << std::endl;
Expand Down
4 changes: 2 additions & 2 deletions src/MainBus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ namespace sn
LOG(Error) << "callback argument is nullptr" << std::endl;
return false;
}
return m_writeCallbacks.insert({reg, callback}).second;
return m_writeCallbacks.emplace(reg, callback).second;
}

bool MainBus::setReadCallback(IORegisters reg, std::function<Byte(void)> callback)
Expand All @@ -162,7 +162,7 @@ namespace sn
LOG(Error) << "callback argument is nullptr" << std::endl;
return false;
}
return m_readCallbacks.insert({reg, callback}).second;
return m_readCallbacks.emplace(reg, callback).second;
}

};
11 changes: 10 additions & 1 deletion src/Mapper.cpp
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
#include "Mapper.h"
#include "MapperNROM.h"
#include "MapperSxROM.h"
#include "MapperUxROM.h"
#include "MapperCNROM.h"

namespace sn
{
std::unique_ptr<Mapper> Mapper::createMapper(Mapper::Type mapper_t, sn::Cartridge& cart)
NameTableMirroring Mapper::getNameTableMirroring()
{
return static_cast<NameTableMirroring>(m_cartridge.getNameTableMirroring());
}

std::unique_ptr<Mapper> Mapper::createMapper(Mapper::Type mapper_t, sn::Cartridge& cart, std::function<void(void)> mirroring_cb)
{
std::unique_ptr<Mapper> ret(nullptr);
switch (mapper_t)
{
case NROM:
ret.reset(new MapperNROM(cart));
break;
case SxROM:
ret.reset(new MapperSxROM(cart, mirroring_cb));
break;
case UxROM:
ret.reset(new MapperUxROM(cart));
break;
Expand Down
174 changes: 174 additions & 0 deletions src/MapperSxROM.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#include "MapperSxROM.h"
#include "Log.h"

namespace sn
{
MapperSxROM::MapperSxROM(Cartridge &cart, std::function<void(void)> mirroring_cb) :
Mapper(cart, Mapper::SxROM),
m_mirroringCallback(mirroring_cb),
m_modeCHR(0),
m_modePRG(3),
m_tempRegister(0),
m_writeCounter(0),
m_regPRG(0),
m_regCHR0(0),
m_regCHR1(0),
m_firstBankPRG(nullptr),
m_secondBankPRG(nullptr),
m_firstBankCHR(nullptr),
m_secondBankCHR(nullptr)
{
if (cart.getVROM().size() == 0)
{
m_usesCharacterRAM = true;
m_characterRAM.resize(0x2000);
LOG(Info) << "Uses character RAM" << std::endl;
}
else
{
LOG(Info) << "Using CHR-ROM" << std::endl;
m_usesCharacterRAM = false;
m_firstBankCHR = &cart.getVROM()[0];
m_secondBankCHR = &cart.getVROM()[0x1000 * m_regCHR1];
}

m_firstBankPRG = &cart.getROM()[0]; //first bank
m_secondBankPRG = &cart.getROM()[cart.getROM().size() - 0x4000/*0x2000 * 0x0e*/]; //last bank
}

Byte MapperSxROM::readPRG(Address addr)
{
if (addr < 0xc000)
return *(m_firstBankPRG + (addr & 0x3fff));
else
return *(m_secondBankPRG + (addr & 0x3fff));
}

NameTableMirroring MapperSxROM::getNameTableMirroring()
{
return m_mirroing;
}

void MapperSxROM::writePRG(Address addr, Byte value)
{
if (!(value & 0x80)) //if reset bit is NOT set
{
m_tempRegister = (m_tempRegister >> 1) | ((value & 1) << 4);
++m_writeCounter;

if (m_writeCounter == 5)
{
if (addr <= 0x9fff)
{
LOG(Info) << "CHR mode : " << m_modeCHR << std::endl;
LOG(Info) << "PRG mode : " << m_modePRG << std::endl;
LOG(Info) << "Mirroring: " << (m_tempRegister & 0x3) << std::endl;
switch (m_tempRegister & 0x3)
{
case 0: m_mirroing = OneScreenLower; break;
case 1: m_mirroing = OneScreenHigher; break;
case 2: m_mirroing = Vertical; break;
case 3: m_mirroing = Horizontal; break;
}
m_mirroringCallback();

m_modeCHR = (m_tempRegister & 0x10) >> 4;
m_modePRG = (m_tempRegister & 0xc) >> 2;
calculatePRGPointers();

//Recalculate CHR pointers
if (m_modeCHR == 0) //one 8KB bank
{
m_firstBankCHR = &m_cartridge.getVROM()[0x1000 * (m_regCHR0 | 1)]; //ignore last bit
m_secondBankCHR = m_firstBankCHR + 0x1000;
}
else //two 4KB banks
{
m_firstBankCHR = &m_cartridge.getVROM()[0x1000 * m_regCHR0];
m_secondBankCHR = &m_cartridge.getVROM()[0x1000 * m_regCHR1];
}
}
else if (addr <= 0xbfff) //CHR Reg 0
{
m_regCHR0 = m_tempRegister;
m_firstBankCHR = &m_cartridge.getVROM()[0x1000 * (m_tempRegister | (1 - m_modeCHR))]; //OR 1 if 8KB mode
if (m_modeCHR == 0)
m_secondBankCHR = m_firstBankCHR + 0x1000;
}
else if (addr <= 0xdfff)
{
m_regCHR1 = m_tempRegister;
if(m_modeCHR == 1)
m_secondBankCHR = &m_cartridge.getVROM()[0x1000 * m_tempRegister];
}
else
{
//TODO PRG-RAM
if ((m_tempRegister & 0x10) == 0x10)
{
LOG(Info) << "PRG-RAM activated" << std::endl;
}

m_tempRegister &= 0xf;
m_regPRG = m_tempRegister;
calculatePRGPointers();
}

m_tempRegister = 0;
m_writeCounter = 0;
}
}
else //reset
{
m_tempRegister = 0;
m_writeCounter = 0;
m_modePRG = 3;
calculatePRGPointers();
}
}

void MapperSxROM::calculatePRGPointers()
{
if (m_modePRG <= 1) //32KB changeable
{
m_firstBankPRG = &m_cartridge.getROM()[0x4000 * (m_regPRG | 1)];
m_secondBankPRG = m_firstBankPRG + 0x4000; //add 16KB
}
else if (m_modePRG == 2) //fix first switch second
{
m_firstBankPRG = &m_cartridge.getROM()[0];
m_secondBankPRG = m_firstBankPRG + 0x4000 * m_regPRG;
}
else //switch first fix second
{
m_firstBankPRG = &m_cartridge.getROM()[0x4000 * m_regPRG];
m_secondBankPRG = &m_cartridge.getROM()[m_cartridge.getROM().size() - 0x4000/*0x2000 * 0x0e*/];
}
}

const Byte* MapperSxROM::getPagePtr(Address addr)
{
if (addr < 0xc000)
return (m_firstBankPRG + (addr & 0x3fff));
else
return (m_secondBankPRG + (addr & 0x3fff));
}

Byte MapperSxROM::readCHR(Address addr)
{
if (m_usesCharacterRAM)
return m_characterRAM[addr];
else if (addr < 0x1000)
return *(m_firstBankCHR + addr);
else
return *(m_secondBankCHR + (addr & 0xfff));
}

void MapperSxROM::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;
}
}
Loading

0 comments on commit 5a12981

Please sign in to comment.