2014-06-19 21:34:42 +00:00
# include <stdarg.h>
# include <trio/trio.h>
2012-06-03 15:48:14 +00:00
# include "mednafen/mednafen.h"
# include "mednafen/git.h"
# include "mednafen/general.h"
2013-04-27 14:40:24 +00:00
# include "mednafen/md5.h"
2012-06-03 15:48:14 +00:00
# include "libretro.h"
2014-06-18 20:10:07 +00:00
# include "thread.h"
2012-06-03 15:48:14 +00:00
2014-06-19 21:34:42 +00:00
# include "mednafen/FileWrapper.h"
2014-06-19 21:10:59 +00:00
# include "mednafen/pce_fast/pce.h"
# include "mednafen/pce_fast/vdc.h"
# include "mednafen/pce_fast/psg.h"
# include "mednafen/pce_fast/input.h"
# include "mednafen/pce_fast/huc.h"
# include "mednafen/pce_fast/pcecd.h"
# include "mednafen/pce_fast/pcecd_drive.h"
# include "mednafen/hw_misc/arcade_card/arcade_card.h"
# include "mednafen/mempatcher.h"
# include "mednafen/cdrom/cdromif.h"
2014-06-19 21:34:42 +00:00
# include "mednafen/cdrom/CDUtility.h"
# ifdef _MSC_VER
# include "msvc_compat.h"
# endif
2014-06-20 20:49:22 +00:00
static bool old_cdimagecache = false ;
2014-06-19 21:34:42 +00:00
extern MDFNGI EmulatedPCE_Fast ;
2014-06-20 20:49:22 +00:00
MDFNGI * MDFNGameInfo = & EmulatedPCE_Fast ;
2014-06-19 21:10:59 +00:00
/* Mednafen - Multi-system Emulator
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
extern " C " unsigned long crc32 ( unsigned long crc , const unsigned char * buf , unsigned int len ) ;
namespace PCE_Fast
{
static PCEFast_PSG * psg = NULL ;
extern ArcadeCard * arcade_card ; // Bah, lousy globals.
static Blip_Buffer sbuf [ 2 ] ;
bool PCE_ACEnabled ;
static bool IsSGX ;
static bool IsHES ;
int pce_overclocked ;
// Statically allocated for speed...or something.
uint8 ROMSpace [ 0x88 * 8192 + 8192 ] ; // + 8192 for PC-as-pointer safety padding
uint8 BaseRAM [ 32768 + 8192 ] ; // 8KB for PCE, 32KB for Super Grafx // + 8192 for PC-as-pointer safety padding
uint8 PCEIODataBuffer ;
readfunc PCERead [ 0x100 ] ;
writefunc PCEWrite [ 0x100 ] ;
static DECLFR ( PCEBusRead )
{
//printf("BUS Read: %02x %04x\n", A >> 13, A);
return ( 0xFF ) ;
}
static DECLFW ( PCENullWrite )
{
//printf("Null Write: %02x, %08x %02x\n", A >> 13, A, V);
}
static DECLFR ( BaseRAMReadSGX )
{
return ( ( BaseRAM - ( 0xF8 * 8192 ) ) [ A ] ) ;
}
static DECLFW ( BaseRAMWriteSGX )
{
( BaseRAM - ( 0xF8 * 8192 ) ) [ A ] = V ;
}
static DECLFR ( BaseRAMRead )
{
return ( ( BaseRAM - ( 0xF8 * 8192 ) ) [ A ] ) ;
}
static DECLFR ( BaseRAMRead_Mirrored )
{
return ( BaseRAM [ A & 0x1FFF ] ) ;
}
static DECLFW ( BaseRAMWrite )
{
( BaseRAM - ( 0xF8 * 8192 ) ) [ A ] = V ;
}
static DECLFW ( BaseRAMWrite_Mirrored )
{
BaseRAM [ A & 0x1FFF ] = V ;
}
static DECLFR ( IORead )
{
# define IOREAD_SGX 0
# include "mednafen/pce_fast/ioread.inc"
# undef IOREAD_SGX
}
static DECLFR ( IOReadSGX )
{
# define IOREAD_SGX 1
# include "mednafen/pce_fast/ioread.inc"
# undef IOREAD_SGX
}
static DECLFW ( IOWrite )
{
A & = 0x1FFF ;
switch ( A > > 10 )
{
case 0 : HuC6280_StealCycle ( ) ;
VDC_Write ( A , V ) ;
break ;
case 1 : HuC6280_StealCycle ( ) ;
VCE_Write ( A , V ) ;
break ;
case 2 : PCEIODataBuffer = V ;
psg - > Write ( HuCPU . timestamp / pce_overclocked , A , V ) ;
break ;
case 3 : PCEIODataBuffer = V ;
HuC6280_TimerWrite ( A , V ) ;
break ;
case 4 : PCEIODataBuffer = V ; INPUT_Write ( A , V ) ; break ;
case 5 : PCEIODataBuffer = V ; HuC6280_IRQStatusWrite ( A , V ) ; break ;
case 6 :
if ( ! PCE_IsCD )
break ;
if ( ( A & 0x1E00 ) = = 0x1A00 )
{
if ( arcade_card )
arcade_card - > Write ( A & 0x1FFF , V ) ;
}
else
{
PCECD_Write ( HuCPU . timestamp * 3 , A , V ) ;
}
break ;
case 7 : break ; // Expansion.
}
}
static void PCECDIRQCB ( bool asserted )
{
if ( asserted )
HuC6280_IRQBegin ( MDFN_IQIRQ2 ) ;
else
HuC6280_IRQEnd ( MDFN_IQIRQ2 ) ;
}
bool PCE_InitCD ( void )
{
PCECD_Settings cd_settings ;
memset ( & cd_settings , 0 , sizeof ( PCECD_Settings ) ) ;
cd_settings . CDDA_Volume = ( double ) MDFN_GetSettingUI ( " pce_fast.cddavolume " ) / 100 ;
cd_settings . CD_Speed = MDFN_GetSettingUI ( " pce_fast.cdspeed " ) ;
cd_settings . ADPCM_Volume = ( double ) MDFN_GetSettingUI ( " pce_fast.adpcmvolume " ) / 100 ;
cd_settings . ADPCM_LPF = MDFN_GetSettingB ( " pce_fast.adpcmlp " ) ;
if ( cd_settings . CDDA_Volume ! = 1.0 )
MDFN_printf ( _ ( " CD-DA Volume: %d%% \n " ) , ( int ) ( 100 * cd_settings . CDDA_Volume ) ) ;
if ( cd_settings . ADPCM_Volume ! = 1.0 )
MDFN_printf ( _ ( " ADPCM Volume: %d%% \n " ) , ( int ) ( 100 * cd_settings . ADPCM_Volume ) ) ;
return ( PCECD_Init ( & cd_settings , PCECDIRQCB , PCE_MASTER_CLOCK , pce_overclocked , & sbuf [ 0 ] , & sbuf [ 1 ] ) ) ;
}
static int LoadCommon ( void ) ;
static void LoadCommonPre ( void ) ;
static bool TestMagic ( const char * name , MDFNFILE * fp )
{
if ( memcmp ( GET_FDATA_PTR ( fp ) , " HESM " , 4 ) & & strcasecmp ( GET_FEXTS_PTR ( fp ) , " pce " ) & & strcasecmp ( GET_FEXTS_PTR ( fp ) , " sgx " ) )
return ( FALSE ) ;
return ( TRUE ) ;
}
static int Load ( const char * name , MDFNFILE * fp )
{
uint32 headerlen = 0 ;
uint32 r_size ;
IsHES = 0 ;
IsSGX = 0 ;
if ( ! memcmp ( GET_FDATA_PTR ( fp ) , " HESM " , 4 ) )
IsHES = 1 ;
LoadCommonPre ( ) ;
if ( ! IsHES )
{
if ( GET_FSIZE_PTR ( fp ) & 0x200 ) // 512 byte header!
headerlen = 512 ;
}
r_size = GET_FSIZE_PTR ( fp ) - headerlen ;
if ( r_size > 4096 * 1024 ) r_size = 4096 * 1024 ;
for ( int x = 0 ; x < 0x100 ; x + + )
{
PCERead [ x ] = PCEBusRead ;
PCEWrite [ x ] = PCENullWrite ;
}
uint32 crc = crc32 ( 0 , GET_FDATA_PTR ( fp ) + headerlen , GET_FSIZE_PTR ( fp ) - headerlen ) ;
HuCLoad ( GET_FDATA_PTR ( fp ) + headerlen , GET_FSIZE_PTR ( fp ) - headerlen , crc ) ;
if ( ! strcasecmp ( GET_FEXTS_PTR ( fp ) , " sgx " ) )
IsSGX = TRUE ;
if ( GET_FSIZE_PTR ( fp ) > = 8192 & & ! memcmp ( GET_FDATA_PTR ( fp ) + headerlen , " DARIUS Version 1.11b " , strlen ( " DARIUS VERSION 1.11b " ) ) )
{
MDFN_printf ( " SuperGfx: Darius Plus \n " ) ;
IsSGX = 1 ;
}
if ( crc = = 0x4c2126b0 )
{
MDFN_printf ( " SuperGfx: Aldynes \n " ) ;
IsSGX = 1 ;
}
if ( crc = = 0x8c4588e2 )
{
MDFN_printf ( " SuperGfx: 1941 - Counter Attack \n " ) ;
IsSGX = 1 ;
}
if ( crc = = 0x1f041166 )
{
MDFN_printf ( " SuperGfx: Madouou Granzort \n " ) ;
IsSGX = 1 ;
}
if ( crc = = 0xb486a8ed )
{
MDFN_printf ( " SuperGfx: Daimakaimura \n " ) ;
IsSGX = 1 ;
}
if ( crc = = 0x3b13af61 )
{
MDFN_printf ( " SuperGfx: Battle Ace \n " ) ;
IsSGX = 1 ;
}
return ( LoadCommon ( ) ) ;
}
static void LoadCommonPre ( void )
{
// FIXME: Make these globals less global!
pce_overclocked = MDFN_GetSettingUI ( " pce_fast.ocmultiplier " ) ;
PCE_ACEnabled = MDFN_GetSettingB ( " pce_fast.arcadecard " ) ;
if ( pce_overclocked > 1 )
MDFN_printf ( _ ( " CPU overclock: %dx \n " ) , pce_overclocked ) ;
if ( MDFN_GetSettingUI ( " pce_fast.cdspeed " ) > 1 )
MDFN_printf ( _ ( " CD-ROM speed: %ux \n " ) , ( unsigned int ) MDFN_GetSettingUI ( " pce_fast.cdspeed " ) ) ;
memset ( HuCPUFastMap , 0 , sizeof ( HuCPUFastMap ) ) ;
for ( int x = 0 ; x < 0x100 ; x + + )
{
PCERead [ x ] = PCEBusRead ;
PCEWrite [ x ] = PCENullWrite ;
}
MDFNMP_Init ( 1024 , ( 1 < < 21 ) / 1024 ) ;
}
static int LoadCommon ( void )
{
IsSGX | = MDFN_GetSettingB ( " pce_fast.forcesgx " ) ? 1 : 0 ;
if ( IsHES )
IsSGX = 1 ;
// Don't modify IsSGX past this point.
VDC_Init ( IsSGX ) ;
if ( IsSGX )
{
MDFN_printf ( " SuperGrafx Emulation Enabled. \n " ) ;
PCERead [ 0xF8 ] = PCERead [ 0xF9 ] = PCERead [ 0xFA ] = PCERead [ 0xFB ] = BaseRAMReadSGX ;
PCEWrite [ 0xF8 ] = PCEWrite [ 0xF9 ] = PCEWrite [ 0xFA ] = PCEWrite [ 0xFB ] = BaseRAMWriteSGX ;
for ( int x = 0xf8 ; x < 0xfb ; x + + )
HuCPUFastMap [ x ] = BaseRAM - 0xf8 * 8192 ;
PCERead [ 0xFF ] = IOReadSGX ;
}
else
{
PCERead [ 0xF8 ] = BaseRAMRead ;
PCERead [ 0xF9 ] = PCERead [ 0xFA ] = PCERead [ 0xFB ] = BaseRAMRead_Mirrored ;
PCEWrite [ 0xF8 ] = BaseRAMWrite ;
PCEWrite [ 0xF9 ] = PCEWrite [ 0xFA ] = PCEWrite [ 0xFB ] = BaseRAMWrite_Mirrored ;
for ( int x = 0xf8 ; x < 0xfb ; x + + )
HuCPUFastMap [ x ] = BaseRAM - x * 8192 ;
PCERead [ 0xFF ] = IORead ;
}
MDFNMP_AddRAM ( IsSGX ? 32768 : 8192 , 0xf8 * 8192 , BaseRAM ) ;
PCEWrite [ 0xFF ] = IOWrite ;
HuC6280_Init ( ) ;
psg = new PCEFast_PSG ( & sbuf [ 0 ] , & sbuf [ 1 ] ) ;
psg - > SetVolume ( 1.0 ) ;
if ( PCE_IsCD )
{
unsigned int cdpsgvolume = MDFN_GetSettingUI ( " pce_fast.cdpsgvolume " ) ;
if ( cdpsgvolume ! = 100 )
{
MDFN_printf ( _ ( " CD PSG Volume: %d%% \n " ) , cdpsgvolume ) ;
}
psg - > SetVolume ( 0.678 * cdpsgvolume / 100 ) ;
}
PCEINPUT_Init ( ) ;
PCE_Power ( ) ;
MDFNGameInfo - > LayerNames = IsSGX ? " BG0 \0 SPR0 \0 BG1 \0 SPR1 \0 " : " Background \0 Sprites \0 " ;
MDFNGameInfo - > fps = ( uint32 ) ( ( double ) 7159090.90909090 / 455 / 263 * 65536 * 256 ) ;
// Clean this up:
if ( ! MDFN_GetSettingB ( " pce_fast.correct_aspect " ) )
MDFNGameInfo - > fb_width = 682 ;
if ( ! IsHES )
{
MDFNGameInfo - > nominal_width = MDFN_GetSettingB ( " pce_fast.correct_aspect " ) ? 288 : 341 ;
MDFNGameInfo - > nominal_height = MDFN_GetSettingUI ( " pce_fast.slend " ) - MDFN_GetSettingUI ( " pce_fast.slstart " ) + 1 ;
MDFNGameInfo - > lcm_width = MDFN_GetSettingB ( " pce_fast.correct_aspect " ) ? 1024 : 341 ;
MDFNGameInfo - > lcm_height = MDFNGameInfo - > nominal_height ;
}
return ( 1 ) ;
}
static bool TestMagicCD ( std : : vector < CDIF * > * CDInterfaces )
{
static const uint8 magic_test [ 0x20 ] = { 0x82 , 0xB1 , 0x82 , 0xCC , 0x83 , 0x76 , 0x83 , 0x8D , 0x83 , 0x4F , 0x83 , 0x89 , 0x83 , 0x80 , 0x82 , 0xCC ,
0x92 , 0x98 , 0x8D , 0xEC , 0x8C , 0xA0 , 0x82 , 0xCD , 0x8A , 0x94 , 0x8E , 0xAE , 0x89 , 0xEF , 0x8E , 0xD0
} ;
uint8 sector_buffer [ 2048 ] ;
CDIF * cdiface = ( * CDInterfaces ) [ 0 ] ;
CDUtility : : TOC toc ;
bool ret = FALSE ;
memset ( sector_buffer , 0 , sizeof ( sector_buffer ) ) ;
cdiface - > ReadTOC ( & toc ) ;
for ( int32 track = toc . first_track ; track < = toc . last_track ; track + + )
{
if ( toc . tracks [ track ] . control & 0x4 )
{
cdiface - > ReadSector ( sector_buffer , toc . tracks [ track ] . lba , 1 ) ;
if ( ! memcmp ( ( char * ) sector_buffer , ( char * ) magic_test , 0x20 ) )
ret = TRUE ;
// PCE CD BIOS apparently only looks at the first data track.
break ;
}
}
// If it's a PC-FX CD(Battle Heat), return false.
// This is very kludgy.
for ( int32 track = toc . first_track ; track < = toc . last_track ; track + + )
{
if ( toc . tracks [ track ] . control & 0x4 )
{
cdiface - > ReadSector ( sector_buffer , toc . tracks [ track ] . lba , 1 ) ;
if ( ! strncmp ( " PC-FX:Hu_CD-ROM " , ( char * ) sector_buffer , strlen ( " PC-FX:Hu_CD-ROM " ) ) )
{
return ( false ) ;
}
}
}
// Now, test for the Games Express CD games. The GE BIOS seems to always look at sector 0x10, but only if the first track is a
// data track.
if ( toc . first_track = = 1 & & ( toc . tracks [ 1 ] . control & 0x4 ) )
{
if ( cdiface - > ReadSector ( sector_buffer , 0x10 , 1 ) )
{
if ( ! memcmp ( ( char * ) sector_buffer + 0x8 , " HACKER CD ROM SYSTEM " , 0x14 ) )
{
ret = TRUE ;
}
}
}
return ( ret ) ;
}
static int LoadCD ( std : : vector < CDIF * > * CDInterfaces )
{
std : : string bios_path = MDFN_MakeFName ( MDFNMKF_FIRMWARE , 0 , MDFN_GetSettingS ( " pce_fast.cdbios " ) . c_str ( ) ) ;
IsHES = 0 ;
IsSGX = 0 ;
LoadCommonPre ( ) ;
if ( ! HuCLoadCD ( bios_path . c_str ( ) ) )
return ( 0 ) ;
PCECD_Drive_SetDisc ( true , NULL , true ) ;
PCECD_Drive_SetDisc ( false , ( * CDInterfaces ) [ 0 ] , true ) ;
return ( LoadCommon ( ) ) ;
}
static void CloseGame ( void )
{
{
HuCClose ( ) ;
}
VDC_Close ( ) ;
if ( psg )
{
delete psg ;
psg = NULL ;
}
}
static void Emulate ( EmulateSpecStruct * espec )
{
INPUT_Frame ( ) ;
MDFNMP_ApplyPeriodicCheats ( ) ;
#if 0
{
static bool firstcat = true ;
MDFN_PixelFormat nf ;
nf . bpp = 16 ;
nf . colorspace = MDFN_COLORSPACE_RGB ;
nf . Rshift = 11 ;
nf . Gshift = 5 ;
nf . Bshift = 0 ;
nf . Ashift = 16 ;
nf . Rprec = 5 ;
nf . Gprec = 6 ;
nf . Bprec = 5 ;
nf . Aprec = 8 ;
espec - > surface - > SetFormat ( nf , false ) ;
espec - > VideoFormatChanged = firstcat ;
firstcat = false ;
}
# endif
#if 0
static bool firstcat = true ;
MDFN_PixelFormat tmp_pf ;
tmp_pf . Rshift = 0 ;
tmp_pf . Gshift = 0 ;
tmp_pf . Bshift = 0 ;
tmp_pf . Ashift = 8 ;
tmp_pf . Rprec = 0 ;
tmp_pf . Gprec = 0 ;
tmp_pf . Bprec = 0 ;
tmp_pf . Aprec = 0 ;
tmp_pf . bpp = 8 ;
tmp_pf . colorspace = MDFN_COLORSPACE_RGB ;
espec - > surface - > SetFormat ( tmp_pf , false ) ;
espec - > VideoFormatChanged = firstcat ;
firstcat = false ;
# endif
if ( espec - > VideoFormatChanged )
VDC_SetPixelFormat ( espec - > surface - > format ) ; //.Rshift, espec->surface->format.Gshift, espec->surface->format.Bshift);
if ( espec - > SoundFormatChanged )
{
for ( int y = 0 ; y < 2 ; y + + )
{
sbuf [ y ] . set_sample_rate ( espec - > SoundRate ? espec - > SoundRate : 44100 , 50 ) ;
sbuf [ y ] . clock_rate ( ( long ) ( PCE_MASTER_CLOCK / 3 ) ) ;
sbuf [ y ] . bass_freq ( 10 ) ;
}
}
VDC_RunFrame ( espec , IsHES ) ;
if ( PCE_IsCD )
{
PCECD_Run ( HuCPU . timestamp * 3 ) ;
}
psg - > EndFrame ( HuCPU . timestamp / pce_overclocked ) ;
if ( espec - > SoundBuf )
{
for ( int y = 0 ; y < 2 ; y + + )
{
sbuf [ y ] . end_frame ( HuCPU . timestamp / pce_overclocked ) ;
espec - > SoundBufSize = sbuf [ y ] . read_samples ( espec - > SoundBuf + y , espec - > SoundBufMaxSize , 1 ) ;
}
}
espec - > MasterCycles = HuCPU . timestamp * 3 ;
INPUT_FixTS ( ) ;
HuC6280_ResetTS ( ) ;
if ( PCE_IsCD )
PCECD_ResetTS ( ) ;
}
static int StateAction ( StateMem * sm , int load , int data_only )
{
SFORMAT StateRegs [ ] =
{
SFARRAY ( BaseRAM , IsSGX ? 32768 : 8192 ) ,
SFVAR ( PCEIODataBuffer ) ,
SFEND
} ;
//for(int i = 8192; i < 32768; i++)
// if(BaseRAM[i] != 0xFF)
// printf("%d %02x\n", i, BaseRAM[i]);
int ret = MDFNSS_StateAction ( sm , load , data_only , StateRegs , " MAIN " ) ;
ret & = HuC6280_StateAction ( sm , load , data_only ) ;
ret & = VDC_StateAction ( sm , load , data_only ) ;
ret & = psg - > StateAction ( sm , load , data_only ) ;
ret & = INPUT_StateAction ( sm , load , data_only ) ;
ret & = HuC_StateAction ( sm , load , data_only ) ;
if ( load )
{
}
return ( ret ) ;
}
void PCE_Power ( void )
{
memset ( BaseRAM , 0x00 , sizeof ( BaseRAM ) ) ;
if ( ! IsSGX )
for ( int i = 8192 ; i < 32768 ; i + + )
BaseRAM [ i ] = 0xFF ;
PCEIODataBuffer = 0xFF ;
HuC6280_Power ( ) ;
VDC_Power ( ) ;
psg - > Power ( HuCPU . timestamp / pce_overclocked ) ;
HuC_Power ( ) ;
if ( PCE_IsCD )
{
PCECD_Power ( HuCPU . timestamp * 3 ) ;
}
}
static void DoSimpleCommand ( int cmd )
{
switch ( cmd )
{
case MDFN_MSC_RESET : PCE_Power ( ) ; break ;
case MDFN_MSC_POWER : PCE_Power ( ) ; break ;
}
}
static MDFNSetting PCESettings [ ] =
{
{ " pce_fast.correct_aspect " , MDFNSF_CAT_VIDEO , gettext_noop ( " Correct the aspect ratio. " ) , NULL , MDFNST_BOOL , " 1 " } ,
{ " pce_fast.slstart " , MDFNSF_NOFLAGS , gettext_noop ( " First rendered scanline. " ) , NULL , MDFNST_UINT , " 4 " , " 0 " , " 239 " } ,
{ " pce_fast.slend " , MDFNSF_NOFLAGS , gettext_noop ( " Last rendered scanline. " ) , NULL , MDFNST_UINT , " 235 " , " 0 " , " 239 " } ,
{ " pce_fast.mouse_sensitivity " , MDFNSF_NOFLAGS , gettext_noop ( " Mouse sensitivity. " ) , NULL , MDFNST_FLOAT , " 0.50 " , NULL , NULL , NULL , PCEINPUT_SettingChanged } ,
{ " pce_fast.disable_softreset " , MDFNSF_NOFLAGS , gettext_noop ( " If set, when RUN+SEL are pressed simultaneously, disable both buttons temporarily. " ) , NULL , MDFNST_BOOL , " 0 " , NULL , NULL , NULL , PCEINPUT_SettingChanged } ,
{ " pce_fast.forcesgx " , MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE , gettext_noop ( " Force SuperGrafx emulation. " ) , NULL , MDFNST_BOOL , " 0 " } ,
{ " pce_fast.arcadecard " , MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE , gettext_noop ( " Enable Arcade Card emulation. " ) , NULL , MDFNST_BOOL , " 1 " } ,
{ " pce_fast.ocmultiplier " , MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE , gettext_noop ( " CPU overclock multiplier. " ) , NULL , MDFNST_UINT , " 1 " , " 1 " , " 100 " } ,
{ " pce_fast.cdspeed " , MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE , gettext_noop ( " CD-ROM data transfer speed multiplier. " ) , NULL , MDFNST_UINT , " 1 " , " 1 " , " 100 " } ,
{ " pce_fast.nospritelimit " , MDFNSF_NOFLAGS , gettext_noop ( " Remove 16-sprites-per-scanline hardware limit. " ) , NULL , MDFNST_BOOL , " 0 " } ,
{ " pce_fast.cdbios " , MDFNSF_EMU_STATE , gettext_noop ( " Path to the CD BIOS " ) , NULL , MDFNST_STRING , " syscard3.pce " } ,
{ " pce_fast.adpcmlp " , MDFNSF_NOFLAGS , gettext_noop ( " Enable dynamic ADPCM lowpass filter. " ) , NULL , MDFNST_BOOL , " 0 " } ,
{ " pce_fast.cdpsgvolume " , MDFNSF_NOFLAGS , gettext_noop ( " PSG volume when playing a CD game. " ) , NULL , MDFNST_UINT , " 100 " , " 0 " , " 200 " } ,
{ " pce_fast.cddavolume " , MDFNSF_NOFLAGS , gettext_noop ( " CD-DA volume. " ) , NULL , MDFNST_UINT , " 100 " , " 0 " , " 200 " } ,
{ " pce_fast.adpcmvolume " , MDFNSF_NOFLAGS , gettext_noop ( " ADPCM volume. " ) , NULL , MDFNST_UINT , " 100 " , " 0 " , " 200 " } ,
{ NULL }
} ;
static uint8 MemRead ( uint32 addr )
{
return ( PCERead [ ( addr / 8192 ) & 0xFF ] ( addr ) ) ;
}
static const FileExtensionSpecStruct KnownExtensions [ ] =
{
{ " .pce " , gettext_noop ( " PC Engine ROM Image " ) } ,
{ " .hes " , gettext_noop ( " PC Engine Music Rip " ) } ,
{ " .sgx " , gettext_noop ( " SuperGrafx ROM Image " ) } ,
{ NULL , NULL }
} ;
2014-06-20 17:54:30 +00:00
static const uint8 BRAM_Init_String [ 8 ] = { ' H ' , ' U ' , ' B ' , ' M ' , 0x00 , 0x88 , 0x10 , 0x80 } ; //"HUBM\x00\x88\x10\x80";
ArcadeCard * arcade_card = NULL ;
static uint8 * HuCROM = NULL ;
static bool IsPopulous ;
bool PCE_IsCD ;
uint8 SaveRAM [ 2048 ] ;
static DECLFW ( ACPhysWrite )
{
arcade_card - > PhysWrite ( A , V ) ;
}
static DECLFR ( ACPhysRead )
{
return ( arcade_card - > PhysRead ( A ) ) ;
}
static DECLFR ( SaveRAMRead )
{
if ( ( ! PCE_IsCD | | PCECD_IsBRAMEnabled ( ) ) & & ( A & 8191 ) < 2048 )
return ( SaveRAM [ A & 2047 ] ) ;
else
return ( 0xFF ) ;
}
static DECLFW ( SaveRAMWrite )
{
if ( ( ! PCE_IsCD | | PCECD_IsBRAMEnabled ( ) ) & & ( A & 8191 ) < 2048 )
SaveRAM [ A & 2047 ] = V ;
}
static DECLFR ( HuCRead )
{
return ROMSpace [ A ] ;
}
static DECLFW ( HuCRAMWrite )
{
ROMSpace [ A ] = V ;
}
static DECLFW ( HuCRAMWriteCDSpecial ) // Hyper Dyne Special hack
{
BaseRAM [ 0x2000 | ( A & 0x1FFF ) ] = V ;
ROMSpace [ A ] = V ;
}
static uint8 HuCSF2Latch = 0 ;
static DECLFR ( HuCSF2Read )
{
return ( HuCROM [ ( A & 0x7FFFF ) + 0x80000 + HuCSF2Latch * 0x80000 ] ) ; // | (HuCSF2Latch << 19) ]);
}
static DECLFW ( HuCSF2Write )
{
if ( ( A & 0x1FFC ) = = 0x1FF0 )
{
HuCSF2Latch = ( A & 0x3 ) ;
}
}
int HuCLoad ( const uint8 * data , uint32 len , uint32 crc32 )
{
uint32 sf2_threshold = 2048 * 1024 ;
uint32 sf2_required_size = 2048 * 1024 + 512 * 1024 ;
uint32 m_len = ( len + 8191 ) & ~ 8191 ;
bool sf2_mapper = FALSE ;
if ( m_len > = sf2_threshold )
{
sf2_mapper = TRUE ;
if ( m_len ! = sf2_required_size )
m_len = sf2_required_size ;
}
IsPopulous = 0 ;
PCE_IsCD = 0 ;
md5_context md5 ;
md5 . starts ( ) ;
md5 . update ( data , len ) ;
md5 . finish ( MDFNGameInfo - > MD5 ) ;
MDFN_printf ( _ ( " ROM: %dKiB \n " ) , ( len + 1023 ) / 1024 ) ;
MDFN_printf ( _ ( " ROM CRC32: 0x%04x \n " ) , crc32 ) ;
MDFN_printf ( _ ( " ROM MD5: 0x%s \n " ) , md5_context : : asciistr ( MDFNGameInfo - > MD5 , 0 ) . c_str ( ) ) ;
if ( ! ( HuCROM = ( uint8 * ) MDFN_malloc ( m_len , _ ( " HuCard ROM " ) ) ) )
{
return ( 0 ) ;
}
memset ( HuCROM , 0xFF , m_len ) ;
memcpy ( HuCROM , data , ( m_len < len ) ? m_len : len ) ;
memset ( ROMSpace , 0xFF , 0x88 * 8192 + 8192 ) ;
if ( m_len = = 0x60000 )
{
memcpy ( ROMSpace + 0x00 * 8192 , HuCROM , 0x20 * 8192 ) ;
memcpy ( ROMSpace + 0x20 * 8192 , HuCROM , 0x20 * 8192 ) ;
memcpy ( ROMSpace + 0x40 * 8192 , HuCROM + 0x20 * 8192 , 0x10 * 8192 ) ;
memcpy ( ROMSpace + 0x50 * 8192 , HuCROM + 0x20 * 8192 , 0x10 * 8192 ) ;
memcpy ( ROMSpace + 0x60 * 8192 , HuCROM + 0x20 * 8192 , 0x10 * 8192 ) ;
memcpy ( ROMSpace + 0x70 * 8192 , HuCROM + 0x20 * 8192 , 0x10 * 8192 ) ;
}
else if ( m_len = = 0x80000 )
{
memcpy ( ROMSpace + 0x00 * 8192 , HuCROM , 0x40 * 8192 ) ;
memcpy ( ROMSpace + 0x40 * 8192 , HuCROM + 0x20 * 8192 , 0x20 * 8192 ) ;
memcpy ( ROMSpace + 0x60 * 8192 , HuCROM + 0x20 * 8192 , 0x20 * 8192 ) ;
}
else
{
memcpy ( ROMSpace + 0x00 * 8192 , HuCROM , ( m_len < 1024 * 1024 ) ? m_len : 1024 * 1024 ) ;
}
for ( int x = 0x00 ; x < 0x80 ; x + + )
{
HuCPUFastMap [ x ] = ROMSpace ;
PCERead [ x ] = HuCRead ;
}
if ( ! memcmp ( HuCROM + 0x1F26 , " POPULOUS " , strlen ( " POPULOUS " ) ) )
{
uint8 * PopRAM = ROMSpace + 0x40 * 8192 ;
memset ( PopRAM , 0xFF , 32768 ) ;
IsPopulous = 1 ;
MDFN_printf ( " Populous \n " ) ;
for ( int x = 0x40 ; x < 0x44 ; x + + )
{
HuCPUFastMap [ x ] = & PopRAM [ ( x & 3 ) * 8192 ] - x * 8192 ;
PCERead [ x ] = HuCRead ;
PCEWrite [ x ] = HuCRAMWrite ;
}
MDFNMP_AddRAM ( 32768 , 0x40 * 8192 , PopRAM ) ;
}
else
{
memset ( SaveRAM , 0x00 , 2048 ) ;
memcpy ( SaveRAM , BRAM_Init_String , 8 ) ; // So users don't have to manually intialize the file cabinet
// in the CD BIOS screen.
PCEWrite [ 0xF7 ] = SaveRAMWrite ;
PCERead [ 0xF7 ] = SaveRAMRead ;
MDFNMP_AddRAM ( 2048 , 0xF7 * 8192 , SaveRAM ) ;
}
// 0x1A558
//if(len >= 0x20000 && !memcmp(HuCROM + 0x1A558, "STREET FIGHTER#", strlen("STREET FIGHTER#")))
if ( sf2_mapper )
{
for ( int x = 0x40 ; x < 0x80 ; x + + )
{
// FIXME: PCE_FAST
HuCPUFastMap [ x ] = NULL ; // Make sure our reads go through our read function, and not a table lookup
PCERead [ x ] = HuCSF2Read ;
}
PCEWrite [ 0 ] = HuCSF2Write ;
MDFN_printf ( " Street Fighter 2 Mapper \n " ) ;
HuCSF2Latch = 0 ;
}
return ( 1 ) ;
}
bool IsBRAMUsed ( void )
{
if ( memcmp ( SaveRAM , BRAM_Init_String , 8 ) ) // HUBM string is modified/missing
return ( 1 ) ;
for ( int x = 8 ; x < 2048 ; x + + )
if ( SaveRAM [ x ] ) return ( 1 ) ;
return ( 0 ) ;
}
int HuCLoadCD ( const char * bios_path )
{
static const FileExtensionSpecStruct KnownBIOSExtensions [ ] =
{
{ " .pce " , gettext_noop ( " PC Engine ROM Image " ) } ,
{ " .bin " , gettext_noop ( " PC Engine ROM Image " ) } ,
{ " .bios " , gettext_noop ( " BIOS Image " ) } ,
{ NULL , NULL }
} ;
MDFNFILE fp ;
if ( ! fp . Open ( bios_path , KnownBIOSExtensions , _ ( " CD BIOS " ) ) )
{
return ( 0 ) ;
}
memset ( ROMSpace , 0xFF , 262144 ) ;
memcpy ( ROMSpace , GET_FDATA ( fp ) + ( GET_FSIZE ( fp ) & 512 ) , ( ( GET_FSIZE ( fp ) & ~ 512 ) > 262144 ) ? 262144 : ( GET_FSIZE ( fp ) & ~ 512 ) ) ;
fp . Close ( ) ;
PCE_IsCD = 1 ;
PCE_InitCD ( ) ;
md5_context md5 ;
md5 . starts ( ) ;
// md5_update(&md5, HuCROM, 262144);
#if 0
int32 track = CDIF_GetFirstTrack ( ) ;
int32 last_track = CDIF_GetLastTrack ( ) ;
bool DTFound = 0 ;
for ( ; track < = last_track ; track + + )
{
CDIF_Track_Format format ;
if ( CDIF_GetTrackFormat ( track , format ) & & format = = CDIF_FORMAT_MODE1 )
{
DTFound = 1 ;
break ;
}
}
if ( DTFound ) // Only add the MD5 hash if we were able to find a data track.
{
uint32 start_sector = CDIF_GetTrackStartPositionLBA ( track ) ;
uint8 sector_buffer [ 2048 ] ;
for ( int x = 0 ; x < 128 ; x + + )
{
memset ( sector_buffer , 0 , 2048 ) ;
CDIF_ReadSector ( sector_buffer , NULL , start_sector + x , 1 ) ;
md5 . update ( sector_buffer , 2048 ) ;
}
}
md5 . finish ( MDFNGameInfo - > MD5 ) ;
MDFN_printf ( _ ( " CD MD5(first 256KiB): 0x%s \n " ) , md5_context : : asciistr ( MDFNGameInfo - > MD5 , 0 ) . c_str ( ) ) ;
# endif
MDFN_printf ( _ ( " Arcade Card Emulation: %s \n " ) , PCE_ACEnabled ? _ ( " Enabled " ) : _ ( " Disabled " ) ) ;
for ( int x = 0 ; x < 0x40 ; x + + )
{
HuCPUFastMap [ x ] = ROMSpace ;
PCERead [ x ] = HuCRead ;
}
for ( int x = 0x68 ; x < 0x88 ; x + + )
{
HuCPUFastMap [ x ] = ROMSpace ;
PCERead [ x ] = HuCRead ;
PCEWrite [ x ] = HuCRAMWrite ;
}
PCEWrite [ 0x80 ] = HuCRAMWriteCDSpecial ; // Hyper Dyne Special hack
MDFNMP_AddRAM ( 262144 , 0x68 * 8192 , ROMSpace + 0x68 * 8192 ) ;
if ( PCE_ACEnabled )
{
try
{
arcade_card = new ArcadeCard ( ) ;
}
catch ( std : : exception & e )
{
MDFN_PrintError ( _ ( " Error creating %s object: %s " ) , " ArcadeCard " , e . what ( ) ) ;
//Cleanup(); // TODO
return ( 0 ) ;
}
for ( int x = 0x40 ; x < 0x44 ; x + + )
{
HuCPUFastMap [ x ] = NULL ;
PCERead [ x ] = ACPhysRead ;
PCEWrite [ x ] = ACPhysWrite ;
}
}
memset ( SaveRAM , 0x00 , 2048 ) ;
memcpy ( SaveRAM , BRAM_Init_String , 8 ) ; // So users don't have to manually intialize the file cabinet
// in the CD BIOS screen.
PCEWrite [ 0xF7 ] = SaveRAMWrite ;
PCERead [ 0xF7 ] = SaveRAMRead ;
MDFNMP_AddRAM ( 2048 , 0xF7 * 8192 , SaveRAM ) ;
return ( 1 ) ;
}
int HuC_StateAction ( StateMem * sm , int load , int data_only )
{
SFORMAT StateRegs [ ] =
{
SFARRAY ( ROMSpace + 0x40 * 8192 , IsPopulous ? 32768 : 0 ) ,
SFARRAY ( SaveRAM , IsPopulous ? 0 : 2048 ) ,
SFARRAY ( ROMSpace + 0x68 * 8192 , PCE_IsCD ? 262144 : 0 ) ,
SFVAR ( HuCSF2Latch ) ,
SFEND
} ;
int ret = MDFNSS_StateAction ( sm , load , data_only , StateRegs , " HuC " ) ;
if ( load )
HuCSF2Latch & = 0x3 ;
if ( PCE_IsCD )
{
ret & = PCECD_StateAction ( sm , load , data_only ) ;
if ( arcade_card )
ret & = arcade_card - > StateAction ( sm , load , data_only ) ;
}
return ( ret ) ;
}
void HuCClose ( void )
{
if ( arcade_card )
{
delete arcade_card ;
arcade_card = NULL ;
}
if ( PCE_IsCD )
{
PCECD_Close ( ) ;
}
if ( HuCROM )
{
MDFN_free ( HuCROM ) ;
HuCROM = NULL ;
}
}
void HuC_Power ( void )
{
if ( PCE_IsCD )
memset ( ROMSpace + 0x68 * 8192 , 0x00 , 262144 ) ;
if ( arcade_card )
arcade_card - > Power ( ) ;
}
2014-06-19 21:10:59 +00:00
} ;
MDFNGI EmulatedPCE_Fast =
{
" pce_fast " ,
" PC Engine (CD)/TurboGrafx 16 (CD)/SuperGrafx " ,
KnownExtensions ,
MODPRIO_INTERNAL_LOW ,
NULL ,
& PCEInputInfo ,
Load ,
TestMagic ,
LoadCD ,
TestMagicCD ,
CloseGame ,
VDC_SetLayerEnableMask ,
NULL ,
NULL ,
NULL ,
NULL ,
NULL ,
MemRead ,
NULL ,
false ,
StateAction ,
Emulate ,
PCEINPUT_SetInput ,
DoSimpleCommand ,
PCESettings ,
MDFN_MASTERCLOCK_FIXED ( PCE_MASTER_CLOCK ) ,
0 ,
true , // Multires possible?
0 , // lcm_width
0 , // lcm_height
NULL , // Dummy
288 , // Nominal width
232 , // Nominal height
512 , // Framebuffer width
242 , // Framebuffer height
2 , // Number of output sound channels
} ;
2014-06-19 21:34:42 +00:00
# ifdef NEED_CD
static void ReadM3U ( std : : vector < std : : string > & file_list , std : : string path , unsigned depth = 0 )
{
std : : vector < std : : string > ret ;
FileWrapper m3u_file ( path . c_str ( ) , FileWrapper : : MODE_READ , _ ( " M3U CD Set " ) ) ;
std : : string dir_path ;
char linebuf [ 2048 ] ;
MDFN_GetFilePathComponents ( path , & dir_path ) ;
while ( m3u_file . get_line ( linebuf , sizeof ( linebuf ) ) )
{
std : : string efp ;
if ( linebuf [ 0 ] = = ' # ' ) continue ;
MDFN_rtrim ( linebuf ) ;
if ( linebuf [ 0 ] = = 0 ) continue ;
efp = MDFN_EvalFIP ( dir_path , std : : string ( linebuf ) ) ;
if ( efp . size ( ) > = 4 & & efp . substr ( efp . size ( ) - 4 ) = = " .m3u " )
{
if ( efp = = path )
throw ( MDFN_Error ( 0 , _ ( " M3U at \" %s \" references self. " ) , efp . c_str ( ) ) ) ;
if ( depth = = 99 )
throw ( MDFN_Error ( 0 , _ ( " M3U load recursion too deep! " ) ) ) ;
ReadM3U ( file_list , efp , depth + + ) ;
}
else
file_list . push_back ( efp ) ;
}
}
# ifdef NEED_CD
static std : : vector < CDIF * > CDInterfaces ; // FIXME: Cleanup on error out.
# endif
// TODO: LoadCommon()
MDFNGI * MDFNI_LoadCD ( const char * force_module , const char * devicename )
{
uint8 LayoutMD5 [ 16 ] ;
MDFN_printf ( _ ( " Loading %s... \n \n " ) , devicename ? devicename : _ ( " PHYSICAL CD " ) ) ;
try
{
if ( devicename & & strlen ( devicename ) > 4 & & ! strcasecmp ( devicename + strlen ( devicename ) - 4 , " .m3u " ) )
{
std : : vector < std : : string > file_list ;
ReadM3U ( file_list , devicename ) ;
for ( unsigned i = 0 ; i < file_list . size ( ) ; i + + )
{
2014-06-20 20:49:22 +00:00
CDInterfaces . push_back ( CDIF_Open ( file_list [ i ] . c_str ( ) , false , old_cdimagecache ) ) ;
2014-06-19 21:34:42 +00:00
}
}
else
{
2014-06-20 20:49:22 +00:00
CDInterfaces . push_back ( CDIF_Open ( devicename , false , old_cdimagecache ) ) ;
2014-06-19 21:34:42 +00:00
}
}
catch ( std : : exception & e )
{
MDFND_PrintError ( e . what ( ) ) ;
MDFN_PrintError ( _ ( " Error opening CD. " ) ) ;
return ( 0 ) ;
}
//
// Print out a track list for all discs.
//
MDFN_indent ( 1 ) ;
for ( unsigned i = 0 ; i < CDInterfaces . size ( ) ; i + + )
{
CDUtility : : TOC toc ;
CDInterfaces [ i ] - > ReadTOC ( & toc ) ;
MDFN_printf ( _ ( " CD %d Layout: \n " ) , i + 1 ) ;
MDFN_indent ( 1 ) ;
for ( int32 track = toc . first_track ; track < = toc . last_track ; track + + )
{
MDFN_printf ( _ ( " Track %2d, LBA: %6d %s \n " ) , track , toc . tracks [ track ] . lba , ( toc . tracks [ track ] . control & 0x4 ) ? " DATA " : " AUDIO " ) ;
}
MDFN_printf ( " Leadout: %6d \n " , toc . tracks [ 100 ] . lba ) ;
MDFN_indent ( - 1 ) ;
MDFN_printf ( " \n " ) ;
}
MDFN_indent ( - 1 ) ;
// Calculate layout MD5. The system emulation LoadCD() code is free to ignore this value and calculate
// its own, or to use it to look up a game in its database.
{
md5_context layout_md5 ;
layout_md5 . starts ( ) ;
for ( unsigned i = 0 ; i < CDInterfaces . size ( ) ; i + + )
{
CD_TOC toc ;
CDInterfaces [ i ] - > ReadTOC ( & toc ) ;
layout_md5 . update_u32_as_lsb ( toc . first_track ) ;
layout_md5 . update_u32_as_lsb ( toc . last_track ) ;
layout_md5 . update_u32_as_lsb ( toc . tracks [ 100 ] . lba ) ;
for ( uint32 track = toc . first_track ; track < = toc . last_track ; track + + )
{
layout_md5 . update_u32_as_lsb ( toc . tracks [ track ] . lba ) ;
layout_md5 . update_u32_as_lsb ( toc . tracks [ track ] . control & 0x4 ) ;
}
}
layout_md5 . finish ( LayoutMD5 ) ;
}
// This if statement will be true if force_module references a system without CDROM support.
if ( ! MDFNGameInfo - > LoadCD )
{
MDFN_PrintError ( _ ( " Specified system \" %s \" doesn't support CDs! " ) , force_module ) ;
return ( 0 ) ;
}
MDFN_printf ( _ ( " Using module: %s(%s) \n \n " ) , MDFNGameInfo - > shortname , MDFNGameInfo - > fullname ) ;
// TODO: include module name in hash
memcpy ( MDFNGameInfo - > MD5 , LayoutMD5 , 16 ) ;
if ( ! ( MDFNGameInfo - > LoadCD ( & CDInterfaces ) ) )
{
for ( unsigned i = 0 ; i < CDInterfaces . size ( ) ; i + + )
delete CDInterfaces [ i ] ;
CDInterfaces . clear ( ) ;
MDFNGameInfo = NULL ;
return ( 0 ) ;
}
//MDFNI_SetLayerEnableMask(~0ULL);
MDFN_LoadGameCheats ( NULL ) ;
MDFNMP_InstallReadPatches ( ) ;
return ( MDFNGameInfo ) ;
}
# endif
MDFNGI * MDFNI_LoadGame ( const char * force_module , const char * name )
{
MDFNFILE GameFile ;
std : : vector < FileExtensionSpecStruct > valid_iae ;
MDFNGameInfo = & EmulatedPCE_Fast ;
# ifdef NEED_CD
if ( strlen ( name ) > 4 & & ( ! strcasecmp ( name + strlen ( name ) - 4 , " .cue " ) | | ! strcasecmp ( name + strlen ( name ) - 4 , " .ccd " ) | | ! strcasecmp ( name + strlen ( name ) - 4 , " .toc " ) | | ! strcasecmp ( name + strlen ( name ) - 4 , " .m3u " ) ) )
return ( MDFNI_LoadCD ( force_module , name ) ) ;
# endif
MDFN_printf ( _ ( " Loading %s... \n " ) , name ) ;
MDFN_indent ( 1 ) ;
// Construct a NULL-delimited list of known file extensions for MDFN_fopen()
const FileExtensionSpecStruct * curexts = MDFNGameInfo - > FileExtensions ;
while ( curexts - > extension & & curexts - > description )
{
valid_iae . push_back ( * curexts ) ;
curexts + + ;
}
if ( ! GameFile . Open ( name , & valid_iae [ 0 ] , _ ( " game " ) ) )
{
MDFNGameInfo = NULL ;
return 0 ;
}
MDFN_printf ( _ ( " Using module: %s(%s) \n \n " ) , MDFNGameInfo - > shortname , MDFNGameInfo - > fullname ) ;
MDFN_indent ( 1 ) ;
//
// Load per-game settings
//
// Maybe we should make a "pgcfg" subdir, and automatically load all files in it?
// End load per-game settings
//
if ( MDFNGameInfo - > Load ( name , & GameFile ) < = 0 )
{
GameFile . Close ( ) ;
MDFN_indent ( - 2 ) ;
MDFNGameInfo = NULL ;
return ( 0 ) ;
}
MDFN_LoadGameCheats ( NULL ) ;
MDFNMP_InstallReadPatches ( ) ;
MDFN_indent ( - 2 ) ;
if ( ! MDFNGameInfo - > name )
{
unsigned int x ;
char * tmp ;
MDFNGameInfo - > name = ( UTF8 * ) strdup ( GetFNComponent ( name ) ) ;
for ( x = 0 ; x < strlen ( ( char * ) MDFNGameInfo - > name ) ; x + + )
{
if ( MDFNGameInfo - > name [ x ] = = ' _ ' )
MDFNGameInfo - > name [ x ] = ' ' ;
}
if ( ( tmp = strrchr ( ( char * ) MDFNGameInfo - > name , ' . ' ) ) )
* tmp = 0 ;
}
return ( MDFNGameInfo ) ;
}
static int curindent = 0 ;
void MDFN_indent ( int indent )
{
curindent + = indent ;
}
static uint8 lastchar = 0 ;
void MDFN_printf ( const char * format , . . . )
{
char * format_temp ;
char * temp ;
unsigned int x , newlen ;
va_list ap ;
va_start ( ap , format ) ;
// First, determine how large our format_temp buffer needs to be.
uint8 lastchar_backup = lastchar ; // Save lastchar!
for ( newlen = x = 0 ; x < strlen ( format ) ; x + + )
{
if ( lastchar = = ' \n ' & & format [ x ] ! = ' \n ' )
{
int y ;
for ( y = 0 ; y < curindent ; y + + )
newlen + + ;
}
newlen + + ;
lastchar = format [ x ] ;
}
format_temp = ( char * ) malloc ( newlen + 1 ) ; // Length + NULL character, duh
// Now, construct our format_temp string
lastchar = lastchar_backup ; // Restore lastchar
for ( newlen = x = 0 ; x < strlen ( format ) ; x + + )
{
if ( lastchar = = ' \n ' & & format [ x ] ! = ' \n ' )
{
int y ;
for ( y = 0 ; y < curindent ; y + + )
format_temp [ newlen + + ] = ' ' ;
}
format_temp [ newlen + + ] = format [ x ] ;
lastchar = format [ x ] ;
}
format_temp [ newlen ] = 0 ;
temp = trio_vaprintf ( format_temp , ap ) ;
free ( format_temp ) ;
MDFND_Message ( temp ) ;
free ( temp ) ;
va_end ( ap ) ;
}
void MDFN_PrintError ( const char * format , . . . )
{
char * temp ;
va_list ap ;
va_start ( ap , format ) ;
temp = trio_vaprintf ( format , ap ) ;
MDFND_PrintError ( temp ) ;
free ( temp ) ;
va_end ( ap ) ;
}
void MDFN_DebugPrintReal ( const char * file , const int line , const char * format , . . . )
{
char * temp ;
va_list ap ;
va_start ( ap , format ) ;
temp = trio_vaprintf ( format , ap ) ;
fprintf ( stderr , " %s:%d %s \n " , file , line , temp ) ;
free ( temp ) ;
va_end ( ap ) ;
}
2014-06-19 21:10:59 +00:00
2012-06-03 15:48:14 +00:00
static MDFNGI * game ;
2014-04-21 22:25:50 +00:00
struct retro_perf_callback perf_cb ;
retro_get_cpu_features_t perf_get_cpu_features_cb = NULL ;
2014-04-20 14:32:46 +00:00
retro_log_printf_t log_cb ;
2012-06-03 15:48:14 +00:00
static retro_video_refresh_t video_cb ;
static retro_audio_sample_t audio_cb ;
static retro_audio_sample_batch_t audio_batch_cb ;
static retro_environment_t environ_cb ;
static retro_input_poll_t input_poll_cb ;
static retro_input_state_t input_state_cb ;
2013-02-25 19:39:39 +00:00
static bool overscan ;
2012-11-16 14:12:25 +00:00
static double last_sound_rate ;
static MDFN_PixelFormat last_pixel_format ;
2012-06-03 15:48:14 +00:00
static MDFN_Surface * surf ;
2012-06-15 23:00:17 +00:00
static bool failed_init ;
2012-06-03 15:48:14 +00:00
2012-10-13 13:31:49 +00:00
std : : string retro_base_directory ;
std : : string retro_base_name ;
2014-02-07 07:16:01 +00:00
std : : string retro_save_directory ;
2012-10-13 13:31:49 +00:00
2013-04-27 14:40:24 +00:00
static void set_basename ( const char * path )
{
const char * base = strrchr ( path , ' / ' ) ;
if ( ! base )
base = strrchr ( path , ' \\ ' ) ;
if ( base )
retro_base_name = base + 1 ;
else
retro_base_name = path ;
retro_base_name = retro_base_name . substr ( 0 , retro_base_name . find_last_of ( ' . ' ) ) ;
}
2014-06-18 20:01:17 +00:00
# include "mednafen/pce_fast/pcecd.h"
2014-06-18 19:55:15 +00:00
2012-10-20 23:47:02 +00:00
# define MEDNAFEN_CORE_NAME_MODULE "pce_fast"
2012-10-20 21:32:28 +00:00
# define MEDNAFEN_CORE_NAME "Mednafen PCE Fast"
2014-04-20 21:05:37 +00:00
# define MEDNAFEN_CORE_VERSION "v0.9.33.3"
2014-04-20 22:24:36 +00:00
# define MEDNAFEN_CORE_EXTENSIONS "pce|sgx|cue|ccd"
2012-10-20 23:47:02 +00:00
# define MEDNAFEN_CORE_TIMING_FPS 59.82
2014-06-20 20:49:22 +00:00
# define MEDNAFEN_CORE_GEOMETRY_BASE_W (EmulatedPCE_Fast.nominal_width)
# define MEDNAFEN_CORE_GEOMETRY_BASE_H (EmulatedPCE_Fast.nominal_height)
2012-10-20 23:47:02 +00:00
# define MEDNAFEN_CORE_GEOMETRY_MAX_W 512
# define MEDNAFEN_CORE_GEOMETRY_MAX_H 242
# define MEDNAFEN_CORE_GEOMETRY_ASPECT_RATIO (4.0 / 3.0)
# define FB_WIDTH 512
# define FB_HEIGHT 242
2012-10-22 12:34:14 +00:00
2013-10-01 12:28:59 +00:00
# define FB_MAX_HEIGHT FB_HEIGHT
2012-10-20 21:32:28 +00:00
static void check_system_specs ( void )
{
2012-10-22 12:34:14 +00:00
unsigned level = 0 ;
environ_cb ( RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL , & level ) ;
2012-10-20 21:32:28 +00:00
}
2014-04-21 22:25:50 +00:00
void retro_init ( void )
2012-06-03 15:48:14 +00:00
{
2014-01-02 01:50:09 +00:00
struct retro_log_callback log ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_LOG_INTERFACE , & log ) )
log_cb = log . log ;
else
log_cb = NULL ;
2014-06-19 21:34:42 +00:00
# ifdef NEED_CD
CDUtility : : CDUtility_Init ( ) ;
# endif
2012-06-03 15:48:14 +00:00
2012-06-11 23:03:09 +00:00
const char * dir = NULL ;
2012-06-15 23:00:17 +00:00
2012-06-11 23:03:09 +00:00
if ( environ_cb ( RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY , & dir ) & & dir )
{
2012-10-13 13:31:49 +00:00
retro_base_directory = dir ;
2012-11-10 01:20:13 +00:00
// Make sure that we don't have any lingering slashes, etc, as they break Windows.
2012-11-10 11:59:05 +00:00
size_t last = retro_base_directory . find_last_not_of ( " / \\ " ) ;
if ( last ! = std : : string : : npos )
last + + ;
retro_base_directory = retro_base_directory . substr ( 0 , last ) ;
2012-06-11 23:03:09 +00:00
}
2012-06-15 23:00:17 +00:00
else
2012-06-11 23:03:09 +00:00
{
2013-12-17 01:24:08 +00:00
/* TODO: Add proper fallback */
if ( log_cb )
log_cb ( RETRO_LOG_WARN , " System directory is not defined. Fallback on using same dir as ROM for system directory later ... \n " ) ;
2012-06-15 23:00:17 +00:00
failed_init = true ;
2012-06-11 23:03:09 +00:00
}
2014-02-07 07:07:58 +00:00
if ( environ_cb ( RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY , & dir ) & & dir )
{
2014-02-07 22:34:14 +00:00
// If save directory is defined use it, otherwise use system directory
retro_save_directory = * dir ? dir : retro_base_directory ;
2014-02-07 07:07:58 +00:00
// Make sure that we don't have any lingering slashes, etc, as they break Windows.
size_t last = retro_save_directory . find_last_not_of ( " / \\ " ) ;
if ( last ! = std : : string : : npos )
last + + ;
retro_save_directory = retro_save_directory . substr ( 0 , last ) ;
}
else
{
/* TODO: Add proper fallback */
if ( log_cb )
2014-02-07 22:34:14 +00:00
log_cb ( RETRO_LOG_WARN , " Save directory is not defined. Fallback on using SYSTEM directory ... \n " ) ;
2014-02-07 07:07:58 +00:00
retro_save_directory = retro_base_directory ;
}
2012-06-09 22:46:41 +00:00
2012-10-22 12:34:14 +00:00
# if defined(WANT_16BPP) && defined(FRONTEND_SUPPORTS_RGB565)
enum retro_pixel_format rgb565 = RETRO_PIXEL_FORMAT_RGB565 ;
2013-12-17 01:24:08 +00:00
if ( environ_cb ( RETRO_ENVIRONMENT_SET_PIXEL_FORMAT , & rgb565 ) & & log_cb )
log_cb ( RETRO_LOG_INFO , " Frontend supports RGB565 - will use that instead of XRGB1555. \n " ) ;
2012-10-22 12:34:14 +00:00
# endif
2014-04-21 22:25:50 +00:00
if ( environ_cb ( RETRO_ENVIRONMENT_GET_PERF_INTERFACE , & perf_cb ) )
perf_get_cpu_features_cb = perf_cb . get_cpu_features ;
else
perf_get_cpu_features_cb = NULL ;
2012-10-20 21:32:28 +00:00
check_system_specs ( ) ;
2012-06-03 15:48:14 +00:00
}
2014-04-20 14:32:46 +00:00
void retro_reset ( void )
2012-06-03 15:48:14 +00:00
{
2014-06-20 20:49:22 +00:00
DoSimpleCommand ( MDFN_MSC_RESET ) ;
2012-06-03 15:48:14 +00:00
}
bool retro_load_game_special ( unsigned , const struct retro_game_info * , size_t )
{
return false ;
}
2013-05-24 15:26:57 +00:00
static void set_volume ( uint32_t * ptr , unsigned number )
{
switch ( number )
{
default :
* ptr = number ;
break ;
}
}
2014-06-20 20:49:22 +00:00
2013-04-09 02:05:18 +00:00
static void check_variables ( void )
{
struct retro_variable var = { 0 } ;
2014-06-20 20:49:22 +00:00
var . key = " pce_fast_cdimagecache " ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
{
bool cdimage_cache = true ;
if ( strcmp ( var . value , " enabled " ) = = 0 )
cdimage_cache = true ;
else if ( strcmp ( var . value , " disabled " ) = = 0 )
cdimage_cache = false ;
if ( cdimage_cache ! = old_cdimagecache )
old_cdimagecache = cdimage_cache ;
}
2013-04-09 02:05:18 +00:00
var . key = " pce_nospritelimit " ;
2014-06-20 20:49:22 +00:00
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
2013-04-09 02:05:18 +00:00
{
if ( strcmp ( var . value , " disabled " ) = = 0 )
setting_pce_fast_nospritelimit = 0 ;
else if ( strcmp ( var . value , " enabled " ) = = 0 )
setting_pce_fast_nospritelimit = 1 ;
}
2013-05-24 15:26:57 +00:00
2013-05-24 15:37:36 +00:00
var . key = " pce_keepaspect " ;
2014-06-20 20:49:22 +00:00
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
2013-05-24 15:37:36 +00:00
{
if ( strcmp ( var . value , " disabled " ) = = 0 )
{
setting_pce_keepaspect = 0 ;
2014-06-20 20:49:22 +00:00
EmulatedPCE_Fast . fb_width = 512 ;
EmulatedPCE_Fast . nominal_width = 341 ;
EmulatedPCE_Fast . lcm_width = 341 ;
2013-05-24 15:37:36 +00:00
}
else if ( strcmp ( var . value , " enabled " ) = = 0 )
{
setting_pce_keepaspect = 1 ;
2014-06-20 20:49:22 +00:00
EmulatedPCE_Fast . fb_width = 682 ;
EmulatedPCE_Fast . nominal_width = 288 ;
EmulatedPCE_Fast . lcm_width = 1024 ;
2013-05-24 15:37:36 +00:00
}
}
2013-05-24 15:26:57 +00:00
bool do_cdsettings = false ;
var . key = " pce_cddavolume " ;
2014-06-20 20:49:22 +00:00
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
2013-05-24 15:26:57 +00:00
{
do_cdsettings = true ;
setting_pce_fast_cddavolume = atoi ( var . value ) ;
}
var . key = " pce_adpcmvolume " ;
2014-06-20 20:49:22 +00:00
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
2013-05-24 15:26:57 +00:00
{
do_cdsettings = true ;
setting_pce_fast_adpcmvolume = atoi ( var . value ) ;
}
var . key = " pce_cdpsgvolume " ;
2014-06-20 20:49:22 +00:00
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
2013-05-24 15:26:57 +00:00
{
do_cdsettings = true ;
setting_pce_fast_cdpsgvolume = atoi ( var . value ) ;
}
var . key = " pce_cdspeed " ;
2014-06-20 20:49:22 +00:00
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
2013-05-24 15:26:57 +00:00
{
do_cdsettings = true ;
setting_pce_fast_cdspeed = atoi ( var . value ) ;
}
if ( do_cdsettings )
{
2014-04-21 22:31:36 +00:00
PCE_Fast : : PCECD_Settings settings = { 0 } ;
2014-06-05 16:06:15 +00:00
settings . CDDA_Volume = ( double ) setting_pce_fast_cddavolume / 100 ;
2013-05-24 15:26:57 +00:00
settings . CD_Speed = setting_pce_fast_cdspeed ;
2014-06-05 16:06:15 +00:00
settings . ADPCM_Volume = ( double ) setting_pce_fast_adpcmvolume / 100 ;
2013-05-24 15:26:57 +00:00
2013-12-17 01:24:08 +00:00
if ( PCECD_SetSettings ( & settings ) & & log_cb )
log_cb ( RETRO_LOG_INFO , " PCE CD Audio settings changed. \n " ) ;
2013-05-24 15:26:57 +00:00
}
2013-04-09 02:05:18 +00:00
}
2013-04-09 03:23:42 +00:00
# define MAX_PLAYERS 5
# define MAX_BUTTONS 13
static uint8_t input_buf [ MAX_PLAYERS ] [ 2 ] = { 0 } ;
2012-06-03 15:48:14 +00:00
bool retro_load_game ( const struct retro_game_info * info )
{
2012-06-15 23:00:17 +00:00
if ( failed_init )
return false ;
2012-10-20 23:47:02 +00:00
# ifdef WANT_32BPP
2012-06-16 13:07:18 +00:00
enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888 ;
2013-12-17 10:08:34 +00:00
if ( ! environ_cb ( RETRO_ENVIRONMENT_SET_PIXEL_FORMAT , & fmt ) )
2012-10-21 00:37:11 +00:00
{
2013-12-17 01:24:08 +00:00
if ( log_cb )
log_cb ( RETRO_LOG_ERROR , " Pixel format XRGB8888 not supported by platform, cannot use %s. \n " , MEDNAFEN_CORE_NAME ) ;
2012-10-21 00:37:11 +00:00
return false ;
}
2012-10-20 23:47:02 +00:00
# endif
2012-06-16 13:07:18 +00:00
2013-02-25 19:39:39 +00:00
overscan = false ;
environ_cb ( RETRO_ENVIRONMENT_GET_OVERSCAN , & overscan ) ;
2013-04-27 14:40:24 +00:00
set_basename ( info - > path ) ;
2012-10-13 13:31:49 +00:00
2014-06-20 20:49:22 +00:00
check_variables ( ) ;
2012-10-20 23:47:02 +00:00
game = MDFNI_LoadGame ( MEDNAFEN_CORE_NAME_MODULE , info - > path ) ;
2012-09-23 09:52:47 +00:00
if ( ! game )
return false ;
2012-08-22 19:38:30 +00:00
MDFN_PixelFormat pix_fmt ( MDFN_COLORSPACE_RGB , 16 , 8 , 0 , 24 ) ;
2012-11-16 14:12:25 +00:00
memset ( & last_pixel_format , 0 , sizeof ( MDFN_PixelFormat ) ) ;
2013-10-01 12:28:59 +00:00
2014-06-18 20:43:41 +00:00
surf = new MDFN_Surface ( NULL , FB_WIDTH , FB_HEIGHT , FB_WIDTH , pix_fmt ) ;
2012-10-13 13:31:49 +00:00
2013-09-17 00:03:54 +00:00
2014-06-18 20:20:38 +00:00
// Possible endian bug ...
for ( unsigned i = 0 ; i < MAX_PLAYERS ; i + + )
2014-06-19 22:08:27 +00:00
PCEINPUT_SetInput ( i , " gamepad " , & input_buf [ i ] [ 0 ] ) ;
2014-06-18 20:20:38 +00:00
2012-06-03 15:48:14 +00:00
return game ;
}
2014-06-19 21:34:42 +00:00
void retro_unload_game ( void )
2012-06-03 15:48:14 +00:00
{
2014-06-19 22:08:27 +00:00
if ( ! MDFNGameInfo )
2013-01-19 09:22:57 +00:00
return ;
2012-11-29 22:21:44 +00:00
2014-06-19 21:34:42 +00:00
MDFN_FlushGameCheats ( 0 ) ;
MDFNGameInfo - > CloseGame ( ) ;
if ( MDFNGameInfo - > name )
free ( MDFNGameInfo - > name ) ;
MDFNGameInfo - > name = NULL ;
2012-06-03 15:48:14 +00:00
2014-06-19 21:34:42 +00:00
MDFNMP_Kill ( ) ;
2013-04-09 03:23:42 +00:00
2014-06-19 21:34:42 +00:00
MDFNGameInfo = NULL ;
# ifdef NEED_CD
for ( unsigned i = 0 ; i < CDInterfaces . size ( ) ; i + + )
delete CDInterfaces [ i ] ;
CDInterfaces . clear ( ) ;
# endif
}
2012-07-25 01:17:14 +00:00
2012-10-20 21:32:28 +00:00
static void update_input ( void )
2012-06-03 16:58:46 +00:00
{
2012-10-20 23:47:02 +00:00
static unsigned map [ ] = {
2012-11-22 20:03:38 +00:00
RETRO_DEVICE_ID_JOYPAD_A ,
2012-10-20 23:47:02 +00:00
RETRO_DEVICE_ID_JOYPAD_B ,
RETRO_DEVICE_ID_JOYPAD_SELECT ,
RETRO_DEVICE_ID_JOYPAD_START ,
RETRO_DEVICE_ID_JOYPAD_UP ,
RETRO_DEVICE_ID_JOYPAD_RIGHT ,
RETRO_DEVICE_ID_JOYPAD_DOWN ,
RETRO_DEVICE_ID_JOYPAD_LEFT ,
2012-11-22 20:03:38 +00:00
RETRO_DEVICE_ID_JOYPAD_Y ,
2012-10-20 23:47:02 +00:00
RETRO_DEVICE_ID_JOYPAD_X ,
RETRO_DEVICE_ID_JOYPAD_L ,
RETRO_DEVICE_ID_JOYPAD_R ,
RETRO_DEVICE_ID_JOYPAD_L2
} ;
2013-04-09 03:23:42 +00:00
for ( unsigned j = 0 ; j < MAX_PLAYERS ; j + + )
2012-10-20 23:47:02 +00:00
{
2013-04-09 03:23:42 +00:00
uint16_t input_state = 0 ;
for ( unsigned i = 0 ; i < MAX_BUTTONS ; i + + )
input_state | = input_state_cb ( j , RETRO_DEVICE_JOYPAD , 0 , map [ i ] ) ? ( 1 < < i ) : 0 ;
2012-10-20 23:47:02 +00:00
2013-04-09 03:23:42 +00:00
// Input data must be little endian.
input_buf [ j ] [ 0 ] = ( input_state > > 0 ) & 0xff ;
input_buf [ j ] [ 1 ] = ( input_state > > 8 ) & 0xff ;
2012-10-20 23:47:02 +00:00
}
2012-06-03 15:48:14 +00:00
}
2012-09-20 19:38:19 +00:00
static uint64_t video_frames , audio_frames ;
2014-06-18 19:55:15 +00:00
void retro_run ( void )
2012-06-03 15:48:14 +00:00
{
2014-06-18 19:55:15 +00:00
MDFNGI * curgame = ( MDFNGI * ) game ;
2012-11-29 22:21:44 +00:00
2012-06-03 15:48:14 +00:00
input_poll_cb ( ) ;
2012-06-03 16:58:46 +00:00
update_input ( ) ;
2012-06-03 15:48:14 +00:00
static int16_t sound_buf [ 0x10000 ] ;
2013-10-01 12:28:59 +00:00
static MDFN_Rect rects [ FB_MAX_HEIGHT ] ;
2012-06-16 13:07:18 +00:00
rects [ 0 ] . w = ~ 0 ;
2012-06-03 15:48:14 +00:00
2012-07-25 01:17:14 +00:00
EmulateSpecStruct spec = { 0 } ;
2012-06-03 15:48:14 +00:00
spec . surface = surf ;
spec . SoundRate = 44100 ;
spec . SoundBuf = sound_buf ;
spec . LineWidths = rects ;
spec . SoundBufMaxSize = sizeof ( sound_buf ) / 2 ;
spec . SoundVolume = 1.0 ;
spec . soundmultiplier = 1.0 ;
2012-11-16 14:12:25 +00:00
spec . SoundBufSize = 0 ;
spec . VideoFormatChanged = false ;
spec . SoundFormatChanged = false ;
2013-01-19 09:22:57 +00:00
if ( memcmp ( & last_pixel_format , & spec . surface - > format , sizeof ( MDFN_PixelFormat ) ) )
2012-11-16 14:12:25 +00:00
{
spec . VideoFormatChanged = TRUE ;
last_pixel_format = spec . surface - > format ;
}
2013-01-19 09:22:57 +00:00
if ( spec . SoundRate ! = last_sound_rate )
2012-11-16 14:12:25 +00:00
{
spec . SoundFormatChanged = true ;
last_sound_rate = spec . SoundRate ;
}
2014-06-19 22:08:27 +00:00
Emulate ( & spec ) ;
2012-11-16 14:12:25 +00:00
2012-11-29 22:21:44 +00:00
int16 * const SoundBuf = spec . SoundBuf + spec . SoundBufSizeALMS * curgame - > soundchan ;
2012-11-16 14:12:25 +00:00
int32 SoundBufSize = spec . SoundBufSize - spec . SoundBufSizeALMS ;
const int32 SoundBufMaxSize = spec . SoundBufMaxSize - spec . SoundBufSizeALMS ;
2012-06-03 15:48:14 +00:00
2012-11-16 14:12:25 +00:00
spec . SoundBufSize = spec . SoundBufSizeALMS + SoundBufSize ;
2012-06-03 15:48:14 +00:00
2012-11-21 01:27:23 +00:00
unsigned width = spec . DisplayRect . w ;
unsigned height = spec . DisplayRect . h ;
2012-10-20 21:56:43 +00:00
2013-02-23 23:45:47 +00:00
# if defined(WANT_32BPP)
2012-11-21 01:28:26 +00:00
const uint32_t * pix = surf - > pixels ;
2012-11-21 01:27:23 +00:00
video_cb ( pix , width , height , FB_WIDTH < < 2 ) ;
2012-10-22 12:34:14 +00:00
# elif defined(WANT_16BPP)
2012-10-20 23:47:02 +00:00
const uint16_t * pix = surf - > pixels16 ;
video_cb ( pix , width , height , FB_WIDTH < < 1 ) ;
2012-10-20 21:56:43 +00:00
# endif
2012-06-03 15:48:14 +00:00
2012-09-20 19:38:19 +00:00
video_frames + + ;
audio_frames + = spec . SoundBufSize ;
2012-06-03 15:48:14 +00:00
audio_batch_cb ( spec . SoundBuf , spec . SoundBufSize ) ;
2013-04-09 02:05:18 +00:00
bool updated = false ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE , & updated ) & & updated )
check_variables ( ) ;
2012-06-03 15:48:14 +00:00
}
void retro_get_system_info ( struct retro_system_info * info )
{
memset ( info , 0 , sizeof ( * info ) ) ;
2012-10-20 21:32:28 +00:00
info - > library_name = MEDNAFEN_CORE_NAME ;
2012-10-22 12:34:14 +00:00
info - > library_version = MEDNAFEN_CORE_VERSION ;
2012-06-03 15:48:14 +00:00
info - > need_fullpath = true ;
2012-10-20 21:56:43 +00:00
info - > valid_extensions = MEDNAFEN_CORE_EXTENSIONS ;
2012-10-20 23:47:02 +00:00
info - > block_extract = false ;
2012-06-03 15:48:14 +00:00
}
void retro_get_system_av_info ( struct retro_system_av_info * info )
{
memset ( info , 0 , sizeof ( * info ) ) ;
2013-10-01 12:28:59 +00:00
info - > timing . fps = MEDNAFEN_CORE_TIMING_FPS ;
2012-06-03 15:48:14 +00:00
info - > timing . sample_rate = 44100 ;
2012-10-20 21:56:43 +00:00
info - > geometry . base_width = MEDNAFEN_CORE_GEOMETRY_BASE_W ;
info - > geometry . base_height = MEDNAFEN_CORE_GEOMETRY_BASE_H ;
info - > geometry . max_width = MEDNAFEN_CORE_GEOMETRY_MAX_W ;
info - > geometry . max_height = MEDNAFEN_CORE_GEOMETRY_MAX_H ;
info - > geometry . aspect_ratio = MEDNAFEN_CORE_GEOMETRY_ASPECT_RATIO ;
2012-06-03 15:48:14 +00:00
}
2012-09-20 19:38:19 +00:00
void retro_deinit ( )
{
delete surf ;
surf = NULL ;
2013-12-17 01:24:08 +00:00
if ( log_cb )
{
log_cb ( RETRO_LOG_INFO , " [%s]: Samples / Frame: %.5f \n " ,
2014-06-19 22:08:27 +00:00
MEDNAFEN_CORE_NAME , ( double ) audio_frames / video_frames ) ;
2013-12-17 01:24:08 +00:00
log_cb ( RETRO_LOG_INFO , " [%s]: Estimated FPS: %.5f \n " ,
2014-06-19 22:08:27 +00:00
MEDNAFEN_CORE_NAME , ( double ) video_frames * 44100 / audio_frames ) ;
2013-12-17 01:24:08 +00:00
}
2012-09-20 19:38:19 +00:00
}
2012-06-03 15:48:14 +00:00
unsigned retro_get_region ( void )
{
2013-10-01 12:28:59 +00:00
return RETRO_REGION_NTSC ; // FIXME: Regions for other cores.
2012-06-03 15:48:14 +00:00
}
unsigned retro_api_version ( void )
{
return RETRO_API_VERSION ;
}
2012-07-25 01:17:14 +00:00
void retro_set_controller_port_device ( unsigned in_port , unsigned device )
{
2014-05-01 00:17:23 +00:00
MDFNGI * currgame = ( MDFNGI * ) game ;
if ( ! currgame )
2012-08-17 21:01:08 +00:00
return ;
2014-05-01 00:32:39 +00:00
switch ( device )
{
case RETRO_DEVICE_JOYPAD :
2014-06-19 22:08:27 +00:00
PCEINPUT_SetInput ( in_port , " gamepad " , & input_buf [ in_port ] [ 0 ] ) ;
2014-05-01 00:32:39 +00:00
break ;
case RETRO_DEVICE_MOUSE :
2014-06-19 22:08:27 +00:00
PCEINPUT_SetInput ( in_port , " mouse " , & input_buf [ in_port ] [ 0 ] ) ;
2014-05-01 00:32:39 +00:00
break ;
}
2012-07-25 01:17:14 +00:00
}
2012-06-03 15:48:14 +00:00
void retro_set_environment ( retro_environment_t cb )
{
environ_cb = cb ;
2013-04-09 02:05:18 +00:00
static const struct retro_variable vars [ ] = {
2014-06-20 20:49:22 +00:00
{ " pce_fast_cdimagecache " , " CD Image Cache (Restart); disabled|enabled " } ,
2013-04-09 02:05:18 +00:00
{ " pce_nospritelimit " , " No Sprite Limit; disabled|enabled " } ,
2013-05-24 15:37:36 +00:00
{ " pce_keepaspect " , " Keep Aspect; enabled|disabled " } ,
2014-06-05 16:06:15 +00:00
{ " pce_cddavolume " , " (CD) CDDA Volume; 0|10|20|30|40|50|60|70|80|90|100 " } ,
{ " pce_adpcmvolume " , " (CD) ADPCM Volume; 0|10|20|30|40|50|60|70|80|90|100 " } ,
{ " pce_cdpsgvolume " , " (CD) CD PSG Volume; 0|10|20|30|40|50|60|70|80|90|100 " } ,
2013-05-24 15:26:57 +00:00
{ " pce_cdspeed " , " (CD) CD Speed; 1|2|4|8 " } ,
2013-04-09 02:05:18 +00:00
{ NULL , NULL } ,
} ;
2014-05-01 00:43:04 +00:00
static const struct retro_controller_description pads [ ] = {
{ " PCE Joypad " , RETRO_DEVICE_JOYPAD } ,
{ " Mouse " , RETRO_DEVICE_MOUSE } ,
} ;
static const struct retro_controller_info ports [ ] = {
{ pads , 2 } ,
{ pads , 2 } ,
{ 0 } ,
} ;
2013-05-19 17:55:15 +00:00
cb ( RETRO_ENVIRONMENT_SET_VARIABLES , ( void * ) vars ) ;
2014-05-01 00:43:04 +00:00
environ_cb ( RETRO_ENVIRONMENT_SET_CONTROLLER_INFO , ( void * ) ports ) ;
2012-06-03 15:48:14 +00:00
}
void retro_set_audio_sample ( retro_audio_sample_t cb )
{
audio_cb = cb ;
}
void retro_set_audio_sample_batch ( retro_audio_sample_batch_t cb )
{
audio_batch_cb = cb ;
}
void retro_set_input_poll ( retro_input_poll_t cb )
{
input_poll_cb = cb ;
}
void retro_set_input_state ( retro_input_state_t cb )
{
input_state_cb = cb ;
}
void retro_set_video_refresh ( retro_video_refresh_t cb )
{
video_cb = cb ;
}
2012-10-20 23:47:02 +00:00
static size_t serialize_size ;
2012-06-03 15:48:14 +00:00
size_t retro_serialize_size ( void )
{
2014-04-20 19:44:56 +00:00
MDFNGI * curgame = ( MDFNGI * ) game ;
2012-10-21 01:46:12 +00:00
//if (serialize_size)
// return serialize_size;
2014-06-20 20:49:22 +00:00
if ( ! StateAction )
2012-10-21 01:46:12 +00:00
{
2013-12-17 01:24:08 +00:00
if ( log_cb )
2014-06-20 20:49:22 +00:00
log_cb ( RETRO_LOG_WARN , " [mednafen]: Module %s doesn't support save states. \n " , EmulatedPCE_Fast . shortname ) ;
2012-10-21 01:46:12 +00:00
return 0 ;
}
StateMem st ;
memset ( & st , 0 , sizeof ( st ) ) ;
2012-11-14 00:41:02 +00:00
if ( ! MDFNSS_SaveSM ( & st , 0 , 0 , NULL , NULL , NULL ) )
2012-10-21 01:46:12 +00:00
{
2013-12-17 01:24:08 +00:00
if ( log_cb )
2014-06-20 20:49:22 +00:00
log_cb ( RETRO_LOG_WARN , " [mednafen]: Module %s doesn't support save states. \n " , EmulatedPCE_Fast . shortname ) ;
2012-10-21 01:46:12 +00:00
return 0 ;
}
free ( st . data ) ;
return serialize_size = st . len ;
2012-06-03 15:48:14 +00:00
}
2012-10-21 01:46:12 +00:00
bool retro_serialize ( void * data , size_t size )
2012-06-03 15:48:14 +00:00
{
2012-10-21 01:46:12 +00:00
StateMem st ;
memset ( & st , 0 , sizeof ( st ) ) ;
st . data = ( uint8_t * ) data ;
st . malloced = size ;
2012-11-14 00:41:02 +00:00
return MDFNSS_SaveSM ( & st , 0 , 0 , NULL , NULL , NULL ) ;
2012-06-03 15:48:14 +00:00
}
2012-10-21 01:46:12 +00:00
bool retro_unserialize ( const void * data , size_t size )
2012-06-03 15:48:14 +00:00
{
2012-10-21 01:46:12 +00:00
StateMem st ;
memset ( & st , 0 , sizeof ( st ) ) ;
st . data = ( uint8_t * ) data ;
st . len = size ;
2012-11-14 00:41:02 +00:00
return MDFNSS_LoadSM ( & st , 0 , 0 ) ;
2012-06-03 15:48:14 +00:00
}
2014-06-20 17:54:30 +00:00
void * retro_get_memory_data ( unsigned type )
2012-06-03 15:48:14 +00:00
{
2014-06-20 17:54:30 +00:00
uint8_t * data ;
switch ( type )
{
case RETRO_MEMORY_SAVE_RAM :
if ( IsPopulous )
data = ( uint8_t * ) ( ROMSpace + 0x40 * 8192 ) ;
else
data = ( uint8_t * ) SaveRAM ;
break ;
default :
data = NULL ;
break ;
}
return data ;
2012-06-03 15:48:14 +00:00
}
2014-06-20 17:54:30 +00:00
size_t retro_get_memory_size ( unsigned type )
2012-06-03 15:48:14 +00:00
{
2014-06-20 17:54:30 +00:00
unsigned size ;
switch ( type )
{
case RETRO_MEMORY_SAVE_RAM :
if ( IsPopulous )
size = 32768 ;
else
size = 2048 ;
break ;
default :
size = 0 ;
break ;
}
return size ;
2012-06-03 15:48:14 +00:00
}
void retro_cheat_reset ( void )
{ }
void retro_cheat_set ( unsigned , bool , const char * )
{ }
2014-06-18 20:10:07 +00:00
MDFN_Thread * MDFND_CreateThread ( int ( * fn ) ( void * ) , void * data )
{
return ( MDFN_Thread * ) sthread_create ( ( void ( * ) ( void * ) ) fn , data ) ;
}
void MDFND_WaitThread ( MDFN_Thread * thr , int * val )
{
sthread_join ( ( sthread_t * ) thr ) ;
if ( val )
{
* val = 0 ;
fprintf ( stderr , " WaitThread relies on return value. \n " ) ;
}
}
void MDFND_KillThread ( MDFN_Thread * )
{
fprintf ( stderr , " Killing a thread is a BAD IDEA! \n " ) ;
}
MDFN_Mutex * MDFND_CreateMutex ( )
{
return ( MDFN_Mutex * ) slock_new ( ) ;
}
void MDFND_DestroyMutex ( MDFN_Mutex * lock )
{
slock_free ( ( slock_t * ) lock ) ;
}
int MDFND_LockMutex ( MDFN_Mutex * lock )
{
slock_lock ( ( slock_t * ) lock ) ;
return 0 ;
}
int MDFND_UnlockMutex ( MDFN_Mutex * lock )
{
slock_unlock ( ( slock_t * ) lock ) ;
return 0 ;
}
# ifdef _WIN32
static void sanitize_path ( std : : string & path )
{
size_t size = path . size ( ) ;
for ( size_t i = 0 ; i < size ; i + + )
if ( path [ i ] = = ' / ' )
path [ i ] = ' \\ ' ;
}
# endif
// Use a simpler approach to make sure that things go right for libretro.
std : : string MDFN_MakeFName ( MakeFName_Type type , int id1 , const char * cd1 )
{
char slash ;
# ifdef _WIN32
slash = ' \\ ' ;
# else
slash = ' / ' ;
# endif
std : : string ret ;
switch ( type )
{
case MDFNMKF_SAV :
ret = retro_save_directory + slash + retro_base_name +
std : : string ( " . " ) +
# ifndef _XBOX
md5_context : : asciistr ( MDFNGameInfo - > MD5 , 0 ) + std : : string ( " . " ) +
# endif
std : : string ( cd1 ) ;
break ;
case MDFNMKF_FIRMWARE :
ret = retro_base_directory + slash + std : : string ( cd1 ) ;
# ifdef _WIN32
2014-06-19 22:08:27 +00:00
sanitize_path ( ret ) ; // Because Windows path handling is mongoloid.
2014-06-18 20:10:07 +00:00
# endif
break ;
default :
break ;
}
if ( log_cb )
log_cb ( RETRO_LOG_INFO , " MDFN_MakeFName: %s \n " , ret . c_str ( ) ) ;
return ret ;
}
void MDFND_Message ( const char * str )
{
if ( log_cb )
log_cb ( RETRO_LOG_INFO , " %s \n " , str ) ;
}
void MDFND_MidSync ( const EmulateSpecStruct * )
{ }
void MDFN_MidLineUpdate ( EmulateSpecStruct * espec , int y )
{
//MDFND_MidLineUpdate(espec, y);
}
void MDFND_PrintError ( const char * err )
{
if ( log_cb )
log_cb ( RETRO_LOG_ERROR , " %s \n " , err ) ;
}
void MDFND_Sleep ( unsigned int time )
{
retro_sleep ( time ) ;
}
2014-06-19 21:34:42 +00:00
/* forward declarations */
extern void MDFND_DispMessage ( unsigned char * str ) ;
void MDFND_DispMessage ( unsigned char * str )
{
const char * strc = ( const char * ) str ;
struct retro_message msg =
{
strc ,
180
} ;
environ_cb ( RETRO_ENVIRONMENT_SET_MESSAGE , & msg ) ;
}
void MDFN_DispMessage ( const char * format , . . . )
{
struct retro_message msg ;
va_list ap ;
va_start ( ap , format ) ;
char * str = NULL ;
const char * strc = NULL ;
trio_vasprintf ( & str , format , ap ) ;
va_end ( ap ) ;
strc = str ;
msg . frames = 180 ;
msg . msg = strc ;
environ_cb ( RETRO_ENVIRONMENT_SET_MESSAGE , & msg ) ;
}
void MDFN_ResetMessages ( void )
{
}