diff --git a/CMakeLists.txt b/CMakeLists.txt index 4653830..ab8c120 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,8 +13,6 @@ add_executable(nes src/Nes.h src/Cpu.cpp src/Cpu.h - src/Bus.cpp - src/Bus.h src/Mapper/Mapper.cpp src/Mapper/Mapper.h src/Mapper/Mapper0.cpp diff --git a/src/Bus.cpp b/src/Bus.cpp deleted file mode 100644 index d3ead41..0000000 --- a/src/Bus.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// -// Created by Selim Mustafaev on 12.08.2023. -// - -#include "Bus.h" -#include -#include - -namespace nes { - - Bus::Bus(): _cartridge{nullptr} { - _ram = std::make_unique(2*1024); - } - - uint8_t Bus::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 Bus::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 - } - else if(address == 0x4016) { - _controller1->poll(); - } - else if(address == 0x4017) { - // Controller 2 - } - } - - void Bus::connect(std::shared_ptr cartridge) { - _cartridge = std::move(cartridge); - } - - void Bus::connect(std::shared_ptr ppu) { - _ppu = std::move(ppu); - } - - void Bus::connect(std::shared_ptr controller) { - _controller1 = std::move(controller); - } - - // For debug - // Calc "hash" - just sum of the bytes of first page - // Can be useful for detecting change in ram - uint32_t Bus::zpHash() const { - uint32_t sum = 0; - for(size_t i = 0; i < 2048; ++i) { - sum += _ram[i]; - } - return sum; - } -} \ No newline at end of file diff --git a/src/Bus.h b/src/Bus.h deleted file mode 100644 index 6e9db1e..0000000 --- a/src/Bus.h +++ /dev/null @@ -1,36 +0,0 @@ -// -// Created by Selim Mustafaev on 12.08.2023. -// - -#ifndef NES_BUS_H -#define NES_BUS_H - -#include "Cartridge.h" -#include "Ppu.h" -#include "Controller.h" - -#include -#include - -namespace nes { - - class Bus { - public: - Bus(); - uint8_t read(uint16_t address); - void write(uint16_t address, uint8_t value); - void connect(std::shared_ptr cartridge); - void connect(std::shared_ptr ppu); - void connect(std::shared_ptr controller); - [[nodiscard]] uint32_t zpHash() const; - - private: - std::unique_ptr _ram; - std::shared_ptr _cartridge; - std::shared_ptr _ppu; - std::shared_ptr _controller1; - }; - -} - -#endif //NES_BUS_H diff --git a/src/Cpu.cpp b/src/Cpu.cpp index 5ab294c..01a6aef 100644 --- a/src/Cpu.cpp +++ b/src/Cpu.cpp @@ -3,13 +3,14 @@ // #include "Cpu.h" +#include "Nes.h" #include #include namespace nes { - Cpu::Cpu(): _ticks{}, A{}, X{}, Y{}, PC{}, SP{}, flags{} { - _bus = std::make_unique(); + Cpu::Cpu(Nes* system): _ticks{}, A{}, X{}, Y{}, PC{}, SP{}, flags{} { + _system = system; _instructions = std::vector(256); _instructions[0x00] = {"BRK", &Cpu::BRK, &Cpu::IMP, 7, false}; _instructions[0x01] = {"ORA", &Cpu::ORA, &Cpu::IZX, 6, false}; @@ -170,8 +171,8 @@ namespace nes { SP = 0xFD; flags = 0; - uint16_t lo = _bus->read(0xFFFC); - uint16_t hi = _bus->read(0xFFFD); + uint16_t lo = _system->read(0xFFFC); + uint16_t hi = _system->read(0xFFFD); PC = (hi << 8) | lo; @@ -182,7 +183,7 @@ namespace nes { bool executed = false; if(_ticks == 0) { - uint8_t opcode = _bus->read(PC++); + uint8_t opcode = _system->read(PC++); auto instruction = _instructions[opcode]; _currentOpcode = opcode; @@ -207,16 +208,16 @@ namespace nes { } void Cpu::nmi() { - _bus->write(STACK_BASE + SP--, PC >> 8); - _bus->write(STACK_BASE + SP--, PC & 0x00FF); + _system->write(STACK_BASE + SP--, PC >> 8); + _system->write(STACK_BASE + SP--, PC & 0x00FF); setFlag(Break, false); setFlag(Unused, true); setFlag(InterruptDisable, true); - _bus->write(STACK_BASE + SP--, flags); + _system->write(STACK_BASE + SP--, flags); - uint8_t lo = _bus->read(0xFFFA); - uint8_t hi = _bus->read(0xFFFB); + uint8_t lo = _system->read(0xFFFA); + uint8_t hi = _system->read(0xFFFB); PC = (hi << 8) | lo; _ticks = 8; @@ -234,7 +235,7 @@ namespace nes { (int)getFlag(InterruptDisable), (int)getFlag(Zero), (int)getFlag(Carry), - _bus->zpHash()); + _system->zpHash()); } void Cpu::setFlag(CpuFlags flag, bool value) { @@ -253,10 +254,6 @@ namespace nes { PC = address; } - Bus* Cpu::bus() const { - return _bus.get(); - } - void Cpu::branch(Cpu::InstructionArgs args) { _ticks++; @@ -278,8 +275,8 @@ namespace nes { } Cpu::InstructionArgs Cpu::ABS() { - uint8_t lo = _bus->read(PC++); - uint8_t hi = _bus->read(PC++); + uint8_t lo = _system->read(PC++); + uint8_t hi = _system->read(PC++); uint16_t address = (hi << 8) | lo; return {address, 0}; } @@ -289,7 +286,7 @@ namespace nes { } Cpu::InstructionArgs Cpu::REL() { - uint16_t address = _bus->read(PC++); + uint16_t address = _system->read(PC++); if (address & 0x80) { address |= 0xFF00; @@ -299,22 +296,22 @@ namespace nes { } Cpu::InstructionArgs Cpu::ZP0() { - uint16_t address = _bus->read(PC++); + uint16_t address = _system->read(PC++); return {address, 0}; } Cpu::InstructionArgs Cpu::IZX() { - uint8_t ptrAddress = _bus->read(PC++) + X; - uint8_t lo = _bus->read(ptrAddress); - uint8_t hi = _bus->read(++ptrAddress); + uint8_t ptrAddress = _system->read(PC++) + X; + uint8_t lo = _system->read(ptrAddress); + uint8_t hi = _system->read(++ptrAddress); uint16_t address = (hi << 8) | lo; return {address, 0}; } Cpu::InstructionArgs Cpu::IZY() { - uint8_t ptrAddress = _bus->read(PC++); - uint8_t lo = _bus->read(ptrAddress); - uint8_t hi = _bus->read(++ptrAddress); + uint8_t ptrAddress = _system->read(PC++); + uint8_t lo = _system->read(ptrAddress); + uint8_t hi = _system->read(++ptrAddress); uint16_t address = (hi << 8) | lo; address += Y; @@ -327,17 +324,17 @@ namespace nes { } Cpu::InstructionArgs Cpu::IND() { - uint8_t ptrLo = _bus->read(PC++); - uint8_t ptrHi = _bus->read(PC++); + uint8_t ptrLo = _system->read(PC++); + uint8_t ptrHi = _system->read(PC++); uint16_t ptrAddress = (ptrHi << 8) | ptrLo; - uint8_t lo = _bus->read(ptrAddress); + uint8_t lo = _system->read(ptrAddress); uint8_t hi = 0; if(ptrLo == 0xFF) { - hi = _bus->read(ptrAddress & 0xFF00); + hi = _system->read(ptrAddress & 0xFF00); } else { - hi = _bus->read(++ptrAddress); + hi = _system->read(++ptrAddress); } uint16_t address = (hi << 8) | lo; @@ -345,8 +342,8 @@ namespace nes { } Cpu::InstructionArgs Cpu::ABX() { - uint8_t lo = _bus->read(PC++); - uint8_t hi = _bus->read(PC++); + uint8_t lo = _system->read(PC++); + uint8_t hi = _system->read(PC++); uint16_t address = (hi << 8) | lo; address += X; @@ -359,8 +356,8 @@ namespace nes { } Cpu::InstructionArgs Cpu::ABY() { - uint8_t lo = _bus->read(PC++); - uint8_t hi = _bus->read(PC++); + uint8_t lo = _system->read(PC++); + uint8_t hi = _system->read(PC++); uint16_t address = (hi << 8) | lo; address += Y; @@ -373,41 +370,41 @@ namespace nes { } Cpu::InstructionArgs Cpu::ZPX() { - uint8_t address = _bus->read(PC++) + X; + uint8_t address = _system->read(PC++) + X; return {address, 0}; } Cpu::InstructionArgs Cpu::ZPY() { - uint8_t address = _bus->read(PC++) + Y; + uint8_t address = _system->read(PC++) + Y; return {address, 0}; } // CPU instructions void Cpu::LDA(Cpu::InstructionArgs args) { - A = _bus->read(args.address); + A = _system->read(args.address); setFlag(Negative, A & 0x80); setFlag(Zero, A == 0); } void Cpu::LDX(InstructionArgs args) { - X = _bus->read(args.address); + X = _system->read(args.address); setFlag(Negative, X & 0x80); setFlag(Zero, X == 0); } void Cpu::LDY(Cpu::InstructionArgs args) { - Y = _bus->read(args.address); + Y = _system->read(args.address); setFlag(Negative, Y & 0x80); setFlag(Zero, Y == 0); } void Cpu::STA(Cpu::InstructionArgs args) { - _bus->write(args.address, A); + _system->write(args.address, A); } void Cpu::STX(InstructionArgs args) { - _bus->write(args.address, X); + _system->write(args.address, X); } void Cpu::CLC(Cpu::InstructionArgs args) { @@ -415,7 +412,7 @@ namespace nes { } void Cpu::ADC(Cpu::InstructionArgs args) { - uint16_t value = _bus->read(args.address); + uint16_t value = _system->read(args.address); uint16_t result = A + value + getFlag(Carry); setFlag(Carry, result > 255); @@ -427,7 +424,7 @@ namespace nes { } void Cpu::SBC(Cpu::InstructionArgs args) { - uint16_t value = _bus->read(args.address) ^ 0xFF; + uint16_t value = _system->read(args.address) ^ 0xFF; uint16_t result = A + value + getFlag(Carry); setFlag(Carry, result > 255); @@ -477,8 +474,8 @@ namespace nes { void Cpu::JSR(Cpu::InstructionArgs args) { PC--; - _bus->write(STACK_BASE + SP--, PC >> 8); - _bus->write(STACK_BASE + SP--, PC & 0x00FF); + _system->write(STACK_BASE + SP--, PC >> 8); + _system->write(STACK_BASE + SP--, PC & 0x00FF); PC = args.address; } @@ -505,7 +502,7 @@ namespace nes { } void Cpu::BIT(Cpu::InstructionArgs args) { - uint8_t value = _bus->read(args.address); + uint8_t value = _system->read(args.address); setFlag(Zero, (A & value) == 0); setFlag(Negative, value & (1 << 7)); setFlag(Overflow, value & (1 << 6)); @@ -524,8 +521,8 @@ namespace nes { } void Cpu::RTS(Cpu::InstructionArgs args) { - uint16_t lo = _bus->read(STACK_BASE + ++SP); - uint16_t hi = _bus->read(STACK_BASE + ++SP); + uint16_t lo = _system->read(STACK_BASE + ++SP); + uint16_t hi = _system->read(STACK_BASE + ++SP); PC = (hi << 8) | lo; PC++; @@ -536,25 +533,25 @@ namespace nes { } void Cpu::PHP(Cpu::InstructionArgs args) { - _bus->write(STACK_BASE + SP--, flags | Break | Unused); + _system->write(STACK_BASE + SP--, flags | Break | Unused); setFlag(Break, false); setFlag(Unused, false); } void Cpu::PLA(Cpu::InstructionArgs args) { - A = _bus->read(STACK_BASE + ++SP); + A = _system->read(STACK_BASE + ++SP); setFlag(Zero, A == 0); setFlag(Negative, A & 0x80); } void Cpu::AND(Cpu::InstructionArgs args) { - A &= _bus->read(args.address);; + A &= _system->read(args.address);; setFlag(Zero, A == 0); setFlag(Negative, A & 0x80); } void Cpu::CMP(Cpu::InstructionArgs args) { - uint16_t value = _bus->read(args.address); + uint16_t value = _system->read(args.address); uint16_t diff = A - value; setFlag(Carry, A >= value); setFlag(Zero, (diff & 0x00FF) == 0); @@ -568,16 +565,16 @@ namespace nes { } void Cpu::PHA(Cpu::InstructionArgs args) { - _bus->write(STACK_BASE + SP--, A); + _system->write(STACK_BASE + SP--, A); } void Cpu::PLP(Cpu::InstructionArgs args) { - flags = _bus->read(STACK_BASE + ++SP); + flags = _system->read(STACK_BASE + ++SP); setFlag(Unused, true); } void Cpu::ORA(Cpu::InstructionArgs args) { - A |= _bus->read(args.address); + A |= _system->read(args.address); setFlag(Zero, A == 0); setFlag(Negative, A & 0x80); } @@ -587,13 +584,13 @@ namespace nes { } void Cpu::EOR(Cpu::InstructionArgs args) { - A ^= _bus->read(args.address); + A ^= _system->read(args.address); setFlag(Zero, A == 0); setFlag(Negative, A & 0x80); } void Cpu::CPY(Cpu::InstructionArgs args) { - uint16_t value = _bus->read(args.address); + uint16_t value = _system->read(args.address); uint16_t diff = Y - value; setFlag(Carry, Y >= value); setFlag(Zero, (diff & 0x00FF) == 0); @@ -601,7 +598,7 @@ namespace nes { } void Cpu::CPX(Cpu::InstructionArgs args) { - uint16_t value = _bus->read(args.address); + uint16_t value = _system->read(args.address); uint16_t diff = X - value; setFlag(Carry, X >= value); setFlag(Zero, (diff & 0x00FF) == 0); @@ -609,7 +606,7 @@ namespace nes { } void Cpu::STY(Cpu::InstructionArgs args) { - _bus->write(args.address, Y); + _system->write(args.address, Y); } void Cpu::INY(Cpu::InstructionArgs args) { @@ -664,25 +661,25 @@ namespace nes { PC++; setFlag(InterruptDisable, true); - _bus->write(STACK_BASE + SP--, PC >> 8); - _bus->write(STACK_BASE + SP--, PC & 0x00FF); + _system->write(STACK_BASE + SP--, PC >> 8); + _system->write(STACK_BASE + SP--, PC & 0x00FF); setFlag(Break, true); - _bus->write(STACK_BASE + SP--, flags); + _system->write(STACK_BASE + SP--, flags); setFlag(Break, false); - uint16_t lo = _bus->read(0xFFFE); - uint16_t hi = _bus->read(0xFFFF); + uint16_t lo = _system->read(0xFFFE); + uint16_t hi = _system->read(0xFFFF); PC = (hi << 8) | lo; } void Cpu::RTI(Cpu::InstructionArgs args) { - flags = _bus->read(STACK_BASE + ++SP); + flags = _system->read(STACK_BASE + ++SP); setFlag(Break, false); setFlag(Unused, false); - uint16_t lo = _bus->read(STACK_BASE + ++SP); - uint16_t hi = _bus->read(STACK_BASE + ++SP); + uint16_t lo = _system->read(STACK_BASE + ++SP); + uint16_t hi = _system->read(STACK_BASE + ++SP); PC = (hi << 8) | lo; } @@ -694,12 +691,12 @@ namespace nes { } void Cpu::LSR(Cpu::InstructionArgs args) { - uint8_t value = _bus->read(args.address); + uint8_t value = _system->read(args.address); setFlag(Carry, value & 0x01); value = value >> 1; setFlag(Zero, value == 0); setFlag(Negative, value & 0x80); - _bus->write(args.address, value); + _system->write(args.address, value); } void Cpu::ASL_ACC(Cpu::InstructionArgs args) { @@ -710,12 +707,12 @@ namespace nes { } void Cpu::ASL(Cpu::InstructionArgs args) { - uint8_t value = _bus->read(args.address); + uint8_t value = _system->read(args.address); setFlag(Carry, value & 0x80); value = value << 1; setFlag(Zero, value == 0); setFlag(Negative, value & 0x80); - _bus->write(args.address, value); + _system->write(args.address, value); } void Cpu::ROR_ACC(Cpu::InstructionArgs args) { @@ -727,13 +724,13 @@ namespace nes { } void Cpu::ROR(Cpu::InstructionArgs args) { - uint8_t value = _bus->read(args.address); + uint8_t value = _system->read(args.address); uint8_t carryOriginal = getFlag(Carry); setFlag(Carry, value & 0x01); value = (value >> 1) | (carryOriginal << 7); setFlag(Zero, value == 0); setFlag(Negative, value & 0x80); - _bus->write(args.address, value); + _system->write(args.address, value); } void Cpu::ROL_ACC(Cpu::InstructionArgs args) { @@ -745,25 +742,25 @@ namespace nes { } void Cpu::ROL(Cpu::InstructionArgs args) { - uint8_t value = _bus->read(args.address); + uint8_t value = _system->read(args.address); uint8_t carryOriginal = getFlag(Carry); setFlag(Carry, value & 0x80); value = (value << 1) | carryOriginal; setFlag(Zero, value == 0); setFlag(Negative, value & 0x80); - _bus->write(args.address, value); + _system->write(args.address, value); } void Cpu::INC(Cpu::InstructionArgs args) { - uint8_t value = _bus->read(args.address); - _bus->write(args.address, ++value); + uint8_t value = _system->read(args.address); + _system->write(args.address, ++value); setFlag(Zero, value == 0); setFlag(Negative, value & 0x80); } void Cpu::DEC(Cpu::InstructionArgs args) { - uint8_t value = _bus->read(args.address); - _bus->write(args.address, --value); + uint8_t value = _system->read(args.address); + _system->write(args.address, --value); setFlag(Zero, value == 0); setFlag(Negative, value & 0x80); } diff --git a/src/Cpu.h b/src/Cpu.h index b1ca692..4295105 100644 --- a/src/Cpu.h +++ b/src/Cpu.h @@ -5,12 +5,14 @@ #ifndef NES_CPU_H #define NES_CPU_H -#include "Bus.h" #include #include +#include namespace nes { + class Nes; + enum CpuFlags: uint8_t { Carry = (1 << 0), Zero = (1 << 1), @@ -40,19 +42,18 @@ namespace nes { static constexpr uint16_t STACK_BASE = 0x0100; public: - Cpu(); + explicit Cpu(Nes* system); void reset(); bool tick(); void setFlag(CpuFlags flag, bool value); bool getFlag(CpuFlags flag) const; void setStartAddress(uint16_t address); - Bus* bus() const; void nmi(); std::string state() const; private: size_t _ticks; - std::unique_ptr _bus; + Nes* _system; std::vector _instructions; private: diff --git a/src/Nes.cpp b/src/Nes.cpp index f90a8b3..e5e8e6d 100644 --- a/src/Nes.cpp +++ b/src/Nes.cpp @@ -5,8 +5,11 @@ #include "Nes.h" #include "Cartridge.h" #include "Cpu.h" +#include "Ppu.h" +#include "Controller.h" #include +#include namespace nes { @@ -16,20 +19,19 @@ namespace nes { ,_logger(500*1024*1024) #endif { - _cpu = std::make_unique(); - _ppu = std::make_shared(); + _ram = std::make_unique(2*1024); + _cpu = std::make_unique(this); + _ppu = std::make_unique(); } void Nes::insertCartridge(const fs::path &path, std::optional address) { - _cartridge = std::make_shared(path); - _cpu->bus()->connect(_cartridge); - _cpu->bus()->connect(_ppu); - _ppu->connect(_cartridge); + _cartridge = std::make_unique(path); + _ppu->connect(_cartridge.get()); reset(address); } void Nes::connect(std::shared_ptr controller) { - _cpu->bus()->connect(std::move(controller)); + _controller1 = std::move(controller); } void Nes::reset(std::optional address) { @@ -77,4 +79,56 @@ namespace nes { _cycles++; } + uint8_t Nes::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 Nes::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 + } + 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 Nes::zpHash() const { + uint32_t sum = 0; + for(size_t i = 0; i < 2048; ++i) { + sum += _ram[i]; + } + return sum; + } } diff --git a/src/Nes.h b/src/Nes.h index 5d37b00..f8a1f74 100644 --- a/src/Nes.h +++ b/src/Nes.h @@ -5,16 +5,19 @@ #ifndef NES_NES_H #define NES_NES_H -#include "Cpu.h" -#include "Cartridge.h" -#include "Ppu.h" #include "Logger.h" +#include "Cpu.h" +#include "Ppu.h" +#include "Cartridge.h" #include #include +#include namespace nes { + class Controller; + namespace fs = std::filesystem; class Nes { @@ -26,11 +29,17 @@ namespace nes { void setNewFrameCallback(std::function onNewFrame); void tick(); + uint8_t read(uint16_t address); + void write(uint16_t address, uint8_t value); + [[nodiscard]] uint32_t zpHash() const; + private: uint64_t _cycles; + std::unique_ptr _ram; std::unique_ptr _cpu; - std::shared_ptr _ppu; - std::shared_ptr _cartridge; + std::unique_ptr _ppu; + std::unique_ptr _cartridge; + std::shared_ptr _controller1; #ifdef NES_LOGGING Logger _logger; diff --git a/src/Ppu.cpp b/src/Ppu.cpp index 66d2897..4116cb4 100644 --- a/src/Ppu.cpp +++ b/src/Ppu.cpp @@ -234,8 +234,8 @@ namespace nes { _frameBuffer[index] = pixel; } - void Ppu::connect(std::shared_ptr cartridge) { - _cartridge = std::move(cartridge); + void Ppu::connect(Cartridge* cartridge) { + _cartridge = cartridge; } void Ppu::reset() { diff --git a/src/Ppu.h b/src/Ppu.h index ecf73c7..d3bd7fd 100644 --- a/src/Ppu.h +++ b/src/Ppu.h @@ -110,7 +110,7 @@ namespace nes { void write(uint16_t address, uint8_t value); uint8_t read(uint16_t address); void setPixel(uint16_t row, uint16_t column, Pixel pixel); - void connect(std::shared_ptr cartridge); + void connect(Cartridge* cartridge); void reset(); std::string state() const; @@ -154,7 +154,7 @@ namespace nes { private: std::unique_ptr _frameBuffer; - std::shared_ptr _cartridge; + Cartridge* _cartridge; private: // For debug uint8_t _curPalette;