Add VirtualClock, MockClock, dependency injection
This commit is contained in:
@@ -10,11 +10,9 @@ namespace yaze {
|
|||||||
namespace app {
|
namespace app {
|
||||||
namespace emu {
|
namespace emu {
|
||||||
|
|
||||||
APU::APU(Memory& memory) : memory_(memory) {}
|
|
||||||
|
|
||||||
void APU::Init() {
|
void APU::Init() {
|
||||||
// Set the clock frequency
|
// Set the clock frequency
|
||||||
SetFrequency(kApuClockSpeed);
|
clock_.SetFrequency(kApuClockSpeed);
|
||||||
|
|
||||||
// Initialize registers
|
// Initialize registers
|
||||||
// ...
|
// ...
|
||||||
@@ -22,14 +20,14 @@ void APU::Init() {
|
|||||||
|
|
||||||
void APU::Reset() {
|
void APU::Reset() {
|
||||||
// Reset the clock
|
// Reset the clock
|
||||||
ResetAccumulatedTime();
|
clock_.ResetAccumulatedTime();
|
||||||
|
|
||||||
// Reset the SPC700
|
// Reset the SPC700
|
||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
void APU::Update() {
|
void APU::Update() {
|
||||||
auto cycles_to_run = GetCycleCount();
|
auto cycles_to_run = clock_.GetCycleCount();
|
||||||
|
|
||||||
for (auto i = 0; i < cycles_to_run; ++i) {
|
for (auto i = 0; i < cycles_to_run; ++i) {
|
||||||
// Update the APU
|
// Update the APU
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ const int kApuClockSpeed = 1024000; // 1.024 MHz
|
|||||||
const int apuSampleRate = 32000; // 32 KHz
|
const int apuSampleRate = 32000; // 32 KHz
|
||||||
const int apuClocksPerSample = 64; // 64 clocks per sample
|
const int apuClocksPerSample = 64; // 64 clocks per sample
|
||||||
|
|
||||||
class APU : public SPC700, public Clock {
|
class APU : public SPC700, public Observer {
|
||||||
public:
|
public:
|
||||||
// Initializes the APU with the necessary resources and dependencies
|
// Initializes the APU with the necessary resources and dependencies
|
||||||
APU(Memory &memory);
|
APU(Memory &memory, VirtualClock &clock) : memory_(memory), clock_(clock) {}
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
|
|
||||||
@@ -28,6 +28,14 @@ class APU : public SPC700, public Clock {
|
|||||||
// Runs the APU for one frame
|
// Runs the APU for one frame
|
||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
|
void Notify(uint32_t address, uint8_t data) override {
|
||||||
|
if (address >= 0x2140 && address <= 0x2143) {
|
||||||
|
// Handle communication with the APU
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateClock(int delta_time) { clock_.UpdateClock(delta_time); }
|
||||||
|
|
||||||
// Reads a byte from the specified APU register
|
// Reads a byte from the specified APU register
|
||||||
uint8_t ReadRegister(uint16_t address);
|
uint8_t ReadRegister(uint16_t address);
|
||||||
|
|
||||||
@@ -57,6 +65,7 @@ class APU : public SPC700, public Clock {
|
|||||||
|
|
||||||
// Member variables to store internal APU state and resources
|
// Member variables to store internal APU state and resources
|
||||||
Memory &memory_;
|
Memory &memory_;
|
||||||
|
VirtualClock &clock_;
|
||||||
std::vector<int16_t> audioSamples_;
|
std::vector<int16_t> audioSamples_;
|
||||||
// Other state variables (registers, counters, channel settings, etc.)
|
// Other state variables (registers, counters, channel settings, etc.)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,17 @@ namespace yaze {
|
|||||||
namespace app {
|
namespace app {
|
||||||
namespace emu {
|
namespace emu {
|
||||||
|
|
||||||
class Clock {
|
class VirtualClock {
|
||||||
|
public:
|
||||||
|
virtual ~VirtualClock() = 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 Clock : public VirtualClock {
|
||||||
public:
|
public:
|
||||||
Clock() = default;
|
Clock() = default;
|
||||||
virtual ~Clock() = default;
|
virtual ~Clock() = default;
|
||||||
@@ -27,15 +37,17 @@ class Clock {
|
|||||||
cycleCount++;
|
cycleCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateClock(double delta) {
|
void UpdateClock(double delta) override {
|
||||||
UpdateCycleCount(delta);
|
UpdateCycleCount(delta);
|
||||||
ResetAccumulatedTime();
|
ResetAccumulatedTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long long GetCycleCount() const { return cycleCount; }
|
void ResetAccumulatedTime() override { accumulatedTime = 0.0; }
|
||||||
float GetFrequency() const { return frequency; }
|
unsigned long long GetCycleCount() const override { return cycleCount; }
|
||||||
void SetFrequency(float new_frequency) { this->frequency = new_frequency; }
|
float GetFrequency() const override { return frequency; }
|
||||||
void ResetAccumulatedTime() { accumulatedTime = 0.0; }
|
void SetFrequency(float new_frequency) override {
|
||||||
|
this->frequency = new_frequency;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t cycle = 0; // Current cycle
|
uint64_t cycle = 0; // Current cycle
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ uint8_t CPU::FetchByteDirectPage(uint8_t operand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CPU::Update() {
|
void CPU::Update() {
|
||||||
auto cycles_to_run = GetCycleCount();
|
auto cycles_to_run = clock.GetCycleCount();
|
||||||
|
|
||||||
// Execute the calculated number of cycles
|
// Execute the calculated number of cycles
|
||||||
for (int i = 0; i < cycles_to_run; i++) {
|
for (int i = 0; i < cycles_to_run; i++) {
|
||||||
|
|||||||
@@ -72,11 +72,13 @@ const std::unordered_map<uint8_t, std::string> opcode_to_mnemonic = {
|
|||||||
|
|
||||||
const int kCpuClockSpeed = 21477272; // 21.477272 MHz
|
const int kCpuClockSpeed = 21477272; // 21.477272 MHz
|
||||||
|
|
||||||
class CPU : public Memory, public Clock, public Loggable {
|
class CPU : public Memory, public Loggable {
|
||||||
public:
|
public:
|
||||||
explicit CPU(Memory& mem) : memory(mem) {}
|
explicit CPU(Memory& mem, VirtualClock& vclock)
|
||||||
|
: memory(mem), clock(vclock) {}
|
||||||
|
|
||||||
void Init() {
|
void Init() {
|
||||||
SetFrequency(kCpuClockSpeed);
|
clock.SetFrequency(kCpuClockSpeed);
|
||||||
memory.ClearMemory();
|
memory.ClearMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1037,6 +1039,7 @@ class CPU : public Memory, public Clock, public Loggable {
|
|||||||
}
|
}
|
||||||
int16_t SP() const override { return memory.SP(); }
|
int16_t SP() const override { return memory.SP(); }
|
||||||
void SetSP(int16_t value) override { memory.SetSP(value); }
|
void SetSP(int16_t value) override { memory.SetSP(value); }
|
||||||
|
void UpdateClock(int delta_time) { clock.UpdateClock(delta_time); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void compare(uint16_t register_value, uint16_t memory_value) {
|
void compare(uint16_t register_value, uint16_t memory_value) {
|
||||||
@@ -1083,6 +1086,7 @@ class CPU : public Memory, public Clock, public Loggable {
|
|||||||
uint8_t at(int i) const override { return 0; }
|
uint8_t at(int i) const override { return 0; }
|
||||||
|
|
||||||
Memory& memory;
|
Memory& memory;
|
||||||
|
VirtualClock& clock;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace emu
|
} // namespace emu
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ namespace yaze {
|
|||||||
namespace app {
|
namespace app {
|
||||||
namespace emu {
|
namespace emu {
|
||||||
|
|
||||||
PPU::PPU(Memory& memory) : memory_(memory) {}
|
|
||||||
|
|
||||||
void PPU::RenderScanline() {
|
void PPU::RenderScanline() {
|
||||||
// Fetch the tile data from VRAM, tile map data from memory, and palette data
|
// Fetch the tile data from VRAM, tile map data from memory, and palette data
|
||||||
// from CGRAM
|
// from CGRAM
|
||||||
@@ -47,7 +45,7 @@ void PPU::RenderScanline() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PPU::Update() {
|
void PPU::Update() {
|
||||||
auto cycles_to_run = GetCycleCount();
|
auto cycles_to_run = clock_.GetCycleCount();
|
||||||
|
|
||||||
UpdateInternalState(cycles_to_run);
|
UpdateInternalState(cycles_to_run);
|
||||||
|
|
||||||
@@ -55,7 +53,7 @@ void PPU::Update() {
|
|||||||
if (currentScanline < visibleScanlines) {
|
if (currentScanline < visibleScanlines) {
|
||||||
// Render the current scanline
|
// Render the current scanline
|
||||||
// This involves fetching tile data, applying palette colors, handling
|
// This involves fetching tile data, applying palette colors, handling
|
||||||
// sprite priorities, etc.
|
// sprite spriorities, etc.
|
||||||
RenderScanline();
|
RenderScanline();
|
||||||
|
|
||||||
// Increment the current scanline
|
// Increment the current scanline
|
||||||
|
|||||||
@@ -631,7 +631,7 @@ const int kPpuClockSpeed = 5369318; // 5.369318 MHz
|
|||||||
class PPU : public Clock {
|
class PPU : public Clock {
|
||||||
public:
|
public:
|
||||||
// Initializes the PPU with the necessary resources and dependencies
|
// Initializes the PPU with the necessary resources and dependencies
|
||||||
PPU(Memory& memory);
|
PPU(Memory& memory, VirtualClock& clock) : memory_(memory), clock_(clock) {}
|
||||||
|
|
||||||
void Init() {
|
void Init() {
|
||||||
// Initialize the frame buffer with a size that corresponds to the
|
// Initialize the frame buffer with a size that corresponds to the
|
||||||
@@ -714,6 +714,7 @@ class PPU : public Clock {
|
|||||||
// ===========================================================
|
// ===========================================================
|
||||||
// Member variables to store internal PPU state and resources
|
// Member variables to store internal PPU state and resources
|
||||||
Memory& memory_;
|
Memory& memory_;
|
||||||
|
VirtualClock& clock_;
|
||||||
std::vector<uint8_t> frame_buffer_;
|
std::vector<uint8_t> frame_buffer_;
|
||||||
|
|
||||||
Tilemap tilemap_;
|
Tilemap tilemap_;
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "app/emu/apu.h"
|
#include "app/emu/apu.h"
|
||||||
|
#include "app/emu/clock.h"
|
||||||
#include "app/emu/cpu.h"
|
#include "app/emu/cpu.h"
|
||||||
#include "app/emu/dbg.h"
|
#include "app/emu/dbg.h"
|
||||||
#include "app/emu/ppu.h"
|
#include "app/emu/ppu.h"
|
||||||
@@ -102,9 +103,11 @@ class SNES : public DMA {
|
|||||||
|
|
||||||
// Components of the SNES
|
// Components of the SNES
|
||||||
MemoryImpl memory_;
|
MemoryImpl memory_;
|
||||||
CPU cpu{memory_};
|
Clock clock_;
|
||||||
PPU ppu{memory_};
|
|
||||||
APU apu{memory_};
|
CPU cpu{memory_, clock_};
|
||||||
|
PPU ppu{memory_, clock_};
|
||||||
|
APU apu{memory_, clock_};
|
||||||
|
|
||||||
// Helper classes
|
// Helper classes
|
||||||
ROMInfo rom_info_;
|
ROMInfo rom_info_;
|
||||||
|
|||||||
@@ -3,12 +3,22 @@
|
|||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "app/emu/clock.h"
|
||||||
#include "app/emu/mem.h"
|
#include "app/emu/mem.h"
|
||||||
|
|
||||||
namespace yaze {
|
namespace yaze {
|
||||||
namespace app {
|
namespace app {
|
||||||
namespace emu {
|
namespace emu {
|
||||||
|
|
||||||
|
class MockClock : public VirtualClock {
|
||||||
|
public:
|
||||||
|
MOCK_METHOD(void, UpdateClock, (double delta), (override));
|
||||||
|
MOCK_METHOD(unsigned long long, GetCycleCount, (), (const, override));
|
||||||
|
MOCK_METHOD(void, ResetAccumulatedTime, (), (override));
|
||||||
|
MOCK_METHOD(void, SetFrequency, (float new_frequency), (override));
|
||||||
|
MOCK_METHOD(float, GetFrequency, (), (const, override));
|
||||||
|
};
|
||||||
|
|
||||||
class MockMemory : public Memory {
|
class MockMemory : public Memory {
|
||||||
public:
|
public:
|
||||||
MOCK_CONST_METHOD1(ReadByte, uint8_t(uint16_t address));
|
MOCK_CONST_METHOD1(ReadByte, uint8_t(uint16_t address));
|
||||||
@@ -133,7 +143,8 @@ class CPUTest : public ::testing::Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MockMemory mock_memory;
|
MockMemory mock_memory;
|
||||||
CPU cpu{mock_memory};
|
MockClock mock_clock;
|
||||||
|
CPU cpu{mock_memory, mock_clock};
|
||||||
};
|
};
|
||||||
|
|
||||||
using ::testing::_;
|
using ::testing::_;
|
||||||
|
|||||||
Reference in New Issue
Block a user