1 #pragma once 2 #include "stdafx.h" 3 #include "BaseMapper.h" 4 #include "CPU.h" 5 #include "MemoryManager.h" 6 7 class Yoko : public BaseMapper 8 { 9 uint8_t _regs[7]; 10 uint8_t _exRegs[4]; 11 uint8_t _mode; 12 uint8_t _bank; 13 uint16_t _irqCounter; 14 bool _irqEnabled; 15 16 protected: GetDipSwitchCount()17 uint32_t GetDipSwitchCount() override { return 2; } RegisterStartAddress()18 uint16_t RegisterStartAddress() override { return 0x5000; } RegisterEndAddress()19 uint16_t RegisterEndAddress() override { return 0x5FFF; } GetPRGPageSize()20 uint16_t GetPRGPageSize() override { return 0x2000; } GetCHRPageSize()21 uint16_t GetCHRPageSize() override { return 0x800; } AllowRegisterRead()22 bool AllowRegisterRead() override { return true; } 23 InitMapper()24 void InitMapper() override 25 { 26 memset(_regs, 0, sizeof(_regs)); 27 memset(_exRegs, 0, sizeof(_exRegs)); 28 _mode = 0; 29 _bank = 0; 30 _irqCounter = 0; 31 _irqEnabled = false; 32 33 RemoveRegisterRange(0x5000, 0x53FF, MemoryOperation::Write); 34 AddRegisterRange(0x8000, 0xFFFF, MemoryOperation::Write); 35 36 UpdateState(); 37 } 38 StreamState(bool saving)39 void StreamState(bool saving) override 40 { 41 BaseMapper::StreamState(saving); 42 43 ArrayInfo<uint8_t> regs { _regs, 7 }; 44 ArrayInfo<uint8_t> exRegs { _exRegs, 4 }; 45 Stream(regs, exRegs, _mode, _bank, _irqCounter, _irqEnabled); 46 } 47 Reset(bool softReset)48 void Reset(bool softReset) override 49 { 50 if(softReset) { 51 _mode = 0; 52 _bank = 0; 53 } 54 } 55 ProcessCpuClock()56 void ProcessCpuClock() override 57 { 58 if(_irqEnabled) { 59 _irqCounter--; 60 if(_irqCounter == 0) { 61 _irqEnabled = false; 62 _irqCounter = 0xFFFF; 63 _console->GetCpu()->SetIrqSource(IRQSource::External); 64 } 65 } 66 } 67 UpdateState()68 void UpdateState() 69 { 70 SetMirroringType(_mode & 0x01 ? MirroringType::Horizontal : MirroringType::Vertical); 71 72 SelectCHRPage(0, _regs[3]); 73 SelectCHRPage(1, _regs[4]); 74 SelectCHRPage(2, _regs[5]); 75 SelectCHRPage(3, _regs[6]); 76 77 if(_mode & 0x10) { 78 uint32_t outer = (_bank & 0x08) << 1; 79 SelectPRGPage(0, outer | (_regs[0] & 0x0F)); 80 SelectPRGPage(1, outer | (_regs[1] & 0x0F)); 81 SelectPRGPage(2, outer | (_regs[2] & 0x0F)); 82 SelectPRGPage(3, outer | 0x0F); 83 } else if(_mode & 0x08) { 84 SelectPrgPage4x(0, (_bank & 0xFE) << 1); 85 } else { 86 SelectPrgPage2x(0, _bank << 1); 87 SelectPrgPage2x(1, -2); 88 } 89 } 90 ReadRegister(uint16_t addr)91 uint8_t ReadRegister(uint16_t addr) override 92 { 93 if(addr <= 0x53FF) { 94 return (_console->GetMemoryManager()->GetOpenBus() & 0xFC) | GetDipSwitches(); 95 } else { 96 return _exRegs[addr & 0x03]; 97 } 98 } 99 WriteRegister(uint16_t addr,uint8_t value)100 void WriteRegister(uint16_t addr, uint8_t value) override 101 { 102 if(addr < 0x8000) { 103 _exRegs[addr & 0x03] = value; 104 } else { 105 switch(addr & 0x8C17) { 106 case 0x8000: _bank = value; UpdateState(); break; 107 case 0x8400: _mode = value; UpdateState(); break; 108 case 0x8800: 109 _irqCounter = (_irqCounter & 0xFF00) | value; 110 _console->GetCpu()->ClearIrqSource(IRQSource::External); 111 break; 112 case 0x8801: 113 _irqEnabled = (_mode & 0x80) != 0; 114 _irqCounter = (_irqCounter & 0xFF) | (value << 8); 115 break; 116 case 0x8c00: _regs[0] = value; UpdateState(); break; 117 case 0x8c01: _regs[1] = value; UpdateState(); break; 118 case 0x8c02: _regs[2] = value; UpdateState(); break; 119 case 0x8c10: _regs[3] = value; UpdateState(); break; 120 case 0x8c11: _regs[4] = value; UpdateState(); break; 121 case 0x8c16: _regs[5] = value; UpdateState(); break; 122 case 0x8c17: _regs[6] = value; UpdateState(); break; 123 } 124 } 125 } 126 }; 127