Mappers: Fixed/improved emulation of multiple unlicensed mappers
Based on NRS' research
This commit is contained in:
parent
11135ec485
commit
933fa3e8ba
12 changed files with 318 additions and 180 deletions
|
@ -649,6 +649,7 @@
|
|||
<ClInclude Include="SuborKeyboard.h" />
|
||||
<ClInclude Include="SuborMouse.h" />
|
||||
<ClInclude Include="T230.h" />
|
||||
<ClInclude Include="TxcChip.h" />
|
||||
<ClInclude Include="Unl158B.h" />
|
||||
<ClInclude Include="Unl8237A.h" />
|
||||
<ClInclude Include="UnlD1038.h" />
|
||||
|
@ -804,7 +805,6 @@
|
|||
<ClInclude Include="Rambo1.h" />
|
||||
<ClInclude Include="Rt01.h" />
|
||||
<ClInclude Include="Sachen74LS374N.h" />
|
||||
<ClInclude Include="Sachen74LS374NB.h" />
|
||||
<ClInclude Include="Sachen8259.h" />
|
||||
<ClInclude Include="Sachen_133.h" />
|
||||
<ClInclude Include="Sachen_136.h" />
|
||||
|
|
|
@ -667,9 +667,6 @@
|
|||
<ClInclude Include="Sachen74LS374N.h">
|
||||
<Filter>Nes\Mappers\Sachen</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sachen74LS374NB.h">
|
||||
<Filter>Nes\Mappers\Sachen</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Mapper227.h">
|
||||
<Filter>Nes\Mappers\Unnamed</Filter>
|
||||
</ClInclude>
|
||||
|
@ -1490,6 +1487,9 @@
|
|||
<ClInclude Include="EventManager.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TxcChip.h">
|
||||
<Filter>Nes\Mappers\Txc</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
|
|
@ -220,7 +220,6 @@
|
|||
#include "Sachen_148.h"
|
||||
#include "Sachen_149.h"
|
||||
#include "Sachen74LS374N.h"
|
||||
#include "Sachen74LS374NB.h"
|
||||
#include "Sachen8259.h"
|
||||
#include "Sachen9602.h"
|
||||
#include "SealieComputing.h"
|
||||
|
@ -441,7 +440,7 @@ BaseMapper* MapperFactory::GetMapperFromID(RomData &romData)
|
|||
case 147: return new Sachen_147();
|
||||
case 148: return new Sachen_148();
|
||||
case 149: return new Sachen_149();
|
||||
case 150: return new Sachen74LS374NB();
|
||||
case 150: return new Sachen74LS374N();
|
||||
case 151: return new VRC1();
|
||||
case 152: return new Bandai74161_7432(true);
|
||||
case 153: return new BandaiFcg();
|
||||
|
|
|
@ -9,16 +9,18 @@ private:
|
|||
uint8_t _regs[8];
|
||||
|
||||
protected:
|
||||
uint32_t GetDipSwitchCount() override { return _romInfo.MapperID == 150 ? 1 : 0; }
|
||||
uint16_t RegisterStartAddress() override { return 0x4100; }
|
||||
uint16_t RegisterEndAddress() override { return 0x7FFF; }
|
||||
uint16_t GetPRGPageSize() override { return 0x8000; }
|
||||
uint16_t GetCHRPageSize() override { return 0x2000; }
|
||||
bool AllowRegisterRead() override { return true; }
|
||||
|
||||
void InitMapper() override
|
||||
{
|
||||
_currentRegister = 0;
|
||||
memset(_regs, 0, sizeof(_regs));
|
||||
SelectPRGPage(0, 0);
|
||||
UpdateState();
|
||||
}
|
||||
|
||||
void StreamState(bool saving) override
|
||||
|
@ -29,28 +31,49 @@ protected:
|
|||
Stream(_currentRegister, regs);
|
||||
}
|
||||
|
||||
virtual void UpdateState()
|
||||
void UpdateState()
|
||||
{
|
||||
uint8_t chrPage = ((_regs[2] & 0x01) << 3) | ((_regs[6] & 0x03) << 1) | (_regs[4] & 0x01);
|
||||
uint8_t chrPage;
|
||||
if(_romInfo.MapperID == 150) {
|
||||
chrPage = ((_regs[4] & 0x01) << 2) | (_regs[6] & 0x03);
|
||||
} else {
|
||||
chrPage = (_regs[2] & 0x01) | ((_regs[4] & 0x01) << 1) | ((_regs[6] & 0x03) << 2);
|
||||
}
|
||||
SelectCHRPage(0, chrPage);
|
||||
SelectPRGPage(0, _regs[5] & 0x01);
|
||||
SelectPRGPage(0, _regs[5] & 0x03);
|
||||
|
||||
SetMirroringType(_regs[7] & 0x01 ? MirroringType::Vertical : MirroringType::Horizontal);
|
||||
switch((_regs[7] >> 1) & 0x03) {
|
||||
case 0: SetNametables(0, 0, 0, 1); break;
|
||||
case 1: SetMirroringType(MirroringType::Horizontal); break;
|
||||
case 2: SetMirroringType(MirroringType::Vertical); break;
|
||||
case 3: SetMirroringType(MirroringType::ScreenAOnly); break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ReadRegister(uint16_t addr) override
|
||||
{
|
||||
uint8_t openBus = _console->GetMemoryManager()->GetOpenBus();
|
||||
if((addr & 0xC101) == 0x4101) {
|
||||
if(GetDipSwitches() & 0x01) {
|
||||
//"In the latter setting, the ASIC sees all writes as being OR'd with $04, while on reads, D2 is open bus."
|
||||
return (openBus & 0xFC) | (_regs[_currentRegister] & 0x03);
|
||||
} else {
|
||||
return (openBus & 0xF8) | (_regs[_currentRegister] & 0x07);
|
||||
}
|
||||
}
|
||||
return openBus;
|
||||
}
|
||||
|
||||
void WriteRegister(uint16_t addr, uint8_t value) override
|
||||
{
|
||||
if(GetDipSwitches() & 0x01) {
|
||||
//"In the latter setting, the ASIC sees all writes as being OR'd with $04, while on reads, D2 is open bus."
|
||||
value |= 0x04;
|
||||
}
|
||||
|
||||
switch(addr & 0xC101) {
|
||||
case 0x4100: _currentRegister = value & 0x07; break;
|
||||
case 0x4101:
|
||||
_regs[_currentRegister] = value;
|
||||
if(_currentRegister == 0) {
|
||||
SelectCHRPage(0, 3);
|
||||
SelectPRGPage(0, 0);
|
||||
} else {
|
||||
UpdateState();
|
||||
}
|
||||
break;
|
||||
case 0x4101: _regs[_currentRegister] = (value & 0x07); UpdateState(); break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "Sachen74LS374N.h"
|
||||
|
||||
class Sachen74LS374NB : public BaseMapper
|
||||
{
|
||||
private:
|
||||
uint8_t _counter;
|
||||
uint8_t _currentRegister;
|
||||
uint8_t _regs[8];
|
||||
|
||||
protected:
|
||||
uint16_t RegisterStartAddress() override { return 0x4100; }
|
||||
uint16_t RegisterEndAddress() override { return 0x7FFF; }
|
||||
uint16_t GetPRGPageSize() override { return 0x8000; }
|
||||
uint16_t GetCHRPageSize() override { return 0x2000; }
|
||||
bool AllowRegisterRead() override { return true; }
|
||||
|
||||
void InitMapper() override
|
||||
{
|
||||
_counter = 0;
|
||||
_currentRegister = 0;
|
||||
memset(_regs, 0, sizeof(_regs));
|
||||
|
||||
SelectPRGPage(0, 0);
|
||||
}
|
||||
|
||||
void StreamState(bool saving) override
|
||||
{
|
||||
BaseMapper::StreamState(saving);
|
||||
ArrayInfo<uint8_t> regs{ _regs, 8 };
|
||||
Stream(_currentRegister, regs, _counter);
|
||||
}
|
||||
|
||||
void Reset(bool softReset) override
|
||||
{
|
||||
if(softReset) {
|
||||
_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ReadRegister(uint16_t addr) override
|
||||
{
|
||||
switch(addr & 0xC101) {
|
||||
case 0x4000: return (~_currentRegister) ^ (_counter & 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void UpdateState()
|
||||
{
|
||||
uint8_t chrPage = ((_regs[2] & 0x01) << 3) | ((_regs[4] & 0x01) << 2) | (_regs[6] & 0x03);
|
||||
SelectCHRPage(0, chrPage);
|
||||
if(_currentRegister == 2) {
|
||||
SelectPRGPage(0, _regs[2] & 0x01);
|
||||
} else {
|
||||
SelectPRGPage(0, _regs[5] & 0x07);
|
||||
}
|
||||
|
||||
switch((_regs[7] >> 1) & 0x02) {
|
||||
case 0: SetMirroringType(MirroringType::Horizontal); break;
|
||||
case 1: SetMirroringType(MirroringType::Vertical); break;
|
||||
case 2: SetNametables(0, 1, 1, 1); break;
|
||||
case 3: SetMirroringType(MirroringType::ScreenAOnly); break;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteRegister(uint16_t addr, uint8_t value) override
|
||||
{
|
||||
switch(addr & 0xC101) {
|
||||
case 0x4100: _currentRegister = value & 0x07; break;
|
||||
case 0x4101: _regs[_currentRegister] = value; UpdateState(); break;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,44 +1,56 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "BaseMapper.h"
|
||||
#include "TxcChip.h"
|
||||
|
||||
class Sachen_136 : public BaseMapper
|
||||
{
|
||||
private:
|
||||
uint8_t _chrReg;
|
||||
TxcChip _txc = TxcChip(true);
|
||||
|
||||
protected:
|
||||
virtual uint16_t GetPRGPageSize() override { return 0x8000; }
|
||||
virtual uint16_t GetCHRPageSize() override { return 0x2000; }
|
||||
virtual uint16_t RegisterStartAddress() override { return 0x4100; }
|
||||
virtual uint16_t RegisterEndAddress() override { return 0xFFFF; }
|
||||
virtual bool AllowRegisterRead() override { return true; }
|
||||
uint16_t GetPRGPageSize() override { return 0x8000; }
|
||||
uint16_t GetCHRPageSize() override { return 0x2000; }
|
||||
uint16_t RegisterStartAddress() override { return 0x8000; }
|
||||
uint16_t RegisterEndAddress() override { return 0xFFFF; }
|
||||
bool AllowRegisterRead() override { return true; }
|
||||
|
||||
void InitMapper() override
|
||||
{
|
||||
_chrReg = 0;
|
||||
AddRegisterRange(0x4020, 0x5FFF, MemoryOperation::Any);
|
||||
RemoveRegisterRange(0x8000, 0xFFFF, MemoryOperation::Read);
|
||||
|
||||
SelectPRGPage(0, 0);
|
||||
SelectCHRPage(0, 0);
|
||||
|
||||
RemoveRegisterRange(0x4101, 0xFFFF, MemoryOperation::Read);
|
||||
}
|
||||
|
||||
void StreamState(bool saving) override
|
||||
{
|
||||
BaseMapper::StreamState(saving);
|
||||
Stream(_chrReg);
|
||||
Stream(&_txc);
|
||||
}
|
||||
|
||||
void UpdateState()
|
||||
{
|
||||
SelectCHRPage(0, _txc.GetOutput());
|
||||
}
|
||||
|
||||
uint8_t ReadRegister(uint16_t addr) override
|
||||
{
|
||||
return (_chrReg & 0x3F) | (_console->GetMemoryManager()->GetOpenBus() & 0xC0);
|
||||
uint8_t openBus = _console->GetMemoryManager()->GetOpenBus();
|
||||
uint8_t value;
|
||||
if((addr & 0x103) == 0x100) {
|
||||
value = (openBus & 0xC0) | (_txc.Read() & 0x3F);
|
||||
} else {
|
||||
value = openBus;
|
||||
}
|
||||
UpdateState();
|
||||
return value;
|
||||
}
|
||||
|
||||
void WriteRegister(uint16_t addr, uint8_t value) override
|
||||
{
|
||||
if((addr & 0x0103) == 0x0102) {
|
||||
_chrReg = value + 3;
|
||||
SelectCHRPage(0, _chrReg & 0x03);
|
||||
}
|
||||
_txc.Write(addr, value & 0x3F);
|
||||
UpdateState();
|
||||
}
|
||||
};
|
|
@ -1,25 +1,59 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "BaseMapper.h"
|
||||
#include "TxcChip.h"
|
||||
|
||||
class Sachen_147 : public BaseMapper
|
||||
{
|
||||
private:
|
||||
TxcChip _txc = TxcChip(true);
|
||||
|
||||
protected:
|
||||
virtual uint16_t GetPRGPageSize() override { return 0x8000; }
|
||||
virtual uint16_t GetCHRPageSize() override { return 0x2000; }
|
||||
virtual uint16_t RegisterStartAddress() override { return 0x4100; }
|
||||
virtual uint16_t RegisterEndAddress() override { return 0x7FFF; }
|
||||
uint16_t GetPRGPageSize() override { return 0x8000; }
|
||||
uint16_t GetCHRPageSize() override { return 0x2000; }
|
||||
uint16_t RegisterStartAddress() override { return 0x8000; }
|
||||
uint16_t RegisterEndAddress() override { return 0xFFFF; }
|
||||
bool AllowRegisterRead() override { return true; }
|
||||
|
||||
void InitMapper() override
|
||||
{
|
||||
AddRegisterRange(0x4020, 0x5FFF, MemoryOperation::Any);
|
||||
RemoveRegisterRange(0x8000, 0xFFFF, MemoryOperation::Read);
|
||||
|
||||
SelectPRGPage(0, 0);
|
||||
SelectCHRPage(0, 0);
|
||||
}
|
||||
|
||||
void StreamState(bool saving) override
|
||||
{
|
||||
BaseMapper::StreamState(saving);
|
||||
Stream(&_txc);
|
||||
}
|
||||
|
||||
void UpdateState()
|
||||
{
|
||||
uint8_t out = _txc.GetOutput();
|
||||
SelectPRGPage(0, ((out & 0x20) >> 4) | (out & 0x01));
|
||||
SelectCHRPage(0, (out & 0x1E) >> 1);
|
||||
}
|
||||
|
||||
uint8_t ReadRegister(uint16_t addr) override
|
||||
{
|
||||
uint8_t openBus = _console->GetMemoryManager()->GetOpenBus();
|
||||
uint8_t value = openBus;
|
||||
if((addr & 0x103) == 0x100) {
|
||||
uint8_t v = _txc.Read();
|
||||
value = ((v & 0x3F) << 2) | ((v & 0xC0) >> 6);
|
||||
}
|
||||
UpdateState();
|
||||
return value;
|
||||
}
|
||||
|
||||
void WriteRegister(uint16_t addr, uint8_t value) override
|
||||
{
|
||||
if((addr & 0x4103) == 0x4102) {
|
||||
SelectPRGPage(0, ((value >> 2) & 0x01) | ((value >> 6) & 0x02));
|
||||
SelectCHRPage(0, (value >> 3) & 0x0F);
|
||||
_txc.Write(addr, ((value & 0xFC) >> 2) | ((value & 0x03) << 6));
|
||||
if(addr >= 0x8000) {
|
||||
UpdateState();
|
||||
}
|
||||
}
|
||||
};
|
|
@ -2,13 +2,13 @@
|
|||
#include "stdafx.h"
|
||||
#include "BaseMapper.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "TxcChip.h"
|
||||
|
||||
class Txc22000 : public BaseMapper
|
||||
{
|
||||
private:
|
||||
uint8_t _state;
|
||||
bool _prgBankingMode;
|
||||
uint8_t _prgBank;
|
||||
TxcChip _txc = TxcChip(false);
|
||||
uint8_t _chrBank;
|
||||
|
||||
protected:
|
||||
virtual uint16_t GetPRGPageSize() override { return 0x8000; }
|
||||
|
@ -22,10 +22,7 @@ protected:
|
|||
AddRegisterRange(0x4100, 0x5FFF, MemoryOperation::Any);
|
||||
RemoveRegisterRange(0x8000, 0xFFFF, MemoryOperation::Read);
|
||||
|
||||
_state = 0;
|
||||
_prgBank = 0;
|
||||
_prgBankingMode = 0;
|
||||
|
||||
_chrBank = 0;
|
||||
SelectPRGPage(0, 0);
|
||||
SelectCHRPage(0, 0);
|
||||
}
|
||||
|
@ -33,39 +30,33 @@ protected:
|
|||
void StreamState(bool saving) override
|
||||
{
|
||||
BaseMapper::StreamState(saving);
|
||||
Stream(_state, _prgBank, _prgBankingMode);
|
||||
Stream(&_txc);
|
||||
Stream(_chrBank);
|
||||
}
|
||||
|
||||
virtual uint8_t ReadRegister(uint16_t addr) override
|
||||
void UpdateState()
|
||||
{
|
||||
return (_console->GetMemoryManager()->GetOpenBus() & 0xCF) | (_state << 4);
|
||||
SelectPRGPage(0, _txc.GetOutput() & 0x03);
|
||||
SelectCHRPage(0, _chrBank);
|
||||
}
|
||||
|
||||
uint8_t ReadRegister(uint16_t addr) override
|
||||
{
|
||||
uint8_t openBus = _console->GetMemoryManager()->GetOpenBus();
|
||||
uint8_t value = openBus;
|
||||
if((addr & 0x103) == 0x100) {
|
||||
value = (openBus & 0xCF) | ((_txc.Read() << 4) & 0x30);
|
||||
}
|
||||
UpdateState();
|
||||
return value;
|
||||
}
|
||||
|
||||
void WriteRegister(uint16_t addr, uint8_t value) override
|
||||
{
|
||||
if(addr < 0x8000) {
|
||||
switch(addr & 0xE303) {
|
||||
//"when M=0, copy PP to RR. When M=1, RR=RR+1"
|
||||
case 0x4100:
|
||||
if(_prgBankingMode) {
|
||||
_state++;
|
||||
} else {
|
||||
_state = _prgBank;
|
||||
if((addr & 0xF200) == 0x4200) {
|
||||
_chrBank = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x4101: break; //"$4101: no visible effect"
|
||||
|
||||
case 0x4102: _prgBank = (value >> 4) & 0x03; break;
|
||||
case 0x4103: _prgBankingMode = (value >> 4) & 0x01; break;
|
||||
|
||||
case 0x4200: case 0x4201: case 0x4202: case 0x4203:
|
||||
SelectCHRPage(0, value & 0x0F);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
SelectPRGPage(0, _state);
|
||||
}
|
||||
|
||||
_txc.Write(addr, (value >> 4) & 0x03);
|
||||
UpdateState();
|
||||
}
|
||||
};
|
|
@ -5,21 +5,19 @@
|
|||
class Txc22211A : public BaseMapper
|
||||
{
|
||||
protected:
|
||||
virtual uint16_t GetPRGPageSize() override { return 0x8000; }
|
||||
virtual uint16_t GetCHRPageSize() override { return 0x2000; }
|
||||
virtual uint16_t RegisterStartAddress() override { return 0x8000; }
|
||||
virtual uint16_t RegisterEndAddress() override { return 0xFFFF; }
|
||||
virtual bool AllowRegisterRead() override { return true; }
|
||||
TxcChip _txc = TxcChip(false);
|
||||
|
||||
uint8_t _regs[4];
|
||||
uint16_t GetPRGPageSize() override { return 0x8000; }
|
||||
uint16_t GetCHRPageSize() override { return 0x2000; }
|
||||
uint16_t RegisterStartAddress() override { return 0x8000; }
|
||||
uint16_t RegisterEndAddress() override { return 0xFFFF; }
|
||||
bool AllowRegisterRead() override { return true; }
|
||||
|
||||
void InitMapper() override
|
||||
{
|
||||
AddRegisterRange(0x4100, 0x4103, MemoryOperation::Any);
|
||||
AddRegisterRange(0x4020, 0x5FFF, MemoryOperation::Any);
|
||||
RemoveRegisterRange(0x8000, 0xFFFF, MemoryOperation::Read);
|
||||
|
||||
memset(_regs, 0, sizeof(_regs));
|
||||
|
||||
SelectPRGPage(0, 0);
|
||||
SelectCHRPage(0, 0);
|
||||
}
|
||||
|
@ -27,27 +25,29 @@ protected:
|
|||
void StreamState(bool saving) override
|
||||
{
|
||||
BaseMapper::StreamState(saving);
|
||||
Stream(_regs[0], _regs[1], _regs[2], _regs[3]);
|
||||
Stream(&_txc);
|
||||
}
|
||||
|
||||
virtual uint8_t ReadRegister(uint16_t addr) override
|
||||
virtual void UpdateState()
|
||||
{
|
||||
return (_regs[1] ^ _regs[2]) | 0x40;
|
||||
SelectPRGPage(0, (_txc.GetOutput() >> 2) & 0x01);
|
||||
SelectCHRPage(0, _txc.GetOutput() & 0x03);
|
||||
}
|
||||
|
||||
virtual void UpdateState(uint8_t value)
|
||||
uint8_t ReadRegister(uint16_t addr) override
|
||||
{
|
||||
SelectPRGPage(0, _regs[2] >> 2);
|
||||
SelectCHRPage(0, _regs[2]);
|
||||
uint8_t openBus = _console->GetMemoryManager()->GetOpenBus();
|
||||
uint8_t value = openBus;
|
||||
if((addr & 0x103) == 0x100) {
|
||||
value = (openBus & 0xF0) | (_txc.Read() & 0x0F);
|
||||
}
|
||||
UpdateState();
|
||||
return value;
|
||||
}
|
||||
|
||||
void WriteRegister(uint16_t addr, uint8_t value) override
|
||||
{
|
||||
if(addr < 0x8000) {
|
||||
_regs[addr & 0x03] = value;
|
||||
} else {
|
||||
UpdateState(value);
|
||||
}
|
||||
|
||||
_txc.Write(addr, value & 0x0F);
|
||||
UpdateState();
|
||||
}
|
||||
};
|
|
@ -1,13 +1,62 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "Txc22211A.h"
|
||||
#include "BaseMapper.h"
|
||||
#include "TxcChip.h"
|
||||
|
||||
class Txc22211B : public Txc22211A
|
||||
class Txc22211B : public BaseMapper
|
||||
{
|
||||
private:
|
||||
TxcChip _txc = TxcChip(true);
|
||||
|
||||
protected:
|
||||
virtual void UpdateState(uint8_t value)
|
||||
uint16_t GetPRGPageSize() override { return 0x8000; }
|
||||
uint16_t GetCHRPageSize() override { return 0x2000; }
|
||||
uint16_t RegisterStartAddress() override { return 0x8000; }
|
||||
uint16_t RegisterEndAddress() override { return 0xFFFF; }
|
||||
bool AllowRegisterRead() override { return true; }
|
||||
|
||||
void InitMapper() override
|
||||
{
|
||||
SelectPRGPage(0, _regs[2] >> 2);
|
||||
SelectCHRPage(0, (((value ^ _regs[2]) >> 3) & 0x02) | (((value ^ _regs[2]) >> 5) & 0x01));
|
||||
AddRegisterRange(0x4020, 0x5FFF, MemoryOperation::Any);
|
||||
RemoveRegisterRange(0x8000, 0xFFFF, MemoryOperation::Read);
|
||||
|
||||
SelectPRGPage(0, 0);
|
||||
SelectCHRPage(0, 0);
|
||||
}
|
||||
|
||||
void StreamState(bool saving) override
|
||||
{
|
||||
BaseMapper::StreamState(saving);
|
||||
Stream(&_txc);
|
||||
}
|
||||
|
||||
void UpdateState()
|
||||
{
|
||||
SelectCHRPage(0, _txc.GetOutput());
|
||||
SetMirroringType(_txc.GetInvertFlag() ? MirroringType::Vertical : MirroringType::Horizontal);
|
||||
}
|
||||
|
||||
uint8_t ConvertValue(uint8_t v)
|
||||
{
|
||||
return ((v & 0x01) << 5) | ((v & 0x02) << 3) | ((v & 0x04) << 1) | ((v & 0x08) >> 1) | ((v & 0x10) >> 3) | ((v & 0x20) >> 5);
|
||||
}
|
||||
|
||||
uint8_t ReadRegister(uint16_t addr) override
|
||||
{
|
||||
uint8_t openBus = _console->GetMemoryManager()->GetOpenBus();
|
||||
uint8_t value = openBus;
|
||||
if((addr & 0x103) == 0x100) {
|
||||
value = (openBus & 0xC0) | ConvertValue(_txc.Read());
|
||||
}
|
||||
UpdateState();
|
||||
return value;
|
||||
}
|
||||
|
||||
void WriteRegister(uint16_t addr, uint8_t value) override
|
||||
{
|
||||
_txc.Write(addr, ConvertValue(value));
|
||||
if(addr >= 0x8000) {
|
||||
UpdateState();
|
||||
}
|
||||
}
|
||||
};
|
|
@ -5,8 +5,17 @@
|
|||
class Txc22211C : public Txc22211A
|
||||
{
|
||||
protected:
|
||||
virtual uint8_t ReadRegister(uint16_t addr) override
|
||||
void UpdateState() override
|
||||
{
|
||||
return (_regs[1] ^ _regs[2]) | 0x41;
|
||||
SelectPRGPage(0, 0);
|
||||
if(_chrRomSize > 0x2000) {
|
||||
SelectCHRPage(0, (_txc.GetOutput() & 0x01) | (_txc.GetY() ? 0x02 : 0) | ((_txc.GetOutput() & 0x02) << 1));
|
||||
} else {
|
||||
if(_txc.GetY()){
|
||||
SelectCHRPage(0, 0);
|
||||
} else {
|
||||
RemovePpuMemoryMapping(0, 0x1FFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
97
Core/TxcChip.h
Normal file
97
Core/TxcChip.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "Snapshotable.h"
|
||||
|
||||
class TxcChip : public Snapshotable
|
||||
{
|
||||
private:
|
||||
uint8_t _accumulator;
|
||||
uint8_t _inverter;
|
||||
uint8_t _staging;
|
||||
uint8_t _output;
|
||||
bool _increase;
|
||||
bool _yFlag;
|
||||
bool _invert;
|
||||
|
||||
uint8_t _mask;
|
||||
bool _isJv001;
|
||||
|
||||
public:
|
||||
TxcChip(bool isJv001)
|
||||
{
|
||||
_accumulator = 0;
|
||||
_inverter = 0;
|
||||
_staging = 0;
|
||||
_output = 0;
|
||||
|
||||
_increase = false;
|
||||
_yFlag = false;
|
||||
|
||||
_isJv001 = isJv001;
|
||||
_mask = isJv001 ? 0x0F : 0x07;
|
||||
_invert = isJv001;
|
||||
}
|
||||
|
||||
void StreamState(bool saving)
|
||||
{
|
||||
Stream(_accumulator, _invert, _inverter, _staging, _output, _increase, _yFlag);
|
||||
}
|
||||
|
||||
bool GetInvertFlag()
|
||||
{
|
||||
return _invert;
|
||||
}
|
||||
|
||||
bool GetY()
|
||||
{
|
||||
return _yFlag;
|
||||
}
|
||||
|
||||
uint8_t GetOutput()
|
||||
{
|
||||
return _output;
|
||||
}
|
||||
|
||||
uint8_t Read()
|
||||
{
|
||||
uint8_t value = (_accumulator & _mask) | ((_inverter ^ (_invert ? 0xFF : 0)) & ~_mask);
|
||||
_yFlag = !_invert || ((value & 0x10) != 0);
|
||||
return value;
|
||||
}
|
||||
|
||||
void Write(uint16_t addr, uint8_t value)
|
||||
{
|
||||
if(addr < 0x8000) {
|
||||
switch(addr & 0xE103) {
|
||||
case 0x4100:
|
||||
if(_increase) {
|
||||
_accumulator++;
|
||||
} else {
|
||||
_accumulator = ((_accumulator & ~_mask) | (_staging & _mask)) ^ (_invert ? 0xFF : 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x4101:
|
||||
_invert = (value & 0x01) != 0;
|
||||
break;
|
||||
|
||||
case 0x4102:
|
||||
_staging = value & _mask;
|
||||
_inverter = value & ~_mask;
|
||||
break;
|
||||
|
||||
case 0x4103:
|
||||
_increase = (value & 0x01) != 0;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(_isJv001) {
|
||||
_output = (_accumulator & 0x0F) | (_inverter & 0xF0);
|
||||
} else {
|
||||
_output = (_accumulator & 0x0F) | ((_inverter & 0x08) << 1);
|
||||
}
|
||||
}
|
||||
|
||||
_yFlag = !_invert || ((value & 0x10) != 0);
|
||||
}
|
||||
};
|
Loading…
Add table
Reference in a new issue