2013-09-30 10:36:30 +00:00
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// sega - Top-level emulation for Saturn and DC
|
|
|
|
//
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#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 init for the whole library
|
|
|
|
//
|
|
|
|
static uint8 library_was_initialized = 0;
|
|
|
|
|
|
|
|
//
|
|
|
|
// Deliberately create a NULL dereference
|
|
|
|
// Useful for calling attention to show-stopper problems like forgetting to
|
|
|
|
// call sega_init() or compiling with the wrong byte order
|
|
|
|
//
|
|
|
|
static void sega_hang(const char *message) {
|
|
|
|
for(;;) { *((volatile char*)0) = *message; }
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Endian check
|
|
|
|
//
|
|
|
|
static void sega_endian_check(void) {
|
|
|
|
uint32 num = 0x61626364;
|
|
|
|
// Big
|
|
|
|
if(!memcmp(&num, "abcd", 4)) {
|
|
|
|
#ifdef SEGA_BIG_ENDIAN
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
sega_hang("endian check");
|
|
|
|
}
|
|
|
|
// Little
|
|
|
|
if(!memcmp(&num, "dcba", 4)) {
|
|
|
|
#ifndef SEGA_BIG_ENDIAN
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
sega_hang("endian check");
|
|
|
|
}
|
|
|
|
// Don't know what!
|
|
|
|
sega_hang("endian check");
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Data type size 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Version information
|
|
|
|
//
|
|
|
|
const char* EMU_CALL sega_getversion(void) {
|
|
|
|
static const char s[] = "SegaCore0001 (built " __DATE__ ")";
|
|
|
|
static char rv[500];
|
2013-10-03 08:00:58 +00:00
|
|
|
int sl = (int)strlen(s);
|
2013-09-30 10:36:30 +00:00
|
|
|
memcpy(rv, s, sl);
|
|
|
|
#ifndef DISABLE_SSF
|
|
|
|
rv[sl] = '\n';
|
|
|
|
#ifdef USE_STARSCREAM
|
|
|
|
strcpy(rv+sl+1, s68000_get_version());
|
2013-10-03 08:00:58 +00:00
|
|
|
#elif defined(USE_M68K)
|
|
|
|
strcpy(rv+sl+1, "M68K");
|
2013-09-30 10:36:30 +00:00
|
|
|
#else
|
|
|
|
strcpy(rv+sl+1, "C68K");
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// State information
|
|
|
|
//
|
|
|
|
|
|
|
|
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 we haven't initialized, we really SHOULD have.
|
|
|
|
//
|
|
|
|
if(!library_was_initialized) sega_hang("library not initialized");
|
|
|
|
|
|
|
|
// Clear local struct
|
|
|
|
memset(state, 0, sizeof(struct SEGA_STATE));
|
|
|
|
// Set up offsets
|
|
|
|
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(); }
|
|
|
|
//
|
|
|
|
// Take care of substructures
|
|
|
|
//
|
|
|
|
#ifndef DISABLE_SSF
|
|
|
|
if(HAVE_SATSOUND) satsound_clear_state(SATSOUNDSTATE);
|
|
|
|
#endif
|
|
|
|
if(HAVE_DCSOUND) dcsound_clear_state(DCSOUNDSTATE);
|
|
|
|
// Done
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Obtain substates
|
|
|
|
//
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Executes the given number of cycles or the given number of samples
|
|
|
|
// (whichever is less)
|
|
|
|
//
|
|
|
|
// Sets *sound_samples to the number of samples actually generated,
|
|
|
|
// which may be ZERO or LESS than the number requested, but never more.
|
|
|
|
//
|
|
|
|
// Return value:
|
|
|
|
// >= 0 The number of cycles actually executed, which may be ZERO, MORE,
|
|
|
|
// or LESS than the number requested
|
|
|
|
// <= -1 Unrecoverable error
|
|
|
|
//
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2013-10-03 08:00:58 +00:00
|
|
|
#if 0
|
2013-09-30 10:36:30 +00:00
|
|
|
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);
|
|
|
|
}
|
2013-10-03 08:00:58 +00:00
|
|
|
#endif
|
2013-09-30 10:36:30 +00:00
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Upload program - must INCLUDE the 4-byte header.
|
|
|
|
// Returns nonzero on error.
|
|
|
|
//
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Get the current program counter
|
|
|
|
//
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// Enable or disable various things
|
|
|
|
//
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|