srctree

Robin Lindén parent 0ae36a8d 4318d963 f6f6220d
Merge pull request #391 from sa12123/branch/apu

APU Interface (w. empty APU implementation)
core/CMakeLists.txt added: 254, removed: 11, total 243
@@ -1,7 +1,9 @@
project(n_e_s_core)
 
add_library(${PROJECT_NAME}
include/nes/core/apu_factory.h
include/nes/core/cpu_factory.h
include/nes/core/iapu.h
include/nes/core/icpu.h
include/nes/core/imembank.h
include/nes/core/immu.h
@@ -19,6 +21,9 @@ add_library(${PROJECT_NAME}
include/nes/core/ppu_factory.h
include/nes/core/ppu_registers.h
include/nes/core/rom_factory.h
src/apu.h
src/apu.cpp
src/apu_factory.cpp
src/cpu_factory.cpp
src/invalid_address.cpp
src/mapped_membank.h
 
filename was Deleted added: 254, removed: 11, total 243
@@ -0,0 +1,13 @@
#pragma once
 
#include "nes/core/iapu.h"
 
#include <memory>
 
namespace n_e_s::core {
class ApuFactory {
public:
[[nodiscard]] static std::unique_ptr<IApu> create();
};
 
} // namespace n_e_s::core
No newline at end of file
 
filename was Deleted added: 254, removed: 11, total 243
@@ -0,0 +1,34 @@
#pragma once
 
#include <cstdint>
#include <functional>
 
namespace n_e_s::core {
 
class IApu {
public:
virtual ~IApu() = default;
 
virtual uint8_t read_byte(uint16_t addr) = 0;
virtual void write_byte(uint16_t addr, uint8_t byte) = 0;
 
virtual void execute() = 0;
 
virtual void set_sample_handler(
const std::function<void(int8_t)> &audio_handler) = 0;
 
// Set sample handlers for individual channels
// (eg. for debugging, custom mixing etc)
virtual void set_sample_handler_pulse_1(
const std::function<void(int8_t)> &audio_handler) = 0;
virtual void set_sample_handler_pulse_2(
const std::function<void(int8_t)> &audio_handler) = 0;
virtual void set_sample_handler_triangle(
const std::function<void(int8_t)> &audio_handler) = 0;
virtual void set_sample_handler_noise(
const std::function<void(int8_t)> &audio_handler) = 0;
virtual void set_sample_handler_pcm(
const std::function<void(int8_t)> &audio_handler) = 0;
};
 
} // namespace n_e_s::core
 
filename was Deleted added: 254, removed: 11, total 243
@@ -0,0 +1,66 @@
#include "apu.h"
 
namespace n_e_s::core {
 
uint8_t Apu::read_byte(uint16_t addr) {
addr_ = addr;
return 0x00;
}
void Apu::write_byte(uint16_t addr, uint8_t byte) {
addr_ = addr;
byte_ = byte;
}
 
void Apu::execute() {
// Dummy calls to sample handlers
if (sample_handler_) {
sample_handler_(0x01);
}
if (sample_handler_pulse_1_) {
sample_handler_pulse_1_(0x02);
}
if (sample_handler_pulse_2_) {
sample_handler_pulse_2_(0x03);
}
if (sample_handler_triangle_) {
sample_handler_triangle_(0x04);
}
if (sample_handler_noise_) {
sample_handler_noise_(0x05);
}
if (sample_handler_pcm_) {
sample_handler_pcm_(0x06);
}
}
 
void Apu::set_sample_handler(
const std::function<void(int8_t)> &sample_handler) {
sample_handler_ = sample_handler;
}
 
void Apu::set_sample_handler_pulse_1(
const std::function<void(int8_t)> &sample_handler) {
sample_handler_pulse_1_ = sample_handler;
}
 
void Apu::set_sample_handler_pulse_2(
const std::function<void(int8_t)> &sample_handler) {
sample_handler_pulse_2_ = sample_handler;
}
 
void Apu::set_sample_handler_triangle(
const std::function<void(int8_t)> &sample_handler) {
sample_handler_triangle_ = sample_handler;
}
 
void Apu::set_sample_handler_noise(
const std::function<void(int8_t)> &sample_handler) {
sample_handler_noise_ = sample_handler;
}
 
void Apu::set_sample_handler_pcm(
const std::function<void(int8_t)> &sample_handler) {
sample_handler_pcm_ = sample_handler;
}
 
} // namespace n_e_s::core
No newline at end of file
 
filename was Deleted added: 254, removed: 11, total 243
@@ -0,0 +1,43 @@
#pragma once
 
#include "nes/core/iapu.h"
 
namespace n_e_s::core {
 
class Apu final : public IApu {
public:
explicit Apu() = default;
 
uint8_t read_byte(uint16_t addr) override;
void write_byte(uint16_t addr, uint8_t byte) override;
 
void execute() override;
 
void set_sample_handler(
const std::function<void(int8_t)> &sample_handler) override;
 
void set_sample_handler_pulse_1(
const std::function<void(int8_t)> &sample_handler) override;
void set_sample_handler_pulse_2(
const std::function<void(int8_t)> &sample_handler) override;
void set_sample_handler_triangle(
const std::function<void(int8_t)> &sample_handler) override;
void set_sample_handler_noise(
const std::function<void(int8_t)> &sample_handler) override;
void set_sample_handler_pcm(
const std::function<void(int8_t)> &sample_handler) override;
 
private:
std::function<void(int8_t)> sample_handler_{[](int8_t) {}};
std::function<void(int8_t)> sample_handler_pulse_1_{[](int8_t) {}};
std::function<void(int8_t)> sample_handler_pulse_2_{[](int8_t) {}};
std::function<void(int8_t)> sample_handler_triangle_{[](int8_t) {}};
std::function<void(int8_t)> sample_handler_noise_{[](int8_t) {}};
std::function<void(int8_t)> sample_handler_pcm_{[](int8_t) {}};
 
// Dummys for stub
uint16_t addr_{};
uint8_t byte_{};
};
 
} // namespace n_e_s::core
No newline at end of file
 
filename was Deleted added: 254, removed: 11, total 243
@@ -0,0 +1,11 @@
#include "nes/core/apu_factory.h"
 
#include "apu.h"
 
namespace n_e_s::core {
 
std::unique_ptr<IApu> ApuFactory::create() {
return std::make_unique<Apu>();
}
 
} // namespace n_e_s::core
No newline at end of file
 
core/test/CMakeLists.txt added: 254, removed: 11, total 243
@@ -11,6 +11,7 @@ add_executable(${PROJECT_NAME}
src/ippu_helpers.h
src/main.cpp
src/opcode.h
src/test_apu.cpp
src/test_cpu.cpp
src/test_cpu_absolute_indexed_instructions.cpp
src/test_cpu_absolute_instructions.cpp
 
filename was Deleted added: 254, removed: 11, total 243
@@ -0,0 +1,53 @@
#include "nes/core/apu_factory.h"
 
#include <gtest/gtest.h>
 
using namespace n_e_s::core;
 
namespace {
 
class ApuTest : public ::testing::Test {
public:
ApuTest() : apu(ApuFactory::create()) {}
 
void step_execution(uint32_t cycles) {
for (uint32_t i = 0; i < cycles; ++i) {
apu->execute();
}
}
 
std::unique_ptr<IApu> apu;
};
 
// Placeholder for future tests
// For now only dummy test...
TEST_F(ApuTest, dummy_test) {
EXPECT_EQ(0x00, apu->read_byte(0x1234));
apu->write_byte(0x0000, 0x00);
int8_t sample{};
int8_t sample_pulse_1{};
int8_t sample_pulse_2{};
int8_t sample_triangle{};
int8_t sample_noise{};
int8_t sample_pcm{};
apu->execute();
apu->set_sample_handler([&sample](int8_t s) { sample = s; });
apu->set_sample_handler_pulse_1(
[&sample_pulse_1](int8_t s) { sample_pulse_1 = s; });
apu->set_sample_handler_pulse_2(
[&sample_pulse_2](int8_t s) { sample_pulse_2 = s; });
apu->set_sample_handler_triangle(
[&sample_triangle](int8_t s) { sample_triangle = s; });
apu->set_sample_handler_noise(
[&sample_noise](int8_t s) { sample_noise = s; });
apu->set_sample_handler_pcm([&sample_pcm](int8_t s) { sample_pcm = s; });
apu->execute();
EXPECT_EQ(sample, 0x01);
EXPECT_EQ(sample_pulse_1, 0x02);
EXPECT_EQ(sample_pulse_2, 0x03);
EXPECT_EQ(sample_triangle, 0x04);
EXPECT_EQ(sample_noise, 0x05);
EXPECT_EQ(sample_pcm, 0x06);
}
 
} // namespace
No newline at end of file
 
nes/include/nes/nes.h added: 254, removed: 11, total 243
@@ -13,6 +13,8 @@ struct CpuRegisters;
class IPpu;
struct PpuRegisters;
 
class IApu;
 
class IMmu;
 
class IRom;
@@ -45,6 +47,8 @@ public:
n_e_s::core::IMmu &ppu_mmu();
const n_e_s::core::IMmu &ppu_mmu() const;
 
n_e_s::core::IApu &apu() const;
 
n_e_s::core::CpuRegisters &cpu_registers();
const n_e_s::core::CpuRegisters &cpu_registers() const;
 
@@ -65,6 +69,8 @@ private:
 
std::unique_ptr<n_e_s::core::IMmu> mmu_;
 
std::unique_ptr<n_e_s::core::IApu> apu_;
 
std::unique_ptr<n_e_s::core::CpuRegisters> cpu_registers_;
std::unique_ptr<n_e_s::core::IMos6502> cpu_;
 
 
nes/src/nes.cpp added: 254, removed: 11, total 243
@@ -1,6 +1,8 @@
#include "nes/nes.h"
 
#include "nes/core/apu_factory.h"
#include "nes/core/cpu_factory.h"
#include "nes/core/iapu.h"
#include "nes/core/immu.h"
#include "nes/core/imos6502.h"
#include "nes/core/ippu.h"
@@ -46,6 +48,7 @@ Nes::Nes()
ppu_registers_(std::make_unique<n_e_s::core::PpuRegisters>()),
ppu_(PpuFactory::create(ppu_registers_.get(), ppu_mmu_.get())),
mmu_(MmuFactory::create_empty()),
apu_(ApuFactory::create()),
cpu_registers_(std::make_unique<n_e_s::core::CpuRegisters>()),
cpu_(CpuFactory::create_mos6502(cpu_registers_.get(),
mmu_.get(),
@@ -68,11 +71,15 @@ std::optional<core::Pixel> Nes::execute() {
cpu_->execute();
}
 
// The APU runs at master clock % 24. (every other CPU tick)
if (cycle_ % 24 == 0) {
apu_->execute();
}
 
if (cycle_ % 4 == 0) {
return ppu_->execute();
}
 
// The APU runs at master clock % 24. (every other CPU tick)
return {};
}
 
@@ -122,6 +129,10 @@ const n_e_s::core::IMmu &Nes::ppu_mmu() const {
return *ppu_mmu_;
}
 
n_e_s::core::IApu &Nes::apu() const {
return *apu_;
}
 
n_e_s::core::CpuRegisters &Nes::cpu_registers() {
return *cpu_registers_;
}