mirror of
https://github.com/libretro/Mesen.git
synced 2024-11-23 17:19:39 +00:00
Mapper 24 & 26 (VRC6) support (Incomplete)
This commit is contained in:
parent
b00a565354
commit
4d8a007e5f
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -491,7 +491,7 @@
|
||||
<ClInclude Include="TaitoX1005.h" />
|
||||
<ClInclude Include="TraceLogger.h" />
|
||||
<ClInclude Include="TriangleChannel.h" />
|
||||
<ClInclude Include="TxSRom.h" />
|
||||
<ClInclude Include="TxSRom.h" />
|
||||
<ClInclude Include="UnlPci556.h" />
|
||||
<ClInclude Include="UNROM.h" />
|
||||
<ClInclude Include="UnRom_180.h" />
|
||||
@ -499,14 +499,17 @@
|
||||
<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" />
|
||||
<ClCompile Include="ApuLengthCounter.cpp" />
|
||||
<ClCompile Include="AutoRomTest.cpp" />
|
||||
<ClCompile Include="BaseMapper.cpp" />
|
||||
<ClCompile Include="BaseMapper.cpp" />
|
||||
<ClCompile Include="Breakpoint.cpp" />
|
||||
<ClCompile Include="CheatManager.cpp" />
|
||||
<ClCompile Include="CodeDataLogger.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">
|
||||
|
@ -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>
|
@ -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();
|
||||
|
@ -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
140
Core/VRC6.h
Normal 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
77
Core/VrcIrq.h
Normal 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);
|
||||
}
|
||||
|
||||
};
|
Loading…
Reference in New Issue
Block a user