jabyengine/src/Library/src/SPU/spu_mmu.cpp

132 lines
4.7 KiB
C++

#include "../../internal-include/SPU/spu_mmu.hpp"
#include <PSX/System/IOPorts/spu_io.hpp>
#include <PSX/Auxiliary/math_helper.hpp>
#include <PSX/SPU/spu.hpp>
#include <stddef.hpp>
#ifdef __DEBUG_SPU_MMU__
#include <stdio.hpp>
#endif // __DEBUG_SPU_MMU__
namespace JabyEngine {
namespace SPU_MMU {
namespace SPU_MemoryMap = SPU_IO::MemoryMap;
struct SPUMemory {
// TODO: v change to uint16_t??
const uint8_t* adr;
size_t size;
static SPUMemory create(size_t size) {
return SPUMemory{.adr = reinterpret_cast<const uint8_t*>(SPU_MemoryMap::ADPCM), .size = size};
}
constexpr void clear() {
this->adr = nullptr;
this->size = 0;
}
constexpr const uint8_t* get_end_adr() const {
return (this->adr + this->size);
}
constexpr bool is_free() const {
return this->adr == nullptr;
}
constexpr bool intersects(const SPUMemory& other) const {
const auto* min = max_of(this->adr, other.adr);
const auto* max = min_of(this->get_end_adr(), other.get_end_adr());
return min < max;
}
};
struct AllocatedVoice {
SPUMemory memory;
AllocatedVoice* next_entry;
};
struct VoiceManager {
struct Iterator {
AllocatedVoice* *prev_voice;
AllocatedVoice* current_voice;
void next() {
this->prev_voice = &this->current_voice->next_entry;
this->current_voice = this->current_voice->next_entry;
}
bool has_next() const {
return this->current_voice;
}
operator bool() const {
return Iterator::has_next();
}
};
AllocatedVoice allocated_voice_buffer[SPU_IO::VoiceCount + SPU_IO::ReverbCount] = {0};
AllocatedVoice* first_allocated_voice = nullptr;
Iterator iterator() {
return Iterator{.prev_voice = &this->first_allocated_voice, .current_voice = this->first_allocated_voice};
}
AllocatedVoice& get_voice(uint8_t id) {
return this->allocated_voice_buffer[id];
}
};
static VoiceManager voice_mgr;
using MemoryFoundCallback = const uint8_t* (AllocatedVoice& new_entry, AllocatedVoice* &prev_entry, AllocatedVoice* next_entry);
static const uint8_t* verify_and_add(AllocatedVoice& new_entry, AllocatedVoice* &prev_entry, AllocatedVoice* next_entry) {
// TODO: Verify that we are not crashing into reverb or that we are higher then SPU
prev_entry = &new_entry;
new_entry.next_entry = next_entry;
return new_entry.memory.adr;
}
static const uint8_t* find_first_fit(AllocatedVoice &new_entry, MemoryFoundCallback memory_found) {
auto iterator = voice_mgr.iterator();
while(iterator) {
if(!iterator.current_voice->memory.intersects(new_entry.memory)) {
break;
}
new_entry.memory.adr = iterator.current_voice->memory.get_end_adr();
iterator.next();
}
return memory_found(new_entry, *iterator.prev_voice, iterator.current_voice);
}
const uint8_t* allocate(uint8_t voice, size_t size) {
auto& voice_entry = voice_mgr.get_voice(voice);
if(!voice_entry.memory.is_free()) {
deallocate(voice);
}
voice_entry.memory = SPUMemory::create(size);
const auto* mem_adr = find_first_fit(voice_entry, verify_and_add);
#ifdef __DEBUG_SPU_MMU__
printf("SPU: Allocated %i @0x%p to 0x%p (%i bytes)\n", voice, mem_adr, (mem_adr + size), size);
#endif // __DEBUG_SPU_MMU__
return mem_adr;
}
void deallocate(uint8_t voice) {
auto* voice_adr = &voice_mgr.get_voice(voice);
auto iterator = voice_mgr.iterator();
voice_adr->memory.clear();
while(iterator) {
if(iterator.current_voice == voice_adr) {
*iterator.prev_voice = voice_adr->next_entry;
break;
}
iterator.next();
}
}
}
}