From a1d04e4d6353f482635dad86e50883c89db0e167 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Thu, 21 Aug 2025 18:06:34 +0300 Subject: [PATCH 1/4] Move ownership of DSP memory to user Co-Authored-By: TheTurtle <47210458+raphaelthegreat@users.noreply.github.com> --- include/teakra/teakra.h | 12 +++++++++--- src/shared_memory.h | 8 +++++--- src/teakra.cpp | 12 ++++++------ src/teakra_c.cpp | 7 ++----- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/include/teakra/teakra.h b/include/teakra/teakra.h index b5561ab..74a284c 100644 --- a/include/teakra/teakra.h +++ b/include/teakra/teakra.h @@ -19,15 +19,21 @@ struct AHBMCallback { std::function write32; }; +struct UserConfig { + std::uint8_t* dsp_memory; +}; + +static constexpr std::uint32_t DspMemorySize = 0x80000; + class Teakra { public: - Teakra(); + Teakra(const UserConfig& config); ~Teakra(); void Reset(); - std::array& GetDspMemory(); - const std::array& GetDspMemory() const; + uint8_t* GetDspMemory(); + const uint8_t* GetDspMemory() const; RegisterState& GetRegisterState(); const RegisterState& GetRegisterState() const; diff --git a/src/shared_memory.h b/src/shared_memory.h index 8dfcb05..6fb16e4 100644 --- a/src/shared_memory.h +++ b/src/shared_memory.h @@ -1,11 +1,13 @@ #pragma once -#include -#include + #include "common_types.h" namespace Teakra { struct SharedMemory { - std::array raw{}; + u8* raw; + + SharedMemory(u8* mem) : raw{mem} {} + u16 ReadWord(u32 word_address) const { u32 byte_address = word_address * 2; u8 low = raw[byte_address]; diff --git a/src/teakra.cpp b/src/teakra.cpp index 894b20d..af14ab6 100644 --- a/src/teakra.cpp +++ b/src/teakra.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include "ahbm.h" #include "apbp.h" #include "btdmp.h" @@ -30,7 +30,7 @@ struct Teakra::Impl { MemoryInterface memory_interface{shared_memory, miu}; Processor processor{core_timing, memory_interface}; - Impl() { + Impl(u8* dsp_memory) : shared_memory{dsp_memory} { memory_interface.SetMMIO(mmio); using namespace std::placeholders; icu.SetInterruptHandler(std::bind(&Processor::SignalInterrupt, &processor, _1), @@ -51,7 +51,7 @@ struct Teakra::Impl { } void Reset() { - shared_memory.raw.fill(0); + std::memset(shared_memory.raw, 0, DspMemorySize); miu.Reset(); apbp_from_cpu.Reset(); apbp_from_dsp.Reset(); @@ -65,18 +65,18 @@ struct Teakra::Impl { } }; -Teakra::Teakra() : impl(new Impl) {} +Teakra::Teakra(const UserConfig& config) : impl(std::make_unique(config.dsp_memory)) {} Teakra::~Teakra() = default; void Teakra::Reset() { impl->Reset(); } -std::array& Teakra::GetDspMemory() { +uint8_t* Teakra::GetDspMemory() { return impl->shared_memory.raw; } -const std::array& Teakra::GetDspMemory() const { +const uint8_t* Teakra::GetDspMemory() const { return impl->shared_memory.raw; } diff --git a/src/teakra_c.cpp b/src/teakra_c.cpp index 531465f..df6687f 100644 --- a/src/teakra_c.cpp +++ b/src/teakra_c.cpp @@ -4,7 +4,8 @@ extern "C" { struct TeakraObject { - Teakra::Teakra teakra; + Teakra::UserConfig config; + Teakra::Teakra teakra{config}; }; TeakraContext* Teakra_Create() { @@ -19,10 +20,6 @@ void Teakra_Reset(TeakraContext* context) { context->teakra.Reset(); } -uint8_t* Teakra_GetDspMemory(TeakraContext* context) { - return context->teakra.GetDspMemory().data(); -} - int Teakra_SendDataIsEmpty(const TeakraContext* context, uint8_t index) { return context->teakra.SendDataIsEmpty(index); } From f8dca4bbc76d4aea1a2512c3686bddd2160da4d7 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Thu, 21 Aug 2025 18:19:55 +0300 Subject: [PATCH 2/4] Allow SharedMemory to be owned by either the user or Teakra, fix tests --- src/shared_memory.h | 16 +++++++++++++++- src/teakra_c.cpp | 16 +++++++++------- tests/dma.cpp | 10 +++++----- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/shared_memory.h b/src/shared_memory.h index 6fb16e4..7fbde2e 100644 --- a/src/shared_memory.h +++ b/src/shared_memory.h @@ -5,8 +5,22 @@ namespace Teakra { struct SharedMemory { u8* raw; + bool own_dsp_mem; - SharedMemory(u8* mem) : raw{mem} {} + SharedMemory(u8* mem = nullptr) : raw{mem} { + if (mem == nullptr) { + raw = new uint8_t[0x80000]; + own_dsp_mem = true; + } else { + own_dsp_mem = false; + } + } + + ~SharedMemory() { + if (own_dsp_mem) { + delete[] raw; + } + } u16 ReadWord(u32 word_address) const { u32 byte_address = word_address * 2; diff --git a/src/teakra_c.cpp b/src/teakra_c.cpp index df6687f..fd7d4f9 100644 --- a/src/teakra_c.cpp +++ b/src/teakra_c.cpp @@ -20,6 +20,10 @@ void Teakra_Reset(TeakraContext* context) { context->teakra.Reset(); } +uint8_t* Teakra_GetDspMemory(TeakraContext* context) { + return context->teakra.GetDspMemory(); +} + int Teakra_SendDataIsEmpty(const TeakraContext* context, uint8_t index) { return context->teakra.SendDataIsEmpty(index); } @@ -91,7 +95,7 @@ void Teakra_MMIOWrite(TeakraContext* context, uint16_t address, uint16_t value) uint16_t Teakra_DMAChan0GetSrcHigh(TeakraContext* context) { return context->teakra.DMAChan0GetSrcHigh(); } -uint16_t Teakra_DMAChan0GetDstHigh(TeakraContext* context){ +uint16_t Teakra_DMAChan0GetDstHigh(TeakraContext* context) { return context->teakra.DMAChan0GetDstHigh(); } @@ -122,11 +126,10 @@ void Teakra_Run(TeakraContext* context, unsigned cycle) { context->teakra.Run(cycle); } -void Teakra_SetAHBMCallback(TeakraContext* context, - Teakra_AHBMReadCallback8 read8 , Teakra_AHBMWriteCallback8 write8 , - Teakra_AHBMReadCallback16 read16, Teakra_AHBMWriteCallback16 write16, - Teakra_AHBMReadCallback32 read32, Teakra_AHBMWriteCallback32 write32, - void* userdata) { +void Teakra_SetAHBMCallback(TeakraContext* context, Teakra_AHBMReadCallback8 read8, + Teakra_AHBMWriteCallback8 write8, Teakra_AHBMReadCallback16 read16, + Teakra_AHBMWriteCallback16 write16, Teakra_AHBMReadCallback32 read32, + Teakra_AHBMWriteCallback32 write32, void* userdata) { Teakra::AHBMCallback callback; callback.read8 = [=](uint32_t address) { return read8(userdata, address); }; callback.write8 = [=](uint32_t address, uint8_t value) { write8(userdata, address, value); }; @@ -137,7 +140,6 @@ void Teakra_SetAHBMCallback(TeakraContext* context, context->teakra.SetAHBMCallback(callback); } - void Teakra_SetAudioCallback(TeakraContext* context, Teakra_AudioCallback callback, void* userdata) { context->teakra.SetAudioCallback( diff --git a/tests/dma.cpp b/tests/dma.cpp index 1d00bd4..e400aed 100644 --- a/tests/dma.cpp +++ b/tests/dma.cpp @@ -33,13 +33,14 @@ TEST_CASE("DMA + AHBM test", "[dma]") { }, [&fcram](u32 address) -> u32 { REQUIRE(address >= 0x20000000); - return fcram[address - 0x20000000] | ((u32)fcram[address - 0x20000000 + 1] << 8) - | ((u32)fcram[address - 0x20000000 + 2] << 16) | ((u32)fcram[address - 0x20000000 + 3] << 24); + return fcram[address - 0x20000000] | ((u32)fcram[address - 0x20000000 + 1] << 8) | + ((u32)fcram[address - 0x20000000 + 2] << 16) | + ((u32)fcram[address - 0x20000000 + 3] << 24); }, [&fcram](u32 address, u32 v) { REQUIRE(address >= 0x20000000); fcram[address - 0x20000000 + 0] = (u8)v; - fcram[address - 0x20000000 + 1] = (u8)(v >> 8); + fcram[address - 0x20000000 + 1] = (u8)(v >> 8); fcram[address - 0x20000000 + 2] = (u8)(v >> 16); fcram[address - 0x20000000 + 3] = (u8)(v >> 24); }); @@ -50,8 +51,7 @@ TEST_CASE("DMA + AHBM test", "[dma]") { } auto GetDspTestArea = [&shared_memory]() { - return std::vector(shared_memory.raw.begin() + 0x40000, - shared_memory.raw.begin() + 0x40000 + 0x80); + return std::vector(shared_memory.raw + 0x40000, shared_memory.raw + 0x40000 + 0x80); }; auto GenerateExpected = [](const std::string& str, u8 base = 0) { From caacf53704985cba836d42536b90163794885976 Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Thu, 21 Aug 2025 18:24:59 +0300 Subject: [PATCH 3/4] Fix C bindings --- include/teakra/teakra.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/teakra/teakra.h b/include/teakra/teakra.h index 74a284c..be7a865 100644 --- a/include/teakra/teakra.h +++ b/include/teakra/teakra.h @@ -20,7 +20,9 @@ struct AHBMCallback { }; struct UserConfig { - std::uint8_t* dsp_memory; + // DSP memory. By default set to nullptr. If it stays nullptr then Teakra will create its own + // DSP memory and retain ownership of it. Otherwise, the user will own it. + std::uint8_t* dsp_memory = nullptr; }; static constexpr std::uint32_t DspMemorySize = 0x80000; From c59a641133f24ab0f6bb56b71c4f65a9578b6dda Mon Sep 17 00:00:00 2001 From: wheremyfoodat <44909372+wheremyfoodat@users.noreply.github.com> Date: Thu, 21 Aug 2025 20:50:18 +0300 Subject: [PATCH 4/4] Address comments --- src/shared_memory.h | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/shared_memory.h b/src/shared_memory.h index 7fbde2e..eddd5d8 100644 --- a/src/shared_memory.h +++ b/src/shared_memory.h @@ -1,24 +1,20 @@ #pragma once - +#include +#include +#include #include "common_types.h" namespace Teakra { struct SharedMemory { + // We allocate our own memory if the user doesn't supply their own + std::unique_ptr> own_memory; + // Points to either own own memory or user-supplied memory u8* raw; - bool own_dsp_mem; SharedMemory(u8* mem = nullptr) : raw{mem} { if (mem == nullptr) { - raw = new uint8_t[0x80000]; - own_dsp_mem = true; - } else { - own_dsp_mem = false; - } - } - - ~SharedMemory() { - if (own_dsp_mem) { - delete[] raw; + own_memory = std::make_unique>(); + raw = own_memory->data(); } }