141 lines
3.5 KiB
C++
141 lines
3.5 KiB
C++
//
|
|
// Created by Selim Mustafaev on 11.08.2023.
|
|
//
|
|
|
|
#include "System.h"
|
|
#include "Cartridge.h"
|
|
#include "Cpu.h"
|
|
#include "Ppu.h"
|
|
#include "Controller.h"
|
|
|
|
#include <utility>
|
|
#include <iostream>
|
|
|
|
namespace nes {
|
|
|
|
System::System():
|
|
_cycles{}
|
|
#ifdef NES_LOGGING
|
|
,_logger(500*1024*1024)
|
|
#endif
|
|
{
|
|
_ram = std::make_unique<uint8_t[]>(2*1024);
|
|
_cpu = std::make_unique<Cpu>(this);
|
|
_ppu = std::make_unique<Ppu>();
|
|
_dma = std::make_unique<Dma>(this, _ppu.get());
|
|
_controller1 = std::make_shared<Controller>();
|
|
}
|
|
|
|
void System::insertCartridge(const fs::path &path, std::optional<uint16_t> address) {
|
|
_cartridge = std::make_unique<Cartridge>(path);
|
|
_ppu->connect(_cartridge.get());
|
|
reset(address);
|
|
}
|
|
|
|
void System::connect(std::shared_ptr<Controller> controller) {
|
|
_controller1 = std::move(controller);
|
|
}
|
|
|
|
void System::reset(std::optional<uint16_t> address) {
|
|
_cpu->reset();
|
|
_ppu->reset();
|
|
if(address) {
|
|
_cpu->setStartAddress(address.value());
|
|
}
|
|
}
|
|
|
|
void System::setNewFrameCallback(std::function<void(const Pixel *)> 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;
|
|
}
|
|
}
|