// // Created by Selim Mustafaev on 11.08.2023. // #include "System.h" #include "Cartridge.h" #include "Cpu.h" #include "Ppu.h" #include "Controller.h" #include #include namespace nes { System::System(): _cycles{} #ifdef NES_LOGGING ,_logger(500*1024*1024) #endif { _ram = std::make_unique(2*1024); _cpu = std::make_unique(this); _ppu = std::make_unique(); _dma = std::make_unique(this, _ppu.get()); } void System::insertCartridge(const fs::path &path, std::optional address) { _cartridge = std::make_unique(path); _ppu->connect(_cartridge.get()); reset(address); } void System::connect(std::shared_ptr controller) { _controller1 = std::move(controller); } void System::reset(std::optional address) { _cpu->reset(); _ppu->reset(); if(address) { _cpu->setStartAddress(address.value()); } } void System::setNewFrameCallback(std::function onNewFrame) { _ppu->onNewFrame = std::move(onNewFrame); } void System::tick() { bool needInterrupt = _ppu->tick(); #ifdef NES_LOGGING _logger.addLine(_cycles, _ppu->state()); #endif if(_cycles % 3 == 0) { if(_dma->active()) { _dma->tick(_cycles); } else { bool instructionExecuted = _cpu->tick(); #ifdef NES_LOGGING if(instructionExecuted) { _logger.addLine(_cycles, _cpu->state()); } #endif } } if(needInterrupt) { _cpu->nmi(); #ifdef NES_LOGGING _logger.addLine(_cycles, "NMI"); _logger.addLine(_cycles, _cpu->state()); #endif } #ifdef NES_LOGGING if(_cycles == 3000000) { _logger.dump("/home/selim/Documents/log.txt"); } #endif _cycles++; } uint8_t System::read(uint16_t address) { if(address < 0x2000) { return _ram[address & 0x07FF]; } else if(address >= 0x2000 && address < 0x4000) { return _ppu->read(address & 0x0007); } else if(address >= 0x8000) { return _cartridge->readPrg(address); } else if(address == 0x4016) { return _controller1->read(); } else if(address == 0x4017) { // Controller 2 return 0; } return 0; } void System::write(uint16_t address, uint8_t value) { if(address < 0x2000) { _ram[address & 0x07FF] = value; } else if(address >= 0x2000 && address < 0x4000) { _ppu->write(address & 0x0007, value); } else if(address >= 0x8000) { std::cout << "Cartridge write at address: " << address << std::endl; } else if(address == 0x4014) { _dma->start(value); } else if(address == 0x4016) { _controller1->poll(); } else if(address == 0x4017) { // Controller 2 } } // For debug // Calc "hash" - just sum of the bytes of RAM // Can be useful for detecting changes in memory uint32_t System::zpHash() const { uint32_t sum = 0; for(size_t i = 0; i < 2048; ++i) { sum += _ram[i]; } return sum; } }