started docs on cpu

This commit is contained in:
Lauchmelder 2022-02-28 16:57:23 +01:00
parent 7c424b3137
commit dfef02df47
No known key found for this signature in database
GPG key ID: C2403C69D78F011D
2 changed files with 91 additions and 30 deletions

View file

@ -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);

View file

@ -11,6 +11,9 @@ class Bus;
using Operation = std::function<void(void)>;
using AddressingMode = std::function<void(void)>;
/**
* @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<Word> pastPCs;
std::deque<Instruction*> pastPCs; //< For debugging, saves the past 50 instructions
bool halted = false;
#ifndef NDEBUG
std::stringstream debugString;
#endif