2016-09-24 19:51:36 +00:00
# include <stdarg.h>
2019-07-30 01:47:01 +00:00
# include <complex>
2017-12-16 02:07:16 +00:00
# include <retro_miscellaneous.h>
# include <streams/file_stream.h>
# include <string/stdstring.h>
2017-12-16 02:12:36 +00:00
# include <encodings/crc32.h>
2017-12-16 02:07:16 +00:00
# include <libretro.h>
2012-06-03 15:48:14 +00:00
# include "mednafen/mednafen.h"
# include "mednafen/git.h"
# include "mednafen/general.h"
2015-10-03 06:08:31 +00:00
2012-06-03 15:48:14 +00:00
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"
2016-10-23 18:48:05 +00:00
# include "mednafen/settings-driver.h"
2014-06-19 21:10:59 +00:00
# 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"
2019-07-31 21:25:33 +00:00
# include "libretro_core_options.h"
2014-06-19 21:34:42 +00:00
# ifdef _MSC_VER
2014-06-24 23:57:10 +00:00
# include "mednafen/msvc_compat.h"
2014-06-19 21:34:42 +00:00
# endif
2016-07-18 07:32:52 +00:00
# define MEDNAFEN_CORE_NAME_MODULE "pce_fast"
2018-09-05 14:53:16 +00:00
# define MEDNAFEN_CORE_NAME "Beetle PCE Fast"
2016-07-18 07:32:52 +00:00
# define MEDNAFEN_CORE_VERSION "v0.9.38.7"
2017-08-05 17:47:05 +00:00
# define MEDNAFEN_CORE_EXTENSIONS "pce|cue|ccd|chd"
2016-07-18 07:32:52 +00:00
# define MEDNAFEN_CORE_TIMING_FPS 59.82
2019-11-10 21:36:57 +00:00
# define MEDNAFEN_CORE_GEOMETRY_BASE_W 256
2016-07-18 07:32:52 +00:00
# define MEDNAFEN_CORE_GEOMETRY_BASE_H 243
# define MEDNAFEN_CORE_GEOMETRY_MAX_W 512
# define MEDNAFEN_CORE_GEOMETRY_MAX_H 243
2016-10-16 09:59:18 +00:00
# define MEDNAFEN_CORE_GEOMETRY_ASPECT_RATIO (6.0 / 5.0)
2016-07-18 07:32:52 +00:00
# define FB_WIDTH 512
# define FB_HEIGHT 243
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
*/
static PCEFast_PSG * psg = NULL ;
extern ArcadeCard * arcade_card ; // Bah, lousy globals.
static Blip_Buffer sbuf [ 2 ] ;
bool PCE_ACEnabled ;
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 ;
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 ( BaseRAMRead )
{
2019-12-15 10:23:12 +00:00
return BaseRAM [ ( size_t ) A - ( 0xF8 * 8192 ) ] ;
2014-06-19 21:10:59 +00:00
}
static DECLFR ( BaseRAMRead_Mirrored )
{
return ( BaseRAM [ A & 0x1FFF ] ) ;
}
static DECLFW ( BaseRAMWrite )
{
2019-12-15 10:23:12 +00:00
BaseRAM [ ( size_t ) A - ( 0xF8 * 8192 ) ] = V ;
2014-06-19 21:10:59 +00:00
}
static DECLFW ( BaseRAMWrite_Mirrored )
{
BaseRAM [ A & 0x1FFF ] = V ;
}
static DECLFR ( IORead )
{
# include "mednafen/pce_fast/ioread.inc"
}
static DECLFW ( IOWrite )
{
A & = 0x1FFF ;
2019-12-14 17:21:27 +00:00
2014-06-19 21:10:59 +00:00
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 ;
2019-12-14 17:21:27 +00:00
case 6 :
2014-06-19 21:10:59 +00:00
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 )
2018-01-03 13:55:06 +00:00
MDFN_printf ( " CD-DA Volume: %d%% \n " , ( int ) ( 100 * cd_settings . CDDA_Volume ) ) ;
2014-06-19 21:10:59 +00:00
if ( cd_settings . ADPCM_Volume ! = 1.0 )
2018-01-03 13:55:06 +00:00
MDFN_printf ( " ADPCM Volume: %d%% \n " , ( int ) ( 100 * cd_settings . ADPCM_Volume ) ) ;
2014-06-19 21:10:59 +00:00
return ( PCECD_Init ( & cd_settings , PCECDIRQCB , PCE_MASTER_CLOCK , pce_overclocked , & sbuf [ 0 ] , & sbuf [ 1 ] ) ) ;
}
static int LoadCommon ( void ) ;
static void LoadCommonPre ( void ) ;
static int Load ( const char * name , MDFNFILE * fp )
{
uint32 headerlen = 0 ;
uint32 r_size ;
LoadCommonPre ( ) ;
{
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 + + )
{
2019-12-15 10:23:12 +00:00
HuCPU . PCERead [ x ] = PCEBusRead ;
HuCPU . PCEWrite [ x ] = PCENullWrite ;
2014-06-19 21:10:59 +00:00
}
2017-12-16 02:12:36 +00:00
uint32 crc = encoding_crc32 ( 0 , GET_FDATA_PTR ( fp ) + headerlen , GET_FSIZE_PTR ( fp ) - headerlen ) ;
2017-12-01 16:54:33 +00:00
2019-12-15 10:23:12 +00:00
HuCLoad ( GET_FDATA_PTR ( fp ) + headerlen , GET_FSIZE_PTR ( fp ) - headerlen , crc ) ;
2014-06-19 21:10:59 +00:00
2017-12-02 07:36:37 +00:00
if ( crc = = 0xfae0fc60 )
2017-12-01 17:02:15 +00:00
OrderOfGriffonFix = true ;
2014-06-19 21:10:59 +00:00
return ( LoadCommon ( ) ) ;
}
static void LoadCommonPre ( void )
{
2019-12-15 10:23:12 +00:00
HuC6280_Init ( ) ;
2014-06-19 21:10:59 +00:00
// FIXME: Make these globals less global!
pce_overclocked = MDFN_GetSettingUI ( " pce_fast.ocmultiplier " ) ;
PCE_ACEnabled = MDFN_GetSettingB ( " pce_fast.arcadecard " ) ;
if ( pce_overclocked > 1 )
2018-01-03 13:55:06 +00:00
MDFN_printf ( " CPU overclock: %dx \n " , pce_overclocked ) ;
2014-06-19 21:10:59 +00:00
if ( MDFN_GetSettingUI ( " pce_fast.cdspeed " ) > 1 )
2018-01-03 13:55:06 +00:00
MDFN_printf ( " CD-ROM speed: %ux \n " , ( unsigned int ) MDFN_GetSettingUI ( " pce_fast.cdspeed " ) ) ;
2014-06-19 21:10:59 +00:00
for ( int x = 0 ; x < 0x100 ; x + + )
{
2019-12-15 10:23:12 +00:00
HuCPU . PCERead [ x ] = PCEBusRead ;
HuCPU . PCEWrite [ x ] = PCENullWrite ;
2014-06-19 21:10:59 +00:00
}
MDFNMP_Init ( 1024 , ( 1 < < 21 ) / 1024 ) ;
}
static int LoadCommon ( void )
2019-12-14 17:21:27 +00:00
{
2014-06-22 03:52:15 +00:00
VDC_Init ( false ) ;
2014-06-19 21:10:59 +00:00
{
2019-12-15 10:23:12 +00:00
HuCPU . PCERead [ 0xF8 ] = BaseRAMRead ;
HuCPU . PCERead [ 0xF9 ] = HuCPU . PCERead [ 0xFA ] = HuCPU . PCERead [ 0xFB ] = BaseRAMRead_Mirrored ;
2014-06-19 21:10:59 +00:00
2019-12-15 10:23:12 +00:00
HuCPU . PCEWrite [ 0xF8 ] = BaseRAMWrite ;
HuCPU . PCEWrite [ 0xF9 ] = HuCPU . PCEWrite [ 0xFA ] = HuCPU . PCEWrite [ 0xFB ] = BaseRAMWrite_Mirrored ;
2014-06-19 21:10:59 +00:00
for ( int x = 0xf8 ; x < 0xfb ; x + + )
2019-12-15 10:23:12 +00:00
HuCPU . FastMap [ x ] = & BaseRAM [ 0 ] ;
2014-06-19 21:10:59 +00:00
2019-12-15 10:23:12 +00:00
HuCPU . PCERead [ 0xFF ] = IORead ;
2014-06-19 21:10:59 +00:00
}
2014-06-22 03:52:15 +00:00
MDFNMP_AddRAM ( 8192 , 0xf8 * 8192 , BaseRAM ) ;
2014-06-19 21:10:59 +00:00
2019-12-15 10:23:12 +00:00
HuCPU . PCEWrite [ 0xFF ] = IOWrite ;
2014-06-19 21:10:59 +00:00
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 )
{
2018-01-03 13:55:06 +00:00
MDFN_printf ( " CD PSG Volume: %d%% \n " , cdpsgvolume ) ;
2014-06-19 21:10:59 +00:00
}
psg - > SetVolume ( 0.678 * cdpsgvolume / 100 ) ;
}
PCEINPUT_Init ( ) ;
PCE_Power ( ) ;
2016-08-09 05:38:20 +00:00
#if 0
2014-06-22 03:52:15 +00:00
MDFNGameInfo - > LayerNames = " Background \0 Sprites \0 " ;
2016-08-09 05:38:20 +00:00
# endif
2014-06-19 21:10:59 +00:00
MDFNGameInfo - > fps = ( uint32 ) ( ( double ) 7159090.90909090 / 455 / 263 * 65536 * 256 ) ;
return ( 1 ) ;
}
static int LoadCD ( std : : vector < CDIF * > * CDInterfaces )
{
std : : string bios_path = MDFN_MakeFName ( MDFNMKF_FIRMWARE , 0 , MDFN_GetSettingS ( " pce_fast.cdbios " ) . c_str ( ) ) ;
LoadCommonPre ( ) ;
if ( ! HuCLoadCD ( bios_path . c_str ( ) ) )
return ( 0 ) ;
PCECD_Drive_SetDisc ( true , NULL , true ) ;
PCECD_Drive_SetDisc ( false , ( * CDInterfaces ) [ 0 ] , true ) ;
return ( LoadCommon ( ) ) ;
}
2014-06-20 21:11:19 +00:00
static void Cleanup_PCE ( void )
{
HuC_Close ( ) ;
VDC_Close ( ) ;
if ( psg )
delete psg ;
psg = NULL ;
}
2014-06-19 21:10:59 +00:00
static void CloseGame ( void )
{
2014-06-20 21:11:19 +00:00
Cleanup_PCE ( ) ;
2014-06-19 21:10:59 +00:00
}
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 ;
2019-12-14 17:21:27 +00:00
2014-06-19 21:10:59 +00:00
nf . Rprec = 5 ;
nf . Gprec = 6 ;
nf . Bprec = 5 ;
nf . Aprec = 8 ;
espec - > surface - > SetFormat ( nf , false ) ;
espec - > VideoFormatChanged = firstcat ;
firstcat = false ;
}
# endif
if ( espec - > SoundFormatChanged )
{
for ( int y = 0 ; y < 2 ; y + + )
{
2016-08-10 03:57:58 +00:00
Blip_Buffer_set_sample_rate ( & sbuf [ y ] ,
espec - > SoundRate ? espec - > SoundRate : 44100 , 50 ) ;
Blip_Buffer_set_clock_rate ( & sbuf [ y ] , ( long ) ( PCE_MASTER_CLOCK / 3 ) ) ;
Blip_Buffer_bass_freq ( & sbuf [ y ] , 10 ) ;
2014-06-19 21:10:59 +00:00
}
}
2014-06-20 21:11:19 +00:00
VDC_RunFrame ( espec , false ) ;
2014-06-19 21:10:59 +00:00
if ( PCE_IsCD )
{
PCECD_Run ( HuCPU . timestamp * 3 ) ;
}
psg - > EndFrame ( HuCPU . timestamp / pce_overclocked ) ;
if ( espec - > SoundBuf )
{
for ( int y = 0 ; y < 2 ; y + + )
{
2016-08-10 03:57:58 +00:00
Blip_Buffer_end_frame ( & sbuf [ y ] , HuCPU . timestamp / pce_overclocked ) ;
espec - > SoundBufSize = Blip_Buffer_read_samples ( & sbuf [ y ] , espec - > SoundBuf + y ,
espec - > SoundBufMaxSize ) ;
2014-06-19 21:10:59 +00:00
}
}
espec - > MasterCycles = HuCPU . timestamp * 3 ;
INPUT_FixTS ( ) ;
HuC6280_ResetTS ( ) ;
if ( PCE_IsCD )
PCECD_ResetTS ( ) ;
}
2016-08-09 05:38:20 +00:00
int StateAction ( StateMem * sm , int load , int data_only )
2014-06-19 21:10:59 +00:00
{
SFORMAT StateRegs [ ] =
{
2014-06-22 03:52:15 +00:00
SFARRAY ( BaseRAM , 8192 ) ,
2014-06-19 21:10:59 +00:00
SFVAR ( PCEIODataBuffer ) ,
SFEND
} ;
//for(int i = 8192; i < 32768; i++)
// if(BaseRAM[i] != 0xFF)
// printf("%d %02x\n", i, BaseRAM[i]);
2017-12-20 05:00:58 +00:00
int ret = MDFNSS_StateAction ( sm , load , data_only , StateRegs , " MAIN " , false ) ;
2014-06-19 21:10:59 +00:00
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 ) ) ;
2014-06-22 03:52:15 +00:00
for ( int i = 8192 ; i < 32768 ; i + + )
BaseRAM [ i ] = 0xFF ;
2014-06-19 21:10:59 +00:00
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 ;
}
}
2019-12-14 17:21:27 +00:00
static MDFNSetting PCESettings [ ] =
2014-06-19 21:10:59 +00:00
{
2016-08-12 16:44:57 +00:00
{ " pce_fast.slstart " , MDFNSF_NOFLAGS , " First rendered scanline. " , NULL , MDFNST_UINT , " 4 " , " 0 " , " 239 " } ,
{ " pce_fast.slend " , MDFNSF_NOFLAGS , " Last rendered scanline. " , NULL , MDFNST_UINT , " 235 " , " 0 " , " 239 " } ,
{ " pce_fast.mouse_sensitivity " , MDFNSF_NOFLAGS , " Mouse sensitivity. " , NULL , MDFNST_FLOAT , " 0.50 " , NULL , NULL , NULL , PCEINPUT_SettingChanged } ,
{ " pce_fast.disable_softreset " , MDFNSF_NOFLAGS , " If set, when RUN+SEL are pressed simultaneously, disable both buttons temporarily. " , NULL , MDFNST_BOOL , " 0 " , NULL , NULL , NULL , PCEINPUT_SettingChanged } ,
{ " pce_fast.arcadecard " , MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE , " Enable Arcade Card emulation. " , NULL , MDFNST_BOOL , " 1 " } ,
{ " pce_fast.ocmultiplier " , MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE , " CPU overclock multiplier. " , NULL , MDFNST_UINT , " 1 " , " 1 " , " 100 " } ,
{ " pce_fast.cdspeed " , MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE , " CD-ROM data transfer speed multiplier. " , NULL , MDFNST_UINT , " 1 " , " 1 " , " 100 " } ,
{ " pce_fast.nospritelimit " , MDFNSF_NOFLAGS , " Remove 16-sprites-per-scanline hardware limit. " , NULL , MDFNST_BOOL , " 0 " } ,
2016-12-19 12:09:56 +00:00
{ " pce_fast.hoverscan " , MDFNSF_NOFLAGS , " Reduce 352 pixels width overscan. " , NULL , MDFNST_UINT , " 300 " , " 300 " , " 352 " } ,
2016-08-12 16:44:57 +00:00
{ " pce_fast.cdbios " , MDFNSF_EMU_STATE , " Path to the CD BIOS " , NULL , MDFNST_STRING , " syscard3.pce " } ,
{ " pce_fast.adpcmlp " , MDFNSF_NOFLAGS , " Enable dynamic ADPCM lowpass filter. " , NULL , MDFNST_BOOL , " 0 " } ,
{ " pce_fast.cdpsgvolume " , MDFNSF_NOFLAGS , " PSG volume when playing a CD game. " , NULL , MDFNST_UINT , " 100 " , " 0 " , " 200 " } ,
{ " pce_fast.cddavolume " , MDFNSF_NOFLAGS , " CD-DA volume. " , NULL , MDFNST_UINT , " 100 " , " 0 " , " 200 " } ,
{ " pce_fast.adpcmvolume " , MDFNSF_NOFLAGS , " ADPCM volume. " , NULL , MDFNST_UINT , " 100 " , " 0 " , " 200 " } ,
2014-06-19 21:10:59 +00:00
{ NULL }
} ;
2016-08-09 05:38:20 +00:00
uint8 MemRead ( uint32 addr )
2014-06-19 21:10:59 +00:00
{
2019-12-15 10:23:12 +00:00
return ( HuCPU . PCERead [ ( addr / 8192 ) & 0xFF ] ( addr ) ) ;
2014-06-19 21:10:59 +00:00
}
static const FileExtensionSpecStruct KnownExtensions [ ] =
{
2016-08-12 16:44:57 +00:00
{ " .pce " , " PC Engine ROM Image " } ,
2014-06-19 21:10:59 +00:00
{ 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 ) ;
}
}
2014-06-20 21:11:19 +00:00
static void Cleanup ( void )
{
if ( arcade_card )
delete arcade_card ;
arcade_card = NULL ;
if ( PCE_IsCD )
PCECD_Close ( ) ;
if ( HuCROM )
2015-07-23 18:08:26 +00:00
free ( HuCROM ) ;
2014-06-20 21:11:19 +00:00
HuCROM = NULL ;
}
2019-12-15 10:23:12 +00:00
int HuCLoad ( const uint8 * data , uint32 len , uint32 crc32 )
2014-06-20 17:54:30 +00:00
{
2019-12-15 10:23:12 +00:00
uint32 crc = 0 ;
2014-06-20 17:54:30 +00:00
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 ;
2018-01-03 13:55:06 +00:00
MDFN_printf ( " ROM: %dKiB \n " , ( len + 1023 ) / 1024 ) ;
2019-12-15 10:23:12 +00:00
MDFN_printf ( " ROM CRC32: 0x%04x \n " , crc32 ) ;
2014-06-20 17:54:30 +00:00
2015-07-23 18:08:26 +00:00
if ( ! ( HuCROM = ( uint8 * ) malloc ( m_len ) ) )
2014-06-20 17:54:30 +00:00
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 + + )
{
2019-12-15 10:23:12 +00:00
HuCPU . FastMap [ x ] = & ROMSpace [ x * 8192 ] ;
HuCPU . PCERead [ x ] = HuCRead ;
2014-06-20 17:54:30 +00:00
}
if ( ! memcmp ( HuCROM + 0x1F26 , " POPULOUS " , strlen ( " POPULOUS " ) ) )
{
uint8 * PopRAM = ROMSpace + 0x40 * 8192 ;
2019-12-14 17:21:27 +00:00
2014-06-20 17:54:30 +00:00
memset ( PopRAM , 0xFF , 32768 ) ;
IsPopulous = 1 ;
MDFN_printf ( " Populous \n " ) ;
for ( int x = 0x40 ; x < 0x44 ; x + + )
{
2019-12-15 10:23:12 +00:00
HuCPU . FastMap [ x ] = & PopRAM [ ( x & 3 ) * 8192 ] ;
HuCPU . PCERead [ x ] = HuCRead ;
HuCPU . PCEWrite [ x ] = HuCRAMWrite ;
2014-06-20 17:54:30 +00:00
}
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.
2019-12-15 10:23:12 +00:00
HuCPU . PCEWrite [ 0xF7 ] = SaveRAMWrite ;
HuCPU . PCERead [ 0xF7 ] = SaveRAMRead ;
2014-06-20 17:54:30 +00:00
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 + + )
{
2019-12-15 10:23:12 +00:00
HuCPU . PCERead [ x ] = HuCSF2Read ;
2014-06-20 17:54:30 +00:00
}
2019-12-15 10:23:12 +00:00
HuCPU . PCEWrite [ 0 ] = HuCSF2Write ;
2014-06-20 17:54:30 +00:00
MDFN_printf ( " Street Fighter 2 Mapper \n " ) ;
HuCSF2Latch = 0 ;
}
return ( 1 ) ;
}
2019-12-14 17:21:27 +00:00
2014-06-20 17:54:30 +00:00
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 [ ] =
{
2016-08-12 16:44:57 +00:00
{ " .pce " , " PC Engine ROM Image " } ,
{ " .bin " , " PC Engine ROM Image " } ,
{ " .bios " , " BIOS Image " } ,
2014-06-20 17:54:30 +00:00
{ NULL , NULL }
} ;
2016-07-21 03:20:31 +00:00
MDFNFILE * fp = file_open ( bios_path ) ;
2014-06-20 17:54:30 +00:00
2016-07-21 03:20:31 +00:00
if ( ! fp )
2014-06-20 17:54:30 +00:00
return ( 0 ) ;
memset ( ROMSpace , 0xFF , 262144 ) ;
2016-07-21 03:20:31 +00:00
memcpy ( ROMSpace , GET_FDATA_PTR ( fp ) + ( GET_FSIZE_PTR ( fp ) & 512 ) , ( ( GET_FSIZE_PTR ( fp ) & ~ 512 ) > 262144 ) ? 262144 : ( GET_FSIZE_PTR ( fp ) & ~ 512 ) ) ;
2014-06-20 17:54:30 +00:00
2016-07-21 03:20:31 +00:00
if ( fp )
file_close ( fp ) ;
fp = NULL ;
2014-06-20 17:54:30 +00:00
PCE_IsCD = 1 ;
PCE_InitCD ( ) ;
2019-12-14 17:21:27 +00:00
MDFN_printf ( " Arcade Card Emulation: %s \n " , PCE_ACEnabled ? " Enabled " : " Disabled " ) ;
2014-06-20 17:54:30 +00:00
for ( int x = 0 ; x < 0x40 ; x + + )
{
2019-12-15 10:23:12 +00:00
HuCPU . FastMap [ x ] = & ROMSpace [ x * 8192 ] ;
HuCPU . PCERead [ x ] = HuCRead ;
2014-06-20 17:54:30 +00:00
}
for ( int x = 0x68 ; x < 0x88 ; x + + )
{
2019-12-15 10:23:12 +00:00
HuCPU . FastMap [ x ] = & ROMSpace [ x * 8192 ] ;
HuCPU . PCERead [ x ] = HuCRead ;
HuCPU . PCEWrite [ x ] = HuCRAMWrite ;
2014-06-20 17:54:30 +00:00
}
2019-12-15 10:23:12 +00:00
HuCPU . PCEWrite [ 0x80 ] = HuCRAMWriteCDSpecial ; // Hyper Dyne Special hack
2014-06-20 17:54:30 +00:00
MDFNMP_AddRAM ( 262144 , 0x68 * 8192 , ROMSpace + 0x68 * 8192 ) ;
if ( PCE_ACEnabled )
{
2014-06-20 21:11:19 +00:00
if ( ! ( arcade_card = new ArcadeCard ( ) ) )
{
2018-01-03 13:55:06 +00:00
MDFN_PrintError ( " Error creating %s object. \n " , " ArcadeCard " ) ;
2014-06-20 21:11:19 +00:00
Cleanup ( ) ;
return ( 0 ) ;
}
for ( int x = 0x40 ; x < 0x44 ; x + + )
{
2019-12-15 10:23:12 +00:00
HuCPU . PCERead [ x ] = ACPhysRead ;
HuCPU . PCEWrite [ x ] = ACPhysWrite ;
2014-06-20 21:11:19 +00:00
}
2014-06-20 17:54:30 +00:00
}
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.
2019-12-15 10:23:12 +00:00
HuCPU . PCEWrite [ 0xF7 ] = SaveRAMWrite ;
HuCPU . PCERead [ 0xF7 ] = SaveRAMRead ;
2014-06-20 17:54:30 +00:00
MDFNMP_AddRAM ( 2048 , 0xF7 * 8192 , SaveRAM ) ;
return ( 1 ) ;
}
int HuC_StateAction ( StateMem * sm , int load , int data_only )
{
2019-12-14 17:21:27 +00:00
SFORMAT StateRegs [ ] =
2014-06-20 17:54:30 +00:00
{
SFARRAY ( ROMSpace + 0x40 * 8192 , IsPopulous ? 32768 : 0 ) ,
SFARRAY ( SaveRAM , IsPopulous ? 0 : 2048 ) ,
SFARRAY ( ROMSpace + 0x68 * 8192 , PCE_IsCD ? 262144 : 0 ) ,
SFVAR ( HuCSF2Latch ) ,
SFEND
} ;
2017-12-20 05:00:58 +00:00
int ret = MDFNSS_StateAction ( sm , load , data_only , StateRegs , " HuC " , false ) ;
2014-06-20 17:54:30 +00:00
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 ) ;
}
2014-06-20 21:11:19 +00:00
void HuC_Close ( void )
2014-06-20 17:54:30 +00:00
{
2014-06-20 21:11:19 +00:00
Cleanup ( ) ;
2014-06-20 17:54:30 +00:00
}
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 =
{
PCESettings ,
MDFN_MASTERCLOCK_FIXED ( PCE_MASTER_CLOCK ) ,
0 ,
true , // Multires possible?
0 , // lcm_width
2019-12-14 17:21:27 +00:00
0 , // lcm_height
2014-06-19 21:10:59 +00:00
NULL , // Dummy
2016-07-18 07:32:52 +00:00
MEDNAFEN_CORE_GEOMETRY_BASE_W , // Nominal width
MEDNAFEN_CORE_GEOMETRY_BASE_H , // Nominal height
2014-06-19 21:10:59 +00:00
2016-07-18 07:32:52 +00:00
FB_WIDTH , // Framebuffer width
FB_HEIGHT , // Framebuffer height
2014-06-19 21:10:59 +00:00
2 , // Number of output sound channels
} ;
2016-08-14 13:01:30 +00:00
static bool ReadM3U ( std : : vector < std : : string > & file_list , std : : string path , unsigned depth = 0 )
2014-06-19 21:34:42 +00:00
{
2015-10-01 02:21:52 +00:00
std : : string dir_path ;
char linebuf [ 2048 ] ;
FILE * fp = fopen ( path . c_str ( ) , " rb " ) ;
2014-06-19 21:34:42 +00:00
2016-08-14 13:01:30 +00:00
if ( ! fp )
return false ;
2014-06-19 21:34:42 +00:00
2015-10-01 02:21:52 +00:00
MDFN_GetFilePathComponents ( path , & dir_path ) ;
2014-06-19 21:34:42 +00:00
2015-10-01 02:21:52 +00:00
while ( fgets ( linebuf , sizeof ( linebuf ) , fp ) )
{
std : : string efp ;
2014-06-19 21:34:42 +00:00
2015-10-01 02:21:52 +00:00
if ( linebuf [ 0 ] = = ' # ' )
continue ;
2016-06-09 06:12:51 +00:00
string_trim_whitespace_right ( linebuf ) ;
2015-10-01 02:21:52 +00:00
if ( linebuf [ 0 ] = = 0 )
continue ;
2014-06-19 21:34:42 +00:00
2015-10-01 02:21:52 +00:00
efp = MDFN_EvalFIP ( dir_path , std : : string ( linebuf ) ) ;
2014-06-19 21:34:42 +00:00
2015-10-01 02:21:52 +00:00
if ( efp . size ( ) > = 4 & & efp . substr ( efp . size ( ) - 4 ) = = " .m3u " )
{
if ( efp = = path )
2016-08-14 13:01:30 +00:00
{
log_cb ( RETRO_LOG_ERROR , " M3U at \" %s \" references self. \n " , efp . c_str ( ) ) ;
fclose ( fp ) ;
return false ;
}
2014-06-19 21:34:42 +00:00
2015-10-01 02:21:52 +00:00
if ( depth = = 99 )
2016-08-14 13:01:30 +00:00
{
log_cb ( RETRO_LOG_ERROR , " M3U load recursion too deep! \n " ) ;
fclose ( fp ) ;
return false ;
}
2015-10-01 02:21:52 +00:00
ReadM3U ( file_list , efp , depth + + ) ;
}
else
file_list . push_back ( efp ) ;
}
fclose ( fp ) ;
2016-08-14 13:01:30 +00:00
return true ;
2014-06-19 21:34:42 +00:00
}
static std : : vector < CDIF * > CDInterfaces ; // FIXME: Cleanup on error out.
// TODO: LoadCommon()
2016-08-12 09:27:28 +00:00
static MDFNGI * MDFNI_LoadCD ( const char * devicename )
2014-06-19 21:34:42 +00:00
{
2016-08-14 13:01:30 +00:00
bool ret = false ;
log_cb ( RETRO_LOG_INFO , " Loading %s... \n \n " , devicename ) ;
2014-06-19 21:34:42 +00:00
2016-08-14 13:01:30 +00:00
if ( devicename & & strlen ( devicename ) > 4 & & ! strcasecmp ( devicename + strlen ( devicename ) - 4 , " .m3u " ) )
2016-08-12 09:27:28 +00:00
{
2016-08-14 13:01:30 +00:00
std : : vector < std : : string > file_list ;
2014-06-19 21:34:42 +00:00
2016-08-14 13:01:30 +00:00
if ( ReadM3U ( file_list , devicename ) )
ret = true ;
2014-06-19 21:34:42 +00:00
2016-08-14 13:01:30 +00:00
for ( unsigned i = 0 ; i < file_list . size ( ) ; i + + )
{
CDIF * cdif = CDIF_Open ( file_list [ i ] . c_str ( ) , false ) ;
CDInterfaces . push_back ( cdif ) ;
2016-08-12 09:27:28 +00:00
}
2016-08-14 13:01:30 +00:00
}
else
{
CDIF * cdif = CDIF_Open ( devicename , false ) ;
if ( cdif )
2016-08-12 09:27:28 +00:00
{
2016-08-14 13:01:30 +00:00
ret = true ;
2016-08-12 09:27:28 +00:00
CDInterfaces . push_back ( cdif ) ;
}
}
2016-08-14 13:01:30 +00:00
if ( ! ret )
2014-06-19 21:34:42 +00:00
{
2016-08-14 13:01:30 +00:00
log_cb ( RETRO_LOG_ERROR , " Error opening CD. \n " ) ;
return NULL ;
2014-06-19 21:34:42 +00:00
}
2016-08-14 13:01:30 +00:00
/* Print out a track list for all discs. */
2016-08-12 09:27:28 +00:00
MDFN_indent ( 1 ) ;
for ( unsigned i = 0 ; i < CDInterfaces . size ( ) ; i + + )
{
TOC toc ;
2014-06-19 21:34:42 +00:00
2016-08-12 09:27:28 +00:00
CDInterfaces [ i ] - > ReadTOC ( & toc ) ;
2014-06-19 21:34:42 +00:00
2018-01-03 13:55:06 +00:00
MDFN_printf ( " CD %d Layout: \n " , i + 1 ) ;
2016-08-12 09:27:28 +00:00
MDFN_indent ( 1 ) ;
2014-06-19 21:34:42 +00:00
2016-08-12 09:27:28 +00:00
for ( int32 track = toc . first_track ; track < = toc . last_track ; track + + )
{
2018-01-03 13:55:06 +00:00
MDFN_printf ( " Track %2d, LBA: %6d %s \n " , track , toc . tracks [ track ] . lba , ( toc . tracks [ track ] . control & 0x4 ) ? " DATA " : " AUDIO " ) ;
2016-08-12 09:27:28 +00:00
}
2014-06-19 21:34:42 +00:00
2016-08-12 09:27:28 +00:00
MDFN_printf ( " Leadout: %6d \n " , toc . tracks [ 100 ] . lba ) ;
MDFN_indent ( - 1 ) ;
MDFN_printf ( " \n " ) ;
}
MDFN_indent ( - 1 ) ;
2014-06-19 21:34:42 +00:00
2016-08-12 09:27:28 +00:00
MDFN_printf ( " Using module: pce_fast. \n " ) ;
2014-06-19 21:34:42 +00:00
2016-08-12 09:27:28 +00:00
if ( ! ( LoadCD ( & CDInterfaces ) ) )
{
for ( unsigned i = 0 ; i < CDInterfaces . size ( ) ; i + + )
delete CDInterfaces [ i ] ;
CDInterfaces . clear ( ) ;
2014-06-19 21:34:42 +00:00
2016-08-12 09:27:28 +00:00
MDFNGameInfo = NULL ;
return ( 0 ) ;
}
2014-06-19 21:34:42 +00:00
2016-08-12 09:27:28 +00:00
//MDFNI_SetLayerEnableMask(~0ULL);
2014-06-19 21:34:42 +00:00
2016-08-12 09:27:28 +00:00
MDFN_LoadGameCheats ( NULL ) ;
MDFNMP_InstallReadPatches ( ) ;
2014-06-19 21:34:42 +00:00
2016-08-12 09:27:28 +00:00
return ( MDFNGameInfo ) ;
2014-06-19 21:34:42 +00:00
}
2016-08-12 09:27:28 +00:00
static MDFNGI * MDFNI_LoadGame ( const char * name )
2014-06-19 21:34:42 +00:00
{
2016-07-21 03:20:31 +00:00
std : : vector < FileExtensionSpecStruct > valid_iae ;
MDFNFILE * GameFile = NULL ;
2014-06-19 21:34:42 +00:00
MDFNGameInfo = & EmulatedPCE_Fast ;
2017-08-05 17:47:05 +00:00
if ( strlen ( name ) > 4 & & ( ! strcasecmp ( name + strlen ( name ) - 4 , " .cue " ) | | ! strcasecmp ( name + strlen ( name ) - 4 , " .ccd " ) | | ! strcasecmp ( name + strlen ( name ) - 4 , " .chd " ) | | ! strcasecmp ( name + strlen ( name ) - 4 , " .toc " ) | | ! strcasecmp ( name + strlen ( name ) - 4 , " .m3u " ) ) )
2016-08-12 09:27:28 +00:00
return ( MDFNI_LoadCD ( name ) ) ;
2014-06-19 21:34:42 +00:00
2018-01-03 13:55:06 +00:00
MDFN_printf ( " Loading %s... \n " , name ) ;
2014-06-19 21:34:42 +00:00
2016-07-21 03:20:31 +00:00
MDFN_indent ( 1 ) ;
2014-06-19 21:34:42 +00:00
2016-07-21 03:20:31 +00:00
// Construct a NULL-delimited list of known file extensions for MDFN_fopen()
2016-08-09 05:38:20 +00:00
const FileExtensionSpecStruct * curexts = KnownExtensions ;
2014-06-19 21:34:42 +00:00
while ( curexts - > extension & & curexts - > description )
{
valid_iae . push_back ( * curexts ) ;
curexts + + ;
}
2016-07-21 03:20:31 +00:00
GameFile = file_open ( name ) ;
2014-06-19 21:34:42 +00:00
2016-07-21 03:20:31 +00:00
if ( ! GameFile )
goto error ;
2014-06-19 21:34:42 +00:00
2018-01-03 13:55:06 +00:00
MDFN_printf ( " Using module: pce_fast. \n \n " ) ;
2016-07-21 03:20:31 +00:00
MDFN_indent ( 1 ) ;
2014-06-19 21:34:42 +00:00
2016-07-21 03:20:31 +00:00
//
// Load per-game settings
//
// Maybe we should make a "pgcfg" subdir, and automatically load all files in it?
// End load per-game settings
//
2014-06-19 21:34:42 +00:00
2016-08-09 05:38:20 +00:00
if ( Load ( name , GameFile ) < = 0 )
2016-07-21 03:20:31 +00:00
goto error ;
2014-06-19 21:34:42 +00:00
2016-07-21 03:20:31 +00:00
MDFN_LoadGameCheats ( NULL ) ;
MDFNMP_InstallReadPatches ( ) ;
2014-06-19 21:34:42 +00:00
2016-07-21 03:20:31 +00:00
MDFN_indent ( - 2 ) ;
2014-06-19 21:34:42 +00:00
return ( MDFNGameInfo ) ;
2016-07-21 03:20:31 +00:00
error :
if ( GameFile )
file_close ( GameFile ) ;
MDFNGameInfo = NULL ;
return NULL ;
2014-06-19 21:34:42 +00:00
}
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 ;
2019-07-26 02:29:28 +00:00
temp = ( char * ) malloc ( 4096 * sizeof ( char ) ) ;
2016-06-06 00:09:18 +00:00
vsnprintf ( temp , 4096 , format_temp , ap ) ;
2014-06-19 21:34:42 +00:00
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 ) ;
2019-07-26 02:29:28 +00:00
temp = ( char * ) malloc ( 4096 * sizeof ( char ) ) ;
2016-06-06 00:09:18 +00:00
vsnprintf ( temp , 4096 , format , ap ) ;
2014-06-19 21:34:42 +00:00
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 ) ;
2019-07-26 02:29:28 +00:00
temp = ( char * ) malloc ( 4096 * sizeof ( char ) ) ;
2016-06-06 00:09:18 +00:00
vsnprintf ( temp , 4096 , format , ap ) ;
2014-06-19 21:34:42 +00:00
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 ;
2012-11-16 14:12:25 +00:00
static double last_sound_rate ;
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 ;
2013-04-27 14:40:24 +00:00
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 21:32:28 +00:00
static void check_system_specs ( void )
{
2014-06-23 01:12:05 +00:00
unsigned level = 5 ;
2012-10-22 12:34:14 +00:00
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 ;
2019-12-14 17:21:27 +00:00
else
2014-01-02 01:50:09 +00:00
log_cb = NULL ;
2016-08-07 13:38:04 +00:00
CDUtility_Init ( ) ;
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
}
2019-12-14 17:21:27 +00:00
2012-10-22 12:34:14 +00:00
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
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 ;
2019-12-14 17:21:27 +00:00
2016-05-15 05:15:00 +00:00
bool yes = true ;
environ_cb ( RETRO_ENVIRONMENT_SET_SUPPORT_ACHIEVEMENTS , & yes ) ;
2019-12-14 17:21:27 +00:00
2014-06-25 18:16:22 +00:00
setting_initial_scanline = 0 ;
setting_last_scanline = 242 ;
2014-04-21 22:25:50 +00:00
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 ;
}
}
2016-09-24 19:51:36 +00:00
# define MAX_PLAYERS 5
2017-12-09 16:10:42 +00:00
# define MAX_BUTTONS 15
2019-12-28 01:33:42 +00:00
static uint8_t input_buf [ MAX_PLAYERS ] [ 5 ] = { } ;
2016-09-24 19:51:36 +00:00
// Array to keep track of whether a given player's button is turbo
static int turbo_enable [ MAX_PLAYERS ] [ MAX_BUTTONS ] = { } ;
// Array to keep track of each buttons turbo status
static int turbo_counter [ MAX_PLAYERS ] [ MAX_BUTTONS ] = { } ;
// The number of frames between each firing of a turbo button
static int Turbo_Delay ;
2017-01-15 02:38:35 +00:00
static int Turbo_Toggling = 1 ;
2017-12-09 16:10:42 +00:00
static bool turbo_toggle_alt = false ;
2017-01-15 02:38:35 +00:00
static int turbo_toggle_down [ MAX_PLAYERS ] [ MAX_BUTTONS ] = { } ;
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 ;
}
2017-07-11 21:42:11 +00:00
var . key = " pce_fast_cdbios " ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
{
if ( strcmp ( var . value , " System Card 3 " ) = = 0 )
setting_pce_fast_cdbios = " syscard3.pce " ;
else if ( strcmp ( var . value , " System Card 2 " ) = = 0 )
setting_pce_fast_cdbios = " syscard2.pce " ;
else if ( strcmp ( var . value , " System Card 1 " ) = = 0 )
setting_pce_fast_cdbios = " syscard1.pce " ;
else if ( strcmp ( var . value , " Games Express " ) = = 0 )
setting_pce_fast_cdbios = " gexpress.pce " ;
2018-06-07 16:01:20 +00:00
else if ( strcmp ( var . value , " System Card 3 US " ) = = 0 )
setting_pce_fast_cdbios = " syscard3u.pce " ;
else if ( strcmp ( var . value , " System Card 2 US " ) = = 0 )
setting_pce_fast_cdbios = " syscard2u.pce " ;
2019-12-14 17:21:27 +00:00
2017-07-11 21:42:11 +00:00
}
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 ;
}
2019-12-14 17:21:27 +00:00
2016-10-28 21:26:57 +00:00
var . key = " pce_ocmultiplier " ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
{
setting_pce_overclocked = atoi ( var . value ) ;
}
2019-12-14 17:21:27 +00:00
2016-10-14 23:04:45 +00:00
var . key = " pce_hoverscan " ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
{
2016-12-19 12:09:56 +00:00
setting_pce_hoverscan = atoi ( var . value ) ;
2016-10-14 23:04:45 +00:00
}
2019-12-14 17:21:27 +00:00
2014-06-25 18:03:28 +00:00
var . key = " pce_initial_scanline " ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
{
2014-06-25 18:16:22 +00:00
setting_initial_scanline = atoi ( var . value ) ;
2014-06-25 18:03:28 +00:00
}
var . key = " pce_last_scanline " ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
{
2014-06-25 18:16:22 +00:00
setting_last_scanline = atoi ( var . value ) ;
2014-06-25 18:03:28 +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 )
{
2015-07-23 18:03:21 +00:00
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
2017-01-15 02:38:35 +00:00
// Set Turbo_Toggling
2019-12-14 13:40:27 +00:00
var . key = " pce_turbo_toggling " ;
2017-01-15 02:38:35 +00:00
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
{
if ( strcmp ( var . value , " enabled " ) = = 0 )
Turbo_Toggling = 1 ;
else
Turbo_Toggling = 0 ;
}
2019-12-14 17:21:27 +00:00
// Set TURBO_DELAY
2019-12-14 13:40:27 +00:00
var . key = " pce_turbo_delay " ;
2019-12-14 17:21:27 +00:00
2016-09-24 19:51:36 +00:00
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
{
2019-12-14 17:21:27 +00:00
Turbo_Delay = atoi ( var . value ) ;
2016-09-24 19:51:36 +00:00
}
2017-12-09 16:10:42 +00:00
// False sets turbo hotkey X/Y, true assigns hotkey to L3/R3
var . key = " pce_turbo_toggle_hotkey " ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE , & var ) & & var . value )
{
if ( strcmp ( var . value , " enabled " ) = = 0 )
turbo_toggle_alt = true ;
else
turbo_toggle_alt = false ;
}
2016-09-24 19:51:36 +00:00
}
2013-04-09 03:23:42 +00:00
2012-06-03 15:48:14 +00:00
bool retro_load_game ( const struct retro_game_info * info )
{
2014-12-04 16:20:00 +00:00
struct retro_input_descriptor desc [ ] = {
2016-09-24 19:51:36 +00:00
# define button_ids(INDEX) \
{ INDEX , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_LEFT , " D-Pad Left " } , \
{ INDEX , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_UP , " D-Pad Up " } , \
{ INDEX , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_DOWN , " D-Pad Down " } , \
{ INDEX , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_RIGHT , " D-Pad Right " } , \
{ INDEX , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_B , " II " } , \
{ INDEX , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_A , " I " } , \
{ INDEX , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_X , " IV " } , \
{ INDEX , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_Y , " III " } , \
{ INDEX , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_L , " V " } , \
{ INDEX , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_R , " VI " } , \
{ INDEX , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_L2 , " Mode Switch " } , \
{ INDEX , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_SELECT , " Select " } , \
{ INDEX , RETRO_DEVICE_JOYPAD , 0 , RETRO_DEVICE_ID_JOYPAD_START , " Run " } ,
button_ids ( 0 )
button_ids ( 1 )
button_ids ( 2 )
button_ids ( 3 )
button_ids ( 4 )
2019-12-14 17:21:27 +00:00
2014-12-04 16:20:00 +00:00
{ 0 } ,
} ;
2017-01-24 14:42:19 +00:00
if ( ! info | | failed_init )
return false ;
2014-12-04 16:20:00 +00:00
environ_cb ( RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS , desc ) ;
2012-10-13 13:31:49 +00:00
2014-06-20 20:49:22 +00:00
check_variables ( ) ;
2016-08-12 09:27:28 +00:00
game = MDFNI_LoadGame ( info - > path ) ;
2012-09-23 09:52:47 +00:00
if ( ! game )
return false ;
2015-07-25 02:15:26 +00:00
surf = ( MDFN_Surface * ) calloc ( 1 , sizeof ( * surf ) ) ;
if ( ! surf )
return false ;
2019-12-14 17:21:27 +00:00
2015-07-25 02:15:26 +00:00
surf - > width = FB_WIDTH ;
surf - > height = FB_HEIGHT ;
surf - > pitch = FB_WIDTH ;
2016-07-18 07:32:52 +00:00
surf - > pixels = ( uint16_t * ) calloc ( 2 , FB_WIDTH * FB_HEIGHT ) ;
2015-07-25 02:15:26 +00:00
if ( ! surf - > pixels )
{
free ( surf ) ;
return false ;
}
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 + + )
2019-12-28 01:33:42 +00:00
PCEINPUT_SetInput ( i , " gamepad " , ( uint8_t * ) & input_buf [ i ] [ 0 ] ) ;
2014-06-18 20:20:38 +00:00
2015-07-25 02:15:26 +00:00
VDC_SetPixelFormat ( ) ;
2019-11-22 14:02:55 +00:00
struct retro_memory_descriptor descs [ 8 ] ;
struct retro_memory_map mmaps ;
int i = 0 ;
memset ( descs , 0 , sizeof ( descs ) ) ;
descs [ i ] . ptr = ( uint8_t * ) BaseRAM ;
descs [ i ] . start = 0xf8 * 8192 ;
descs [ i ] . len = 8192 ;
descs [ i ] . select = 0xFFFFE000 ;
i + + ;
if ( IsPopulous )
{
descs [ i ] . ptr = ( uint8_t * ) ( ROMSpace + 0x40 * 8192 ) ;
descs [ i ] . start = 0x40 * 8192 ;
descs [ i ] . len = 8192 * 4 ;
i + + ;
}
else
{
descs [ i ] . ptr = ( uint8_t * ) SaveRAM ;
descs [ i ] . start = 0xf7 * 8192 ;
descs [ i ] . len = 2048 ;
i + + ;
}
if ( PCE_IsCD )
{
// Super System Card RAM
descs [ i ] . ptr = ( uint8_t * ) ( ROMSpace + 0x68 * 8192 ) ;
descs [ i ] . start = 0x68 * 8192 ;
descs [ i ] . len = 8192 * 24 ;
descs [ i ] . select = 0xFFFD0000 ;
i + + ;
2019-12-14 17:21:27 +00:00
2019-11-22 14:02:55 +00:00
// CD RAM
descs [ i ] . ptr = ( uint8_t * ) ( ROMSpace + 0x80 * 8192 ) ;
descs [ i ] . start = 0x80 * 8192 ;
descs [ i ] . len = 8192 * 8 ;
descs [ i ] . select = 0xFFFF0000 ;
i + + ;
}
mmaps . descriptors = descs ;
mmaps . num_descriptors = i ;
environ_cb ( RETRO_ENVIRONMENT_SET_MEMORY_MAPS , & mmaps ) ;
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 ) ;
2016-08-09 05:38:20 +00:00
CloseGame ( ) ;
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 ;
for ( unsigned i = 0 ; i < CDInterfaces . size ( ) ; i + + )
delete CDInterfaces [ i ] ;
CDInterfaces . clear ( ) ;
}
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
{
2017-12-09 16:10:42 +00:00
static int turbo_map [ ] = { - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , 1 , 0 , - 1 , - 1 , - 1 , - 1 , - 1 } ;
static int turbo_map_alt [ ] = { - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , 1 , 0 } ;
2019-12-14 17:21:27 +00:00
int * turbo_map_selected = ( ! turbo_toggle_alt ? turbo_map : turbo_map_alt ) ;
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 ,
2017-12-09 16:10:42 +00:00
RETRO_DEVICE_ID_JOYPAD_L2 ,
RETRO_DEVICE_ID_JOYPAD_L3 ,
RETRO_DEVICE_ID_JOYPAD_R3
2012-10-20 23:47:02 +00:00
} ;
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 ;
2019-12-14 17:21:27 +00:00
// read normal inputs
2013-04-09 03:23:42 +00:00
for ( unsigned i = 0 ; i < MAX_BUTTONS ; i + + )
2017-03-26 16:44:08 +00:00
{
2019-12-14 17:21:27 +00:00
input_state | = input_state_cb ( j , RETRO_DEVICE_JOYPAD , 0 , map [ i ] ) ? ( 1 < < i ) : 0 ;
// handle turbo buttons
if ( turbo_enable [ j ] [ i ] = = 1 ) // Check whether a given button is turbo-capable
2016-09-24 19:51:36 +00:00
{
2019-12-14 17:21:27 +00:00
if ( input_state & ( 1 < < i ) )
2016-09-24 19:51:36 +00:00
{
2019-12-14 17:21:27 +00:00
if ( turbo_counter [ j ] [ i ] < 2 ) // Some PCE games needs 2 frames to react to button presses, so
input_state | = 1 < < i ; // trigger turbo button at counter 0 and 1
else
input_state & = ~ ( 1 < < i ) ;
turbo_counter [ j ] [ i ] + + ; // Counter is incremented by 1
if ( turbo_counter [ j ] [ i ] > Turbo_Delay ) // When the counter exceeds turbo delay, reset counter to zero
turbo_counter [ j ] [ i ] = 0 ;
2016-09-24 19:51:36 +00:00
}
else
2019-12-14 17:21:27 +00:00
turbo_counter [ j ] [ i ] = 0 ; // Reset counter if button is not pressed.
2016-09-24 19:51:36 +00:00
}
2019-12-14 17:21:27 +00:00
else
turbo_counter [ j ] [ i ] = 0 ; // Reset counter if button is not pressed.
// handle 2/6 button mode switching
if ( turbo_map_selected [ i ] ! = - 1 & & Turbo_Toggling & & ! AVPad6Enabled [ j ] )
2017-01-15 02:38:35 +00:00
{
if ( input_state_cb ( j , RETRO_DEVICE_JOYPAD , 0 , map [ i ] ) )
{
if ( turbo_toggle_down [ j ] [ i ] = = 0 )
{
turbo_toggle_down [ j ] [ i ] = 1 ;
2019-12-14 17:21:27 +00:00
turbo_enable [ j ] [ turbo_map_selected [ i ] ] = turbo_enable [ j ] [ turbo_map_selected [ i ] ] ^ 1 ;
2017-12-09 16:10:42 +00:00
MDFN_DispMessage ( " Pad %i Button %s Turbo %s " , j + 1 ,
i = = ( ! turbo_toggle_alt ? 9 : 14 ) ? " I " : " II " ,
2019-12-14 17:21:27 +00:00
turbo_enable [ j ] [ turbo_map_selected [ i ] ] ? " ON " : " OFF " ) ;
2017-01-15 02:38:35 +00:00
}
}
else turbo_toggle_down [ j ] [ i ] = 0 ;
}
2017-03-26 16:44:08 +00:00
}
2017-01-15 02:38:35 +00:00
2017-03-26 16:44:08 +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 ;
2016-10-23 17:21:31 +00:00
void update_geometry ( unsigned width , unsigned height )
{
struct retro_system_av_info system_av_info ;
system_av_info . geometry . base_width = width ;
system_av_info . geometry . base_height = height ;
2017-08-04 07:01:41 +00:00
system_av_info . geometry . max_width = MEDNAFEN_CORE_GEOMETRY_MAX_W ;
system_av_info . geometry . max_height = MEDNAFEN_CORE_GEOMETRY_MAX_H ;
2019-11-10 21:36:57 +00:00
system_av_info . geometry . aspect_ratio = MEDNAFEN_CORE_GEOMETRY_ASPECT_RATIO * ( ( float ) MEDNAFEN_CORE_GEOMETRY_BASE_H / height ) ;
2016-10-23 17:21:31 +00:00
environ_cb ( RETRO_ENVIRONMENT_SET_GEOMETRY , & system_av_info ) ;
}
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 ] ;
2016-10-13 05:03:18 +00:00
static int32_t rects [ FB_HEIGHT ] ;
2016-10-23 17:50:07 +00:00
static unsigned width , height ;
2016-10-23 17:48:26 +00:00
bool resolution_changed = false ;
2014-06-20 21:11:19 +00:00
rects [ 0 ] = ~ 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 ( 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
2016-10-23 17:48:26 +00:00
if ( width ! = spec . DisplayRect . w | | height ! = spec . DisplayRect . h )
resolution_changed = true ;
width = spec . DisplayRect . w ;
height = spec . DisplayRect . h ;
2016-07-18 07:32:52 +00:00
video_cb ( surf - > pixels + surf - > pitch * spec . DisplayRect . y , width , height , FB_WIDTH * 2 ) ;
2012-09-20 19:38:19 +00:00
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 ;
2016-10-23 17:48:26 +00:00
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE , & updated ) & & updated )
2016-10-23 17:38:05 +00:00
{
2013-04-09 02:05:18 +00:00
check_variables ( ) ;
2016-10-16 09:59:18 +00:00
if ( PCE_IsCD ) {
psg - > SetVolume ( 0.678 * setting_pce_fast_cdpsgvolume / 100 ) ;
}
2016-10-23 18:48:05 +00:00
update_geometry ( width , height ) ;
2016-10-16 12:55:04 +00:00
}
2019-12-14 17:21:27 +00:00
2016-10-23 17:48:26 +00:00
if ( resolution_changed )
update_geometry ( width , height ) ;
video_frames + + ;
audio_frames + = spec . SoundBufSize ;
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 ;
2016-12-09 23:22:00 +00:00
# ifndef GIT_VERSION
# define GIT_VERSION ""
# endif
info - > library_version = MEDNAFEN_CORE_VERSION GIT_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 ( )
{
2015-07-25 02:15:26 +00:00
if ( surf )
free ( surf ) ;
2012-09-20 19:38:19 +00:00
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:32:39 +00:00
switch ( device )
{
case RETRO_DEVICE_JOYPAD :
2019-12-28 01:33:42 +00:00
PCEINPUT_SetInput ( in_port , " gamepad " , ( uint8_t * ) & input_buf [ in_port ] [ 0 ] ) ;
2014-05-01 00:32:39 +00:00
break ;
case RETRO_DEVICE_MOUSE :
2019-12-28 01:33:42 +00:00
PCEINPUT_SetInput ( in_port , " mouse " , ( uint8_t * ) & 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 )
{
2017-12-16 02:07:16 +00:00
struct retro_vfs_interface_info vfs_iface_info ;
2012-06-03 15:48:14 +00:00
environ_cb = cb ;
2013-04-09 02:05:18 +00:00
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 [ ] = {
2019-12-28 01:33:42 +00:00
{ pads , 2 } ,
{ pads , 2 } ,
{ pads , 2 } ,
2014-05-01 00:43:04 +00:00
{ pads , 2 } ,
{ pads , 2 } ,
{ 0 } ,
} ;
2019-07-31 21:25:33 +00:00
libretro_set_core_options ( cb ) ;
2014-05-01 00:43:04 +00:00
environ_cb ( RETRO_ENVIRONMENT_SET_CONTROLLER_INFO , ( void * ) ports ) ;
2017-12-16 02:07:16 +00:00
vfs_iface_info . required_interface_version = 1 ;
vfs_iface_info . iface = NULL ;
if ( environ_cb ( RETRO_ENVIRONMENT_GET_VFS_INTERFACE , & vfs_iface_info ) )
filestream_vfs_init ( & vfs_iface_info ) ;
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 )
{
2012-10-21 01:46:12 +00:00
StateMem st ;
2017-12-17 17:25:05 +00:00
st . data = NULL ;
st . loc = 0 ;
st . len = 0 ;
st . malloced = 0 ;
st . initial_malloc = 0 ;
2012-10-21 01:46:12 +00:00
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
return 0 ;
free ( st . data ) ;
2017-12-17 17:25:05 +00:00
2012-10-21 01:46:12 +00:00
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 ;
2017-12-17 17:25:05 +00:00
bool ret = false ;
uint8_t * _dat = ( uint8_t * ) malloc ( size ) ;
if ( ! _dat )
return false ;
/* Mednafen can realloc the buffer so we need to ensure this is safe. */
st . data = _dat ;
st . loc = 0 ;
st . len = 0 ;
st . malloced = size ;
st . initial_malloc = 0 ;
ret = MDFNSS_SaveSM ( & st , 0 , 0 , NULL , NULL , NULL ) ;
memcpy ( data , st . data , size ) ;
free ( st . data ) ;
2012-10-21 01:46:12 +00:00
2017-12-17 17:25:05 +00:00
return ret ;
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 ;
2017-12-17 17:43:51 +00:00
st . data = ( uint8_t * ) data ;
st . loc = 0 ;
st . len = size ;
st . malloced = 0 ;
st . initial_malloc = 0 ;
2012-10-21 01:46:12 +00:00
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
switch ( type )
{
case RETRO_MEMORY_SAVE_RAM :
if ( IsPopulous )
2015-07-29 16:07:30 +00:00
return ( uint8_t * ) ( ROMSpace + 0x40 * 8192 ) ;
return ( uint8_t * ) SaveRAM ;
2016-05-15 03:57:22 +00:00
case RETRO_MEMORY_SYSTEM_RAM :
return BaseRAM ;
2014-06-20 17:54:30 +00:00
default :
break ;
}
2015-07-29 16:07:30 +00:00
return NULL ;
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
switch ( type )
{
case RETRO_MEMORY_SAVE_RAM :
if ( IsPopulous )
2015-07-29 16:07:30 +00:00
return 32768 ;
return 2048 ;
2016-05-15 03:57:22 +00:00
case RETRO_MEMORY_SYSTEM_RAM :
2019-11-22 14:02:55 +00:00
return 8192 ;
2014-06-20 17:54:30 +00:00
default :
break ;
}
2015-07-29 16:07:30 +00:00
return 0 ;
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
# 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_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 ;
2019-12-14 17:21:27 +00:00
default :
2014-06-18 20:10:07 +00:00
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_PrintError ( const char * err )
{
if ( log_cb )
log_cb ( RETRO_LOG_ERROR , " %s \n " , err ) ;
}
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 ) ;
2019-07-29 17:31:15 +00:00
free ( str ) ;
2014-06-19 21:34:42 +00:00
}
void MDFN_DispMessage ( const char * format , . . . )
{
va_list ap ;
2019-07-26 02:45:52 +00:00
struct retro_message msg ;
2014-06-19 21:34:42 +00:00
const char * strc = NULL ;
2019-07-26 02:45:52 +00:00
char * str = ( char * ) malloc ( 4096 * sizeof ( char ) ) ;
va_start ( ap , format ) ;
2014-06-19 21:34:42 +00:00
2016-06-06 01:25:53 +00:00
vsnprintf ( str , 4096 , format , ap ) ;
2014-06-19 21:34:42 +00:00
va_end ( ap ) ;
2019-07-26 02:45:52 +00:00
strc = str ;
2014-06-19 21:34:42 +00:00
msg . frames = 180 ;
2019-07-26 02:45:52 +00:00
msg . msg = strc ;
2014-06-19 21:34:42 +00:00
environ_cb ( RETRO_ENVIRONMENT_SET_MESSAGE , & msg ) ;
2019-07-26 02:45:52 +00:00
free ( str ) ;
2014-06-19 21:34:42 +00:00
}