#ifndef EMU_COMPILE
#error "Hi I forgot to set EMU_COMPILE"
#endif
#include "dcsound.h"
#include "arm.h"
#include "yam.h"
sint32 EMU_CALL dcsound_init(void) { return 0; }
#define CYCLES_PER_SAMPLE (128)
struct DCSOUND_STATE {
struct DCSOUND_STATE *myself;
uint32 offset_to_map_load;
uint32 offset_to_map_store;
uint32 offset_to_arm;
uint32 offset_to_yam;
uint32 offset_to_ram;
uint32 sound_samples_remaining;
uint32 cycles_ahead_of_sound;
sint32 cycles_executed;
};
#define DCSOUNDSTATE ((struct DCSOUND_STATE*)(state))
#define MAPLOAD ((void*)(((char*)(DCSOUNDSTATE))+(DCSOUNDSTATE->offset_to_map_load)))
#define MAPSTORE ((void*)(((char*)(DCSOUNDSTATE))+(DCSOUNDSTATE->offset_to_map_store)))
#define ARMSTATE ((void*)(((char*)(DCSOUNDSTATE))+(DCSOUNDSTATE->offset_to_arm)))
#define YAMSTATE ((void*)(((char*)(DCSOUNDSTATE))+(DCSOUNDSTATE->offset_to_yam)))
#define RAMBYTEPTR ((uint8*)(((char*)(DCSOUNDSTATE))+(DCSOUNDSTATE->offset_to_ram)))
extern const uint32 dcsound_map_load_entries;
extern const uint32 dcsound_map_store_entries;
uint32 EMU_CALL dcsound_get_state_size(void) {
uint32 offset = 0;
offset += sizeof(struct DCSOUND_STATE);
offset += sizeof(struct ARM_MEMORY_MAP) * dcsound_map_load_entries;
offset += sizeof(struct ARM_MEMORY_MAP) * dcsound_map_store_entries;
offset += arm_get_state_size();
offset += yam_get_state_size(2);
offset += 0x800000;
return offset;
}
static void recompute_memory_maps(struct DCSOUND_STATE *state);
static void EMU_CALL dcsound_advance(void *state, uint32 elapse);
void EMU_CALL dcsound_clear_state(void *state) {
uint32 offset;
memset(state, 0, sizeof(struct DCSOUND_STATE));
offset = sizeof(struct DCSOUND_STATE);
DCSOUNDSTATE->offset_to_map_load = offset; offset += sizeof(struct ARM_MEMORY_MAP) * dcsound_map_load_entries;
DCSOUNDSTATE->offset_to_map_store = offset; offset += sizeof(struct ARM_MEMORY_MAP) * dcsound_map_store_entries;
DCSOUNDSTATE->offset_to_arm = offset; offset += arm_get_state_size();
DCSOUNDSTATE->offset_to_yam = offset; offset += yam_get_state_size(2);
DCSOUNDSTATE->offset_to_ram = offset; offset += 0x800000;
memset(RAMBYTEPTR, 0, 0x800000);
recompute_memory_maps(DCSOUNDSTATE);
arm_clear_state(ARMSTATE);
arm_set_advance_callback(ARMSTATE, dcsound_advance, DCSOUNDSTATE);
arm_set_memory_maps(ARMSTATE, MAPLOAD, MAPSTORE);
yam_clear_state(YAMSTATE, 2);
yam_setram(YAMSTATE, (uint32*)(RAMBYTEPTR), 0x800000, EMU_ENDIAN_XOR(3), EMU_ENDIAN_XOR(2));
yam_aica_store_reg(YAMSTATE, 0x289C, 0x0040, 0xFFFF, NULL);
yam_aica_store_reg(YAMSTATE, 0x28A8, 0x0018, 0xFFFF, NULL);
yam_aica_store_reg(YAMSTATE, 0x28AC, 0x0050, 0xFFFF, NULL);
yam_aica_store_reg(YAMSTATE, 0x28B0, 0x0008, 0xFFFF, NULL);
DCSOUNDSTATE->myself = DCSOUNDSTATE;
}
#define TIMEDCSOUND (0)
#define TIMEARM (1)
#define TIMEYAM (2)
#define timeenter(x,y)
#define timeleave(x)
#define timeswitch(x,y)
static void location_check(struct DCSOUND_STATE *state) {
if(state->myself != state) {
recompute_memory_maps(state);
arm_set_advance_callback(ARMSTATE, dcsound_advance, DCSOUNDSTATE);
arm_set_memory_maps(ARMSTATE, MAPLOAD, MAPSTORE);
yam_setram(YAMSTATE, (uint32*)(RAMBYTEPTR), 0x800000, EMU_ENDIAN_XOR(3), EMU_ENDIAN_XOR(2));
state->myself = state;
}
}
void* EMU_CALL dcsound_get_arm_state(void *state) { return ARMSTATE; }
void* EMU_CALL dcsound_get_yam_state(void *state) { return YAMSTATE; }
static uint32 EMU_CALL dcsound_yam_lw(void *state, uint32 a, uint32 mask) {
uint16 d;
timeswitch(DCSOUNDSTATE, TIMEYAM);
d = yam_aica_load_reg(YAMSTATE, a, mask) & mask;
timeswitch(DCSOUNDSTATE, TIMEARM);
return d;
}
static void EMU_CALL dcsound_yam_sw(void *state, uint32 a, uint32 d, uint32 mask) {
uint8 b = 0;
timeswitch(DCSOUNDSTATE, TIMEYAM);
yam_aica_store_reg(YAMSTATE, a, d, mask, &b);
timeswitch(DCSOUNDSTATE, TIMEARM);
if(b) arm_break(ARMSTATE);
}
static void sync_sound(struct DCSOUND_STATE *state) {
if(state->cycles_ahead_of_sound >= CYCLES_PER_SAMPLE) {
uint32 samples = (state->cycles_ahead_of_sound) / CYCLES_PER_SAMPLE;
if(samples > state->sound_samples_remaining) {
samples = state->sound_samples_remaining;
}
if(samples > 0) {
timeswitch(state, TIMEYAM);
yam_advance(YAMSTATE, samples);
timeswitch(state, TIMEDCSOUND);
state->cycles_ahead_of_sound -= CYCLES_PER_SAMPLE * samples;
state->sound_samples_remaining -= samples;
}
}
}
static void EMU_CALL dcsound_advance(void *state, uint32 elapse) {
timeswitch(DCSOUNDSTATE, TIMEDCSOUND);
DCSOUNDSTATE->cycles_executed += elapse;
DCSOUNDSTATE->cycles_ahead_of_sound += elapse;
sync_sound(DCSOUNDSTATE);
timeswitch(DCSOUNDSTATE, TIMEARM);
}
static uint32 cycles_until_next_interrupt(
struct DCSOUND_STATE *state
) {
uint32 yamsamples;
uint32 yamcycles;
timeswitch(state, TIMEYAM);
yamsamples = yam_get_min_samples_until_interrupt(YAMSTATE);
timeswitch(state, TIMEDCSOUND);
if(yamsamples > 0x10000) { yamsamples = 0x10000; }
yamcycles = yamsamples * CYCLES_PER_SAMPLE;
if(yamcycles <= state->cycles_ahead_of_sound) return 1;
return yamcycles - state->cycles_ahead_of_sound;
}
static uint32 EMU_CALL catcher_lw(void *state, uint32 a, uint32 mask) { return 0; }
static void EMU_CALL catcher_sw(void *state, uint32 a, uint32 d, uint32 mask) { }
static const struct ARM_MEMORY_MAP dcsound_map_load[] = {
{ 0x00000000, 0x007FFFFF, { 0x007FFFFF, ARM_MAP_TYPE_POINTER , NULL } },
{ 0x00800000, 0x0080FFFF, { 0x0000FFFF, ARM_MAP_TYPE_CALLBACK, dcsound_yam_lw } },
{ 0x00000000, 0xFFFFFFFF, { 0xFFFFFFFF, ARM_MAP_TYPE_CALLBACK, catcher_lw } }
};
static const struct ARM_MEMORY_MAP dcsound_map_store[] = {
{ 0x00000000, 0x007FFFFF, { 0x007FFFFF, ARM_MAP_TYPE_POINTER , NULL } },
{ 0x00800000, 0x0080FFFF, { 0x0000FFFF, ARM_MAP_TYPE_CALLBACK, dcsound_yam_sw } },
{ 0x00000000, 0xFFFFFFFF, { 0xFFFFFFFF, ARM_MAP_TYPE_CALLBACK, catcher_sw } }
};
#define DCSOUND_ARRAY_ENTRIES(x) (sizeof(x)/sizeof((x)[0]))
const uint32 dcsound_map_load_entries = DCSOUND_ARRAY_ENTRIES(dcsound_map_load );
const uint32 dcsound_map_store_entries = DCSOUND_ARRAY_ENTRIES(dcsound_map_store);
static void recompute_memory_maps(struct DCSOUND_STATE *state) {
struct ARM_MEMORY_MAP *mapload = MAPLOAD;
struct ARM_MEMORY_MAP *mapstore = MAPSTORE;
memcpy(mapload , dcsound_map_load , sizeof(dcsound_map_load ));
memcpy(mapstore, dcsound_map_store, sizeof(dcsound_map_store));
mapload [0].type.p = RAMBYTEPTR;
mapstore[0].type.p = RAMBYTEPTR;
}
sint32 EMU_CALL dcsound_execute(
void *state,
sint32 cycles,
sint16 *sound_buf,
uint32 *sound_samples
) {
sint32 error = 0;
uint8 *yamintptr;
if(cycles < 0) { return -1; }
timeenter(DCSOUNDSTATE, TIMEDCSOUND);
location_check(DCSOUNDSTATE);
if(cycles > 0x1000000) { cycles = 0x1000000; }
if((*sound_samples) > 0x10000) { (*sound_samples) = 0x10000; }
timeswitch(DCSOUNDSTATE, TIMEYAM);
yam_beginbuffer(YAMSTATE, sound_buf);
timeswitch(DCSOUNDSTATE, TIMEDCSOUND);
DCSOUNDSTATE->sound_samples_remaining = *sound_samples;
timeswitch(DCSOUNDSTATE, TIMEYAM);
yamintptr = yam_get_interrupt_pending_ptr(YAMSTATE);
timeswitch(DCSOUNDSTATE, TIMEDCSOUND);
DCSOUNDSTATE->cycles_executed = 0;
sync_sound(DCSOUNDSTATE);
{ sint32 cap = CYCLES_PER_SAMPLE * DCSOUNDSTATE->sound_samples_remaining;
cap -= DCSOUNDSTATE->cycles_ahead_of_sound;
if(cap < 0) cap = 0;
if(cycles > cap) cycles = cap;
}
while(DCSOUNDSTATE->cycles_executed < cycles) {
sint32 r;
uint32 remain = cycles - DCSOUNDSTATE->cycles_executed;
uint32 ci = cycles_until_next_interrupt(DCSOUNDSTATE);
if(remain > ci) { remain = ci; }
if(remain > 0x1000000) { remain = 0x1000000; }
timeswitch(DCSOUNDSTATE, TIMEARM);
r = arm_execute(ARMSTATE, remain, (*yamintptr) != 0);
timeswitch(DCSOUNDSTATE, TIMEDCSOUND);
if(r < 0) { error = -1; break; }
}
timeswitch(DCSOUNDSTATE, TIMEYAM);
yam_flush(YAMSTATE);
timeswitch(DCSOUNDSTATE, TIMEDCSOUND);
(*sound_samples) -= DCSOUNDSTATE->sound_samples_remaining;
timeleave(DCSOUNDSTATE);
if(error) return error;
return DCSOUNDSTATE->cycles_executed;
}
uint32 EMU_CALL dcsound_getword(void *state, uint32 a) {
return *((uint32*)(RAMBYTEPTR+(a&0x7FFFFC)));
}
void EMU_CALL dcsound_setword(void *state, uint32 a, uint32 d) {
*((uint32*)(RAMBYTEPTR+(a&0x7FFFFC))) = d;
}
void EMU_CALL dcsound_upload_to_ram(
void *state,
uint32 address,
void *src,
uint32 len
) {
uint32 i;
for(i = 0; i < len; i++) {
(RAMBYTEPTR)[((address+i)^(EMU_ENDIAN_XOR(3)))&0x7FFFFF] =
((uint8*)src)[i];
}
}
uint32 EMU_CALL dcsound_get_pc(void *state) {
return arm_getreg(ARMSTATE, ARM_REG_GEN+15);
}