///////////////////////////////////////////////////////////////////////////// // // 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]; int sl = (int)strlen(s); memcpy(rv, s, sl); #ifndef DISABLE_SSF rv[sl] = '\n'; #ifdef USE_STARSCREAM strcpy(rv+sl+1, s68000_get_version()); #elif defined(USE_M68K) strcpy(rv+sl+1, "M68K"); #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); } #if 0 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); } #endif ///////////////////////////////////////////////////////////////////////////// // // 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); } /////////////////////////////////////////////////////////////////////////////