Mapper 24 & 26 (VRC6) support (Incomplete)

This commit is contained in:
Souryo 2016-01-24 14:20:35 -05:00
parent b00a565354
commit 4d8a007e5f
8 changed files with 254 additions and 10 deletions

View File

@ -134,6 +134,18 @@ uint8_t BaseMapper::InternalReadRam(uint16_t addr)
return _prgPages[addr >> 8] ? _prgPages[addr >> 8][addr & 0xFF] : 0;
}
void BaseMapper::SelectPrgPage4x(uint16_t slot, uint16_t page, PrgMemoryType memoryType)
{
SelectPrgPage2x(slot*2, page, memoryType);
SelectPrgPage2x(slot*2+1, page+2, memoryType);
}
void BaseMapper::SelectPrgPage2x(uint16_t slot, uint16_t page, PrgMemoryType memoryType)
{
SelectPRGPage(slot*2, page, memoryType);
SelectPRGPage(slot*2+1, page+1, memoryType);
}
void BaseMapper::SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType)
{
_prgPageNumbers[slot] = page;

View File

@ -104,6 +104,8 @@ protected:
virtual void WriteRegister(uint16_t addr, uint8_t value) { }
virtual uint8_t ReadRegister(uint16_t addr) { return 0; }
void SelectPrgPage4x(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom);
void SelectPrgPage2x(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom);
virtual void SelectPRGPage(uint16_t slot, uint16_t page, PrgMemoryType memoryType = PrgMemoryType::PrgRom);
void SetCpuMemoryMapping(uint16_t startAddr, uint16_t endAddr, int16_t pageNumber, PrgMemoryType type, int8_t accessType = -1);

View File

@ -499,8 +499,11 @@
<ClInclude Include="VideoDecoder.h" />
<ClInclude Include="BaseVideoFilter.h" />
<ClInclude Include="VirtualController.h" />
<ClInclude Include="VRC1.h" />
<ClInclude Include="VRC2_4.h" />
<ClInclude Include="VRC3.h" />
<ClInclude Include="VRC6.h" />
<ClInclude Include="VrcIrq.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="APU.cpp" />
@ -549,7 +552,6 @@
<ClCompile Include="VideoDecoder.cpp" />
<ClCompile Include="BaseVideoFilter.cpp" />
<ClCompile Include="VirtualController.cpp" />
<ClCompile Include="VRC1.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@ -467,10 +467,19 @@
<ClInclude Include="MMC3_45.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
<ClInclude Include="BaseMapper.cpp">
<ClInclude Include="BaseMapper.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
<ClInclude Include="BaseMapper.h">
<ClInclude Include="TxSRom.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="VRC6.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
<ClInclude Include="VRC1.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="VrcIrq.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
</ItemGroup>
@ -508,9 +517,6 @@
<ClCompile Include="AutoRomTest.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="VRC1.h">
<Filter>Nes\Mappers</Filter>
</ClCompile>
<ClCompile Include="BaseVideoFilter.cpp">
<Filter>VideoDecoder</Filter>
</ClCompile>
@ -586,8 +592,8 @@
<ClCompile Include="SoundMixer.cpp">
<Filter>Nes\APU</Filter>
</ClCompile>
<ClCompile Include="TxSRom.h">
<Filter>Nes\Mappers</Filter>
<ClCompile Include="BaseMapper.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@ -84,6 +84,7 @@
#include "VRC1.h"
#include "VRC2_4.h"
#include "VRC3.h"
#include "VRC6.h"
BaseMapper* MapperFactory::GetMapperFromID(ROMLoader &romLoader)
{
@ -110,7 +111,9 @@ BaseMapper* MapperFactory::GetMapperFromID(ROMLoader &romLoader)
case 21: return new VRC2_4(VRCVariant::VRC4a); //Conflicts: VRC4c
case 22: return new VRC2_4(VRCVariant::VRC2a);
case 23: return new VRC2_4(VRCVariant::VRC2b); //Conflicts: VRC4e
case 24: return new VRC6(VRCVariant::VRC6a);
case 25: return new VRC2_4(VRCVariant::VRC4b); //Conflicts: VRC2c, VRC4d
case 26: return new VRC6(VRCVariant::VRC6b);
case 27: return new VRC2_4(VRCVariant::VRC4_27); //Untested
case 32: return new IremG101();
case 33: return new TaitoTc0190();

View File

@ -13,6 +13,8 @@ enum class VRCVariant
VRC4d, //25
VRC4e, //23
VRC4_27, //27
VRC6a,
VRC6b
};
class VRC2_4 : public BaseMapper

140
Core/VRC6.h Normal file
View File

@ -0,0 +1,140 @@
#pragma once
#include "stdafx.h"
#include "BaseMapper.h"
#include "VrcIrq.h"
enum class VRCVariant;
//incomplete - missing audio and more
class VRC6 : public BaseMapper
{
private:
VrcIrq _irq;
VRCVariant _model;
uint8_t _bankingMode;
uint8_t _chrRegisters[8];
void UpdatePrgRamAccess()
{
SetCpuMemoryMapping(0x6000, 0x7FFF, 0, HasBattery() ? PrgMemoryType::SaveRam : PrgMemoryType::WorkRam, (_bankingMode & 0x80) ? MemoryAccessType::ReadWrite : MemoryAccessType::NoAccess);
}
protected:
virtual uint16_t GetPRGPageSize() { return 0x2000; }
virtual uint16_t GetCHRPageSize() { return 0x0400; }
void InitMapper()
{
_irq.Reset();
_bankingMode = 0;
memset(_chrRegisters, 0, sizeof(_chrRegisters));
SelectPRGPage(3, -1);
}
virtual void StreamState(bool saving)
{
BaseMapper::StreamState(saving);
Stream(_irq);
Stream<uint8_t>(_bankingMode);
StreamArray<uint8_t>(_chrRegisters, 8);
if(!saving) {
UpdatePrgRamAccess();
}
}
void ProcessCpuClock()
{
_irq.ProcessCpuClock();
}
void UpdatePpuBanking()
{
switch(_bankingMode & 0x03) {
case 0:
SelectCHRPage(0, _chrRegisters[0]);
SelectCHRPage(1, _chrRegisters[1]);
SelectCHRPage(2, _chrRegisters[2]);
SelectCHRPage(3, _chrRegisters[3]);
SelectCHRPage(4, _chrRegisters[4]);
SelectCHRPage(5, _chrRegisters[5]);
SelectCHRPage(6, _chrRegisters[6]);
SelectCHRPage(7, _chrRegisters[7]);
break;
case 1:
SelectChrPage2x(0, _chrRegisters[0]);
SelectChrPage2x(1, _chrRegisters[1]);
SelectChrPage2x(2, _chrRegisters[2]);
SelectChrPage2x(3, _chrRegisters[3]);
break;
case 2: case 3:
SelectCHRPage(0, _chrRegisters[0]);
SelectCHRPage(1, _chrRegisters[1]);
SelectCHRPage(2, _chrRegisters[2]);
SelectCHRPage(3, _chrRegisters[3]);
SelectChrPage2x(2, _chrRegisters[4]);
SelectChrPage2x(3, _chrRegisters[5]);
break;
}
//This is incorrect, but seems ok for all commercial games? (Based on old Disch documents)
switch((_bankingMode >> 2) & 0x03) {
case 0: SetMirroringType(MirroringType::Vertical); break;
case 1: SetMirroringType(MirroringType::Horizontal); break;
case 2: SetMirroringType(MirroringType::ScreenAOnly); break;
case 3: SetMirroringType(MirroringType::ScreenBOnly); break;
}
UpdatePrgRamAccess();
}
void WriteRegister(uint16_t addr, uint8_t value)
{
if(_model == VRCVariant::VRC6b) {
addr = (addr & 0xFFFC) | ((addr & 0x01) << 1) | ((addr & 0x02) >> 1);
}
switch(addr & 0xF003) {
case 0x8000: case 0x8001: case 0x8002: case 0x8003:
SelectPrgPage2x(0, (value & 0x0F) << 1);
break;
case 0xB003:
_bankingMode = value;
UpdatePpuBanking();
break;
case 0xC000: case 0xC001: case 0xC002: case 0xC003:
SelectPRGPage(2, value & 0x1F);
break;
case 0xD000: case 0xD001: case 0xD002: case 0xD003:
_chrRegisters[addr & 0x03] = value;
UpdatePpuBanking();
break;
case 0xE000: case 0xE001: case 0xE002: case 0xE003:
_chrRegisters[4 + (addr & 0x03)] = value;
UpdatePpuBanking();
break;
case 0xF000:
_irq.SetReloadValue(value);
break;
case 0xF001:
_irq.SetControlValue(value);
break;
case 0xF002:
_irq.AcknowledgeIrq();
break;
}
}
public:
VRC6(VRCVariant model) : _model(model)
{
}
};

77
Core/VrcIrq.h Normal file
View File

@ -0,0 +1,77 @@
#pragma once
#include "Snapshotable.h"
#include "CPU.h"
class VrcIrq : Snapshotable
{
private:
uint8_t _irqReloadValue;
uint8_t _irqCounter;
int16_t _irqPrescalerCounter;
bool _irqEnabled;
bool _irqEnabledAfterAck;
bool _irqCycleMode;
protected:
void StreamState(bool saving)
{
Stream<uint8_t>(_irqReloadValue);
Stream<uint8_t>(_irqCounter);
Stream<int16_t>(_irqPrescalerCounter);
Stream<bool>(_irqEnabled);
Stream<bool>(_irqEnabledAfterAck);
Stream<bool>(_irqCycleMode);
}
public:
void Reset()
{
_irqPrescalerCounter = 0;
_irqReloadValue = 0;
_irqCounter = 0;
_irqEnabled = false;
_irqEnabledAfterAck = false;
_irqCycleMode = false;
}
void ProcessCpuClock()
{
if(_irqEnabled) {
_irqPrescalerCounter -= 3;
if(_irqCycleMode || (_irqPrescalerCounter <= 0 && !_irqCycleMode)) {
if(_irqCounter == 0xFF) {
_irqCounter = _irqReloadValue;
CPU::SetIRQSource(IRQSource::External);
} else {
_irqCounter++;
}
_irqPrescalerCounter += 341;
}
}
}
void SetReloadValue(uint8_t value)
{
_irqReloadValue = value;
}
void SetControlValue(uint8_t value)
{
_irqEnabledAfterAck = (value & 0x01) == 0x01;
_irqEnabled = (value & 0x02) == 0x02;
_irqCycleMode = (value & 0x04) == 0x04;
if(_irqEnabled) {
_irqCounter = _irqReloadValue;
_irqPrescalerCounter = 341;
}
}
void AcknowledgeIrq()
{
_irqEnabled = _irqEnabledAfterAck;
CPU::ClearIRQSource(IRQSource::External);
}
};