#ifndef EMU_COMPILE
#error "Hi I forgot to set EMU_COMPILE"
#endif
#include "satsound.h"
#ifdef USE_STARSCREAM
#include "Starscream/starcpu.h"
#elif defined(USE_M68K)
#include <setjmp.h>
#include "m68k/m68kconf.h"
#include "m68k/m68k.h"
#else
#include "c68k/c68k.h"
#endif
#include "yam.h"
using namespace m68k;
sint32 EMU_CALL satsound_init(void) { return 0; }
#define CYCLES_PER_SAMPLE (256)
struct SATSOUND_STATE {
struct SATSOUND_STATE *myself;
uint32 offset_to_maps;
uint32 offset_to_scpu;
uint32 offset_to_yam;
uint32 offset_to_ram;
uint8 yam_prev_int;
uint32 scpu_odometer_checkpoint;
#ifndef USE_STARSCREAM
uint32 scpu_odometer_save;
#endif
uint32 sound_samples_remaining;
uint32 cycles_ahead_of_sound;
sint32 cycles_executed;
};
#define RAMSLOP (0x9000)
#define SATSOUNDSTATE ((struct SATSOUND_STATE*)(state))
#define MAPS ((void*)(((char*)(SATSOUNDSTATE))+(SATSOUNDSTATE->offset_to_maps)))
#ifdef USE_STARSCREAM
#define SCPUSTATE ((void*)(((char*)(SATSOUNDSTATE))+(SATSOUNDSTATE->offset_to_scpu)))
#elif defined(USE_M68K)
#define SCPUSTATE ((m68ki_cpu_core*)(((char*)(SATSOUNDSTATE))+(SATSOUNDSTATE->offset_to_scpu)))
#else
#define SCPUSTATE ((c68k_struc*)(((char*)(SATSOUNDSTATE))+(SATSOUNDSTATE->offset_to_scpu)))
#endif
#define YAMSTATE ((void*)(((char*)(SATSOUNDSTATE))+(SATSOUNDSTATE->offset_to_yam)))
#define RAMBYTEPTR (((uint8*)(((char*)(SATSOUNDSTATE))+(SATSOUNDSTATE->offset_to_ram)))+RAMSLOP)
#ifdef USE_STARSCREAM
extern const uint32 satsound_total_maps_size;
#endif
uint32 EMU_CALL satsound_get_state_size(void) {
uint32 offset = 0;
offset += sizeof(struct SATSOUND_STATE);
#ifdef USE_STARSCREAM
offset += satsound_total_maps_size;
offset += s68000_get_state_size();
#elif defined(USE_M68K)
offset += sizeof(m68ki_cpu_core);
#else
offset += sizeof(c68k_struc);
#endif
offset += yam_get_state_size(1);
offset += 0x80000 + 2*RAMSLOP;
return offset;
}
#if defined(USE_STARSCREAM) || defined(USE_M68K)
static void recompute_and_set_memory_maps(struct SATSOUND_STATE *state);
#endif
static void location_check(struct SATSOUND_STATE *state) {
if(state->myself != state) {
#if defined(USE_STARSCREAM) || defined(USE_M68K)
recompute_and_set_memory_maps(SATSOUNDSTATE);
#else
C68k_Set_Fetch(SCPUSTATE, 0x00000, 0x7FFFF, RAMBYTEPTR);
#endif
yam_setram(YAMSTATE, (uint32*)(RAMBYTEPTR), 0x80000, EMU_ENDIAN_XOR(1) ^ 1, 0);
state->myself = state;
}
}
#if !defined(USE_STARSCREAM) && !defined(USE_M68K)
static void satsound_advancesync(struct SATSOUND_STATE *state);
u32 FASTCALL satsound_cb_readb(void *state, const u32 address)
{
if (address < (512*1024)) return RAMBYTEPTR[address^EMU_ENDIAN_XOR(1)^1];
if (address >= 0x100000 && address < 0x100c00) {
int shift = ((address & 1) ^ 1) * 8;
satsound_advancesync(SATSOUNDSTATE);
return (yam_scsp_load_reg(YAMSTATE, address & 0xFFE, 0xFF << shift) >> shift) & 0xFF;
}
return 0;
}
u32 FASTCALL satsound_cb_readw(void *state, const u32 address)
{
if (address < (512*1024)) return ((uint16*)(RAMBYTEPTR))[address/2];
if (address >= 0x100000 && address < 0x100c00) {
satsound_advancesync(SATSOUNDSTATE);
return yam_scsp_load_reg(YAMSTATE, address & 0xFFE, 0xFFFF);
}
return 0;
}
void FASTCALL satsound_cb_writeb(void *state, const u32 address, u32 data)
{
if (address < (512*1024)) {
RAMBYTEPTR[address^EMU_ENDIAN_XOR(1)^1] = data;
return;
}
if (address >= 0x100000 && address < 0x100c00) {
uint8 breakcpu = 0;
int shift = ((address & 1) ^ 1) * 8;
satsound_advancesync(SATSOUNDSTATE);
yam_scsp_store_reg(
YAMSTATE,
address & 0xFFE,
(data & 0xFF) << shift,
0xFF << shift,
&breakcpu
);
if(breakcpu) C68k_Release_Cycle(SCPUSTATE);
return;
}
}
void FASTCALL satsound_cb_writew(void *state, const u32 address, u32 data)
{
if (address < (512*1024)) {
((uint16*)(RAMBYTEPTR))[address/2] = data;
return;
}
if (address >= 0x100000 && address < 0x100c00) {
uint8 breakcpu = 0;
satsound_advancesync(SATSOUNDSTATE);
yam_scsp_store_reg(
YAMSTATE,
address & 0xFFE,
data & 0xFFFF,
0xFFFF,
&breakcpu
);
if(breakcpu) C68k_Release_Cycle(SCPUSTATE);
return;
}
}
#endif
void EMU_CALL satsound_clear_state(void *state) {
uint32 offset;
memset(state, 0, sizeof(struct SATSOUND_STATE));
offset = sizeof(struct SATSOUND_STATE);
#ifdef USE_STARSCREAM
SATSOUNDSTATE->offset_to_maps = offset; offset += satsound_total_maps_size;
SATSOUNDSTATE->offset_to_scpu = offset; offset += s68000_get_state_size();
#elif defined(USE_M68K)
SATSOUNDSTATE->offset_to_maps = offset;
SATSOUNDSTATE->offset_to_scpu = offset; offset += sizeof(m68ki_cpu_core);
#else
SATSOUNDSTATE->offset_to_maps = offset;
SATSOUNDSTATE->offset_to_scpu = offset; offset += sizeof(c68k_struc);
#endif
SATSOUNDSTATE->offset_to_yam = offset; offset += yam_get_state_size(1);
SATSOUNDSTATE->offset_to_ram = offset; offset += 0x80000 + 2*RAMSLOP;
memset(RAMBYTEPTR-RAMSLOP, 0xFF, RAMSLOP);
memset(RAMBYTEPTR , 0x00, 0x80000);
memset(RAMBYTEPTR+0x80000, 0xFF, RAMSLOP);
#ifdef USE_STARSCREAM
s68000_clear_state(SCPUSTATE);
#elif defined(USE_M68K)
memset(SCPUSTATE, 0, sizeof(m68ki_cpu_core));
m68k_init(SCPUSTATE);
#else
C68k_Init(SCPUSTATE, NULL);
C68k_Set_Callback_Param(SCPUSTATE, state);
C68k_Set_Fetch(SCPUSTATE, 0x00000, 0x7FFFF, RAMBYTEPTR);
C68k_Set_ReadB(SCPUSTATE, satsound_cb_readb);
C68k_Set_ReadW(SCPUSTATE, satsound_cb_readw);
C68k_Set_WriteB(SCPUSTATE, satsound_cb_writeb);
C68k_Set_WriteW(SCPUSTATE, satsound_cb_writew);
#endif
yam_clear_state(YAMSTATE, 1);
location_check(SATSOUNDSTATE);
}
void* EMU_CALL satsound_get_scpu_state(void *state) { return (void*)SCPUSTATE; }
void* EMU_CALL satsound_get_yam_state(void *state) { return YAMSTATE; }
void EMU_CALL satsound_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(1)^1))&0x7FFFF] =
((uint8*)src)[i];
}
#ifdef USE_STARSCREAM
s68000_reset(SCPUSTATE);
#elif defined(USE_M68K)
m68k_pulse_reset(SCPUSTATE);
#else
C68k_Reset(SCPUSTATE);
#endif
}
static void sync_sound(struct SATSOUND_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) {
yam_advance(YAMSTATE, samples);
state->cycles_ahead_of_sound -= CYCLES_PER_SAMPLE * samples;
state->sound_samples_remaining -= samples;
}
}
}
static void satsound_advancesync(struct SATSOUND_STATE *state) {
uint32 odometer, elapse;
#ifdef USE_STARSCREAM
odometer = s68000_read_odometer(SCPUSTATE);
#elif defined(USE_M68K)
odometer = SCPUSTATE->initial_cycles - SCPUSTATE->remaining_cycles;
#else
odometer = C68k_Get_CycleDone(SCPUSTATE);
if(odometer == ~0) odometer = state->scpu_odometer_save;
#endif
elapse = odometer - (state->scpu_odometer_checkpoint);
state->scpu_odometer_checkpoint = odometer;
state->cycles_executed += elapse;
state->cycles_ahead_of_sound += elapse;
sync_sound(SATSOUNDSTATE);
}
#ifdef USE_STARSCREAM
static unsigned STARSCREAM_CALL satsound_yam_readbyte(
void *state,
unsigned address
) {
int shift = ((address & 1) ^ 1) * 8;
satsound_advancesync(SATSOUNDSTATE);
return (yam_scsp_load_reg(YAMSTATE, address & 0xFFE, 0xFF << shift) >> shift) & 0xFF;
}
static unsigned STARSCREAM_CALL satsound_yam_readword(
void *state,
unsigned address
) {
satsound_advancesync(SATSOUNDSTATE);
return yam_scsp_load_reg(YAMSTATE, address & 0xFFE, 0xFFFF) & 0xFFFF;
}
static void STARSCREAM_CALL satsound_yam_writebyte(
void *state,
unsigned address,
unsigned data
) {
uint8 breakcpu = 0;
int shift = ((address & 1) ^ 1) * 8;
satsound_advancesync(SATSOUNDSTATE);
yam_scsp_store_reg(
YAMSTATE,
address & 0xFFE,
(data & 0xFF) << shift,
0xFF << shift,
&breakcpu
);
if(breakcpu) s68000_break(SCPUSTATE);
}
static void STARSCREAM_CALL satsound_yam_writeword(
void *state,
unsigned address,
unsigned data
) {
uint8 breakcpu = 0;
satsound_advancesync(SATSOUNDSTATE);
yam_scsp_store_reg(
YAMSTATE,
address & 0xFFE,
data & 0xFFFF,
0xFFFF,
&breakcpu
);
if(breakcpu) s68000_break(SCPUSTATE);
}
static const struct STARSCREAM_PROGRAMREGION satsound_map_fetch[] = {
{ 0x000000, 0x07FFFF, 0 },
{ -1, -1, NULL }
};
static const struct STARSCREAM_DATAREGION satsound_map_readbyte[] = {
{ 0x000000, 0x07FFFF, NULL, NULL },
{ 0x100000, 0x100FFF, satsound_yam_readbyte, NULL },
{ -1, -1, NULL, NULL }
};
static const struct STARSCREAM_DATAREGION satsound_map_readword[] = {
{ 0x000000, 0x07FFFF, NULL, NULL },
{ 0x100000, 0x100FFF, satsound_yam_readword, NULL },
{ -1, -1, NULL, NULL }
};
static const struct STARSCREAM_DATAREGION satsound_map_writebyte[] = {
{ 0x000000, 0x07FFFF, NULL, NULL },
{ 0x100000, 0x100FFF, satsound_yam_writebyte, NULL },
{ -1, -1, NULL, NULL }
};
static const struct STARSCREAM_DATAREGION satsound_map_writeword[] = {
{ 0x000000, 0x07FFFF, NULL, NULL },
{ 0x100000, 0x100FFF, satsound_yam_writeword, NULL },
{ -1, -1, NULL, NULL }
};
static void *computemap_program(
struct SATSOUND_STATE *state,
struct STARSCREAM_PROGRAMREGION *dst,
const struct STARSCREAM_PROGRAMREGION *src
) {
int i;
for(i = 0;; i++) {
memcpy(dst + i, src + i, sizeof(struct STARSCREAM_PROGRAMREGION));
if(dst[i].lowaddr == ((uint32)(-1))) { i++; break; }
}
dst[0].offset = RAMBYTEPTR;
return dst + i;
}
static void *computemap_data(
struct SATSOUND_STATE *state,
struct STARSCREAM_DATAREGION *dst,
const struct STARSCREAM_DATAREGION *src
) {
int i;
for(i = 0;; i++) {
memcpy(dst + i, src + i, sizeof(struct STARSCREAM_DATAREGION));
if(dst[i].lowaddr == ((uint32)(-1))) { i++; break; }
}
dst[0].userdata = RAMBYTEPTR;
dst[1].userdata = state;
return dst + i;
}
const uint32 satsound_total_maps_size =
sizeof(satsound_map_fetch) +
sizeof(satsound_map_readbyte) +
sizeof(satsound_map_readword) +
sizeof(satsound_map_writebyte) +
sizeof(satsound_map_writeword);
static void recompute_and_set_memory_maps(
struct SATSOUND_STATE *state
) {
void *mapinfo[10];
mapinfo[0] = MAPS;
mapinfo[1] = computemap_program(state, mapinfo[0], satsound_map_fetch);
mapinfo[2] = computemap_data (state, mapinfo[1], satsound_map_readbyte);
mapinfo[3] = computemap_data (state, mapinfo[2], satsound_map_readword);
mapinfo[4] = computemap_data (state, mapinfo[3], satsound_map_writebyte);
computemap_data (state, mapinfo[4], satsound_map_writeword);
mapinfo[5] = mapinfo[0];
mapinfo[6] = mapinfo[1];
mapinfo[7] = mapinfo[2];
mapinfo[8] = mapinfo[3];
mapinfo[9] = mapinfo[4];
s68000_set_memory_maps(SCPUSTATE, mapinfo);
}
#endif
#ifdef USE_M68K
static unsigned int satsound_read_dummy(void *param, unsigned int address)
{
return 0;
}
static void satsound_write_dummy(void *param, unsigned int address, unsigned int data)
{
}
static unsigned int satsound_apu_read8(void *state, unsigned int address)
{
if (address >= 0x100000 && address < 0x100c00) {
int shift = ((address & 1) ^ 1) * 8;
satsound_advancesync(SATSOUNDSTATE);
return (yam_scsp_load_reg(YAMSTATE, address & 0xFFE, 0xFF << shift) >> shift) & 0xFF;
}
return 0;
}
static unsigned int satsound_apu_read16(void *state, unsigned int address)
{
if (address >= 0x100000 && address < 0x100c00) {
satsound_advancesync(SATSOUNDSTATE);
return yam_scsp_load_reg(YAMSTATE, address & 0xFFE, 0xFFFF) & 0xFFFF;
}
return 0;
}
static void satsound_apu_write8(void *state, unsigned int address, unsigned int data)
{
if (address >= 0x100000 && address < 0x100c00) {
uint8 breakcpu = 0;
int shift = ((address & 1) ^ 1) * 8;
satsound_advancesync(SATSOUNDSTATE);
yam_scsp_store_reg(
YAMSTATE,
address & 0xFFE,
(data & 0xFF) << shift,
0xFF << shift,
&breakcpu
);
if(breakcpu) {
SATSOUNDSTATE->scpu_odometer_save = SCPUSTATE->remaining_cycles;
SCPUSTATE->remaining_cycles = 0;
}
}
}
static void satsound_apu_write16(void *state, unsigned int address, unsigned int data)
{
if (address >= 0x100000 && address < 0x100c00) {
uint8 breakcpu = 0;
satsound_advancesync(SATSOUNDSTATE);
yam_scsp_store_reg(
YAMSTATE,
address & 0xFFE,
data,
0xFFFF,
&breakcpu
);
if(breakcpu) {
SATSOUNDSTATE->scpu_odometer_save = SCPUSTATE->remaining_cycles;
SCPUSTATE->remaining_cycles = 0;
}
}
}
static void recompute_and_set_memory_maps(
struct SATSOUND_STATE *state
) {
uint32 i;
cpu_memory_map * map;
for(i = 0; i < 8; i++) {
map = SCPUSTATE->memory_map + i;
map->param = NULL;
map->base = RAMBYTEPTR + (i << 16);
map->read8 = NULL;
map->read16 = NULL;
map->write8 = NULL;
map->write16 = NULL;
}
for(; i < 0x10; i++) {
map = SCPUSTATE->memory_map + i;
map->param = NULL;
map->base = NULL;
map->read8 = satsound_read_dummy;
map->read16 = satsound_read_dummy;
map->write8 = satsound_write_dummy;
map->write16 = satsound_write_dummy;
}
map = SCPUSTATE->memory_map + 0x10;
map->param = state;
map->base = NULL;
map->read8 = satsound_apu_read8;
map->read16 = satsound_apu_read16;
map->write8 = satsound_apu_write8;
map->write16 = satsound_apu_write16;
for(i = 0x11; i < 0x100; i++) {
map = SCPUSTATE->memory_map + i;
map->param = NULL;
map->base = NULL;
map->read8 = satsound_read_dummy;
map->read16 = satsound_read_dummy;
map->write8 = satsound_write_dummy;
map->write16 = satsound_write_dummy;
}
}
#endif
static uint32 cycles_until_next_interrupt(struct SATSOUND_STATE *state) {
uint32 yamsamples;
uint32 yamcycles;
yamsamples = yam_get_min_samples_until_interrupt(YAMSTATE);
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;
}
#if defined(SCSP_LOG) && !defined(USE_STARSCREAM)
unsigned char ** scsp_pc;
unsigned char ** scsp_basepc;
#endif
sint32 EMU_CALL satsound_execute(
void *state,
sint32 cycles,
sint16 *sound_buf,
uint32 *sound_samples
) {
sint32 error = 0;
uint8 *yamintptr;
if(cycles < 0) { return -1; }
location_check(SATSOUNDSTATE);
if(cycles > 0x1000000) { cycles = 0x1000000; }
if((*sound_samples) > 0x10000) { (*sound_samples) = 0x10000; }
yam_beginbuffer(YAMSTATE, sound_buf);
SATSOUNDSTATE->sound_samples_remaining = *sound_samples;
yamintptr = yam_get_interrupt_pending_ptr(YAMSTATE);
SATSOUNDSTATE->cycles_executed = 0;
#ifdef USE_STARSCREAM
SATSOUNDSTATE->scpu_odometer_checkpoint = s68000_read_odometer(SCPUSTATE);
#elif defined(USE_M68K)
SATSOUNDSTATE->scpu_odometer_checkpoint = 0;
#else
SATSOUNDSTATE->scpu_odometer_checkpoint = 0;
#endif
sync_sound(SATSOUNDSTATE);
{ sint32 cap = CYCLES_PER_SAMPLE * SATSOUNDSTATE->sound_samples_remaining;
cap -= SATSOUNDSTATE->cycles_ahead_of_sound;
if(cap < 0) cap = 0;
if(cycles > cap) cycles = cap;
}
#if defined(SCSP_LOG) && !defined(USE_STARSCREAM)
scsp_pc = &(SCPUSTATE->PC);
scsp_basepc = &(SCPUSTATE->BasePC);
#endif
while(SATSOUNDSTATE->cycles_executed < cycles) {
#ifdef USE_STARSCREAM
uint32 r;
#else
sint32 r;
#endif
uint32 remain = cycles - SATSOUNDSTATE->cycles_executed;
uint32 ci = cycles_until_next_interrupt(SATSOUNDSTATE);
if(remain > ci) { remain = ci; }
if(remain > 0x1000000) { remain = 0x1000000; }
if((SATSOUNDSTATE->yam_prev_int) != (*yamintptr)) {
#ifdef USE_STARSCREAM
SATSOUNDSTATE->yam_prev_int = (*yamintptr);
if(*yamintptr) {
s68000_interrupt(
SCPUSTATE,
((-1)*256) + ((SATSOUNDSTATE->yam_prev_int)&7)
);
}
#elif defined(USE_M68K)
unsigned line = ((*yamintptr) ? *yamintptr : SATSOUNDSTATE->yam_prev_int) & 7;
unsigned line_state = *yamintptr ? ASSERT_LINE : RESET_LINE;
m68k_set_irq(
SCPUSTATE,
line,
line_state
);
SATSOUNDSTATE->yam_prev_int = (*yamintptr);
#else
SATSOUNDSTATE->yam_prev_int = (*yamintptr);
if(*yamintptr) {
C68k_Set_IRQ(
SCPUSTATE,
(SATSOUNDSTATE->yam_prev_int)&7
);
}
#endif
}
#ifdef USE_STARSCREAM
r = s68000_execute(SCPUSTATE, remain);
if(r != 0x80000000) {
#elif defined(USE_M68K)
SATSOUNDSTATE->scpu_odometer_save = ~0;
r = m68k_execute(SCPUSTATE, remain);
if (0) {
#else
r = C68k_Exec(SCPUSTATE, remain);
if(r < 0) {
#endif
error = -1; break;
}
#if !defined(USE_STARSCREAM) && !defined(USE_M68K)
SATSOUNDSTATE->scpu_odometer_save = r;
#endif
#ifdef USE_M68K
if(SATSOUNDSTATE->scpu_odometer_save != ~0) {
SCPUSTATE->remaining_cycles += SATSOUNDSTATE->scpu_odometer_save;
}
#endif
satsound_advancesync(SATSOUNDSTATE);
#if !defined(USE_STARSCREAM)
SATSOUNDSTATE->scpu_odometer_checkpoint = 0;
#endif
}
yam_flush(YAMSTATE);
(*sound_samples) -= SATSOUNDSTATE->sound_samples_remaining;
if(error) return error;
return SATSOUNDSTATE->cycles_executed;
}
uint16 EMU_CALL satsound_getword(void *state, uint32 a) {
return *((uint16*)(RAMBYTEPTR+(a&0x7FFFE)));
}
void EMU_CALL satsound_setword(void *state, uint32 a, uint16 d) {
*((uint16*)(RAMBYTEPTR+(a&0x7FFFE))) = d;
}
uint32 EMU_CALL satsound_get_pc(void *state) {
#ifdef USE_STARSCREAM
return s68000_getreg(SCPUSTATE, STARSCREAM_REG_PC);
#elif defined(USE_M68K)
return SCPUSTATE->pc;
#else
return C68k_Get_PC(SCPUSTATE);
#endif
}