Moar Teak LLE

Co-Authored-By: PSISP <12768103+psi-rockin@users.noreply.github.com>
This commit is contained in:
wheremyfoodat 2024-02-17 03:48:37 +02:00
parent 363c71e66c
commit 5dd3c02ffb
10 changed files with 284 additions and 21 deletions

View file

@ -1,4 +1,5 @@
#pragma once
#include <array>
#include <functional>
#include <memory>
#include <vector>
@ -7,15 +8,19 @@
#include "logger.hpp"
#include "memory.hpp"
// The DSP core must have access to the DSP service to be able to trigger interrupts properly
class DSPService;
namespace Audio {
class DSPCore {
protected:
Memory& mem;
DSPService& dspService;
MAKE_LOG_FUNCTION(log, dspLogger)
public:
enum class Type { Null, Teakra };
DSPCore(Memory& mem) : mem(mem) {}
DSPCore(Memory& mem, DSPService& dspService) : mem(mem), dspService(dspService) {}
virtual void reset() = 0;
virtual void runAudioFrame() = 0;
@ -31,5 +36,5 @@ namespace Audio {
virtual void setSemaphoreMask(u16 value) = 0;
};
std::unique_ptr<DSPCore> makeDSPCore(DSPCore::Type type, Memory& mem);
std::unique_ptr<DSPCore> makeDSPCore(DSPCore::Type type, Memory& mem, DSPService& dspService);
} // namespace Audio

View file

@ -20,7 +20,7 @@ namespace Audio {
void resetAudioPipe();
public:
NullDSP(Memory& mem) : DSPCore(mem) {}
NullDSP(Memory& mem, DSPService& dspService) : DSPCore(mem, dspService) {}
void reset() override;
void runAudioFrame() override {}

View file

@ -1,5 +1,6 @@
#pragma once
#include "audio/dsp_core.hpp"
#include "swap.hpp"
#include "teakra/teakra.h"
namespace Audio {
@ -8,8 +9,63 @@ namespace Audio {
u32 pipeBaseAddr;
bool running;
// Get a pointer to a data memory address
u8* getDataPointer(u32 address) { return getDspMemory() + Memory::DSP_DATA_MEMORY_OFFSET + address; }
enum class PipeDirection {
DSPtoCPU = 0,
CPUtoDSP = 1,
};
// A lot of Teakra integration code, especially pipe stuff are based on Citra's integration here:
// https://github.com/citra-emu/citra/blob/master/src/audio_core/lle/lle.cpp
struct PipeStatus {
// All addresses and sizes here refer to byte values, NOT 16-bit values.
u16_le address;
u16_le byteSize;
u16_le readPointer;
u16_le writePointer;
u8 slot;
u8 flags;
static constexpr u16 wrapBit = 0x8000;
static constexpr u16 pointerMask = 0x7FFF;
bool isFull() const { return (readPointer ^ writePointer) == wrapBit; }
bool isEmpty() const { return (readPointer ^ writePointer) == 0; }
// isWrapped: Are read and write pointers in different memory passes.
// true: xxxx]----[xxxx (data is wrapping around the end of memory)
// false: ----[xxxx]----
bool isWrapped() const { return (readPointer ^ writePointer) >= wrapBit; }
};
static_assert(sizeof(PipeStatus) == 10, "Teakra: Pipe Status size is wrong");
static constexpr u8 pipeToSlotIndex(u8 pipe, PipeDirection direction) { return (pipe * 2) + u8(direction); }
PipeStatus getPipeStatus(u8 pipe, PipeDirection direction) {
PipeStatus ret;
const u8 index = pipeToSlotIndex(pipe, direction);
std::memcpy(&ret, getDataPointer(pipeBaseAddr * 2 + index * sizeof(PipeStatus)), sizeof(PipeStatus));
return ret;
}
void updatePipeStatus(const PipeStatus& status) {
u8 slot = status.slot;
u8* statusAddress = getDataPointer(pipeBaseAddr * 2 + slot * sizeof(PipeStatus));
if (slot % 2 == 0) {
std::memcpy(statusAddress + 4, &status.readPointer, sizeof(u16));
} else {
std::memcpy(statusAddress + 6, &status.writePointer, sizeof(u16));
}
}
bool signalledData;
bool signalledSemaphore;
public:
TeakraDSP(Memory& mem);
TeakraDSP(Memory& mem, DSPService& dspService);
void reset() override;
void runAudioFrame() override {

View file

@ -10,7 +10,8 @@ struct Scheduler {
enum class EventType {
VBlank = 0, // End of frame event
UpdateTimers = 1, // Update kernel timer objects
Panic = 2, // Dummy event that is always pending and should never be triggered (Timestamp = UINT64_MAX)
RunDSP = 2, // Make the emulated DSP run for one audio frame
Panic = 3, // Dummy event that is always pending and should never be triggered (Timestamp = UINT64_MAX)
TotalNumberOfEvents // How many event types do we have in total?
};
static constexpr usize totalNumberOfEvents = static_cast<usize>(EventType::TotalNumberOfEvents);
@ -49,6 +50,7 @@ struct Scheduler {
// Clear any pending events
events.clear();
addEvent(Scheduler::EventType::VBlank, arm11Clock / 60);
addEvent(Scheduler::EventType::RunDSP, 16384 * 2);
// Add a dummy event to always keep the scheduler non-empty
addEvent(EventType::Panic, std::numeric_limits<u64>::max());

View file

@ -63,4 +63,8 @@ public:
};
void signalEvents();
void triggerPipeEvent(int index);
void triggerSemaphoreEvent();
void triggerInterrupt0();
void triggerInterrupt1();
};