From dfef02df473dc813023ec5ed2c518bb992e891f0 Mon Sep 17 00:00:00 2001 From: Lauchmelder Date: Mon, 28 Feb 2022 16:57:23 +0100 Subject: [PATCH] started docs on cpu --- src/CPU.cpp | 9 ++--- src/CPU.hpp | 112 ++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 91 insertions(+), 30 deletions(-) diff --git a/src/CPU.cpp b/src/CPU.cpp index 59c11a8..8ba1230 100644 --- a/src/CPU.cpp +++ b/src/CPU.cpp @@ -53,14 +53,13 @@ uint8_t CPU::Tick() RESET_DEBUG_STRING(); APPEND_DEBUG_STRING(std::setw(4) << pc.Raw << " "); - // Implement instructions - pastPCs.push_back(pc.Raw); - if (pastPCs.size() > 50) - pastPCs.pop_front(); - Byte opcode = Read(pc.Raw++); currentInstruction = &(InstructionTable[opcode]); + pastPCs.push_back(currentInstruction); + if (pastPCs.size() > 50) + pastPCs.pop_front(); + if (currentInstruction->Operation == nullptr || currentInstruction->Mode == nullptr) { LOG_DEBUG_ERROR("Unknown instruction {0:02X} at ${1:04X}", opcode, pc.Raw); diff --git a/src/CPU.hpp b/src/CPU.hpp index 313b0ab..38ec0a0 100644 --- a/src/CPU.hpp +++ b/src/CPU.hpp @@ -11,6 +11,9 @@ class Bus; using Operation = std::function; using AddressingMode = std::function; +/** + * @brief Addressing modes of the CPU. + */ enum class Addressing { ABS, @@ -45,18 +48,25 @@ union StatusFlag Word Raw; }; +/** + * @brief Stores data of an instruction. + */ struct Instruction { Operation Operation = nullptr; - AddressingMode Mode = nullptr; - Addressing AddrType = Addressing::IMP; + AddressingMode Mode = nullptr; + Addressing AddrType = Addressing::IMP; uint8_t Size = 0; uint8_t Cycles = 0; char Mnemonic[5] = " XXX"; }; +/** + * @brief Represents the CPU. + */ class CPU { + // Give certain debugger components direct access friend class Debugger; friend class CPUWatcher; friend class Disassembler; @@ -64,44 +74,95 @@ class CPU public: CPU(Bus* bus); + /** + * @brief Do one CPU cycle. + */ uint8_t Tick(); + + /** + * @brief Powerup the CPU. + * Internal state is equal to the powerup state + */ void Powerup(); + + /** + * @brief Reset the CPU. + * Internal state is equal to the reset state + */ void Reset(); + + /** + * @brief Halt the CPU (stops it from executing anything). + */ inline void Halt() { halted = true; } + /** + * @brief Request an interrupt. + * Can be blocked if the IRQ disable flag is set in the status register + */ void IRQ(); + + /** + * @brief Trigger a non-maskable interrupt. + */ void NMI(); private: + /** + * @brief Create a lookup table of instructions. + */ void CreateInstructionTable(); + /** + * @brief Push a byte to the stack + */ inline void Push(Byte val) { Write(0x0100 | (sp--), val); } + + /** + * @brief Pop a byte from the stack. + */ inline Byte Pop() { return Read(0x0100 | (++sp)); } + + /** + * @brief Wraps Bus::ReadCPU. + */ Byte Read(Word addr); + + /** + * @brief Wraps Bus::WriteCPU. + */ void Write(Word addr, Byte val); -private: - Address rawAddress; - Address absoluteAddress; - Byte relativeAddress; - Byte fetchedVal; + +private: // Stuff regarding addressing modes + Address rawAddress; //< Temporary storage while decoding addresses + Address absoluteAddress; //< Address the current instruction operates on + Byte relativeAddress; //< (Relative) address the current instruction operates on + Byte fetchedVal; //< The value needed for the current instruction bool accumulatorAddressing = false; - void ABS(); - void ABX(); - void ABY(); - void ACC(); - void IDX(); - void IDY(); - void IMM(); - void IMP(); - void IND(); - void REL(); - void ZPG(); - void ZPX(); - void ZPY(); -private: + // The following functions all perform the same steps: + // 1. Fetch bytes needed for opcode (if any) and advance PC + // 2. Construct the address the instruction operates on (addressing mode specific) + // 3. Fetch the value in RAM at that address + void ABS(); // Absolute + void ABX(); // Absolute X-indexed + void ABY(); // Absolute Y-indexed + void ACC(); // Accumulator + void IDX(); // X-indexed indirect + void IDY(); // Indirect Y-indexed + void IMM(); // Immediate + void IMP(); // Implied + void IND(); // Indirect + void REL(); // Relative + void ZPG(); // Zeropage + void ZPX(); // Zeropage X-indexed + void ZPY(); // Zeropage Y-indexed + +private: // Stuff regarding instructions + // Instructions that the NES can perform + // They simply perform the operations needed void ADC(); void AND(); void ASL(); @@ -167,20 +228,21 @@ private: void TXS(); void TYA(); -private: +private: // CPU internals + // Registers Byte acc; Byte idx, idy; Address pc; Word sp; - StatusFlag status; Instruction* currentInstruction = nullptr; uint8_t remainingCycles = 0; - uint8_t additionalCycles = 0; + uint8_t additionalCycles = 0; //< E.g. when a page boundary was crossed uint64_t totalCycles = 0; - std::deque pastPCs; + std::deque pastPCs; //< For debugging, saves the past 50 instructions bool halted = false; + #ifndef NDEBUG std::stringstream debugString; #endif