Improve SPU code and support state of voice

This commit is contained in:
Jaby 2024-09-24 22:21:58 +02:00
parent 6c94bca700
commit 332476cd4e
7 changed files with 59 additions and 67 deletions

View File

@ -11,7 +11,7 @@ namespace JabyEngine {
// TODO: Rename to sample...? // TODO: Rename to sample...?
struct Voice { struct Voice {
size_t get_id() { size_t get_id() const {
return reinterpret_cast<size_t>(this); return reinterpret_cast<size_t>(this);
} }
@ -33,11 +33,22 @@ namespace JabyEngine {
SPU_IO::Key::On.write(SPU_IO::KeyOn::for_specific(Voice::get_id())); SPU_IO::Key::On.write(SPU_IO::KeyOn::for_specific(Voice::get_id()));
} }
void play_if_end() {
if(Voice::is_end()) {
Voice::play();
}
}
void stop() { void stop() {
SPU_IO::Key::Off.write(SPU_IO::KeyOff::for_specific(Voice::get_id())); SPU_IO::Key::Off.write(SPU_IO::KeyOff::for_specific(Voice::get_id()));
} }
bool is_end() const {
// TODO: Make work in XEBRA
return SPU_IO::Key::Status.read().is_set(Voice::get_id());
}
}; };
extern Voice voice[SPU_IO::VoiceCount]; static auto& voice = __new_declare_io_port_array(Voice, SPU_IO::VoiceCount, 0x0);
} }
} }

View File

@ -4,23 +4,6 @@
namespace JabyEngine { namespace JabyEngine {
namespace SPU_IO_Values { namespace SPU_IO_Values {
namespace internal {
template<typename T>
struct AliasUbus32IOPort : public IOPort<ubus32_t> {
T read() const {
return T{IOPort<ubus32_t>::read()};
}
void write(T value) {
IOPort<ubus32_t>::write(value.raw);
}
};
#define alias_ioport_ubus32(type) \
template<> \
struct IOPort<type> : public SPU_IO_Values::internal::AliasUbus32IOPort<type> {}
}
namespace MemoryMap { namespace MemoryMap {
static constexpr uintptr_t ADPCM = 0x01000; static constexpr uintptr_t ADPCM = 0x01000;
} }
@ -64,7 +47,7 @@ namespace JabyEngine {
} }
}; };
__declare_io_value(Echo, ubus32_t) { __declare_io_value(Echo, uint32_t) {
static constexpr auto EchoBits = BitRange::from_to(0, 23); static constexpr auto EchoBits = BitRange::from_to(0, 23);
static constexpr Echo AllOff() { static constexpr Echo AllOff() {
@ -72,27 +55,27 @@ namespace JabyEngine {
} }
}; };
__declare_io_value(KeyOff, ubus32_t) { __declare_io_value(KeyOff, uint32_t) {
static constexpr KeyOff for_specific(uint32_t id) { static constexpr KeyOff for_specific(uint32_t id) {
return KeyOff{ubus32_t::from(1 << id)}; return KeyOff{1u << id};
} }
static constexpr KeyOff all() { static constexpr KeyOff all() {
return KeyOff{ubus32_t::from(UI32_MAX)}; return KeyOff{UI32_MAX};
} }
}; };
__declare_io_value(KeyOn, ubus32_t) { __declare_io_value(KeyOn, uint32_t) {
static constexpr KeyOn for_specific(uint32_t id) { static constexpr KeyOn for_specific(uint32_t id) {
return KeyOn{ubus32_t::from(1 << id)}; return KeyOn{1u << id};
} }
static constexpr KeyOn all() { static constexpr KeyOn all() {
return KeyOn{ubus32_t::from(UI32_MAX)}; return KeyOn{UI32_MAX};
} }
}; };
__declare_io_value(KeyStatus, ubus32_t) { __declare_io_value(KeyStatus, uint32_t) {
}; };
__declare_io_value(Noise, uint16_t) { __declare_io_value(Noise, uint16_t) {
@ -103,7 +86,7 @@ namespace JabyEngine {
} }
}; };
__declare_io_value(PitchModulation, ubus32_t) { __declare_io_value(PitchModulation, uint32_t) {
static constexpr auto EnableBits = BitRange::from_to(1, 23); static constexpr auto EnableBits = BitRange::from_to(1, 23);
static constexpr PitchModulation AllOff() { static constexpr PitchModulation AllOff() {
@ -228,10 +211,4 @@ namespace JabyEngine {
} }
}; };
} }
alias_ioport_ubus32(SPU_IO_Values::Echo);
alias_ioport_ubus32(SPU_IO_Values::Noise);
alias_ioport_ubus32(SPU_IO_Values::KeyOff);
alias_ioport_ubus32(SPU_IO_Values::KeyOn);
alias_ioport_ubus32(SPU_IO_Values::KeyStatus);
alias_ioport_ubus32(SPU_IO_Values::PitchModulation);
} }

View File

@ -65,15 +65,6 @@ namespace JabyEngine {
}; };
} }
struct ubus32_t {
uint16_t low;
uint16_t high;
static constexpr ubus32_t from(uint32_t value) {
return {.low = static_cast<uint16_t>(value & 0xFFFF), .high = static_cast<uint16_t>(value >> 16)};
}
};
template<typename T> template<typename T>
struct IOPort { struct IOPort {
using Value = T; using Value = T;
@ -89,25 +80,34 @@ namespace JabyEngine {
}; };
template<> template<>
struct IOPort<ubus32_t> { struct IOPort<uint32_t>;
using Value = ubus32_t;
ubus32_t value;
ubus32_t read() const { template<typename T>
auto*const cv_this = const_cast<const volatile IOPort<ubus32_t>*>(this); struct IOPort32 {
union ValueHelper {
return {.low = cv_this->value.low, .high = cv_this->value.high}; struct {
uint16_t low;
uint16_t high;
};
T value;
};
using Value = T;
T value;
T read() const {
const auto* cast_this = reinterpret_cast<const IOPort32<ValueHelper>*>(this);
const volatile auto* cv_this = const_cast<volatile decltype(cast_this)>(cast_this);
return ValueHelper{.low = cv_this->value.low, .high = cv_this->value.high}.value;
} }
void write(ubus32_t value) { void write(T value) {
auto*const cv_this = const_cast<volatile IOPort<ubus32_t>*>(this); const auto new_value = ValueHelper{.value = value};
auto* cast_this = reinterpret_cast<IOPort32<ValueHelper>*>(this);
volatile auto* v_this = const_cast<volatile decltype(cast_this)>(cast_this);
cv_this->value.low = value.low; v_this->value.low = new_value.low;
cv_this->value.high = value.high; v_this->value.high = new_value.high;
}
void write(uint32_t value) {
IOPort<ubus32_t>::write(ubus32_t::from(value));
} }
}; };

View File

@ -20,12 +20,12 @@ namespace JabyEngine {
using ADIO = IOPort<SPU_IO_Values::AD>; using ADIO = IOPort<SPU_IO_Values::AD>;
using DataTransferControlIO = IOPort<SPU_IO_Values::DataTransferControl>; using DataTransferControlIO = IOPort<SPU_IO_Values::DataTransferControl>;
using EchoIO = IOPort<SPU_IO_Values::Echo>; using EchoIO = IOPort32<SPU_IO_Values::Echo>;
using KeyOffIO = IOPort<SPU_IO_Values::KeyOff>; using KeyOffIO = IOPort32<SPU_IO_Values::KeyOff>;
using KeyOnIO = IOPort<SPU_IO_Values::KeyOn>; using KeyOnIO = IOPort32<SPU_IO_Values::KeyOn>;
using KeyStatusIO = IOPort<SPU_IO_Values::KeyStatus>; using KeyStatusIO = IOPort32<SPU_IO_Values::KeyStatus>;
using NoiseIO = IOPort<SPU_IO_Values::Noise>; using NoiseIO = IOPort<SPU_IO_Values::Noise>;
using PitchModulationIO = IOPort<SPU_IO_Values::PitchModulation>; using PitchModulationIO = IOPort32<SPU_IO_Values::PitchModulation>;
using SampleRateIO = IOPort<SPU_IO_Values::SampleRate>; using SampleRateIO = IOPort<SPU_IO_Values::SampleRate>;
using SimpleVolumeIO = IOPort<SPU_IO_Values::SimpleVolume>; using SimpleVolumeIO = IOPort<SPU_IO_Values::SimpleVolume>;
using StatusRegisterIO = IOPort<SPU_IO_Values::StatusRegister>; using StatusRegisterIO = IOPort<SPU_IO_Values::StatusRegister>;

View File

@ -3,6 +3,7 @@
namespace JabyEngine { namespace JabyEngine {
namespace SPU_MMU { namespace SPU_MMU {
// TODO: Make this work with words? Word align?
const uint8_t* allocate(uint8_t voice, size_t size); const uint8_t* allocate(uint8_t voice, size_t size);
void deallocate(uint8_t voice); void deallocate(uint8_t voice);
} }

View File

@ -59,7 +59,7 @@ namespace JabyEngine {
simple_assert(2, SPU_MMU::allocate(0, 0x300), calculate_spu_adr(0x0)); simple_assert(2, SPU_MMU::allocate(0, 0x300), calculate_spu_adr(0x0));
simple_assert(3, SPU_MMU::allocate(2, 0x300), calculate_spu_adr(0x300)); simple_assert(3, SPU_MMU::allocate(2, 0x300), calculate_spu_adr(0x300));
// TODO: More tests // TODO: More tests
} }
namespace boot { namespace boot {

View File

@ -52,11 +52,14 @@ namespace JabyEngine {
static Progress parse_header(State::Configuration& config, VAGState& state) { static Progress parse_header(State::Configuration& config, VAGState& state) {
if(config.data_bytes >= sizeof(VAGHeader)) { if(config.data_bytes >= sizeof(VAGHeader)) {
const auto& header = *reinterpret_cast<const VAGHeader*>(config.data_adr); const auto& header = *reinterpret_cast<const VAGHeader*>(config.data_adr);
const auto bytes = header.get_sample_size(); const auto words = bytes_to_words(header.get_sample_size());
const auto bytes = words_to_bytes(words);
state.words_left = bytes_to_words(bytes); state.words_left = words;
auto sram_adr = SPU::voice[state.voice_id].allocate(SPU_IO::SampleRate::from_HZ(header.get_sample_frequency()), words_to_bytes(state.words_left)); auto sram_adr = SPU::voice[state.voice_id].allocate(SPU_IO::SampleRate::from_HZ(header.get_sample_frequency()), bytes);
// TODO: Keep this as optional?
printf("SPU: Allocated %i @0x%p to 0x%p (%i bytes)\n", state.voice_id, sram_adr.raw, (sram_adr.raw + bytes), bytes);
SPU::voice[state.voice_id].set_volume(state.inital_vol, state.inital_vol); SPU::voice[state.voice_id].set_volume(state.inital_vol, state.inital_vol);
config.processed(sizeof(VAGHeader)); config.processed(sizeof(VAGHeader));