#ifndef EMU_COMPILE
#error "Hi I forgot to set EMU_COMPILE"
#endif
#include "sega.h"
#include "satsound.h"
#include "dcsound.h"
#include "arm.h"
#include "yam.h"
#ifdef USE_STARSCREAM
#include "Starscream/starcpu.h"
#endif
static uint8 library_was_initialized = 0;
static void sega_hang(const char *message) {
for(;;) { *((volatile char*)0) = *message; }
}
static void sega_endian_check(void) {
uint32 num = 0x61626364;
if(!memcmp(&num, "abcd", 4)) {
#ifdef SEGA_BIG_ENDIAN
return;
#endif
sega_hang("endian check");
}
if(!memcmp(&num, "dcba", 4)) {
#ifndef SEGA_BIG_ENDIAN
return;
#endif
sega_hang("endian check");
}
sega_hang("endian check");
}
static void sega_size_check(void) {
if(sizeof(uint8 ) != 1) sega_hang("size check");
if(sizeof(uint16) != 2) sega_hang("size check");
if(sizeof(uint32) != 4) sega_hang("size check");
if(sizeof(uint64) != 8) sega_hang("size check");
if(sizeof(sint8 ) != 1) sega_hang("size check");
if(sizeof(sint16) != 2) sega_hang("size check");
if(sizeof(sint32) != 4) sega_hang("size check");
if(sizeof(sint64) != 8) sega_hang("size check");
}
sint32 EMU_CALL sega_init(void) {
sint32 r;
sega_endian_check();
sega_size_check();
if(library_was_initialized) return 0;
#ifndef DISABLE_SSF
r = satsound_init(); if(r) return r;
#endif
r = dcsound_init(); if(r) return r;
r = arm_init(); if(r) return r;
r = yam_init(); if(r) return r;
#ifndef DISABLE_SSF
#ifdef USE_STARSCREAM
r = s68000_init(); if(r) return r;
#endif
#endif
library_was_initialized = 1;
return 0;
}
const char* EMU_CALL sega_getversion(void) {
static const char s[] = "SegaCore0001 (built " __DATE__ ")";
static char rv[500];
int sl = strlen(s);
memcpy(rv, s, sl);
#ifndef DISABLE_SSF
rv[sl] = '\n';
#ifdef USE_STARSCREAM
strcpy(rv+sl+1, s68000_get_version());
#else
strcpy(rv+sl+1, "C68K");
#endif
#endif
return rv;
}
struct SEGA_STATE {
uint32 offset_to_dcsound;
uint32 offset_to_satsound;
};
#define SEGASTATE ((struct SEGA_STATE*)(state))
#define DCSOUNDSTATE ((void*)(((char*)(state))+(SEGASTATE->offset_to_dcsound)))
#define SATSOUNDSTATE ((void*)(((char*)(state))+(SEGASTATE->offset_to_satsound)))
#define HAVE_DCSOUND (SEGASTATE->offset_to_dcsound!=0)
#define HAVE_SATSOUND (SEGASTATE->offset_to_satsound!=0)
uint32 EMU_CALL sega_get_state_size(uint8 version) {
uint32 size = 0;
if(version != 2) version = 1;
size += sizeof(struct SEGA_STATE);
#ifndef DISABLE_SSF
if(version == 1) size += satsound_get_state_size();
#endif
if(version == 2) size += dcsound_get_state_size();
return size;
}
void EMU_CALL sega_clear_state(void *state, uint8 version) {
uint32 offset;
if(version != 2) version = 1;
if(!library_was_initialized) sega_hang("library not initialized");
memset(state, 0, sizeof(struct SEGA_STATE));
offset = sizeof(struct SEGA_STATE);
#ifndef DISABLE_SSF
if(version == 1) { SEGASTATE->offset_to_satsound = offset; offset += satsound_get_state_size(); }
#endif
if(version == 2) { SEGASTATE->offset_to_dcsound = offset; offset += dcsound_get_state_size(); }
#ifndef DISABLE_SSF
if(HAVE_SATSOUND) satsound_clear_state(SATSOUNDSTATE);
#endif
if(HAVE_DCSOUND) dcsound_clear_state(DCSOUNDSTATE);
}
void* EMU_CALL sega_get_satsound_state(void *state) {
#ifdef DISABLE_SSF
return NULL;
#else
if(!(HAVE_SATSOUND)) return NULL;
return SATSOUNDSTATE;
#endif
}
void* EMU_CALL sega_get_dcsound_state(void *state) {
if(!(HAVE_DCSOUND)) return NULL;
return DCSOUNDSTATE;
}
sint32 EMU_CALL sega_execute(
void *state,
sint32 cycles,
sint16 *sound_buf,
uint32 *sound_samples
) {
#ifndef DISABLE_SSF
if(HAVE_SATSOUND) {
return satsound_execute(SATSOUNDSTATE, cycles, sound_buf, sound_samples);
} else
#endif
if(HAVE_DCSOUND) {
return dcsound_execute(DCSOUNDSTATE, cycles, sound_buf, sound_samples);
} else {
return -1;
}
}
static uint32 get32lsb(uint8 *src) {
return
((((uint32)(src[0])) & 0xFF) << 0) |
((((uint32)(src[1])) & 0xFF) << 8) |
((((uint32)(src[2])) & 0xFF) << 16) |
((((uint32)(src[3])) & 0xFF) << 24);
}
static uint32 get32msb(uint8 *src) {
return
((((uint32)(src[3])) & 0xFF) << 0) |
((((uint32)(src[2])) & 0xFF) << 8) |
((((uint32)(src[1])) & 0xFF) << 16) |
((((uint32)(src[0])) & 0xFF) << 24);
}
sint32 EMU_CALL sega_upload_program(void *state, void *program, uint32 size) {
uint32 start;
if(size < 5) return -1;
start = get32lsb((uint8*)program);
#ifndef DISABLE_SSF
if(HAVE_SATSOUND) {
satsound_upload_to_ram(SATSOUNDSTATE, start, ((uint8*)program) + 4, size - 4);
} else
#endif
if(HAVE_DCSOUND) {
dcsound_upload_to_ram(DCSOUNDSTATE, start, ((uint8*)program) + 4, size - 4);
} else {
return -1;
}
return 0;
}
uint32 EMU_CALL sega_get_pc(void *state) {
#ifndef DISABLE_SSF
if(HAVE_SATSOUND) return satsound_get_pc(SATSOUNDSTATE);
#endif
if(HAVE_DCSOUND) return dcsound_get_pc(DCSOUNDSTATE);
return 0;
}
static void *getyamstate(struct SEGA_STATE *state) {
void *yamstate = NULL;
#ifndef DISABLE_SSF
if(HAVE_SATSOUND) { yamstate = satsound_get_yam_state(SATSOUNDSTATE); }
#endif
if(HAVE_DCSOUND) { yamstate = dcsound_get_yam_state(DCSOUNDSTATE); }
return yamstate;
}
void EMU_CALL sega_enable_dry(void *state, uint8 enable) {
void *yamstate = getyamstate(SEGASTATE);
if(yamstate) yam_enable_dry(yamstate, enable);
}
void EMU_CALL sega_enable_dsp(void *state, uint8 enable) {
void *yamstate = getyamstate(SEGASTATE);
if(yamstate) yam_enable_dsp(yamstate, enable);
}
void EMU_CALL sega_enable_dsp_dynarec(void *state, uint8 enable) {
void *yamstate = getyamstate(SEGASTATE);
if(yamstate) yam_enable_dsp_dynarec(yamstate, enable);
}