140 lines
3.6 KiB
C
140 lines
3.6 KiB
C
#include "usf.h"
|
|
#include "memory.h"
|
|
#include "audio.h"
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
#include "usf_internal.h"
|
|
|
|
static const uint32_t AI_STATUS_BUSY = 0x40000000;
|
|
static const uint32_t AI_STATUS_FULL = 0x80000000;
|
|
|
|
static uint32_t get_remaining_dma_length(usf_state_t *state) {
|
|
unsigned int next_ai_event;
|
|
unsigned int remaining_dma_duration;
|
|
|
|
if (state->fifo[0].duration == 0)
|
|
return 0;
|
|
|
|
next_ai_event = state->Timers->NextTimer[AiTimer] + state->Timers->Timer;
|
|
if (!state->Timers->Active[AiTimer])
|
|
return 0;
|
|
|
|
remaining_dma_duration = next_ai_event;
|
|
|
|
if (remaining_dma_duration >= 0x80000000)
|
|
return 0;
|
|
|
|
return (uint32_t)((uint64_t)remaining_dma_duration * state->fifo[0].length / state->fifo[0].duration);
|
|
}
|
|
|
|
void AddBuffer(usf_state_t *state, unsigned char *buf, unsigned int length) {
|
|
unsigned int i, do_max;
|
|
int16_t * sample_buffer = state->sample_buffer;
|
|
|
|
if(!state->cpu_running)
|
|
return;
|
|
|
|
do_max = length >> 2;
|
|
|
|
if ( do_max > state->sample_buffer_count )
|
|
do_max = (unsigned int) state->sample_buffer_count;
|
|
|
|
if ( sample_buffer )
|
|
for (i = 0; i < do_max; ++i) {
|
|
*sample_buffer++ = ((int16_t*)buf)[1];
|
|
*sample_buffer++ = ((int16_t*)buf)[0];
|
|
buf += 4;
|
|
}
|
|
else
|
|
buf += 4 * do_max;
|
|
|
|
state->sample_buffer_count -= do_max;
|
|
state->sample_buffer = sample_buffer;
|
|
|
|
length -= do_max << 2;
|
|
|
|
if ( length ) {
|
|
sample_buffer = state->samplebuf;
|
|
do_max = length >> 2;
|
|
for (i = 0; i < do_max; ++i) {
|
|
*sample_buffer++ = ((int16_t*)buf)[1];
|
|
*sample_buffer++ = ((int16_t*)buf)[0];
|
|
buf += 4;
|
|
}
|
|
|
|
state->samples_in_buffer = do_max;
|
|
state->cpu_running = 0;
|
|
}
|
|
}
|
|
|
|
static unsigned int get_dma_duration(usf_state_t *state)
|
|
{
|
|
unsigned int samples_per_sec = state->ROM_PARAMS.aidacrate / (1 + AI_DACRATE_REG);
|
|
|
|
return (uint32_t)(((uint64_t)(AI_LEN_REG)*state->VI_INTR_TIME*state->ROM_PARAMS.vilimit) / (4 * samples_per_sec));
|
|
}
|
|
|
|
void do_dma(usf_state_t * state, const struct ai_dma * dma) {
|
|
AddBuffer(state, state->RDRAM + (dma->address & (state->RdramSize - 1) & ~3), dma->length);
|
|
|
|
if(!(AI_STATUS_REG&AI_STATUS_FULL)) {
|
|
if (state->enableFIFOfull) {
|
|
ChangeTimer(state,AiTimer,dma->duration + state->Timers->Timer);
|
|
}
|
|
else {
|
|
state->AudioIntrReg|=4;
|
|
}
|
|
}
|
|
}
|
|
|
|
void AiQueueInt(usf_state_t *state) {
|
|
ChangeTimer(state,AiTimer,state->enableFIFOfull ? get_dma_duration(state) + state->Timers->Timer : 0);
|
|
}
|
|
|
|
void AiLenChanged(usf_state_t *state) {
|
|
unsigned int duration = get_dma_duration(state);
|
|
|
|
if (AI_STATUS_REG & AI_STATUS_BUSY) {
|
|
state->fifo[1].address = AI_DRAM_ADDR_REG;
|
|
state->fifo[1].length = AI_LEN_REG;
|
|
state->fifo[1].duration = duration;
|
|
|
|
if (state->enableFIFOfull)
|
|
AI_STATUS_REG |= AI_STATUS_FULL;
|
|
else
|
|
do_dma(state, &state->fifo[1]);
|
|
}
|
|
else {
|
|
state->fifo[0].address = AI_DRAM_ADDR_REG;
|
|
state->fifo[0].length = AI_LEN_REG;
|
|
state->fifo[0].duration = duration;
|
|
AI_STATUS_REG |= AI_STATUS_BUSY;
|
|
|
|
do_dma(state, &state->fifo[0]);
|
|
}
|
|
}
|
|
|
|
void AiTimerDone(usf_state_t *state) {
|
|
if (AI_STATUS_REG & AI_STATUS_FULL) {
|
|
state->fifo[0].address = state->fifo[1].address;
|
|
state->fifo[0].length = state->fifo[1].length;
|
|
state->fifo[0].duration = state->fifo[1].duration;
|
|
AI_STATUS_REG &= ~AI_STATUS_FULL;
|
|
|
|
do_dma(state, &state->fifo[0]);
|
|
}
|
|
else {
|
|
AI_STATUS_REG &= ~AI_STATUS_BUSY;
|
|
}
|
|
}
|
|
|
|
unsigned int AiReadLength(usf_state_t * state) {
|
|
return get_remaining_dma_length(state);
|
|
}
|
|
|
|
void AiDacrateChanged(usf_state_t * state, unsigned int value) {
|
|
AI_DACRATE_REG = value;
|
|
state->SampleRate = (state->ROM_PARAMS.aidacrate) / (AI_DACRATE_REG + 1);
|
|
}
|