Refactor PPU and CPU classes by removing Clock dependency and updating constructors

This commit is contained in:
scawful
2025-01-18 00:12:12 -05:00
parent 70510ec0e9
commit 1c53ba24c5
7 changed files with 10 additions and 454 deletions

View File

@@ -1,61 +0,0 @@
#ifndef YAZE_APP_EMU_CLOCK_H_
#define YAZE_APP_EMU_CLOCK_H_
#include <cstdint>
namespace yaze {
namespace emu {
class Clock {
public:
virtual ~Clock() = default;
virtual void UpdateClock(double delta) = 0;
virtual unsigned long long GetCycleCount() const = 0;
virtual void ResetAccumulatedTime() = 0;
virtual void SetFrequency(float new_frequency) = 0;
virtual float GetFrequency() const = 0;
};
class ClockImpl : public Clock {
public:
ClockImpl() = default;
virtual ~ClockImpl() = default;
void UpdateCycleCount(double delta_time) {
accumulated_time += delta_time;
double cycle_time = 1.0 / frequency;
while (accumulated_time >= cycle_time) {
Cycle();
accumulated_time -= cycle_time;
}
}
void Cycle() {
cycle++;
cycle_count++;
}
void UpdateClock(double delta) override {
UpdateCycleCount(delta);
ResetAccumulatedTime();
}
void ResetAccumulatedTime() override { accumulated_time = 0.0; }
unsigned long long GetCycleCount() const override { return cycle_count; }
float GetFrequency() const override { return frequency; }
void SetFrequency(float new_frequency) override {
this->frequency = new_frequency;
}
private:
uint64_t cycle = 0; // Current cycle
float frequency = 0.0; // Frequency of the clock in Hz
unsigned long long cycle_count = 0; // Total number of cycles executed
double accumulated_time = 0.0; // Accumulated time since the last cycle update
};
} // namespace emu
} // namespace yaze
#endif // YAZE_APP_EMU_CLOCK_H_

View File

@@ -102,7 +102,6 @@ void Cpu::DoInterrupt() {
}
void Cpu::ExecuteInstruction(uint8_t opcode) {
uint8_t instruction_length = 0;
uint16_t cache_pc = PC;
uint32_t operand = 0;
bool immediate = false;
@@ -1798,8 +1797,6 @@ void Cpu::ExecuteInstruction(uint8_t opcode) {
if (log_instructions_) {
LogInstructions(cache_pc, opcode, operand, immediate, accumulator_mode);
}
// instruction_length = GetInstructionLength(opcode);
// UpdatePC(instruction_length);
}
void Cpu::LogInstructions(uint16_t PC, uint8_t opcode, uint16_t operand,
@@ -1909,355 +1906,6 @@ void Cpu::LogInstructions(uint16_t PC, uint8_t opcode, uint16_t operand,
std::cout << std::endl;
}
}
/**
uint8_t Cpu::GetInstructionLength(uint8_t opcode) {
switch (opcode) {
case 0x00: // BRK
case 0x02: // COP
PC = next_pc_;
PB = next_pb_;
return 0;
case 0x20: // JSR Absolute
case 0x4C: // JMP Absolute
case 0x6C: // JMP Absolute Indirect
case 0x7C: // JMP Absolute Indexed Indirect
case 0xFC: // JSR Absolute Indexed Indirect
case 0xDC: // JMP Absolute Indirect Long
case 0x6B: // RTL
case 0x82: // BRL Relative Long
PC = next_pc_;
return 0;
case 0x22: // JSL Absolute Long
case 0x5C: // JMP Absolute Indexed Indirect
PC = next_pc_;
PB = next_pb_;
return 0;
case 0x80: // BRA Relative
PC += next_pc_;
return 2;
case 0x60: // RTS
PC = last_call_frame_;
return 3;
// Branch Instructions (BCC, BCS, BNE, BEQ, etc.)
case 0x90: // BCC near
if (!GetCarryFlag()) {
PC = next_pc_;
return 0;
} else {
return 2;
}
case 0xB0: // BCS near
if (GetCarryFlag()) {
PC = next_pc_;
return 0;
} else {
return 2;
}
case 0x30: // BMI near
if (GetNegativeFlag()) {
PC = next_pc_;
return 0;
} else {
return 2;
}
case 0xF0: // BEQ near
if (GetZeroFlag()) {
PC = next_pc_;
return 0;
} else {
return 2;
}
case 0xD0: // BNE Relative
if (!GetZeroFlag()) {
PC += next_pc_;
}
return 2;
case 0x10: // BPL Relative
if (!GetNegativeFlag()) {
PC = next_pc_;
return 0;
} else {
return 2;
}
case 0x50: // BVC Relative
if (!GetOverflowFlag()) {
PC = next_pc_;
return 0;
} else {
return 2;
}
case 0x70: // BVS Relative
if (GetOverflowFlag()) {
PC = next_pc_;
return 0;
} else {
return 2;
}
case 0x18: // CLC
case 0xD8: // CLD
case 0x58: // CLI
case 0xB8: // CLV
case 0xCA: // DEX
case 0x88: // DEY
case 0xE8: // INX
case 0xC8: // INY
case 0xEA: // NOP
case 0x48: // PHA
case 0x8B: // PHB
case 0x0B: // PHD
case 0x4B: // PHK
case 0x08: // PHP
case 0xDA: // PHX
case 0x5A: // PHY
case 0x68: // PLA
case 0xAB: // PLB
case 0x2B: // PLD
case 0x28: // PLP
case 0xFA: // PLX
case 0x7A: // PLY
case 0x40: // RTI
case 0x38: // SEC
case 0xF8: // SED
case 0xBB: // TYX
case 0x78: // SEI
case 0xAA: // TAX
case 0xA8: // TAY
case 0xBA: // TSX
case 0x8A: // TXA
case 0x9B: // TXY
case 0x9A: // TXS
case 0x98: // TYA
case 0x0A: // ASL Accumulator
case 0x2A: // ROL Accumulator
case 0xFB: // XCE
case 0x5B: // TCD
case 0x1B: // TCS
case 0x3A: // DEC Accumulator
case 0x1A: // INC Accumulator
case 0x7B: // TDC
case 0x3B: // TSC
case 0xEB: // XBA
case 0xCB: // WAI
case 0xDB: // STP
case 0x4A: // LSR Accumulator
case 0x6A: // ROR Accumulator
return 1;
case 0xC2: // REP
case 0xE2: // SEP
case 0xE4: // CPX Direct Page
case 0xC4: // CPY Direct Page
case 0xD6: // DEC Direct Page Indexed, X
case 0x45: // EOR Direct Page
case 0xA5: // LDA Direct Page
case 0x05: // ORA Direct Page
case 0x85: // STA Direct Page
case 0xC6: // DEC Direct Page
case 0x97: // STA Direct Page Indexed Y
case 0x25: // AND Direct Page
case 0x32: // AND Direct Page Indirect Indexed Y
case 0x27: // AND Direct Page Indirect Long
case 0x35: // AND Direct Page Indexed X
case 0x21: // AND Direct Page Indirect Indexed Y
case 0x31: // AND Direct Page Indirect Long Indexed Y
case 0x37: // AND Direct Page Indirect Long Indexed Y
case 0x23: // AND Direct Page Indirect Indexed X
case 0x33: // AND Direct Page Indirect Long Indexed Y
case 0xE6: // INC Direct Page
case 0x81: // STA Direct Page Indirect, X
case 0x01: // ORA Direct Page Indirect, X
case 0x19: // ORA Direct Page Indirect Indexed, Y
case 0x1D: // ORA Absolute Indexed, X
case 0x89: // BIT Immediate
case 0x91: // STA Direct Page Indirect Indexed, Y
case 0x65: // ADC Direct Page
case 0x72: // ADC Direct Page Indirect
case 0x67: // ADC Direct Page Indirect Long
case 0x75: // ADC Direct Page Indexed, X
case 0x61: // ADC Direct Page Indirect, X
case 0x71: // ADC DP Indirect Indexed, Y
case 0x77: // ADC DP Indirect Long Indexed, Y
case 0x63: // ADC Stack Relative
case 0x73: // ADC SR Indirect Indexed, Y
case 0x06: // ASL Direct Page
case 0x16: // ASL Direct Page Indexed, X
case 0xB2: // LDA Direct Page Indirect
case 0x57: // EOR Direct Page Indirect Long Indexed, Y
case 0xC1: // CMP Direct Page Indexed Indirect, X
case 0xC3: // CMP Stack Relative
case 0xC5: // CMP Direct Page
case 0x47: // EOR Direct Page Indirect Long
case 0x55: // EOR Direct Page Indexed, X
case 0x41: // EOR Direct Page Indirect, X
case 0x51: // EOR Direct Page Indirect Indexed, Y
case 0x43: // EOR Direct Page Indirect Indexed, X
case 0x53: // EOR Direct Page Indirect Long Indexed, Y
case 0xA1: // LDA Direct Page Indexed Indirect, X
case 0xA3: // LDA Stack Relative
case 0xA7: // LDA Direct Page Indirect Long
case 0xB5: // LDA Direct Page Indexed, X
case 0xB1: // LDA Direct Page Indirect Indexed, Y
case 0xB7: // LDA Direct Page Indirect Long Indexed, Y
case 0xB3: // LDA Direct Page Indirect Indexed, X
case 0xB6: // LDX Direct Page Indexed, Y
case 0xB4: // LDY Direct Page Indexed, X
case 0x46: // LSR Direct Page
case 0x56: // LSR Direct Page Indexed, X
case 0xE1: // SBC Direct Page Indexed Indirect, X
case 0xE3: // SBC Stack Relative
case 0xE5: // SBC Direct Page
case 0xE7: // SBC Direct Page Indirect Long
case 0xF2: // SBC Direct Page Indirect
case 0xF1: // SBC Direct Page Indirect Indexed, Y
case 0xF3: // SBC SR Indirect Indexed, Y
case 0xF5: // SBC Direct Page Indexed, X
case 0xF7: // SBC Direct Page Indirect Long Indexed, Y
case 0xF6: // INC Direct Page Indexed, X
case 0x86: // STX Direct Page
case 0x84: // STY Direct Page
case 0x64: // STZ Direct Page
case 0x74: // STZ Direct Page Indexed, X
case 0x04: // TSB Direct Page
case 0x14: // TRB Direct Page
case 0x44: // MVN
case 0x54: // MVP
case 0x24: // BIT Direct Page
case 0x34: // BIT Direct Page Indexed, X
case 0x94: // STY Direct Page Indexed, X
case 0x87: // STA Direct Page Indirect Long
case 0x92: // STA Direct Page Indirect
case 0x93: // STA SR Indirect Indexed, Y
case 0x95: // STA Direct Page Indexed, X
case 0x96: // STX Direct Page Indexed, Y
case 0xC7: // CMP Direct Page Indirect Long
case 0xD7: // CMP DP Indirect Long Indexed, Y
case 0xD2: // CMP DP Indirect
case 0xD1: // CMP DP Indirect Indexed, Y
case 0x03: // ORA Stack Relative
case 0x13: // ORA SR Indirect Indexed, Y
case 0x07: // ORA Direct Page Indirect Long
case 0x11: // ORA DP Indirect Indexed, Y
case 0x12: // ORA DP Indirect
case 0x15: // ORA DP Indexed, X
case 0x17: // ORA DP Indirect Long Indexed, Y
case 0x26: // ROL Direct Page
case 0x36: // ROL Direct Page Indexed, X
case 0x66: // ROR Direct Page
case 0x76: // ROR Direct Page Indexed, X
case 0x42: // WDM
case 0xD3: // CMP Stack Relative Indirect Indexed, Y
case 0x52: // EOR Direct Page Indirect
case 0xA4: // LDA Direct Page
case 0xA6: // LDX Direct Page
case 0xD4: // PEI
return 2;
case 0x69: // ADC Immediate
case 0x29: // AND Immediate
case 0xC9: // CMP Immediate
case 0x49: // EOR Immediate
case 0xA9: // LDA Immediate
case 0x09: // ORA Immediate
case 0xE9: // SBC Immediate
return GetAccumulatorSize() ? 2 : 3;
case 0xE0: // CPX Immediate
case 0xC0: // CPY Immediate
case 0xA2: // LDX Immediate
case 0xA0: // LDY Immediate
return GetIndexSize() ? 2 : 3;
case 0x0E: // ASL Absolute
case 0x1E: // ASL Absolute Indexed, X
case 0x2D: // AND Absolute
case 0xCD: // CMP Absolute
case 0xEC: // CPX Absolute
case 0xCC: // CPY Absolute
case 0x4D: // EOR Absolute
case 0xAD: // LDA Absolute
case 0xAE: // LDX Absolute
case 0xAC: // LDY Absolute
case 0x0D: // ORA Absolute
case 0xED: // SBC Absolute
case 0x8D: // STA Absolute
case 0x8E: // STX Absolute
case 0x8C: // STY Absolute
case 0xBD: // LDA Absolute Indexed X
case 0xBC: // LDY Absolute Indexed X
case 0x3D: // AND Absolute Indexed X
case 0x39: // AND Absolute Indexed Y
case 0x9C: // STZ Absolute Indexed X
case 0x9D: // STA Absolute Indexed X
case 0x99: // STA Absolute Indexed Y
case 0x3C: // BIT Absolute Indexed X
case 0x7D: // ADC Absolute Indexed, X
case 0x79: // ADC Absolute Indexed, Y
case 0x6D: // ADC Absolute
case 0x5D: // EOR Absolute Indexed, X
case 0x59: // EOR Absolute Indexed, Y
case 0x83: // STA Stack Relative Indirect Indexed, Y
case 0xCE: // DEC Absolute
case 0xD5: // CMP DP Indexed, X
case 0xD9: // CMP Absolute Indexed, Y
case 0xDD: // CMP Absolute Indexed, X
case 0x0C: // TSB Absolute
case 0x1C: // TRB Absolute
case 0xF9: // SBC Absolute Indexed, Y
case 0xFD: // SBC Absolute Indexed, X
case 0x2C: // BIT Absolute
case 0x2E: // ROL Absolute
case 0x3E: // ROL Absolute Indexed, X
case 0x4E: // LSR Absolute
case 0x5E: // LSR Absolute Indexed, X
case 0xDE: // DEC Absolute Indexed, X
case 0xEE: // INC Absolute
case 0xB9: // LDA Absolute Indexed, Y
case 0xBE: // LDX Absolute Indexed, Y
case 0xFE: // INC Absolute Indexed, X
case 0xF4: // PEA
case 0x62: // PER
case 0x6E: // ROR Absolute
case 0x7E: // ROR Absolute Indexed, X
return 3;
case 0x6F: // ADC Absolute Long
case 0x2F: // AND Absolute Long
case 0xCF: // CMP Absolute Long
case 0x4F: // EOR Absolute Long
case 0xAF: // LDA Absolute Long
case 0x0F: // ORA Absolute Long
case 0xEF: // SBC Absolute Long
case 0x8F: // STA Absolute Long
case 0x7F: // ADC Absolute Long Indexed, X
case 0x3F: // AND Absolute Long Indexed, X
case 0xDF: // CMP Absolute Long Indexed, X
case 0x5F: // EOR Absolute Long Indexed, X
case 0x9F: // STA Absolute Long Indexed, X
case 0x1F: // ORA Absolute Long Indexed, X
case 0xBF: // LDA Absolute Long Indexed, X
case 0x9E: // STZ Absolute Long Indexed, X
case 0xFF: // SBC Absolute Long Indexed, X
return 4;
default:
auto mnemonic = opcode_to_mnemonic.at(opcode);
std::cerr << "Unknown instruction length: " << std::hex
<< static_cast<int>(opcode) << ", " << mnemonic << std::endl;
throw std::runtime_error("Unknown instruction length");
return 1; // Default to 1 as a safe fallback
}
}
*/
} // namespace emu
} // namespace yaze

View File

@@ -5,7 +5,6 @@
#include <cstdint>
#include <vector>
#include "app/emu/cpu/clock.h"
#include "app/emu/memory/memory.h"
namespace yaze {
@@ -32,8 +31,8 @@ class InstructionEntry {
class Cpu {
public:
explicit Cpu(Memory& mem, Clock& vclock, CpuCallbacks& callbacks)
: memory(mem), clock(vclock), callbacks_(callbacks) {}
explicit Cpu(Memory& mem, CpuCallbacks& callbacks)
: memory(mem), callbacks_(callbacks) {}
void Reset(bool hard = false);
void RunOpcode();
@@ -42,14 +41,9 @@ class Cpu {
void LogInstructions(uint16_t PC, uint8_t opcode, uint16_t operand,
bool immediate, bool accumulator_mode);
void UpdatePC(uint8_t instruction_length) { PC += instruction_length; }
void UpdateClock(int delta_time) { clock.UpdateClock(delta_time); }
void SetIrq(bool state) { irq_wanted_ = state; }
void Nmi() { nmi_wanted_ = true; }
uint8_t GetInstructionLength(uint8_t opcode);
std::vector<uint32_t> breakpoints_;
std::vector<InstructionEntry> instruction_log_;
@@ -789,7 +783,6 @@ class Cpu {
CpuCallbacks callbacks_;
Memory& memory;
Clock& clock;
};
} // namespace emu

View File

@@ -4,7 +4,6 @@
#include <cstdint>
#include "app/emu/audio/apu.h"
#include "app/emu/cpu/clock.h"
#include "app/emu/cpu/cpu.h"
#include "app/emu/memory/memory.h"
#include "app/emu/video/ppu.h"
@@ -25,18 +24,11 @@ class Snes {
Snes() = default;
~Snes() = default;
// Initialization
void Init(std::vector<uint8_t>& rom_data);
void Reset(bool hard = false);
// Emulation
void RunFrame();
void CatchUpApu();
// Controller input handling
void HandleInput();
// Clock cycling and synchronization
void RunCycle();
void RunCycles(int cycles);
void SyncCycles(bool start, int sync_cycles);
@@ -54,10 +46,13 @@ class Snes {
uint8_t CpuRead(uint32_t adr);
void CpuWrite(uint32_t adr, uint8_t val);
void CpuIdle(bool waiting);
void InitAccessTime(bool recalc);
std::vector<uint8_t> access_time;
void SetSamples(int16_t* sample_data, int wanted_samples);
void SetPixels(uint8_t* pixel_data);
void SetButtonState(int player, int button, bool pressed);
bool running() const { return running_; }
auto cpu() -> Cpu& { return cpu_; }
auto ppu() -> Ppu& { return ppu_; }
@@ -65,28 +60,20 @@ class Snes {
auto Memory() -> MemoryImpl& { return memory_; }
auto get_ram() -> uint8_t* { return ram; }
auto mutable_cycles() -> uint64_t& { return cycles_; }
void InitAccessTime(bool recalc);
std::vector<uint8_t> access_time;
private:
// Components of the SNES
ClockImpl clock_;
MemoryImpl memory_;
CpuCallbacks cpu_callbacks_ = {
[&](uint32_t adr) { return CpuRead(adr); },
[&](uint32_t adr, uint8_t val) { CpuWrite(adr, val); },
[&](bool waiting) { CpuIdle(waiting); },
};
Cpu cpu_{memory_, clock_, cpu_callbacks_};
Ppu ppu_{memory_, clock_};
Cpu cpu_{memory_, cpu_callbacks_};
Ppu ppu_{memory_};
Apu apu_{memory_};
// Currently loaded ROM
std::vector<uint8_t> rom_data;
// Emulation state
bool running_ = false;
// ram

View File

@@ -36,8 +36,6 @@ static const int kBitDepthsPerMode[10][4] = {
static const int kSpriteSizes[8][2] = {{8, 16}, {8, 32}, {8, 64}, {16, 32},
{16, 64}, {32, 64}, {16, 32}, {16, 32}};
void Ppu::Update() {}
void Ppu::Reset() {
memset(vram, 0, sizeof(vram));
vram_pointer = 0;

View File

@@ -5,7 +5,6 @@
#include <cstdint>
#include <vector>
#include "app/emu/cpu/clock.h"
#include "app/emu/memory/memory.h"
#include "app/emu/video/ppu_registers.h"
#include "app/rom.h"
@@ -254,7 +253,7 @@ struct BackgroundLayer {
class Ppu : public SharedRom {
public:
// Initializes the PPU with the necessary resources and dependencies
Ppu(Memory& memory, Clock& clock) : memory_(memory), clock_(clock) {}
Ppu(Memory& memory) : memory_(memory) {}
// Initialize the frame buffer
void Init() {
@@ -262,13 +261,7 @@ class Ppu : public SharedRom {
pixelOutputFormat = 1;
}
// Resets the PPU to its initial state
void Reset();
// Runs the PPU for one frame.
void Update();
void UpdateClock(double delta_time) { clock_.UpdateClock(delta_time); }
void HandleFrameStart();
void RunLine(int line);
void HandlePixel(int x, int y);
@@ -433,7 +426,6 @@ class Ppu : public SharedRom {
uint16_t screen_brightness_ = 0x00;
Memory& memory_;
Clock& clock_;
Tilemap tilemap_;
BackgroundMode bg_mode_;