diff --git a/include/teakra/teakra.h b/include/teakra/teakra.h index b5561ab..be7a865 100644 --- a/include/teakra/teakra.h +++ b/include/teakra/teakra.h @@ -19,15 +19,23 @@ struct AHBMCallback { std::function write32; }; +struct UserConfig { + // 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; + 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..eddd5d8 100644 --- a/src/shared_memory.h +++ b/src/shared_memory.h @@ -1,11 +1,23 @@ #pragma once #include -#include +#include +#include #include "common_types.h" namespace Teakra { struct SharedMemory { - std::array raw{}; + // 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; + + SharedMemory(u8* mem = nullptr) : raw{mem} { + if (mem == nullptr) { + own_memory = std::make_unique>(); + raw = own_memory->data(); + } + } + 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..fd7d4f9 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() { @@ -20,7 +21,7 @@ void Teakra_Reset(TeakraContext* context) { } uint8_t* Teakra_GetDspMemory(TeakraContext* context) { - return context->teakra.GetDspMemory().data(); + return context->teakra.GetDspMemory(); } int Teakra_SendDataIsEmpty(const TeakraContext* context, uint8_t index) { @@ -94,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(); } @@ -125,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); }; @@ -140,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) {