@@ -26,48 +26,124 @@ SOFTWARE.
2626
2727#include " psyqo/spu.hh"
2828
29- #include < EASTL/atomic.h>
30-
31- #include " EASTL/internal/atomic/atomic_memory_order.h"
29+ #include " common/hardware/dma.h"
3230#include " common/hardware/spu.h"
31+ #include " psyqo/kernel.hh"
32+
33+ constexpr uint16_t DUMMY_SAMPLE_POSITION = 0x1000 ;
34+ constexpr uint8_t DUMMY_SAMPLE_SIZE = 16 ;
35+ alignas (4 ) constexpr uint8_t DUMMY_SAMPLE[] = {0x00 , 0b101 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
36+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 };
37+
38+ void psyqo::SPU::dmaWrite (const uint32_t spuAddress, const void *ramAddress, const uint16_t dataSize,
39+ const uint8_t blockSize) {
40+ Kernel::assert (blockSize % sizeof (uint32_t ) == 0 && blockSize != 0 && blockSize <= 16 , " Invalid DMA block size" );
41+ SPU_CTRL &= ~(0b11 << 4 );
42+ waitForStatus<uint16_t >(0b11 << 4 , 0b00 << 4 , &SPU_STATUS);
43+ SPU_CTRL |= 1 << 5 ;
44+ SPU_RAM_DTA = spuAddress / 8 ;
45+ waitForStatus<uint16_t >(1 << 5 , 1 << 5 , &SPU_STATUS);
46+
47+ DPCR |= 1 << 19 ;
48+ DPCR &= ~(0b111 << 16 );
49+ DPCR |= 0b100 << 16 ;
50+ DMA_CTRL[DMA_SPU].MADR = reinterpret_cast <uint32_t >(ramAddress);
51+ DMA_CTRL[DMA_SPU].BCR = blockSize | ((dataSize / blockSize) << 16 );
52+ DMA_CTRL[DMA_SPU].CHCR = 1 | 1 << 9 | 1 << 24 ;
3353
34- void psyqo::SPU::resetVoice (unsigned voiceID) {
35- SPU_VOICES[voiceID].volumeLeft = 0 ;
36- SPU_VOICES[voiceID].volumeRight = 0 ;
37- SPU_VOICES[voiceID].sampleRate = 0 ;
38- SPU_VOICES[voiceID].sampleStartAddr = 0 ;
39- SPU_VOICES[voiceID].ad = 0x000f ;
40- SPU_VOICES[voiceID].currentVolume = 0 ;
41- SPU_VOICES[voiceID].sampleRepeatAddr = 0 ;
42- SPU_VOICES[voiceID].sr = 0x0000 ;
54+ waitForStatus<uint32_t >(1 << 24 , 0 << 24 , &DMA_CTRL[DMA_SPU].CHCR );
4355}
4456
45- void psyqo::SPU::waitIdle () {
46- do {
47- for (unsigned c = 0 ; c < 256 ; c++) eastl::atomic_signal_fence (eastl::memory_order_relaxed);
48- } while ((SPU_STATUS & 0x07ff ) != 0 );
57+ void psyqo::SPU::silenceChannels (const uint32_t channelMask) {
58+ SPU_KEY_OFF_LOW = channelMask & 0xffff ;
59+ SPU_KEY_OFF_HIGH = (channelMask >> 16 ) & 0xffff ;
60+
61+ for (uint8_t channel = 0 ; channel < 24 ; channel++) {
62+ if (!((channelMask >> channel) & 1 )) {
63+ continue ;
64+ }
65+ SPU_VOICES[channel].volumeLeft = 0 ;
66+ SPU_VOICES[channel].volumeRight = 0 ;
67+ SPU_VOICES[channel].sampleRate = 0 ;
68+ SPU_VOICES[channel].sampleStartAddr = DUMMY_SAMPLE_POSITION / 8 ;
69+ SPU_VOICES[channel].sampleRepeatAddr = DUMMY_SAMPLE_POSITION / 8 ;
70+ }
71+
72+ SPU_KEY_ON_LOW = channelMask & 0xffff ;
73+ SPU_KEY_ON_HIGH = (channelMask >> 16 ) & 0xffff ;
4974}
5075
51- void psyqo::SPU::reset () {
52- SPU_VOL_MAIN_LEFT = 0x3800 ;
53- SPU_VOL_MAIN_RIGHT = 0x3800 ;
76+ template <typename T>
77+ bool psyqo::SPU::waitForStatus (const T mask, const T expected, const volatile T *value) {
78+ for (int timeout = 10000 ; timeout >= 0 ; timeout--) {
79+ if ((*value & mask) == expected) {
80+ return true ;
81+ }
82+ }
83+ return false ;
84+ }
85+
86+ void psyqo::SPU::initialize () {
87+ SBUS_DEV4_CTRL = 1 | 0b1110 << 4 | 1 << 8 | 1 << 12 | 1 << 13 | 0b1001 << 16 | 0 << 24 | 1 << 29 ;
88+ DPCR |= 1 << 19 ;
89+
5490 SPU_CTRL = 0 ;
55- SPU_KEY_ON_LOW = 0 ;
56- SPU_KEY_ON_HIGH = 0 ;
57- SPU_KEY_OFF_LOW = 0xffff ;
58- SPU_KEY_OFF_HIGH = 0xffff ;
59- SPU_RAM_DTC = 4 ;
60- SPU_VOL_CD_LEFT = 0 ;
61- SPU_VOL_CD_RIGHT = 0 ;
91+
92+ SPU_VOL_MAIN_LEFT = 0x7fff ;
93+ SPU_VOL_MAIN_RIGHT = 0x7fff ;
94+ SPU_REVERB_LEFT = 0 ;
95+ SPU_REVERB_RIGHT = 0 ;
96+
6297 SPU_PITCH_MOD_LOW = 0 ;
6398 SPU_PITCH_MOD_HIGH = 0 ;
6499 SPU_NOISE_EN_LOW = 0 ;
65100 SPU_NOISE_EN_HIGH = 0 ;
66101 SPU_REVERB_EN_LOW = 0 ;
67102 SPU_REVERB_EN_HIGH = 0 ;
103+ SPU_REVERB_ADDR = 0xfffe ;
104+ SPU_VOL_CD_LEFT = 0 ;
105+ SPU_VOL_CD_RIGHT = 0 ;
68106 SPU_VOL_EXT_LEFT = 0 ;
69107 SPU_VOL_EXT_RIGHT = 0 ;
70- SPU_CTRL = 0x8000 ;
108+ SPU_RAM_DTC = 4 ;
109+
110+ dmaWrite (DUMMY_SAMPLE_POSITION, &DUMMY_SAMPLE, DUMMY_SAMPLE_SIZE, 4 );
111+
112+ SPU_CTRL = 1 << 15 | 1 << 14 | 1 << 6 ;
113+
114+ silenceChannels (0xffffffff );
115+ }
116+
117+ void psyqo::SPU::playADPCM (const uint8_t channelId, const uint16_t spuRamAddress, const ChannelPlaybackConfig &config,
118+ const bool hardCut) {
119+ Kernel::assert (channelId < 24 , " Invalid SPU channel ID" );
120+ if (hardCut) {
121+ if (channelId > 15 ) {
122+ SPU_KEY_OFF_HIGH |= 1 << (channelId - 16 );
123+ } else {
124+ SPU_KEY_OFF_LOW |= 1 << (channelId);
125+ }
126+ }
127+
128+ SPU_VOICES[channelId].volumeLeft = config.volumeLeft ;
129+ SPU_VOICES[channelId].volumeRight = config.volumeRight ;
130+ SPU_VOICES[channelId].sampleRate = config.sampleRate .value ;
131+ SPU_VOICES[channelId].sampleStartAddr = spuRamAddress / 8 ;
132+ SPU_VOICES[channelId].ad = config.adsr & 0xffff ;
133+ SPU_VOICES[channelId].sr = (config.adsr >> 16 ) & 0xffff ;
134+
135+ if (channelId > 15 ) {
136+ SPU_KEY_ON_HIGH |= 1 << (channelId - 16 );
137+ } else {
138+ SPU_KEY_ON_LOW |= 1 << (channelId);
139+ }
140+ }
71141
72- for (unsigned i = 0 ; i < 24 ; i++) resetVoice (i);
142+ uint32_t psyqo::SPU::getNextFreeChannel () {
143+ for (uint8_t channel = 0 ; channel < 24 ; channel++) {
144+ if (SPU_VOICES[channel].currentVolume == 0 ) {
145+ return channel;
146+ }
147+ }
148+ return NO_FREE_CHANNEL;
73149}
0 commit comments